From cd08e8076b5cc67ba4f68b0a1bbe92031b0789a9 Mon Sep 17 00:00:00 2001
From: dg <dg@51575b47-30f0-44d4-a5cc-537603b46e54>
Date: Sun, 12 Feb 2012 21:28:42 +0000
Subject: [PATCH] Weapons now (mostly) have three stats: damage, maximum
 accuracy (used in checkHit()), and critical power (replaces the default 1.5x
 crit multiplier). Item tooltips much easier to read Weapon tooltips display
 useful information, such as how much damage the weapon will actually do.
 (This needs further improvement, as it doesn't account for percentage damage
 increases and decreases, such as those imposed by shield wall or offhand
 penalties) Quivers and shot pouches are now non-consumable items, but require
 reloading using the new 'Reload' talent. Shields are much more active and
 focus on damage mitigation. Riposte now works with a Shield's Block talent
 Staff, shield, bow, sling, and ammo egos mostly rewritten. Resolver for egos
 has been changed to centralize default ego value information for ease of
 balancing. Items can now grant talents (passive or active) Use talents dialog
 now displays passive talents, so that item-granted passives show up
 someplace.

git-svn-id: http://svn.net-core.org/repos/t-engine4@4842 51575b47-30f0-44d4-a5cc-537603b46e54
---
 game/engines/default/engine/Projectile.lua    |   2 +-
 game/modules/tome/ai/tactical.lua             |  15 +-
 game/modules/tome/class/Actor.lua             |  98 ++-
 game/modules/tome/class/Object.lua            | 467 ++++++++++----
 game/modules/tome/class/PlayerDisplay.lua     |   5 +-
 game/modules/tome/class/interface/Archery.lua | 126 ++--
 game/modules/tome/class/interface/Combat.lua  | 189 ++++--
 .../tome/class/interface/PlayerDumpJSON.lua   |  10 +-
 .../tome/class/interface/TooltipsData.lua     |  15 +-
 game/modules/tome/class/uiset/Minimalist.lua  |   2 +-
 .../tome/data/birth/classes/warrior.lua       |   5 +-
 .../modules/tome/data/chats/command-staff.lua | 269 ++++++++
 game/modules/tome/data/chats/ward.lua         |  84 +++
 game/modules/tome/data/damage_types.lua       |  85 ++-
 game/modules/tome/data/general/npcs/ant.lua   |   2 +-
 .../data/general/npcs/aquatic_critter.lua     |   2 +-
 game/modules/tome/data/general/npcs/bear.lua  |   2 +-
 .../modules/tome/data/general/npcs/canine.lua |   2 +-
 .../tome/data/general/npcs/cold-drake.lua     |   2 +-
 .../modules/tome/data/general/npcs/feline.lua |  10 +-
 .../tome/data/general/npcs/fire-drake.lua     |   2 +-
 game/modules/tome/data/general/npcs/ghoul.lua |   4 +-
 .../tome/data/general/npcs/gwelgoroth.lua     |   2 +-
 .../data/general/npcs/multihued-drake.lua     |   2 +-
 game/modules/tome/data/general/npcs/ritch.lua |   2 +-
 .../tome/data/general/npcs/sandworm.lua       |   2 +-
 .../tome/data/general/npcs/snow-giant.lua     |   2 +-
 .../modules/tome/data/general/npcs/spider.lua |  10 +-
 .../tome/data/general/npcs/storm-drake.lua    |   2 +-
 .../tome/data/general/npcs/telugoroth.lua     |  10 +-
 game/modules/tome/data/general/npcs/troll.lua |   2 +-
 .../tome/data/general/npcs/vampire.lua        |   2 +-
 game/modules/tome/data/general/npcs/xorn.lua  |   2 +-
 .../tome/data/general/objects/2haxes.lua      |  53 +-
 .../tome/data/general/objects/2hmaces.lua     |  53 +-
 .../tome/data/general/objects/2hswords.lua    |  51 +-
 .../tome/data/general/objects/2htridents.lua  |  50 +-
 .../tome/data/general/objects/axes.lua        |  49 +-
 .../objects/boss-artifacts-far-east.lua       |   7 +-
 .../data/general/objects/boss-artifacts.lua   | 128 ++--
 .../tome/data/general/objects/bows.lua        | 158 +++--
 .../tome/data/general/objects/egos/ammo.lua   | 226 +++++--
 .../data/general/objects/egos/amulets.lua     | 174 +++---
 .../tome/data/general/objects/egos/armor.lua  | 185 +++---
 .../tome/data/general/objects/egos/belt.lua   | 178 +++---
 .../tome/data/general/objects/egos/boots.lua  | 132 ++--
 .../tome/data/general/objects/egos/bow.lua    |  81 +--
 .../tome/data/general/objects/egos/cloak.lua  | 175 +++---
 .../tome/data/general/objects/egos/digger.lua | 100 +--
 .../tome/data/general/objects/egos/gloves.lua | 274 ++++-----
 .../data/general/objects/egos/heavy-armor.lua |  22 +-
 .../tome/data/general/objects/egos/helm.lua   | 185 +++---
 .../data/general/objects/egos/light-armor.lua |   8 +-
 .../data/general/objects/egos/light-boots.lua |   2 +-
 .../tome/data/general/objects/egos/lite.lua   | 122 ++--
 .../general/objects/egos/massive-armor.lua    |  24 +-
 .../tome/data/general/objects/egos/ranged.lua | 277 +++++++++
 .../tome/data/general/objects/egos/rings.lua  | 201 +++---
 .../tome/data/general/objects/egos/robe.lua   | 222 +++----
 .../tome/data/general/objects/egos/shield.lua | 284 +++++----
 .../tome/data/general/objects/egos/sling.lua  |  81 +--
 .../tome/data/general/objects/egos/staves.lua | 575 ++++++++----------
 .../tome/data/general/objects/egos/weapon.lua | 248 ++++----
 .../data/general/objects/egos/wizard-hat.lua  | 130 ++--
 .../tome/data/general/objects/gauntlets.lua   |  37 +-
 .../tome/data/general/objects/gloves.lua      |  34 +-
 .../tome/data/general/objects/knifes.lua      |  53 +-
 .../tome/data/general/objects/maces.lua       |  49 +-
 .../data/general/objects/quest-artifacts.lua  |  18 +-
 .../tome/data/general/objects/shields.lua     |  80 +--
 .../tome/data/general/objects/slings.lua      | 154 +++--
 .../tome/data/general/objects/staves.lua      |  84 ++-
 .../tome/data/general/objects/swords.lua      |  49 +-
 .../tome/data/general/objects/whips.lua       |   3 +-
 .../objects/world-artifacts-far-east.lua      |   6 +-
 .../data/general/objects/world-artifacts.lua  | 327 +++++-----
 .../tome/data/gfx/effects/counterstrike.png   | Bin 0 -> 2275 bytes
 game/modules/tome/data/gfx/particles/ward.lua |  53 ++
 game/modules/tome/data/gfx/talents/block.png  | Bin 0 -> 4274 bytes
 .../tome/data/gfx/talents/bloodflow.png       | Bin 0 -> 3295 bytes
 .../tome/data/gfx/talents/command_staff.png   | Bin 0 -> 3803 bytes
 .../gfx/talents/elemental_retribution.png     | Bin 0 -> 4320 bytes
 .../tome/data/gfx/talents/fearscape_fog.png   | Bin 0 -> 3100 bytes
 .../tome/data/gfx/talents/lifebind.png        | Bin 0 -> 2214 bytes
 .../tome/data/gfx/talents/perception.png      | Bin 0 -> 3049 bytes
 game/modules/tome/data/gfx/talents/reload.png | Bin 0 -> 4773 bytes
 .../tome/data/gfx/talents/savagery.png        | Bin 0 -> 3767 bytes
 .../tome/data/gfx/talents/soul_drain.png      | Bin 0 -> 4903 bytes
 game/modules/tome/data/gfx/talents/ward.png   | Bin 0 -> 3552 bytes
 .../tome/data/talents/celestial/light.lua     |   2 +-
 .../tome/data/talents/chronomancy/energy.lua  |   2 +-
 .../tome/data/talents/chronomancy/matter.lua  |   2 +-
 .../tome/data/talents/chronomancy/paradox.lua |   2 +-
 .../talents/chronomancy/spacetime-folding.lua |   2 +-
 .../talents/chronomancy/spacetime-weaving.lua |   4 +-
 .../data/talents/chronomancy/timetravel.lua   |  22 +-
 .../tome/data/talents/corruptions/blight.lua  |   2 +-
 .../tome/data/talents/cunning/stealth.lua     |   6 +-
 .../tome/data/talents/gifts/earthen-vines.lua |   2 +-
 .../data/talents/gifts/summon-distance.lua    |   4 +-
 .../tome/data/talents/gifts/summon-melee.lua  |   6 +-
 .../data/talents/gifts/summon-utility.lua     |   2 +-
 .../tome/data/talents/misc/horrors.lua        |   2 +-
 .../tome/data/talents/misc/inscriptions.lua   |   8 +-
 game/modules/tome/data/talents/misc/item.lua  | 491 +++++++++++++++
 game/modules/tome/data/talents/misc/misc.lua  |   3 +
 game/modules/tome/data/talents/misc/races.lua |   2 +-
 .../tome/data/talents/psionic/other.lua       |  19 +-
 .../spells/advanced-necrotic-minions.lua      |   8 +-
 .../tome/data/talents/spells/conveyance.lua   |   4 +-
 .../tome/data/talents/spells/golemancy.lua    |   2 +-
 .../data/talents/spells/necrotic-minions.lua  |  14 +-
 .../tome/data/talents/spells/staff-combat.lua |   9 +-
 .../tome/data/talents/techniques/2hweapon.lua |   2 +-
 .../tome/data/talents/techniques/archery.lua  |   3 +
 .../tome/data/talents/techniques/bow.lua      |  12 +-
 .../talents/techniques/combat-training.lua    |  26 +-
 .../talents/techniques/finishing-moves.lua    |   2 +-
 .../tome/data/talents/techniques/sling.lua    |  13 +-
 .../talents/techniques/unarmed-discipline.lua |   2 +-
 .../data/talents/techniques/weaponshield.lua  |  15 +-
 .../tome/data/timed_effects/magical.lua       |  82 +++
 .../tome/data/timed_effects/mental.lua        |  41 +-
 .../modules/tome/data/timed_effects/other.lua |  31 +-
 .../tome/data/timed_effects/physical.lua      |  72 ++-
 .../modules/tome/data/zones/arena/objects.lua |  24 +-
 .../tome/data/zones/deep-bellow/npcs.lua      |   2 +-
 .../tome/data/zones/high-peak/objects.lua     |  34 +-
 .../tome/data/zones/norgos-lair/npcs.lua      |   2 +-
 .../tome/data/zones/old-forest/npcs.lua       |   2 +-
 .../tome/data/zones/paradox-plane/objects.lua |  11 +-
 .../tome/data/zones/ritch-tunnels/npcs.lua    |   4 +-
 .../tome/data/zones/telmur/objects.lua        |  13 +-
 .../data/zones/tutorial-combat-stats/npcs.lua |   4 +-
 game/modules/tome/dialogs/CharacterSheet.lua  | 166 +++--
 game/modules/tome/dialogs/LevelupDialog.lua   |  10 +-
 game/modules/tome/dialogs/SentientWeapon.lua  | 205 +++++++
 game/modules/tome/dialogs/UseTalents.lua      |  11 +-
 game/modules/tome/resolvers.lua               | 219 ++++++-
 139 files changed, 5409 insertions(+), 3057 deletions(-)
 create mode 100644 game/modules/tome/data/chats/command-staff.lua
 create mode 100644 game/modules/tome/data/chats/ward.lua
 create mode 100644 game/modules/tome/data/general/objects/egos/ranged.lua
 create mode 100644 game/modules/tome/data/gfx/effects/counterstrike.png
 create mode 100644 game/modules/tome/data/gfx/particles/ward.lua
 create mode 100644 game/modules/tome/data/gfx/talents/block.png
 create mode 100644 game/modules/tome/data/gfx/talents/bloodflow.png
 create mode 100644 game/modules/tome/data/gfx/talents/command_staff.png
 create mode 100644 game/modules/tome/data/gfx/talents/elemental_retribution.png
 create mode 100644 game/modules/tome/data/gfx/talents/fearscape_fog.png
 create mode 100644 game/modules/tome/data/gfx/talents/lifebind.png
 create mode 100644 game/modules/tome/data/gfx/talents/perception.png
 create mode 100644 game/modules/tome/data/gfx/talents/reload.png
 create mode 100644 game/modules/tome/data/gfx/talents/savagery.png
 create mode 100644 game/modules/tome/data/gfx/talents/soul_drain.png
 create mode 100644 game/modules/tome/data/gfx/talents/ward.png
 create mode 100644 game/modules/tome/data/talents/misc/item.lua
 create mode 100644 game/modules/tome/dialogs/SentientWeapon.lua

diff --git a/game/engines/default/engine/Projectile.lua b/game/engines/default/engine/Projectile.lua
index 1fe5486a28..7aed1cdb7f 100644
--- a/game/engines/default/engine/Projectile.lua
+++ b/game/engines/default/engine/Projectile.lua
@@ -261,7 +261,7 @@ function _M:makeProject(src, display, def, do_move, do_act, do_stop)
 		def.tg.talent_id = def.tg.talent.id
 		def.tg.talent = nil
 	end
-	speed = speed or 10
+	speed = def.tg.speed or speed or 10
 	local p = _M.new{
 		name = name,
 		display = display.display or ' ', color = display.color or colors.WHITE, image = display.image or nil,
diff --git a/game/modules/tome/ai/tactical.lua b/game/modules/tome/ai/tactical.lua
index 1bb2239d84..99767abb57 100644
--- a/game/modules/tome/ai/tactical.lua
+++ b/game/modules/tome/ai/tactical.lua
@@ -166,7 +166,7 @@ newAI("use_tactical", function(self)
 						val = val * (nb_foes_hit - ally_compassion * nb_allies_hit - self_compassion * nb_self_hit)
 					end
 					-- Only take values greater than 0... allows the ai_talents to turn talents off
-					if val > 0 then
+					if val > 0 and not self:hasEffect(self.EFF_RELOADING) then
 						if not avail[tact] then avail[tact] = {} end
 						-- Save the tactic, if the talent is instant it gets a huge bonus
 						-- Note the addition of a less than one random value, this means the sorting will randomly shift equal values
@@ -181,7 +181,7 @@ newAI("use_tactical", function(self)
 	end
 	if ok then
 		local want = {}
-
+				
 		local need_heal = 0
 		local life = 100 * self.life / self.max_life
 		if life < 20 then need_heal = need_heal + 10 * self_compassion / 5
@@ -196,6 +196,16 @@ newAI("use_tactical", function(self)
 			want.heal = need_heal
 		end
 
+		-- Need ammo
+		local a = self:hasAmmo()
+		if avail.ammo and a and not self:hasEffect(self.EFF_RELOADING) then
+			want.ammo = 0
+			local ammo = 100 * a.combat.shots_left / a.combat.capacity
+			if ammo == 0 then want.ammo = want.ammo + 10
+			elseif ammo < 100 then want.ammo = want.ammo + 0.5
+			end
+		end
+		
 		-- Need mana
 		if avail.mana then
 			want.mana = 0
@@ -363,6 +373,7 @@ newAI("use_tactical", function(self)
 			table.sort(selected_talents, function(a,b) return a.val > b.val end)
 			local tid = selected_talents[1].tid
 			print("Tactical choice:", res[1][1], tid)
+			if a then print("shots left:", a.combat.shots_left) end
 			self:useTalent(tid)
 			return true
 		else
diff --git a/game/modules/tome/class/Actor.lua b/game/modules/tome/class/Actor.lua
index 7556125661..941eac4b5d 100644
--- a/game/modules/tome/class/Actor.lua
+++ b/game/modules/tome/class/Actor.lua
@@ -197,19 +197,27 @@ function _M:init(t, no_default)
 	mod.class.interface.ActorInscriptions.init(self, t)
 
 	-- Default melee barehanded damage
+	self.default_dam = 1
+	self.default_max_acc = 75
+	self.default_critical_power = 1.1
 	self.combat = self.combat or {
-		dam=1,
-		atk=1, apr=0,
+		dam=self.default_dam,
+		atk=0, apr=0,
 		physcrit=0,
 		physspeed =1,
-		dammod = { str=1 },
-		damrange=1.1,
+		critical_power = self.default_critical_power,
+		max_acc = self.default_max_acc,
+
+		dammod = { str=0.1 },
+		damrange=1,
 		talented = "unarmed",
 	}
 	-- Insures we have certain values for gloves to modify
-	self.combat.damrange = self.combat.damrange or 1.1
+	self.combat.damrange = self.combat.damrange or 1
 	self.combat.physspeed = self.combat.physspeed or 1
-	self.combat.dammod = self.combat.dammod or {str=0.6}
+	self.combat.dammod = self.combat.dammod or {str=0.1}
+	self.combat.critical_power = self.combat.critical_power or self.default_critical_power
+	self.combat.max_acc = self.combat.max_acc or self.default_max_acc
 
 	self.talents[self.T_ATTACK] = self.talents[self.T_ATTACK] or 1
 
@@ -299,6 +307,7 @@ function _M:actBase()
 	if not self:attr("no_talents_cooldown") then self:cooldownTalents() end
 	-- Regen resources
 	self:regenLife()
+	self:regenAmmo()
 	if self:knowTalent(self.T_UNNATURAL_BODY) then
 		local t = self:getTalentFromId(self.T_UNNATURAL_BODY)
 		t.do_regenLife(self, t)
@@ -1056,7 +1065,7 @@ function _M:tooltip(x, y, seen_by)
 	if #resists > 0 then ts:add("Resists: ", table.concat(resists, ','), true) end
 	ts:add("Hardiness/Armour: ", tostring(math.floor(self:combatArmorHardiness())), '% / ', tostring(math.floor(self:combatArmor())), true)
 	ts:add("Size: ", {"color", "ANTIQUE_WHITE"}, self:TextSizeCategory(), {"color", "WHITE"}, true)
-
+	
 	ts:add("#FFD700#Accuracy#FFFFFF#: ", self:colorStats("combatAttack"), "  ")
 	ts:add("#0080FF#Defense#FFFFFF#:  ", self:colorStats("combatDefense"), true)
 	ts:add("#FFD700#P. power#FFFFFF#: ", self:colorStats("combatPhysicalpower"), "  ")
@@ -1096,6 +1105,22 @@ function _M:regenLife()
 	end
 end
 
+function _M:regenAmmo()
+	local ammo = self:hasAmmo()
+	--if not ammo then return end
+	local r = (ammo and ammo.combat and ammo.combat.ammo_every)
+	if not r then return end
+	if ammo.combat.shots_left == ammo.combat.capacity then return end
+	--print("reload every r, where r is:", r)
+	ammo.combat.reload_counter = (ammo.combat.reload_counter or 0) + 1
+	--print("reload counter:", ammo.combat.reload_counter)
+	if ammo.combat.reload_counter == r then
+		ammo.combat.reload_counter = 0
+		ammo.combat.shots_left = math.min(ammo.combat.capacity, (ammo.combat.shots_left + 1))
+	end
+
+end
+
 --- Called before healing
 function _M:onHeal(value, src)
 	if self:hasEffect(self.EFF_UNSTOPPABLE) then return 0 end
@@ -2093,6 +2118,14 @@ function _M:onWear(o, bypass_set)
 		t.on_onWear(self, t, o)
 	end
 
+	-- learn item talents
+	
+	if o.wielder and o.wielder.learn_talent then
+		for tid, level in pairs(o.wielder.learn_talent) do
+			self:learnItemTalent(o, tid, level)
+		end
+	end
+	
 	self:updateModdableTile()
 	if self == game.player then game:playSound("actions/wear") end
 end
@@ -2145,6 +2178,16 @@ function _M:onTakeoff(o, bypass_set)
 		t.on_onTakeOff(self, t, o)
 	end
 
+	if o.wielder and o.wielder.learn_talent then
+		for tid, level in pairs(o.wielder.learn_talent) do
+			self:unlearnItemTalent(o, tid, level)
+		end
+	end
+
+	if o.subtype == "arrow" or o.subtype == "shot" then
+		self:breakReloading()
+	end
+	
 	self:updateModdableTile()
 	if self == game.player then game:playSound("actions/takeoff") end
 end
@@ -2277,6 +2320,7 @@ function _M:learnPool(t)
 	end
 	-- If we learn an archery talent, also learn to shoot
 	if t.type[1]:find("^technique/archery") and not self:knowTalent(self.T_SHOOT) then
+		print("oddly, that thing in Actor.lua just taught us Shoot as if we didn't already know it.")
 		self:learnTalent(self.T_SHOOT, true)
 		self.resource_pool_refs[self.T_SHOOT] = (self.resource_pool_refs[self.T_SHOOT] or 0) + 1
 	end
@@ -2312,6 +2356,37 @@ function _M:unlearnTalent(t_id)
 	return true
 end
 
+function _M:learnItemTalent(o, tid, level)
+	local t = self:getTalentFromId(tid)
+	local max = t.hard_cap or (t.points and t.points + 2) or 5
+	if not self.item_talent_surplus_levels then self.item_talent_surplus_levels = {} end
+	--local item_talent_surplus_levels = self.item_talent_surplus_levels or {}
+	if not self.item_talent_surplus_levels[tid] then self.item_talent_surplus_levels[tid] = 0 end
+	--item_talent_levels[tid] = item_talent_levels[tid] + level
+	for i = 1, level do
+		if self:getTalentLevelRaw(t) >= max then 
+			self.item_talent_surplus_levels[tid] = self.item_talent_surplus_levels[tid] + 1 
+		else
+			self:learnTalent(tid, true, 1)
+		end		
+	end
+end
+
+function _M:unlearnItemTalent(o, tid, level)
+	local t = self:getTalentFromId(tid)
+	local max = (t.points and t.points + 2) or 5
+	if not self.item_talent_surplus_levels then self.item_talent_surplus_levels = {} end
+	--local item_talent_surplus_levels = self.item_talent_surplus_levels or {}
+	if not self.item_talent_surplus_levels[tid] then self.item_talent_surplus_levels[tid] = 0 end
+	for i = 1, level do
+		if self.item_talent_surplus_levels[tid] > 0 then 
+			self.item_talent_surplus_levels[tid] = self.item_talent_surplus_levels[tid] - 1 
+		else
+			self:unlearnTalent(tid, true, 1)
+		end	
+	end
+end
+
 --- Equilibrium check
 function _M:equilibriumChance(eq)
 	eq = (eq or 0) + self:getEquilibrium()
@@ -2635,7 +2710,7 @@ function _M:postUseTalent(ab, ret)
 			self:setEffect(self.EFF_TAINT_COOLDOWN, 10, {power=1})
 		end
 	end)
-
+	
 	if not ab.no_energy then
 		if ab.is_spell then
 			self:useEnergy(game.energy_to_act * self:combatSpellSpeed())
@@ -2749,6 +2824,7 @@ function _M:postUseTalent(ab, ret)
 	if ab.id ~= self.T_STEALTH and ab.id ~= self.T_HIDE_IN_PLAIN_SIGHT and not ab.no_break_stealth then self:breakStealth() end
 	if ab.id ~= self.T_LIGHTNING_SPEED then self:breakLightningSpeed() end
 	if ab.id ~= self.T_GATHER_THE_THREADS then self:breakGatherTheThreads() end
+	if ab.id ~= self.T_RELOAD then self:breakReloading() end
 	self:breakStepUp()
 
 	if ab.id ~= self.T_REDUX and self:hasEffect(self.EFF_REDUX) and ab.type[1]:find("^chronomancy/") and ab.mode == "activated" and self:getTalentLevel(self.T_REDUX) >= self:getTalentLevel(ab.id) then
@@ -2791,6 +2867,12 @@ function _M:breakStealth()
 	end
 end
 
+function _M:breakReloading()
+	if self:hasEffect(self.EFF_RELOADING) then
+		self:removeEffect(self.EFF_RELOADING)
+	end
+end
+
 --- Breaks step up if active
 function _M:breakStepUp()
 	if self:hasEffect(self.EFF_STEP_UP) then
diff --git a/game/modules/tome/class/Object.lua b/game/modules/tome/class/Object.lua
index f6b4586571..e0e107de03 100644
--- a/game/modules/tome/class/Object.lua
+++ b/game/modules/tome/class/Object.lua
@@ -132,7 +132,37 @@ function _M:descAttribute(attr)
 		return ("%s%0.2f/turn"):format(i > 0 and "+" or "-", math.abs(i))
 	elseif attr == "COMBAT" then
 		local c = self.combat
-		return c.dam.."-"..(c.dam*(c.damrange or 1.1)).." power, "..(c.apr or 0).." apr"
+		local m = math.min(c.max_acc or 75, 100)
+		return c.dam..", "..(c.critical_power or 1.1).."x, "..m.."%"
+	elseif attr == "COMBAT_RANGED" then
+		local c = self.combat
+		return (c.dam or 0)..", "..(c.critical_power or 1.1).."x"
+	elseif attr == "COMBAT_QUIVER" then
+		local c = self.combat
+		local m = math.min(c.max_acc or 75, 100)
+		--return (c.dam or 0)..", "..(c.max_acc or 75).."%, ".."["..(c.shots_left or 0).."/"..(c.capacity or 0).."]"
+		return (c.dam or 0)..", "..m.."%, "..(c.shots_left or 0).."/"..(c.capacity or 0)
+	elseif attr == "COMBAT_STAFF" then
+		local c = self.combat
+		local m = math.min(c.max_acc or 75, 100)
+		return "+"..c.dam.."%, "..(c.critical_power or 1.1).."x, "..m.."%"
+	elseif attr == "SHIELD" then
+		local c = self.special_combat
+		if c and (game.player:knowTalentType("technique/shield-offense") or game.player:knowTalentType("technique/shield-defense")) then
+			return c.dam.." dam, "..c.block.." block"
+		else
+			return c.block.." block"
+		end
+	elseif attr == "GLOVES" then
+		local c = (self.wielder and self.wielder.combat) or {}
+		if c and game.player:knowTalent(game.player.T_EMPTY_HAND) then
+			local d = c.dam + game.player.default_dam
+			local m = math.min((c.max_acc or 0) + game.player.default_max_acc, 100)
+			local c_power = (c.critical_power or 1.1) + game.player.default_critical_power
+			return d..", "..c_power.."x, "..m.."%"
+		else
+			return (self.wielder and self.wielder.combat_def or 0).." def, "..(self.wielder and self.wielder.combat_armor or 0).." armour"
+		end
 	elseif attr == "COMBAT_DAMTYPE" then
 		local c = self.combat
 		return c.dam.."-"..(c.dam*(c.damrange or 1.1)).." power, "..(c.apr or 0).." apr, "..DamageType:get(c.damtype).name.." damage"
@@ -258,6 +288,38 @@ function _M:getShortName(t)
 	end
 end
 
+function _M:getMeleeProjectDam()
+	local combat = self.combat or self.special_combat or self.wielder.combat or {}
+	if not combat["melee_project"] then return 0 end
+	local tab = {}
+	for k, v in pairs(combat["melee_project"]) do
+		tab[k] = {}
+		tab[k][1] = v
+	end
+	local total = 0
+	for k, v in pairs(tab) do
+		total = total + v[1]
+	end
+
+	return total
+end
+
+function _M:getRangedProjectDam()
+	local combat = self.combat or {}
+	if not combat["ranged_project"] then return 0 end
+	local tab = {}
+	for k, v in pairs(combat["ranged_project"]) do
+		tab[k] = {}
+		tab[k][1] = v
+	end
+	local total = 0
+	for k, v in pairs(tab) do
+		total = total + v[1]
+	end
+
+	return total
+end
+
 --- Gets the full textual desc of the object without the name and requirements
 function _M:getTextualDesc(compare_with)
 	compare_with = compare_with or {}
@@ -265,36 +327,36 @@ function _M:getTextualDesc(compare_with)
 
 	if self.quest then desc:add({"color", "VIOLET"},"[Plot Item]", {"color", "LAST"}, true) end
 
-	desc:add(("Type: %s / %s"):format(rawget(self, 'type') or "unknown", rawget(self, 'subtype') or "unknown"), true)
-	if self.slot_forbid == "OFFHAND" then desc:add("It must be held with both hands.", true) end
-	desc:add(true)
-
 	if self.set_list then
 		desc:add({"color","GREEN"}, "It is part of a set of items.", {"color","LAST"}, true)
 		if self.set_complete then desc:add({"color","LIGHT_GREEN"}, "The set is complete.", {"color","LAST"}, true) end
 	end
-
 	-- Stop here if unided
 	if not self:isIdentified() then return desc end
 
-	local compare_fields = function(item1, items, infield, field, outformat, text, mod, isinversed, isdiffinversed, add_table)
+	local compare_fields = function(item1, items, infield, field, outformat, text, mod, isinversed, isdiffinversed, add_table, change_order, affects_spells)
 		add_table = add_table or {}
 		mod = mod or 1
+		change_order = change_order or true
 		isinversed = isinversed or false
 		isdiffinversed = isdiffinversed or false
 		local ret = tstring{}
 		local added = 0
 		local add = false
-		ret:add(text)
+		if not change_order then ret:add(text) end
 		if isinversed then
 			ret:add(((item1[field] or 0) + (add_table[field] or 0)) > 0 and {"color","RED"} or {"color","LIGHT_GREEN"}, outformat:format(((item1[field] or 0) + (add_table[field] or 0)) * mod), {"color", "LAST"})
 		else
 			ret:add(((item1[field] or 0) + (add_table[field] or 0)) < 0 and {"color","RED"} or {"color","LIGHT_GREEN"}, outformat:format(((item1[field] or 0) + (add_table[field] or 0)) * mod), {"color", "LAST"})
 		end
+		--if change_order then ret:add(text) end
+		--if affects_spells then ret:add(" (affects spells)") end
 		if item1[field] then
 			add = true
 		end
 		for i=1, #items do
+			--if items[i][infield] and field == "max_acc" and items[i][infield][field] then items[i][infield]["max_acc"] = math.min(items[i][infield]["max_acc"], 100) end
+			--if items[i][infield] and field == "attack_speed_bonus" and items[i][infield][field] then items[i][infield]["attack_speed_bonus"] = (1 / (items[i][infield]["physspeed"] or 1))*100 -100 end
 			if items[i][infield] and items[i][infield][field] then
 				if added == 0 then
 					ret:add(" (")
@@ -317,19 +379,23 @@ function _M:getTextualDesc(compare_with)
 		if added > 0 then
 			ret:add(")")
 		end
+		if change_order then ret:add(text) end
+		if affects_spells then ret:add(" (affects spells)") end
 		if add then
 			desc:merge(ret)
 			desc:add(true)
 		end
 	end
 
-	local compare_table_fields = function(item1, items, infield, field, outformat, text, kfunct, mod, isinversed)
+	local compare_table_fields = function(item1, items, infield, field, outformat, text, kfunct, mod, isinversed, separator, change_order)
 		mod = mod or 1
+		separator = separator or ", "
+		change_order = change_order or true
 		isinversed = isinversed or false
 		local ret = tstring{}
 		local added = 0
 		local add = false
-		ret:add(text)
+		if not change_order then ret:add(text) end
 		local tab = {}
 		if item1[field] then
 			for k, v in pairs(item1[field]) do
@@ -349,9 +415,9 @@ function _M:getTextualDesc(compare_with)
 		for k, v in pairs(tab) do
 			local count = 0
 			if isinversed then
-				ret:add(("%s"):format((count1 > 0) and " / " or ""), (v[1] or 0) > 0 and {"color","RED"} or {"color","LIGHT_GREEN"}, outformat:format((v[1] or 0)), {"color","LAST"})
+				ret:add(("%s"):format((count1 > 0 and separator) or ""), (v[1] or 0) > 0 and {"color","RED"} or {"color","LIGHT_GREEN"}, outformat:format((v[1] or 0)), {"color","LAST"})
 			else
-				ret:add(("%s"):format((count1 > 0) and " / " or ""), (v[1] or 0) < 0 and {"color","RED"} or {"color","LIGHT_GREEN"}, outformat:format((v[1] or 0)), {"color","LAST"})
+				ret:add(("%s"):format((count1 > 0 and separator) or ""), (v[1] or 0) < 0 and {"color","RED"} or {"color","LIGHT_GREEN"}, outformat:format((v[1] or 0)), {"color","LAST"})
 			end
 			count1 = count1 + 1
 			if v[1] then
@@ -383,6 +449,8 @@ function _M:getTextualDesc(compare_with)
 			ret:add(kfunct(k))
 		end
 
+		if change_order then ret:add(text) end
+
 		if add then
 			desc:merge(ret)
 			desc:add(true)
@@ -396,8 +464,20 @@ function _M:getTextualDesc(compare_with)
 		compare_with = compare_with or {}
 		local dm = {}
 		for stat, i in pairs(combat.dammod or {}) do
-			dm[#dm+1] = ("%d%% %s"):format((i + (add_table.dammod[stat] or 0)) * 100, Stats.stats_def[stat].short_name:capitalize())
+			dm[#dm+1] = ("#00ff00#%d%%#LAST# %s"):format((i + (add_table.dammod[stat] or 0)) * 100, Stats.stats_def[stat].short_name)
 		end
+		local shooter = game.player:hasShooter()
+		local ammo = game.player:hasAmmo()
+		local add_ammo = false
+		local add_shooter = false
+		if self.archery_ammo and shooter and self.archery_ammo == shooter.archery then add_shooter = true end
+		if self.archery and ammo and self.archery == ammo.archery_ammo then add_ammo = true end
+		local ammo_dam = 0
+		local shooter_dam = 0
+		local melee_project_total = 0
+		local ranged_project_total = 0
+		local ranged_add_string = ""
+		local project_type = "melee_project"
 		if #dm > 0 or combat.dam then
 			local power_diff = ""
 			local diff_count = 0
@@ -418,20 +498,78 @@ function _M:getTextualDesc(compare_with)
 			else
 				power_diff = ("(%s)"):format(power_diff)
 			end
-			desc:add(("Base power: %.1f - %.1f"):format((combat.dam or 0) + (add_table.dam or 0), ((combat.damrange or (1.1 - (add_table.damrange or 0))) + (add_table.damrange or 0)) * ((combat.dam or 0) + (add_table.dam or 0))))
-			desc:merge(power_diff:toTString())
+
+			local tot_dam_per_hit = 0
+			local base_dam = (combat.dam or 0) + (add_table.dam or 0)
+			if add_ammo then
+				ammo_dam = game.player:combatDamage(ammo.combat) + ammo:getRangedProjectDam()
+			end
+			if add_shooter then
+				shooter_dam = game.player:combatDamage(shooter.combat) + shooter:getRangedProjectDam()
+			end
+			if not self.archery and not self.archery_ammo then
+				melee_project_total = self:getMeleeProjectDam()
+			else
+				ranged_project_total = self:getRangedProjectDam()
+				project_type = "ranged_project"
+			end
+			local u_combat = {}
+			u_combat = table.clone(combat, true)
+			if add_table and add_table.dam then u_combat.dam = u_combat.dam + add_table.dam or 0 end
+			if add_table and add_table.dammod then
+				for stat, i in pairs(u_combat.dammod or {}) do
+					u_combat.dammod[stat] = u_combat.dammod[stat] + (add_table.dammod[stat] or 0)
+				end
+			end
+			tot_dam_per_hit = game.player:combatDamage(u_combat) + melee_project_total + ranged_project_total + shooter_dam + ammo_dam
+			desc:add({"color","YELLOW"}, ("          %d damage per hit"):format(tot_dam_per_hit), {"color", "LAST"}, true)
 			desc:add(true)
-			desc:add(("Uses stat%s: %s"):format(#dm > 1 and "s" or "",table.concat(dm, ', ')), true)
-			local col = (combat.damtype and DamageType:get(combat.damtype) and DamageType:get(combat.damtype).text_color or "#WHITE#"):toTString()
-			desc:add("Damage type: ", col[2],DamageType:get(combat.damtype or DamageType.PHYSICAL).name:capitalize(),{"color","LAST"}, true)
+			local damage_type_text = ""
+			if combat.damtype and combat.damtype ~= DamageType.PHYSICAL then
+				local col = (combat.damtype and DamageType:get(combat.damtype) and DamageType:get(combat.damtype).text_color or "#WHITE#")
+				damage_type_text = " "..col..DamageType:get(combat.damtype).name
+			end
+
+			desc:add({"color","LIGHT_GREEN"}, ("%d"):format(base_dam), {"color","LAST"}, ("%s"):format(damage_type_text), {"color","LAST"}, " dam + ", {"color","LIGHT_GREEN"}, ("%d"):format(tot_dam_per_hit - base_dam), {"color","LAST"}, " bonus dam", {"color","RED"}, "*", {"color","LAST"}, true)
+
 		end
 
-		compare_fields(combat, compare_with, field, "atk", "%+d", "Accuracy: ", 1, false, false, add_table)
-		compare_fields(combat, compare_with, field, "apr", "%+d", "Armour Penetration: ", 1, false, false, add_table)
-		compare_fields(combat, compare_with, field, "physcrit", "%+.1f%%", "Physical crit. chance: ", 1, false, false, add_table)
-		compare_fields(combat, compare_with, field, "physspeed", "%.0f%%", "Attack speed: ", 100, false, true, add_table)
+		compare_fields(combat, compare_with, field, "critical_power", "%.1f", " crit multiplier", 1, false, false, add_table, true, combat.affects_spells)
+		compare_fields(combat, compare_with, field, "max_acc", "%d%%", " max hit chance", 1, false, false, add_table, true, combat.affects_spells)
+		compare_fields(combat, compare_with, field, "capacity", "%d", " capacity", 1, false, false, add_table)
+		compare_fields(combat, compare_with, field, "shots_reloaded_per_turn", "%+d", " reload speed", 1, false, false, add_table)
+		compare_fields(combat, compare_with, field, "ammo_every", "%d", " turns elapse between self-loadings", 1, false, false, add_table)
+		desc:add(true)
+		desc:add({"color","RED"}, "*", {"color","LAST"}, ": ")
+		if add_ammo then
+			desc:add({"color","LIGHT_GREEN"}, ("%d "):format(ammo_dam), {"color","LAST"}, "ammo dam + ")
+		end
+		if add_shooter then
+			local s = shooter.archery
+			desc:add({"color","LIGHT_GREEN"}, ("%d "):format(shooter_dam), {"color","LAST"}, ("%s dam + "):format(s))
+		end
+		local talent_dam = game.player:combatCheckTraining(combat)
+		if talent_dam > 0 then desc:add({"color","LIGHT_GREEN"}, ("%d "):format(talent_dam), {"color","LAST"}, "talent dam + ") end
+		desc:add(("%s "):format(table.concat(dm, ' + ')), {"color","LAST"})
+		compare_table_fields(combat, compare_with, field, project_type, "%+d", "", function(item)
+				local col = (DamageType.dam_def[item] and DamageType.dam_def[item].text_color or "#WHITE#"):toTString()
+				return col[2], (" %s"):format(DamageType.dam_def[item].name),{"color","LAST"}
+			end, nil, nil, " ")
+		desc:add(true)
 
-		compare_fields(combat, compare_with, field, "range", "%+d", "Firing range: ", 1, false, false, add_table)
+		local attack_speed_bonus = (1 / ((combat.physspeed or 1) + (add_table.physspeed or 0)))*100 -100
+		if combat.physspeed and combat.physspeed ~= 1 then
+			desc:add({"color","LIGHT_GREEN"}, ("%d%% "):format(attack_speed_bonus), {"color","LAST"}, "attack speed bonus", true)
+			--compare_fields(combat, compare_with, field, "attack_speed_bonus", "%d%%", " attack speed bonus", 1, false, false, add_table, true)
+		end
+		compare_fields(combat, compare_with, field, "apr", "%d", " armour penetration", 1, false, false, add_table)
+		compare_fields(combat, compare_with, field, "range", "%d", " firing range", 1, false, false, add_table)
+		if combat.tg_type and combat.tg_type == "beam" then
+			desc:add({"color","YELLOW"}, ("Shots beam through all targets."), {"color","LAST"}, true)
+		end
+		if combat.concussion then
+			compare_fields(combat, compare_with, field, "concussion", "%d%%", " weapon damage done to nearby foes on crit", 1, false, false, add_table)
+		end
 
 		local talents = {}
 		if combat.talent_on_hit then
@@ -483,85 +621,86 @@ function _M:getTextualDesc(compare_with)
 			desc:add({"color","RED"}, "When used from stealth a simple attack with it will not break stealth.", {"color","LAST"}, true)
 		end
 
-		compare_fields(combat, compare_with, field, "travel_speed", "%+d%%", "Travel speed: ", 1, false, false, add_table)
-
-		compare_table_fields(combat, compare_with, field, "melee_project", "%+d", "Damage when this weapon hits: ", function(item)
-				local col = (DamageType.dam_def[item] and DamageType.dam_def[item].text_color or "#WHITE#"):toTString()
-				return col[2], (" %s"):format(DamageType.dam_def[item].name),{"color","LAST"}
-			end)
+		compare_fields(combat, compare_with, field, "travel_speed", "%d%%", " projectile speed", 1, false, false, add_table)
 
-		compare_table_fields(combat, compare_with, field, "inc_damage_type", "%+d%%", "Damage against: ", function(item)
+		compare_table_fields(combat, compare_with, field, "inc_damage_type", "%+d%%", " damage against ", function(item)
 				local _, _, t, st = item:find("^([^/]+)/?(.*)$")
 				if st and st ~= "" then
 					return st:capitalize()
 				else
 					return t:capitalize()
 				end
-			end)
-
+			end, nil, nil, nil, false)
+		desc:add(true, "---", true)
 	end
 
 	local desc_wielder = function(w, compare_with, field)
 		w = w or {}
 		w = w[field] or {}
-		compare_fields(w, compare_with, field, "combat_atk", "%+d", "Accuracy: ")
-		compare_fields(w, compare_with, field, "combat_apr", "%+d", "Armour penetration: ")
-		compare_fields(w, compare_with, field, "combat_physcrit", "%+.1f%%", "Physical crit. chance: ")
-		compare_fields(w, compare_with, field, "combat_dam", "%+d", "Physical power: ")
+		compare_fields(w, compare_with, field, "cross_tier_bonus", "%+d", " bonus to cross-tier effects")
+		compare_fields(w, compare_with, field, "combat_atk", "%+d", " accuracy")
+		compare_fields(w, compare_with, field, "combat_apr", "%+d", " armour penetration")
+		compare_fields(w, compare_with, field, "combat_physcrit", "%+d%%", " physical crit. chance")
+		compare_fields(w, compare_with, field, "combat_dam", "%+d", " physical power")
 
-		compare_fields(w, compare_with, field, "combat_armor", "%+d", "Armour: ")
-		compare_fields(w, compare_with, field, "combat_armor_hardiness", "%+d%%", "Armour Hardiness: ")
-		compare_fields(w, compare_with, field, "combat_def", "%+d", "Defense: ")
-		compare_fields(w, compare_with, field, "combat_def_ranged", "%+d", "Ranged Defense: ")
+		compare_fields(w, compare_with, field, "combat_armor", "%+d", " armor", nil, nil, nil, nil, true)
+		compare_fields(w, compare_with, field, "combat_armor_hardiness", "%+d%%", " armour hardiness")
+		compare_fields(w, compare_with, field, "combat_def", "%+d", " defense")
+		compare_fields(w, compare_with, field, "combat_def_ranged", "%+d", " ranged defense")
 
-		compare_fields(w, compare_with, field, "fatigue", "%+d%%", "Fatigue: ", 1, true, true)
+		compare_fields(w, compare_with, field, "fatigue", "%+d%%", " fatigue", 1, true, true)
 
-		compare_table_fields(w, compare_with, field, "inc_stats", "%+d", "Changes stats: ", function(item)
+		compare_table_fields(w, compare_with, field, "inc_stats", "%+d", "", function(item)
 				return (" %s"):format(Stats.stats_def[item].short_name:capitalize())
 			end)
 
-		compare_table_fields(w, compare_with, field, "melee_project", "%d", "Damage when the wearer hits(melee): ", function(item)
+		compare_table_fields(w, compare_with, field, "melee_project", "+%d", " melee damage", function(item)
 				local col = (DamageType.dam_def[item] and DamageType.dam_def[item].text_color or "#WHITE#"):toTString()
 				return col[2],(" %s"):format(DamageType.dam_def[item].name),{"color","LAST"}
 			end)
 
-		compare_table_fields(w, compare_with, field, "ranged_project", "%d", "Damage when the wearer hits(ranged): ", function(item)
+		compare_table_fields(w, compare_with, field, "ranged_project", "+%d", " ranged damage", function(item)
 				local col = (DamageType.dam_def[item] and DamageType.dam_def[item].text_color or "#WHITE#"):toTString()
 				return col[2],(" %s"):format(DamageType.dam_def[item].name),{"color","LAST"}
 			end)
 
-		compare_table_fields(w, compare_with, field, "on_melee_hit", "%d", "Damage when the wearer is hit: ", function(item)
+		compare_table_fields(w, compare_with, field, "on_melee_hit", "%d", " damage to any who hits wearer", function(item)
 				local col = (DamageType.dam_def[item] and DamageType.dam_def[item].text_color or "#WHITE#"):toTString()
 				return col[2],(" %s"):format(DamageType.dam_def[item].name),{"color","LAST"}
 			end)
 
-		compare_table_fields(w, compare_with, field, "resists", "%+d%%", "Changes resistances: ", function(item)
+		compare_table_fields(w, compare_with, field, "resists", "%+d%%", " resistance", function(item)
 				local col = (DamageType.dam_def[item] and DamageType.dam_def[item].text_color or "#WHITE#"):toTString()
 				return col[2], (" %s"):format(item == "all" and "all" or DamageType.dam_def[item].name), {"color","LAST"}
 			end)
 
-		compare_table_fields(w, compare_with, field, "resists_cap", "%+d%%", "Changes resistances cap: ", function(item)
+		compare_table_fields(w, compare_with, field, "wards", "%+d", " ward", function(item)
 				local col = (DamageType.dam_def[item] and DamageType.dam_def[item].text_color or "#WHITE#"):toTString()
 				return col[2], (" %s"):format(item == "all" and "all" or DamageType.dam_def[item].name), {"color","LAST"}
 			end)
 
-		compare_table_fields(w, compare_with, field, "resists_pen", "%+d%%", "Changes resistances penetration: ", function(item)
+		compare_table_fields(w, compare_with, field, "resists_cap", "%+d%%", " max resistance", function(item)
 				local col = (DamageType.dam_def[item] and DamageType.dam_def[item].text_color or "#WHITE#"):toTString()
 				return col[2], (" %s"):format(item == "all" and "all" or DamageType.dam_def[item].name), {"color","LAST"}
 			end)
 
-		compare_table_fields(w, compare_with, field, "inc_damage", "%+d%%", "Changes damage: ", function(item)
+		compare_table_fields(w, compare_with, field, "resists_pen", "%+d%%", " resist penetration", function(item)
 				local col = (DamageType.dam_def[item] and DamageType.dam_def[item].text_color or "#WHITE#"):toTString()
 				return col[2], (" %s"):format(item == "all" and "all" or DamageType.dam_def[item].name), {"color","LAST"}
 			end)
 
-		compare_table_fields(w, compare_with, field, "damage_affinity", "%+d%%", "Damage affinity(heal): ", function(item)
+		compare_table_fields(w, compare_with, field, "inc_damage", "%+d%%", " damage", function(item)
 				local col = (DamageType.dam_def[item] and DamageType.dam_def[item].text_color or "#WHITE#"):toTString()
 				return col[2], (" %s"):format(item == "all" and "all" or DamageType.dam_def[item].name), {"color","LAST"}
 			end)
 
+		compare_table_fields(w, compare_with, field, "damage_affinity", "%+d%%", " affinity", function(item)
+				local col = (DamageType.dam_def[item] and DamageType.dam_def[item].text_color or "#WHITE#"):toTString()
+				return col[2], (" %s"):format(item == "all" and "all" or DamageType.dam_def[item].name), {"color","LAST"}
+			end)
 
-		compare_fields(w, compare_with, field, "esp_range", "%+d", "Change telepathy range by : ")
+
+		compare_fields(w, compare_with, field, "esp_range", "%+d", " telepathy range")
 
 		local any_esp = false
 		local esps_compare = {}
@@ -604,14 +743,20 @@ function _M:getTextualDesc(compare_with)
 			any_esp = true
 		end
 		if any_esp then
-			desc:add("Grants telepathy: ")
+			--desc:add("Grants telepathy: ")
+
+			local count = 0
 			for esp, isin in pairs(esps_compare) do
+				local separator = (#esps > 1 and ",") or "x"
+				count = count + 1
 				if isin[2] then
-					desc:add(isin[1] and {"color","WHITE"} or {"color","GREEN"}, ("%s "):format(esp), {"color","LAST"})
+					desc:add(isin[1] and {"color","WHITE"} or {"color","GREEN"}, ("%s"):format(esp), ("%s "):format(((count < #esps_compare) and separator) or ""), {"color","LAST"})
 				else
 					desc:add({"color","RED"}, ("%s "):format(esp), {"color","LAST"})
 				end
+
 			end
+			desc:add(" telepathy")
 			desc:add(true)
 		end
 
@@ -632,7 +777,7 @@ function _M:getTextualDesc(compare_with)
 			any_mastery = any_mastery + 1
 		end
 		if any_mastery > 0 then
-			desc:add(("Talent master%s: "):format(any_mastery > 1 and "ies" or "y"))
+			--desc:add(("Talent master%s: "):format(any_mastery > 1 and "ies" or "y"))
 			for ttn, ttid in pairs(masteries) do
 				local tt = Talents.talents_types_def[ttn]
 				local cat = tt.type:gsub("/.*", "")
@@ -648,6 +793,7 @@ function _M:getTextualDesc(compare_with)
 					desc:add({"color","WHITE"}, ("%+.2f(-) %s "):format(ttid[2] or ttid[1], name), {"color","LAST"})
 				end
 			end
+			desc:add((" talent master%s"):format(any_mastery > 1 and "ies" or "y"))
 			desc:add(true)
 		end
 
@@ -684,6 +830,70 @@ function _M:getTextualDesc(compare_with)
 			desc:add(true)
 		end
 
+		--display learned talents:
+
+		local any_learn_talent = 0
+		local learn_talents = {}
+		for i, v in ipairs(compare_with or {}) do
+			if v[field] and v[field].learn_talent then
+				for tid, tl in pairs(v[field].learn_talent) do
+					learn_talents[tid] = learn_talents[tid] or {}
+					learn_talents[tid][1] = tl
+					any_learn_talent = any_learn_talent + 1
+				end
+			end
+		end
+		for tid, tl in pairs(w.learn_talent or {}) do
+			learn_talents[tid] = learn_talents[tid] or {}
+			learn_talents[tid][2] = tl
+			any_learn_talent = any_learn_talent + 1
+		end
+		if any_learn_talent > 0 then
+			for tid, tl in pairs(learn_talents) do
+				local diff = (tl[2] or 0) - (tl[1] or 0)
+				if diff ~= 0 then
+					if tl[1] then
+						desc:add(("%+d"):format((tl[2] or 0)), diff < 0 and {"color","RED"} or {"color","LIGHT_GREEN"}, ("(%+d) "):format(diff), {"color","GREEN"}, (" %s "):format(Talents.talents_def[tid].name), {"color","WHITE"}, ("talent level%s"):format(((tl[2] or 0) > 1) and "s" or ""), true)
+					else
+						desc:add({"color","LIGHT_GREEN"}, ("%+d"):format((tl[2] or 0)), {"color","GREEN"}, (" %s "):format(Talents.talents_def[tid].name), {"color","WHITE"}, ("talent level%s"):format((tl[2] > 1) and "s" or ""), true)
+					end
+				else
+					--desc:add({"color","LIGHT_GREEN"}, ("(%+d(-) %s talent level%s)"):format(Talents.talents_def[tid].name, (tl[2] or tl[1]), ((tl[2] or 0) > 1) and "s" or ""), {"color","LAST"})
+					desc:add({"color","LIGHT_GREEN"}, ("%+d(-)"):format((tl[2] or 0)), {"color","GREEN"}, (" %s "):format(Talents.talents_def[tid].name), {"color","WHITE"}, ("talent level%s"):format((tl[2] > 1) and "s" or ""), true)
+				end
+			end
+			desc:add(true)
+		end
+
+		-- Retributions:
+		local ret_list = {}
+		local counter = 1
+		for k, v in pairs(w.elemental_retribution or {}) do
+			if v > 0 then
+				ret_list[counter] = k
+				counter = counter + 1
+			end
+		end
+		local n = #ret_list
+		if n >= 1 then
+			local e_string = ""
+			if n == 1 then
+				e_string = DamageType.dam_def[ret_list[1]].text_color..DamageType.dam_def[ret_list[1]].name.."#WHITE#"
+				print("1: e_string is ", e_string)
+			elseif n == 2 then
+				e_string = DamageType.dam_def[ret_list[1]].text_color..DamageType.dam_def[ret_list[1]].name.."#WHITE# and "..DamageType.dam_def[ret_list[2]].text_color..DamageType.dam_def[ret_list[2]].name
+				print("2: e_string is ", e_string)
+			else
+				for i = 1, #ret_list-1 do
+					e_string = e_string..DamageType.dam_def[ret_list[i]].text_color..DamageType.dam_def[ret_list[i]].name.."#WHITE#, "
+					print("3+: e_string is ", e_string)
+				end
+				e_string = e_string.."and "..DamageType.dam_def[ret_list[n]].text_color..DamageType.dam_def[ret_list[n]].name.."#WHITE#"
+			end
+			desc:add(e_string, " retribution", true)
+		end
+
+
 		local any_breath = 0
 		local breaths = {}
 		for i, v in ipairs(compare_with or {}) do
@@ -712,83 +922,83 @@ function _M:getTextualDesc(compare_with)
 			desc:add(true)
 		end
 
-		compare_fields(w, compare_with, field, "combat_critical_power", "%+.2f%%", "Critical mult.: ")
+		compare_fields(w, compare_with, field, "combat_critical_power", "%+.1f", " crit multiplier")
 		compare_fields(w, compare_with, field, "combat_critreduction", "%-d%%", "Reduces opponents crit chance: ")
 
-		compare_fields(w, compare_with, field, "disarm_bonus", "%+d", "Trap disarming bonus: ")
-		compare_fields(w, compare_with, field, "inc_stealth", "%+d", "Stealth bonus: ")
-		compare_fields(w, compare_with, field, "max_encumber", "%+d", "Maximum encumberance: ")
+		compare_fields(w, compare_with, field, "disarm_bonus", "%+d", " trap disarm bonus")
+		compare_fields(w, compare_with, field, "inc_stealth", "%+d", " stealth")
+		compare_fields(w, compare_with, field, "max_encumber", "%+d", " max encumberance")
 
-		compare_fields(w, compare_with, field, "combat_physresist", "%+d", "Physical save: ")
-		compare_fields(w, compare_with, field, "combat_spellresist", "%+d", "Spell save: ")
-		compare_fields(w, compare_with, field, "combat_mentalresist", "%+d", "Mental save: ")
+		compare_fields(w, compare_with, field, "combat_physresist", "%+d", " physical save")
+		compare_fields(w, compare_with, field, "combat_spellresist", "%+d", " spell save")
+		compare_fields(w, compare_with, field, "combat_mentalresist", "%+d", " mental save")
 
-		compare_fields(w, compare_with, field, "blind_immune", "%+d%%", "Blindness immunity: ", 100)
-		compare_fields(w, compare_with, field, "poison_immune", "%+d%%", "Poison immunity: ", 100)
-		compare_fields(w, compare_with, field, "disease_immune", "%+d%%", "Disease immunity: ", 100)
-		compare_fields(w, compare_with, field, "cut_immune", "%+d%%", "Cut immunity: ", 100)
+		compare_fields(w, compare_with, field, "blind_immune", "%+d%%", " blindness immunity", 100)
+		compare_fields(w, compare_with, field, "poison_immune", "%+d%%", " poison immunity", 100)
+		compare_fields(w, compare_with, field, "disease_immune", "%+d%%", " disease immunity", 100)
+		compare_fields(w, compare_with, field, "cut_immune", "%+d%%", " cut immunity", 100)
 
-		compare_fields(w, compare_with, field, "silence_immune", "%+d%%", "Silence immunity: ", 100)
-		compare_fields(w, compare_with, field, "disarm_immune", "%+d%%", "Disarm immunity: ", 100)
-		compare_fields(w, compare_with, field, "confusion_immune", "%+d%%", "Confusion immunity: ", 100)
-		compare_fields(w, compare_with, field, "pin_immune", "%+d%%", "Pinning immunity: ", 100)
+		compare_fields(w, compare_with, field, "silence_immune", "%+d%%", " silence immunity", 100)
+		compare_fields(w, compare_with, field, "disarm_immune", "%+d%%", " disarm immunity", 100)
+		compare_fields(w, compare_with, field, "confusion_immune", "%+d%%", " confusion immunity", 100)
+		compare_fields(w, compare_with, field, "pin_immune", "%+d%%", " pinning immunity", 100)
 
-		compare_fields(w, compare_with, field, "stun_immune", "%+d%%", "Stun/Freeze immunity: ", 100)
-		compare_fields(w, compare_with, field, "fear_immune", "%+d%%", "Fear immunity: ", 100)
-		compare_fields(w, compare_with, field, "knockback_immune", "%+d%%", "Knockback immunity: ", 100)
-		compare_fields(w, compare_with, field, "instakill_immune", "%+d%%", "Instant-death immunity: ", 100)
-		compare_fields(w, compare_with, field, "teleport_immune", "%+d%%", "Teleport immunity: ", 100)
+		compare_fields(w, compare_with, field, "stun_immune", "%+d%%", " stun/freeze immunity", 100)
+		compare_fields(w, compare_with, field, "fear_immune", "%+d%%", " fear immunity", 100)
+		compare_fields(w, compare_with, field, "knockback_immune", "%+d%%", " knockback immunity", 100)
+		compare_fields(w, compare_with, field, "instakill_immune", "%+d%%", " instant-death immunity", 100)
+		compare_fields(w, compare_with, field, "teleport_immune", "%+d%%", " teleport immunity", 100)
 
-		compare_fields(w, compare_with, field, "life_regen", "%+.2f", "Life regen: ")
-		compare_fields(w, compare_with, field, "stamina_regen", "%+.2f", "Stamina each turn: ")
-		compare_fields(w, compare_with, field, "mana_regen", "%+.2f", "Mana each turn: ")
-		compare_fields(w, compare_with, field, "hate_regen", "%+.2f", "Hate each turn: ")
+		compare_fields(w, compare_with, field, "life_regen", "%+.1f", " life regen")
+		compare_fields(w, compare_with, field, "stamina_regen", "%+.1f", " stamina each turn")
+		compare_fields(w, compare_with, field, "mana_regen", "%+.1f", " mana each turn")
+		compare_fields(w, compare_with, field, "hate_regen", "%+.3f", " hate each turn")
 
-		compare_fields(w, compare_with, field, "stamina_regen_on_hit", "%+.2f", "Stamina when hit: ")
-		compare_fields(w, compare_with, field, "mana_regen_on_hit", "%+.2f", "Mana when hit: ")
-		compare_fields(w, compare_with, field, "equilibrium_regen_on_hit", "%+.2f", "Equilibrium when hit: ")
+		compare_fields(w, compare_with, field, "stamina_regen_on_hit", "%+.1f", " stamina when hit")
+		compare_fields(w, compare_with, field, "mana_regen_on_hit", "%+.1f", " mana when hit")
+		compare_fields(w, compare_with, field, "equilibrium_regen_on_hit", "%+.1f", " equilibrium when hit")
 
-		compare_fields(w, compare_with, field, "mana_on_crit", "%+.2f", "Mana when firing critical spell: ")
+		compare_fields(w, compare_with, field, "mana_on_crit", "%+d", " mana when firing critical spell")
 
-		compare_fields(w, compare_with, field, "die_at", "%+.2f life", "Only die when reaching: ", 1, true, true)
-		compare_fields(w, compare_with, field, "max_life", "%+.2f", "Maximum life: ")
-		compare_fields(w, compare_with, field, "max_mana", "%+.2f", "Maximum mana: ")
-		compare_fields(w, compare_with, field, "max_stamina", "%+.2f", "Maximum stamina: ")
-		compare_fields(w, compare_with, field, "max_hate", "%+.2f", "Maximum hate: ")
-		compare_fields(w, compare_with, field, "max_vim", "%+.2f", "Maximum vim: ")
-		compare_fields(w, compare_with, field, "max_air", "%+.2f", "Maximum air capacity: ")
+		compare_fields(w, compare_with, field, "die_at", "%+d life:", " point at which death occurs", 1, true, true)
+		compare_fields(w, compare_with, field, "max_life", "%+d", " maximum life")
+		compare_fields(w, compare_with, field, "max_mana", "%+d", " maximum mana")
+		compare_fields(w, compare_with, field, "max_stamina", "%+d", " maximum stamina")
+		compare_fields(w, compare_with, field, "max_hate", "%+.1f", " maximum hate")
+		compare_fields(w, compare_with, field, "max_vim", "%+d", " maximum vim")
+		compare_fields(w, compare_with, field, "max_air", "%+d", " maximum air capacity")
 
-		compare_fields(w, compare_with, field, "combat_spellpower", "%+d", "Spellpower: ")
-		compare_fields(w, compare_with, field, "combat_spellcrit", "%+d%%", "Spell crit. chance: ")
+		compare_fields(w, compare_with, field, "combat_spellpower", "%+d", " spellpower")
+		compare_fields(w, compare_with, field, "combat_spellcrit", "%+d%%", " spell crit. chance")
 
-		compare_fields(w, compare_with, field, "combat_mindpower", "%+d", "Mindpower: ")
-		compare_fields(w, compare_with, field, "combat_mindcrit", "%+d%%", "Mental crit. chance: ")
+		compare_fields(w, compare_with, field, "combat_mindpower", "%+d", " mindpower")
+		compare_fields(w, compare_with, field, "combat_mindcrit", "%+d%%", " mental crit. chance")
 
-		compare_fields(w, compare_with, field, "lite", "%+d", "Light radius: ")
-		compare_fields(w, compare_with, field, "infravision", "%+d", "Infravision radius: ")
-		compare_fields(w, compare_with, field, "heightened_senses", "%+d", "Heightened senses radius: ")
+		compare_fields(w, compare_with, field, "lite", "%+d", " light radius")
+		compare_fields(w, compare_with, field, "infravision", "%+d", " infravision radius")
+		compare_fields(w, compare_with, field, "heightened_senses", "%+d", " heightened senses radius")
 
-		compare_fields(w, compare_with, field, "see_invisible", "%+d", "See invisible: ")
-		compare_fields(w, compare_with, field, "invisible", "%+d", "Invisibility: ")
+		compare_fields(w, compare_with, field, "see_invisible", "%+d", " see invisible")
+		compare_fields(w, compare_with, field, "invisible", "%+d", " invisibility")
 
-		compare_fields(w, compare_with, field, "movement_speed", "%+d%%", "Movement speed: ", 100)
-		compare_fields(w, compare_with, field, "combat_physspeed", "%+d%%", "Combat speed: ", 100)
-		compare_fields(w, compare_with, field, "combat_spellspeed", "%+d%%", "Casting speed: ", 100)
+		compare_fields(w, compare_with, field, "movement_speed", "%+d%%", " movement speed", 100)
+		compare_fields(w, compare_with, field, "combat_physspeed", "%+d%%", " combat speed", 100)
+		compare_fields(w, compare_with, field, "combat_spellspeed", "%+d%%", " casting speed", 100)
 
-		compare_fields(w, compare_with, field, "healing_factor", "%+d%%", "Healing mod.: ", 100)
+		compare_fields(w, compare_with, field, "healing_factor", "%+d%%", " healing mod.", 100)
 
-		compare_fields(w, compare_with, field, "life_leech_chance", "%+d%%", "Life leech chance: ")
-		compare_fields(w, compare_with, field, "life_leech_value", "%+d%%", "Life leech: ")
+		compare_fields(w, compare_with, field, "life_leech_chance", "%+d%%", " life leech chance")
+		compare_fields(w, compare_with, field, "life_leech_value", "%+d%%", " life leech")
 
-		compare_fields(w, compare_with, field, "resource_leech_chance", "%+d%%", "Resource leech chance: ")
-		compare_fields(w, compare_with, field, "resource_leech_value", "%+d", "Resource leech: ")
+		compare_fields(w, compare_with, field, "resource_leech_chance", "%+d%%", " resource leech chance")
+		compare_fields(w, compare_with, field, "resource_leech_value", "%+d", " resource leech")
 
-		compare_fields(w, compare_with, field, "size_category", "%+d", "Size category: ")
+		compare_fields(w, compare_with, field, "size_category", "%+d", " size category")
 
 		if w.undead then
 			desc:add("The wearer is treated as an undead.", true)
 		end
-		
+
 		if w.blind_fight then
 			desc:add({"color", "YELLOW"}, "Blind-Fight:", {"color", "LAST"}, "This item allows the wearer to attack unseen targets without any penalties.", true)
 		end
@@ -808,13 +1018,13 @@ function _M:getTextualDesc(compare_with)
 
 		if (w and w.combat or can_combat_unarmed) and game.player:knowTalent(game.player.T_EMPTY_HAND) then
 			desc:add({"color","YELLOW"}, "When used to modify unarmed attacks:", {"color", "LAST"}, true)
-			compare_tab = { dam=1, atk=1, apr=0, physcrit=0, physspeed =1, dammod={str=1}, damrange=1.1 }
+			compare_tab = { dam=1, critical_power = 1.1, max_acc = 75, atk=0, apr=0, physcrit=0, physspeed =1, dammod={str=0.1}, damrange=1, unarmed=true }
 			desc_combat(w, compare_unarmed, "combat", compare_tab)
 		end
 	end
+
 	local can_combat = false
 	local can_special_combat = false
-	local can_basic_ammo = false
 	local can_wielder = false
 	local can_carrier = false
 	local can_imbue_powers = false
@@ -826,9 +1036,6 @@ function _M:getTextualDesc(compare_with)
 		if v.special_combat then
 			can_special_combat = true
 		end
-		if v.basic_ammo then
-			can_basic_ammo = true
-		end
 		if v.wielder then
 			can_wielder = true
 		end
@@ -846,6 +1053,7 @@ function _M:getTextualDesc(compare_with)
 
 	if (self.special_combat or can_special_combat) and (game.player:knowTalentType("technique/shield-offense") or game.player:knowTalentType("technique/shield-defense")) then
 		desc:add({"color","YELLOW"}, "When used to attack (with talents):", {"color", "LAST"}, true)
+		desc:add(true)
 		desc_combat(self, compare_with, "special_combat")
 	end
 
@@ -862,16 +1070,11 @@ function _M:getTextualDesc(compare_with)
 		desc:add({"color","RED"}, "It is immune to teleportation, if you teleport it will fall on the ground.", {"color", "LAST"}, true)
 	end
 
-	if self.basic_ammo or can_basic_ammo then
-		desc:add({"color","YELLOW"}, "Default ammo(infinite):", {"color", "LAST"}, true)
-		desc_combat(self, compare_with, "basic_ammo")
-	end
-
 	if self.wielder or can_wielder then
-		desc:add({"color","YELLOW"}, "When wielded/worn:", {"color", "LAST"}, true)
+		desc:add({"color","YELLOW"}, "          When wielded/worn:", {"color", "LAST"}, true)
 		desc_wielder(self, compare_with, "wielder")
 		if self:attr("skullcracker_mult") and game.player:knowTalent(game.player.T_SKULLCRACKER) then
-			compare_fields(self, compare_with, "wielder", "skullcracker_mult", "%+d", "Skullcracker multiplicator: ")
+			compare_fields(self, compare_with, "wielder", "skullcracker_mult", "%+d", " Skullcracker multiplicator", nil, nil, nil, nil, true)
 		end
 	end
 
@@ -933,7 +1136,7 @@ function _M:getTextualDesc(compare_with)
 			desc:add({"color",0xf5,0x3c,0xbe}, game.player.tempeffect_def[self.curse].desc, {"color","LAST"}, true)
 		end
 	end
-
+	desc:add("---", true)
 	local use_desc = self:getUseDesc()
 	if use_desc then desc:merge(use_desc:toTString()) end
 	return desc
@@ -979,11 +1182,21 @@ function _M:getDesc(name_param, compare_with, never_compare)
 		desc:add({"color", "WHITE"}, true)
 		desc:add(true)
 		desc:add({"color", "ANTIQUE_WHITE"})
-		desc:merge(self.desc:toTString())
-		desc:add(true, true)
+		--desc:merge(self.desc:toTString())
+		--desc:add(true, true)
 		desc:add({"color", "WHITE"})
 	end
 
+	local could_compare = false
+	if not name_param.force_compare and not core.key.modState("ctrl") then
+		if compare_with[1] then could_compare = true end
+		compare_with = {}
+	end
+
+	desc:merge(self:getTextualDesc(compare_with, true))
+	desc:add(true)
+	desc:add(true, ("Type: %s / %s"):format(rawget(self, 'type') or "unknown", rawget(self, 'subtype') or "unknown"), true)
+	if self.slot_forbid == "OFFHAND" then desc:add("It must be held with both hands. ") end
 	local reqs = self:getRequirementDesc(game.player)
 	if reqs then
 		desc:merge(reqs)
@@ -1004,14 +1217,6 @@ function _M:getDesc(name_param, compare_with, never_compare)
 
 	desc:add(true, true)
 
-	local could_compare = false
-	if not name_param.force_compare and not core.key.modState("ctrl") then
-		if compare_with[1] then could_compare = true end
-		compare_with = {}
-	end
-
-	desc:merge(self:getTextualDesc(compare_with))
-
 	if could_compare and not never_compare then desc:add(true, {"font","italic"}, {"color","GOLD"}, "Press <control> to compare", {"color","LAST"}, {"font","normal"}) end
 
 	return desc
diff --git a/game/modules/tome/class/PlayerDisplay.lua b/game/modules/tome/class/PlayerDisplay.lua
index 440a40add8..22f44923fe 100644
--- a/game/modules/tome/class/PlayerDisplay.lua
+++ b/game/modules/tome/class/PlayerDisplay.lua
@@ -375,8 +375,9 @@ function _M:display()
 
 	local quiver = player:getInven("QUIVER")
 	local ammo = quiver and quiver[1]
-	if ammo then
-		self:mouseTooltip(self.TOOLTIP_COMBAT_AMMO, self:makeTexture(("#ANTIQUE_WHITE#Ammo:       #ffffff#%d"):format(ammo:getNumber()), 0, h, 255, 255, 255)) h = h + self.font_h
+	if ammo and ammo.combat then
+		local shots_left = ammo.combat.shots_left or 0
+		self:mouseTooltip(self.TOOLTIP_COMBAT_AMMO, self:makeTexture(("#ANTIQUE_WHITE#Ammo:       #ffffff#%d"):format(shots_left), 0, h, 255, 255, 255)) h = h + self.font_h
 	end
 
 	if savefile_pipe.saving then
diff --git a/game/modules/tome/class/interface/Archery.lua b/game/modules/tome/class/interface/Archery.lua
index e54b6055dc..41d2128997 100644
--- a/game/modules/tome/class/interface/Archery.lua
+++ b/game/modules/tome/class/interface/Archery.lua
@@ -32,7 +32,7 @@ module(..., package.seeall, class.make)
 function _M:archeryAcquireTargets(tg, params)
 	local weapon, ammo = self:hasArcheryWeapon()
 	if not weapon then
-		game.logPlayer(self, "You must wield a bow or a sling (%s)!", ammo)
+		game.logPlayer(self, "(%s)", ammo)
 		return nil
 	end
 	params = params or {}
@@ -42,28 +42,27 @@ function _M:archeryAcquireTargets(tg, params)
 	weapon = weapon.combat
 
 	local tg = tg or {type="bolt"}
+	tg.type = weapon.tg_type or ammo.combat.tg_type or tg.type
 
 	if not tg.range then tg.range=weapon.range or 6 end
 	tg.display = tg.display or {display='/'}
-	tg.speed = (tg.speed or 20) * (ammo.travel_speed or 100) / 100
+	tg.speed = (tg.speed or 6) * ((ammo.combat.travel_speed or 100) / 100) * (weapon.travel_speed or 100) / 100
 	local x, y = self:getTarget(tg)
 	if not x or not y then return nil end
 
 	-- Find targets to know how many ammo we use
 	local targets = {}
 	if params.one_shot then
-		local a
-		if not ammo.infinite then
-			a = self:removeObject(self:getInven("QUIVER"), 1)
-		else
-			a = ammo
-		end
-		if a then
-			targets = {{x=x, y=y, ammo=a.combat}}
+		if not ammo.combat.shots_left then return nil end
+		if ammo.combat.shots_left == 0 then
+			game.logPlayer(self, "You are out of ammo!")
+			return nil
 		end
+		ammo.combat.shots_left = ammo.combat.shots_left - 1
+		targets = {{x=x, y=y, ammo=ammo.combat}}
 	else
+		if not ammo.combat.shots_left then return nil end
 		local limit_shots = params.limit_shots
-
 		self:project(tg, x, y, function(tx, ty)
 			local target = game.level.map(tx, ty, game.level.map.ACTOR)
 			if not target then return end
@@ -75,14 +74,9 @@ function _M:archeryAcquireTargets(tg, params)
 			end
 
 			for i = 1, params.multishots or 1 do
-				local a
-				if not ammo.infinite then
-					a = self:removeObject(self:getInven("QUIVER"), 1)
-				else
-					a = ammo
-				end
-				if a then targets[#targets+1] = {x=tx, y=ty, ammo=a.combat}
-				else break end
+				if ammo.combat.shots_left == 0 then break end
+				ammo.combat.shots_left = ammo.combat.shots_left - 1
+				targets[#targets+1] = {x=tx, y=ty, ammo=ammo.combat}
 			end
 		end)
 	end
@@ -95,11 +89,6 @@ function _M:archeryAcquireTargets(tg, params)
 		self:useEnergy(game.energy_to_act * (speed or 1))
 
 		if sound then game:playSoundNear(self, sound) end
-
-		if not ammo.infinite and (ammo:getNumber() < 10 or ammo:getNumber() == 50 or ammo:getNumber() == 40 or ammo:getNumber() == 25) then
-			game.logPlayer(self, "You only have %s left!", ammo:getName{do_color=true})
-		end
-
 		return targets
 	else
 		return nil
@@ -124,14 +113,17 @@ local function archery_projectile(tx, ty, tg, self, tmp)
 	-- Does the blow connect? yes .. complex :/
 	if tg.archery.use_psi_archery then self.use_psi_combat = true end
 	local atk, def = self:combatAttack(weapon, ammo), target:combatDefenseRanged()
-	local dam, apr, armor = self:combatDamage(ammo), self:combatAPR(ammo), target:combatArmor()
+	local armor = target:combatArmor()
+	local dam = self:combatDamage(ammo) + self:combatDamage(weapon)
+	local apr = self:combatAPR(ammo) + self:combatAPR(weapon)
 	atk = atk + (tg.archery.atk or 0)
 	dam = dam + (tg.archery.dam or 0)
 	print("[ATTACK ARCHERY] to ", target.name, " :: ", dam, apr, armor, "::", mult)
 
 	-- If hit is over 0 it connects, if it is 0 we still have 50% chance
 	local hitted = false
-	if self:checkHit(atk, def) and (self:canSee(target) or self:attr("blind_fight") or rng.chance(3)) then
+	local crit = false
+	if self:checkHit(atk, def, 0, self:getMaxAccuracy("physical", ammo)) and (self:canSee(target) or self:attr("blind_fight") or rng.chance(3)) then
 		apr = apr + (tg.archery.apr or 0)
 		print("[ATTACK ARCHERY] raw dam", dam, "versus", armor, "with APR", apr)
 
@@ -140,24 +132,28 @@ local function archery_projectile(tx, ty, tg, self, tmp)
 		dam = math.max(dam * pres - armor, 0) + (dam * (1 - pres))
 		print("[ATTACK ARCHERY] after armor", dam)
 
-		local damrange = self:combatDamageRange(ammo)
-		dam = rng.range(dam, dam * damrange)
-		print("[ATTACK ARCHERY] after range", dam)
-
-		local crit
+		local pre_crit_dam = dam
 		if tg.archery.crit_chance then self.combat_physcrit = self.combat_physcrit + tg.archery.crit_chance end
-		dam, crit = self:physicalCrit(dam, ammo, target, atk, def)
+		dam, crit = self:physicalCrit(dam, weapon, target, atk, def)
 		if tg.archery.crit_chance then self.combat_physcrit = self.combat_physcrit - tg.archery.crit_chance end
 		print("[ATTACK ARCHERY] after crit", dam)
 
 		dam = dam * mult
 		print("[ATTACK ARCHERY] after mult", dam)
 
-		if crit then game.logSeen(self, "#{bold}#%s performs a critical strike!#{normal}#", self.name:capitalize()) end
+		if crit then
+			game.logSeen(self, "#{bold}#%s performs a critical strike!#{normal}#", self.name:capitalize())
+			if (weapon.concussion or ammo.concussion) then
+				dam = pre_crit_dam
+				self:doConcussion(dam, target, {weapon, ammo})
+			end
+		end
 		DamageType:get(damtype).projector(self, target.x, target.y, damtype, math.max(0, dam), tmp)
+
 		game.level.map:particleEmitter(target.x, target.y, 1, "archery")
 		hitted = true
 
+
 		if talent.archery_onhit then talent.archery_onhit(self, talent, target, target.x, target.y) end
 	else
 		local srcname = game.level.map.seens(self.x, self.y) and self.name:capitalize() or "Something"
@@ -179,12 +175,27 @@ local function archery_projectile(tx, ty, tg, self, tmp)
 	end
 
 	-- Ranged project
-	if hitted and not target.dead then for typ, dam in pairs(self.ranged_project) do
+	local weapon_ranged_project = weapon.ranged_project or {}
+	local ammo_ranged_project = ammo.ranged_project or {}
+	local total_ranged_project = {}
+	table.mergeAdd(total_ranged_project, weapon_ranged_project, true)
+	table.mergeAdd(total_ranged_project, ammo_ranged_project, true)
+	if hitted and not target.dead then for typ, dam in pairs(total_ranged_project) do
 		if dam > 0 then
 			DamageType:get(typ).projector(self, target.x, target.y, typ, dam, tmp)
 		end
 	end end
 
+	-- Talent on hit
+	if hitted and not target.dead and weapon and weapon.talent_on_hit and next(weapon.talent_on_hit) then
+		self:doTalentOnHit(target, weapon)
+	end
+
+	-- Special effect
+	if hitted and not target.dead and weapon and weapon.special_on_hit and weapon.special_on_hit.fct then
+		weapon.special_on_hit.fct(weapon, self, target)
+	end
+
 	-- Temporal cast
 	if hitted and not target.dead and self:knowTalent(self.T_WEAPON_FOLDING) and self:isTalentActive(self.T_WEAPON_FOLDING) then
 		local t = self:getTalentFromId(self.T_WEAPON_FOLDING)
@@ -237,6 +248,12 @@ local function archery_projectile(tx, ty, tg, self, tmp)
 		target:knockback(self.x, self.y, math.ceil(math.log(dam)))
 	end
 
+	-- Savagery
+	if hitted and crit and self:knowTalent(self.T_SAVAGERY) then
+		local t = self:getTalentFromId(self.T_SAVAGERY)
+		t.do_savagery(self, t)
+	end
+
 	self.use_psi_combat = false
 end
 
@@ -256,17 +273,20 @@ function _M:archeryShoot(targets, talent, tg, params)
 	weapon = weapon.combat
 
 	local tg = tg or {type="bolt"}
+	tg.type = weapon.tg_type or ammo.combat.tg_type or tg.type
 	tg.talent = tg.talent or talent
 
 	if not tg.range then tg.range=weapon.range or 6 end
 	tg.display = tg.display or {display=' ', particle="arrow", particle_args={tile="shockbolt/"..(ammo.proj_image or realweapon.proj_image):gsub("%.png$", "")}}
-	tg.speed = (tg.speed or 20) * (ammo.travel_speed or 100) / 100
+	tg.speed = (tg.speed or 6) * ((ammo.combat.travel_speed or 100) / 100) * (weapon.travel_speed or 100) / 100
 	tg.archery = params or {}
 	tg.archery.weapon = weapon
+	local grids = nil
 	for i = 1, #targets do
 		local tg = table.clone(tg)
 		tg.archery.ammo = targets[i].ammo
 		self:projectile(tg, targets[i].x, targets[i].y, archery_projectile)
+		if ammo.combat.lite then self:project(tg, targets[i].x, targets[i].y, DamageType.LITE, 1) end
 	end
 end
 
@@ -290,13 +310,43 @@ function _M:hasArcheryWeapon(type)
 		return nil, "no shooter"
 	end
 	if not ammo then
-		-- Launchers provide infinite basic ammo
-		ammo = {name="default", infinite=true, combat=weapon.basic_ammo}
+		return nil, "Your quiver is empty."
 	else
-		if not ammo.archery_ammo or weapon.archery ~= ammo.archery_ammo then
+		if not ammo.archery_ammo or weapon.archery ~= ammo.archery_ammo or not ammo.combat then
 			return nil, "bad ammo"
 		end
 	end
 	if type and weapon.archery ~= type then return nil, "bad type" end
 	return weapon, ammo
 end
+
+--- Check if the actor has a bow or sling
+function _M:hasShooter(type)
+	if not self:getInven("MAINHAND") then return nil, "no shooter" end
+	local weapon = self:getInven("MAINHAND")[1]
+	if self.inven[self.INVEN_PSIONIC_FOCUS] then
+		local pf_weapon = self:getInven("PSIONIC_FOCUS")[1]
+		if pf_weapon and pf_weapon.archery then
+			weapon = pf_weapon
+		end
+	end
+	if not weapon or not weapon.archery then
+		return nil, "no shooter"
+	end
+
+	if type and weapon.archery ~= type then return nil, "bad type" end
+	return weapon
+end
+
+--- Check if the actor has a bow or sling and corresponding ammo
+function _M:hasAmmo(type)
+	if not self:getInven("QUIVER") then return nil, "no ammo" end
+	local ammo = self:getInven("QUIVER")[1]
+
+	if not ammo then return nil, "no ammo" end
+	if not ammo.archery_ammo then return nil, "bad ammo" end
+	if not ammo.combat then return nil, "bad ammo" end
+	if not ammo.combat.capacity then return nil, "bad ammo" end
+	if type and ammo.archery_ammo ~= type then return nil, "bad type" end
+	return ammo, "no problem"
+end
diff --git a/game/modules/tome/class/interface/Combat.lua b/game/modules/tome/class/interface/Combat.lua
index 7c13562791..185b73242d 100644
--- a/game/modules/tome/class/interface/Combat.lua
+++ b/game/modules/tome/class/interface/Combat.lua
@@ -252,7 +252,7 @@ function _M:crossTierEffect(eff_id, apply_power, apply_save, use_given_e)
 		ct_effect = cross_tier_effects[save_for_effects[e.type]]
 	end
 	local dur = self:getTierDiff(apply_power, save)
-	self:setEffect(ct_effect, dur, {})
+	self:setEffect(ct_effect, dur, {no_ct_effect=true})
 end
 
 function _M:getTierDiff(atk, def)
@@ -261,10 +261,28 @@ function _M:getTierDiff(atk, def)
 	return math.max(0, math.max(math.ceil(atk/20), 1) - math.max(math.ceil(def/20), 1))
 end
 
+--- Gets crit magnitude
+function _M:getMaxAccuracy(hit_type, combat)
+	if hit_type == "physical" then return (combat and combat.max_acc) or 75 end
+	local mh = (self:getInven("MAINHAND") and self:getInven("MAINHAND")[1]) or {}
+	local oh = (self:getInven("OFFHAND") and self:getInven("OFFHAND")[1]) or {}
+	local pf = (self:getInven("PSIONIC_FOCUS") and self:getInven("PSIONIC_FOCUS")[1]) or {}
+	if hit_type == "spell" then
+		--if combat and combat.max_acc then return combat.max_acc end
+		return (combat and combat.affects_spells and combat.max_acc) or math.max(
+			(mh.combat and mh.combat.affects_spells and mh.combat.max_acc) or 75,
+			(oh.combat and oh.combat.affects_spells and oh.combat.max_acc) or (oh.special_combat and oh.special_combat.affects_spells and oh.special_combat.max_acc) or 75,
+			(pf.combat and pf.combat.max_acc) or 75
+		)
+	end
+	return 75
+
+end
+
 --New, simpler checkHit that relies on rescaleCombatStats() being used elsewhere
 function _M:checkHit(atk, def, min, max, factor, p)
 	local min = min or 0
-	local max = max or 100
+	local max = max or 75
 	if game.player:hasQuest("tutorial-combat-stats") then
 		min = 0
 		max = 100
@@ -273,6 +291,7 @@ function _M:checkHit(atk, def, min, max, factor, p)
 	local hit = math.ceil(50 + 2.5 * (atk - def))
 	hit = util.bound(hit, min, max)
 	print("=> chance to hit", hit)
+	print("min: ", min, "max: ", max)
 	return rng.percent(hit), hit
 end
 
@@ -337,20 +356,21 @@ function _M:attackTargetWith(target, weapon, damtype, mult, force_dam)
 	local hitted = false
 	local crit = false
 	local evaded = false
+	local pre_crit_dam = 0
 	if repelled then
 		game.logSeen(target, "%s repels an attack from %s.", target.name:capitalize(), self.name)
 	elseif self:checkEvasion(target) then
 		evaded = true
 		game.logSeen(target, "%s evades %s.", target.name:capitalize(), self.name)
-	elseif self:checkHit(atk, def) and (self:canSee(target) or self:attr("blind_fight") or rng.chance(3)) then
+	elseif self:checkHit(atk, def, 0, self:getMaxAccuracy("physical", weapon)) and (self:canSee(target) or self:attr("blind_fight") or rng.chance(3)) then
 		local pres = util.bound(target:combatArmorHardiness() / 100, 0, 1)
 		print("[ATTACK] raw dam", dam, "versus", armor, pres, "with APR", apr)
 		armor = math.max(0, armor - apr)
 		dam = math.max(dam * pres - armor, 0) + (dam * (1 - pres))
 		print("[ATTACK] after armor", dam)
-		local damrange = self:combatDamageRange(weapon)
-		dam = rng.range(dam, dam * damrange)
-		print("[ATTACK] after range", dam)
+--		local damrange = self:combatDamageRange(weapon)
+--		dam = rng.range(dam, dam * damrange)
+--		print("[ATTACK] after range", dam)
 		dam, crit = self:physicalCrit(dam, weapon, target, atk, def)
 		print("[ATTACK] after crit", dam)
 		dam = dam * mult
@@ -362,8 +382,25 @@ function _M:attackTargetWith(target, weapon, damtype, mult, force_dam)
 			end
 			print("[ATTACK] after inc by type", dam)
 		end
-
-		if crit then game.logSeen(self, "#{bold}#%s performs a critical strike!#{normal}#", self.name:capitalize()) end
+		--if target:attr("counterstrike") then
+		if target:hasEffect(target.EFF_COUNTERSTRIKE) then
+			dam = dam * 2
+			--self:removeEffect(target.EFF_COUNTERSTRIKE)
+			local eff = target.tmp[target.EFF_COUNTERSTRIKE]
+			eff.nb = eff.nb - 1
+			if eff.nb == 0 then eff.dur = 0 end
+		end
+		pre_crit_dam = dam
+		dam, crit = self:physicalCrit(dam, weapon, target, atk, def)
+		print("[ATTACK] after crit", dam)
+		if crit then
+			game.logSeen(self, "#{bold}#%s performs a critical strike!#{normal}#", self.name:capitalize())
+			-- Concussion
+			if weapon.concussion then
+				dam = pre_crit_dam
+				self:doConcussion(dam, target, {weapon, ammo})
+			end
+		end
 		DamageType:get(damtype).projector(self, target.x, target.y, damtype, math.max(0, dam))
 		hitted = true
 	else
@@ -464,7 +501,7 @@ function _M:attackTargetWith(target, weapon, damtype, mult, force_dam)
 		t.do_trigger(self, t, target)
 	end
 
-	-- On hit talent
+--[=[	-- On hit talent
 	if hitted and not target.dead and weapon and weapon.talent_on_hit and next(weapon.talent_on_hit) then
 		for tid, data in pairs(weapon.talent_on_hit) do
 			if rng.percent(data.chance) then
@@ -472,6 +509,10 @@ function _M:attackTargetWith(target, weapon, damtype, mult, force_dam)
 			end
 		end
 	end
+]=]
+	if hitted and not target.dead and weapon and weapon.talent_on_hit and next(weapon.talent_on_hit) then
+		self:doTalentOnHit(target, weapon)
+	end
 
 	-- Shattering Impact
 	if hitted and self:attr("shattering_impact") and (not self.shattering_impact_last_turn or self.shattering_impact_last_turn < game.turn) then
@@ -488,15 +529,15 @@ function _M:attackTargetWith(target, weapon, damtype, mult, force_dam)
 		local rx, ry = util.coordAddDir(self.x, self.y, dir_sides[dir or 6].right)
 		local lt, rt = game.level.map(lx, ly, Map.ACTOR), game.level.map(rx, ry, Map.ACTOR)
 
-		if target:checkHit(self:combatAttack(weapon), target:combatPhysicalResist(), 0, 95, 10) and target:canBe("knockback") then
+		if target:checkHit(self:combatAttack(weapon), target:combatPhysicalResist(), 0, self:getMaxAccuracy("physical", weapon), 10) and target:canBe("knockback") then
 			target:knockback(self.x, self.y, self:attr("onslaught"))
 			target:crossTierEffect(target.EFF_OFFBALANCE, self:combatAttack())
 		end
-		if lt and lt:checkHit(self:combatAttack(weapon), lt:combatPhysicalResist(), 0, 95, 10) and lt:canBe("knockback") then
+		if lt and lt:checkHit(self:combatAttack(weapon), lt:combatPhysicalResist(), 0, self:getMaxAccuracy("physical", weapon), 10) and lt:canBe("knockback") then
 			lt:knockback(self.x, self.y, self:attr("onslaught"))
 			target:crossTierEffect(target.EFF_OFFBALANCE, self:combatAttack())
 		end
-		if rt and rt:checkHit(self:combatAttack(weapon), rt:combatPhysicalResist(), 0, 95, 10) and rt:canBe("knockback") then
+		if rt and rt:checkHit(self:combatAttack(weapon), rt:combatPhysicalResist(), 0, self:getMaxAccuracy("physical", weapon), 10) and rt:canBe("knockback") then
 			rt:knockback(self.x, self.y, self:attr("onslaught"))
 			target:crossTierEffect(target.EFF_OFFBALANCE, self:combatAttack())
 		end
@@ -515,6 +556,12 @@ function _M:attackTargetWith(target, weapon, damtype, mult, force_dam)
 		t.do_splash(target, t, self)
 	end
 
+	-- Savagery
+	if hitted and crit and self:knowTalent(self.T_SAVAGERY) then
+		local t = self:getTalentFromId(self.T_SAVAGERY)
+		t.do_savagery(self, t)
+	end
+
 	-- Bloodbath
 	if hitted and crit and self:knowTalent(self.T_BLOODBATH) then
 		local t = self:getTalentFromId(self.T_BLOODBATH)
@@ -579,13 +626,13 @@ function _M:attackTargetWith(target, weapon, damtype, mult, force_dam)
 		local t = target:getTalentFromId(target.T_CARBON_SPIKES)
 		t.do_carbonLoss(target, t)
 	end
-
+--[=[
 	-- Riposte!
 	if not hitted and not target.dead and not evaded and not target:attr("stunned") and not target:attr("dazed") and not target:attr("stoned") and target:knowTalent(target.T_RIPOSTE) and rng.percent(target:getTalentLevel(target.T_RIPOSTE) * (5 + target:getDex(5, true))) then
 		game.logSeen(self, "%s ripostes!", target.name:capitalize())
 		target:attackTarget(self, nil, nil, true)
 	end
-
+]=]
 	-- Set Up
 	if not hitted and not target.dead and not evaded and not target:attr("stunned") and not target:attr("dazed") and not target:attr("stoned") and target:hasEffect(target.EFF_DEFENSIVE_MANEUVER) then
 		local t = target:getTalentFromId(target.T_SET_UP)
@@ -720,7 +767,9 @@ local weapon_talents = {
 function _M:combatCheckTraining(weapon)
 	if not weapon.talented then return 0 end
 	if not weapon_talents[weapon.talented] then return 0 end
-	return self:getTalentLevel(weapon_talents[weapon.talented])
+	local t = self:getTalentFromId(weapon_talents[weapon.talented])
+	return t.getDamage(self, t)
+	--return self:getTalentLevel(weapon_talents[weapon.talented])
 end
 
 --- Gets the defense
@@ -848,10 +897,20 @@ function _M:combatCrit(weapon)
 	return crit
 end
 
+--- Gets crit magnitude
+function _M:combatCritPower(crit_type, weapon)
+	local combat = weapon or self.combat or {}
+	if crit_type == "spell" and not combat.affects_spells then
+		return 1.1
+	else
+		return (combat.critical_power or 1.1) + (self.combat_critical_power or 0)
+	end
+end
+
 --- Gets the damage range
 function _M:combatDamageRange(weapon)
 	weapon = weapon or self.combat or {}
-	return (self.combat_damrange or 0) + (weapon.damrange or 1.1)
+	return (self.combat_damrange or 0) + (weapon.damrange or 1)
 end
 
 
@@ -883,7 +942,7 @@ function _M:combatDamage(weapon)
 	if weapon.talented and weapon.talented == "knife" and self:knowTalent(Talents.T_LETHALITY) then sub_cun_to_str = true end
 
 	local totstat = 0
-	local dammod = weapon.dammod or {str=0.6}
+	local dammod = weapon.dammod or {str=0.1}
 	for stat, mod in pairs(dammod) do
 		if sub_cun_to_str and stat == "str" then stat = "cun" end
 		if self.use_psi_combat and stat == "str" then stat = "wil" end
@@ -898,13 +957,22 @@ function _M:combatDamage(weapon)
 			totstat = totstat * 0.6
 		end
 	end
+	totstat = math.floor(totstat)
+
+	local talent_dam = self:combatCheckTraining(weapon)
+	--print(("[COMBAT DAMAGE] dam(%f) totstat(%f) talent_dam (%f)"):format(weapon.dam, totstat, talent_dam))
+	return math.floor(weapon.dam + totstat + talent_dam)
+end
 
-	local talented_mod = math.sqrt(self:combatCheckTraining(weapon) / 10) / 2 + 1
+function _M:getCombinedDamage(o, offmult)
+	local offmult = offmult or 1
+	local weapon, ammo = self:hasArcheryWeapon()
+	if weapon then
+		return self:combatDamage(weapon.combat)*offmult + self:combatDamage(ammo.combat) + weapon:getRangedProjectDam() + ammo:getRangedProjectDam()
+	else
+		return self:combatDamage(o.combat)*offmult + o:getRangedProjectDam() + o:getMeleeProjectDam()
+	end
 
-	local power = math.max((weapon.dam or 1), 1)
-	power = (math.sqrt(power / 10) - 1) * 0.5 + 1
-	--print(("[COMBAT DAMAGE] power(%f) totstat(%f) talent_mod(%f)"):format(power, totstat, talented_mod))
-	return self:rescaleDamage(0.3*(self:combatPhysicalpower() + totstat) * power * talented_mod)
 end
 
 function _M:combatPhysicalpower(mod)
@@ -920,28 +988,6 @@ function _M:combatPhysicalpower(mod)
 		local t = self:getTalentFromId(self.T_EMPTY_HAND)
 		add = add + t.getDamage(self, t)
 	end
-	if self:knowTalent(Talents.T_WEAPONS_MASTERY) then
-		add = add + 5 * self:getTalentLevel(Talents.T_WEAPONS_MASTERY)
-	end
-	if self:knowTalent(Talents.T_KNIFE_MASTERY) then
-		add = add + 5 * self:getTalentLevel(Talents.T_KNIFE_MASTERY)
-	end
-	if self:knowTalent(Talents.T_EXOTIC_WEAPONS_MASTERY) then
-		add = add + 5 * self:getTalentLevel(Talents.T_EXOTIC_WEAPONS_MASTERY)
-	end
-	if self:knowTalent(Talents.T_UNARMED_MASTERY) then
-		add = add + 5 * self:getTalentLevel(Talents.T_UNARMED_MASTERY)
-	end
-	if self:knowTalent(Talents.T_STAFF_MASTERY) then
-		add = add + 5 * self:getTalentLevel(Talents.T_STAFF_MASTERY)
-	end
-	if self:knowTalent(Talents.T_BOW_MASTERY) then
-		add = add + 5 * self:getTalentLevel(Talents.T_BOW_MASTERY)
-	end
-	if self:knowTalent(Talents.T_SLING_MASTERY) then
-		add = add + 5 * self:getTalentLevel(Talents.T_SLING_MASTERY)
-	end
-
 	return self:rescaleCombatStats((self.combat_dam > 0 and self.combat_dam or 0) + add + self:getStr()) * mod
 end
 
@@ -1050,6 +1096,7 @@ function _M:physicalCrit(dam, weapon, target, atk, def)
 	end
 
 	local chance = self:combatCrit(weapon)
+	local magnitude = self:combatCritPower("physical", weapon)
 	local crit_power_add = 0
 	local crit = false
 	if self:knowTalent(self.T_BACKSTAB) and target:attr("stunned") then chance = chance + self:getTalentLevel(self.T_BACKSTAB) * 10 end
@@ -1063,6 +1110,12 @@ function _M:physicalCrit(dam, weapon, target, atk, def)
 			chance = chance + p.power
 		end
 	end
+	if target:hasEffect(target.EFF_COUNTERSTRIKE) then
+		local p = target:hasEffect(target.EFF_COUNTERSTRIKE)
+		if p and p.src == self then
+			chance = chance + p.crit_inc
+		end
+	end
 	if target:hasEffect(target.EFF_OFFGUARD) then
 		chance = chance + 10
 	end
@@ -1070,7 +1123,7 @@ function _M:physicalCrit(dam, weapon, target, atk, def)
 	if target:hasHeavyArmor() and target:knowTalent(target.T_ARMOUR_TRAINING) then
 		chance = chance - target:getTalentLevel(target.T_ARMOUR_TRAINING) * 1.9
 	end
-	
+
 	if target:attr("combat_critreduction") then
 		chance = chance - target:attr("combat_critreduction")
 	end
@@ -1086,7 +1139,7 @@ function _M:physicalCrit(dam, weapon, target, atk, def)
 		if target:hasEffect(target.EFF_OFFGUARD) then
 			crit_power_add = crit_power_add + 0.1
 		end
-		dam = dam * (1.5 + crit_power_add + (self.combat_critical_power or 0) / 100)
+		dam = dam * (magnitude + crit_power_add + (self.combat_critical_power or 0) / 100)
 		crit = true
 
 	end
@@ -1095,21 +1148,31 @@ end
 
 --- Computes spell crit for a damage
 function _M:spellCrit(dam, add_chance)
-	if self:isTalentActive(self.T_STEALTH) and self:knowTalent(self.T_SHADOWSTRIKE) then
-		return dam * (1.5 + self:getTalentLevel(self.T_SHADOWSTRIKE) / 7), true
-	end
 
 	local chance = self:combatSpellCrit() + (add_chance or 0)
 	local crit = false
 
+	-- get all weapons and use the largest crit magnitude that applies
+	local mh = (self:getInven("MAINHAND") and self:getInven("MAINHAND")[1]) or {}
+	local oh = (self:getInven("OFFHAND") and self:getInven("OFFHAND")[1]) or {}
+	local pf = (self:getInven("PSIONIC_FOCUS") and self:getInven("PSIONIC_FOCUS")[1]) or {}
+	local critical_power = math.max(self:combatCritPower("spell", mh.combat), self:combatCritPower("spell", oh.combat), self:combatCritPower("spell", pf.combat), 1.1)
+
+	if self:isTalentActive(self.T_STEALTH) and self:knowTalent(self.T_SHADOWSTRIKE) then
+		return dam * (critical_power + self:getTalentLevel(self.T_SHADOWSTRIKE) / 7), true
+	end
 	print("[SPELL CRIT %]", chance)
 	if rng.percent(chance) then
-		dam = dam * (1.5 + (self.combat_critical_power or 0) / 100)
+		dam = dam * (critical_power + (self.combat_critical_power or 0) / 100)
 		crit = true
 		game.logSeen(self, "#{bold}#%s's spell attains critical power!#{normal}#", self.name:capitalize())
 
 		if self:attr("mana_on_crit") then self:incMana(self:attr("mana_on_crit")) end
-
+		-- Savagery
+		if self:knowTalent(self.T_SAVAGERY) then
+			local t = self:getTalentFromId(self.T_SAVAGERY)
+			t.do_savagery(self, t)
+		end
 		if self:isTalentActive(self.T_BLOOD_FURY) then
 			local t = self:getTalentFromId(self.T_BLOOD_FURY)
 			t.on_crit(self, t)
@@ -1308,6 +1371,15 @@ function _M:hasStaffWeapon()
 	return weapon
 end
 
+function _M:hasGloves()
+	if not self:getInven("HANDS") then return end
+	local weapon = self:getInven("HANDS")[1]
+	if not weapon then
+		return nil
+	end
+	return weapon
+end
+
 --- Check if the actor has an axe weapon
 function _M:hasAxeWeapon()
 	if self:attr("disarmed") then
@@ -1551,3 +1623,18 @@ function _M:startGrapple(target)
 	end
 end
 
+function _M:doConcussion(dam, target, weapons)
+	local weapon = weapons[1] or {}
+	local ammo = weapons[2] or {}
+	if not weapon and not ammo then return end
+	dam = dam * (weapon.concussion or 0) * 0.01 + dam * (ammo.concussion or 0) * 0.01
+	self:project({type="ball", radius=1, selffire=false}, target.x, target.y, DamageType.PHYSICAL, dam)
+end
+
+function _M:doTalentOnHit(target, weapon)
+	for tid, data in pairs(weapon.talent_on_hit) do
+		if rng.percent(data.chance) then
+			self:forceUseTalent(tid, {ignore_cd=true, ignore_energy=true, force_target=target, force_level=data.level, ignore_ressources=true})
+		end
+	end
+end
diff --git a/game/modules/tome/class/interface/PlayerDumpJSON.lua b/game/modules/tome/class/interface/PlayerDumpJSON.lua
index ba000501c7..50049d9c7e 100644
--- a/game/modules/tome/class/interface/PlayerDumpJSON.lua
+++ b/game/modules/tome/class/interface/PlayerDumpJSON.lua
@@ -120,12 +120,9 @@ function _M:dumpToJSON(js)
 	if self:getInven(self.INVEN_MAINHAND) then
 		for i, o in ipairs(self:getInven(self.INVEN_MAINHAND)) do
 			local mean, dam = o.combat, o.combat
-			if o.archery and mean then
-				dam = (self:getInven("QUIVER")[1] and self:getInven("QUIVER")[1].combat) or o.basic_ammo
-			end
 			if mean and dam then
 				c[#c+1] = { ["accuracy (main hand)"] = string.format("%d", self:combatAttack(mean)) }
-				c[#c+1] = { ["damage (main hand)"] = string.format("%d", self:combatDamage(dam)) }
+				c[#c+1] = { ["damage (main hand)"] = string.format("%d", self:getCombinedDamage(o))}
 				c[#c+1] = { ["APR (main hand)"] = string.format("%d", self:combatAPR(dam)) }
 				c[#c+1] = { ["crit (main hand)"] = string.format("%d%%", self:combatCrit(dam)) }
 				c[#c+1] = { ["speed (main hand)"] = string.format("%0.2f", self:combatSpeed(mean)) }
@@ -149,12 +146,9 @@ function _M:dumpToJSON(js)
 		local offmult = self:getOffHandMult()
 		for i, o in ipairs(self:getInven(self.INVEN_OFFHAND)) do
 			local mean, dam = o.combat, o.combat
-			if o.archery and mean then
-				dam = (self:getInven("QUIVER")[1] and self:getInven("QUIVER")[1].combat) or o.basic_ammo
-			end
 			if mean and dam then
 				c[#c+1] = { ["accuracy (off hand)"] = string.format("%d", self:combatAttack(mean)) }
-				c[#c+1] = { ["damage (off hand)"] = string.format("%d", self:combatDamage(dam) * offmult) }
+				c[#c+1] = { ["damage (off hand)"] = string.format("%d", self:getCombinedDamage(o) * offmult) }
 				c[#c+1] = { ["APR (off hand)"] = string.format("%d", self:combatAPR(dam)) }
 				c[#c+1] = { ["crit(off hand)"] = string.format("%d%%", self:combatCrit(dam)) }
 				c[#c+1] = { ["speed(off hand)"] = string.format("%0.2f", self:combatSpeed(mean)) }
diff --git a/game/modules/tome/class/interface/TooltipsData.lua b/game/modules/tome/class/interface/TooltipsData.lua
index 05d6e9b5af..010399b4ef 100644
--- a/game/modules/tome/class/interface/TooltipsData.lua
+++ b/game/modules/tome/class/interface/TooltipsData.lua
@@ -196,22 +196,21 @@ Measures your ability to deal physical damage in combat.
 When you use Physical Power to inflict temporary physical effects on an enemy, every five points of Physical Power counteracts a single turn of duration reduction granted by the enemy's saving throws.
 ]]
 TOOLTIP_COMBAT_DAMAGE = [[#GOLD#Damage#LAST#
-This is the damage you inflict on your foes when you hit them.
-This damage can be reduced by the target's armour or by percentile damage resistances.
-It is improved by both Strength and Dexterity, some talents can change the stats that affect it.
+This is the damage you typically inflict on your foes when you hit them, though you
+might do less than this because of the target's armour or percentile damage resistances.
 ]]
 TOOLTIP_COMBAT_APR = [[#GOLD#Armour Penetration#LAST#
 Armour penetration allows you to ignore a part of the target's armour (this only works for armour, not damage resistance).
 This can never increase the damage you do beyond reducing armour, so it is only useful against armoured foes.
 ]]
 TOOLTIP_COMBAT_CRIT = [[#GOLD#Critical chance#LAST#
-Each time you deal damage you have a chance to make a critical hit that deals 150% of the normal damage.
+Your chance of dealing a critical hit, which multiplies your normal damage by your critical multiplier.
 Some talents allow you to increase this percentage.
 It is improved by Cunning.
 ]]
 TOOLTIP_COMBAT_SPEED = [[#GOLD#Attack speed#LAST#
-Attack speed represents how fast your attacks are compared to a normal turn.
-The lower it is the faster your attacks are.
+This percentage is the frequency with which you get extra attacks. A bonus of 50%, for example,
+means that you will get in an extra strike on every other attack.
 ]]
 TOOLTIP_COMBAT_RANGE = [[#GOLD#Firing range#LAST#
 The maximum distance your weapon can reach.
@@ -286,8 +285,8 @@ This stacks with individual damage type increases.
 TOOLTIP_INC_DAMAGE = [[#GOLD#Damage increase: specific#LAST#
 All damage of this type that you deal, through any means, is increased by this percentage.
 ]]
-TOOLTIP_INC_CRIT_POWER = [[#GOLD#Critical multiplicator#LAST#
-All critical damage (melee, spells, ...) do this much damage.
+TOOLTIP_INC_CRIT_POWER = [[#GOLD#Critical multiplier#LAST#
+Critical strikes multiply damage by this amount.
 ]]
 TOOLTIP_RESIST_ALL = [[#GOLD#Damage resistance: all#LAST#
 All damage you receive, through any means, is decreased by this percentage.
diff --git a/game/modules/tome/class/uiset/Minimalist.lua b/game/modules/tome/class/uiset/Minimalist.lua
index 3b94b0b8c7..fd749131df 100644
--- a/game/modules/tome/class/uiset/Minimalist.lua
+++ b/game/modules/tome/class/uiset/Minimalist.lua
@@ -834,7 +834,7 @@ function _M:displayResources(scale, bx, by, a)
 		local quiver = player:getInven("QUIVER")
 		local ammo = quiver and quiver[1]
 		if ammo then
-			local amt = ammo:getNumber()
+			local amt = ammo.combat.shots_left
 			local shad, bg
 			if ammo.type == "alchemist-gem" then shad, bg = _M["ammo_shadow_alchemist-gem"], _M["ammo_alchemist-gem"]
 			else shad, bg = _M["ammo_shadow_"..ammo.subtype] or ammo_shadow_default, _M["ammo_"..ammo.subtype] or ammo_default
diff --git a/game/modules/tome/data/birth/classes/warrior.lua b/game/modules/tome/data/birth/classes/warrior.lua
index 84d9168738..79a4cc2217 100644
--- a/game/modules/tome/data/birth/classes/warrior.lua
+++ b/game/modules/tome/data/birth/classes/warrior.lua
@@ -157,7 +157,6 @@ newBirthDescriptor{
 		["cunning/dirty"]={false, 0},
 	},
 	talents = {
-		[ActorTalents.T_SHOOT] = 1,
 		[ActorTalents.T_FLARE] = 1,
 		[ActorTalents.T_STEADY_SHOT] = 1,
 		[ActorTalents.T_BOW_MASTERY] = 1,
@@ -168,11 +167,15 @@ newBirthDescriptor{
 		max_life = 110,
 		resolvers.equip{ id=true,
 			{type="weapon", subtype="longbow", name="elm longbow", autoreq=true, ego_chance=-1000},
+			{type="ammo", subtype="arrow", name="quiver of elm arrows", autoreq=true, ego_chance=-1000},
 			{type="armor", subtype="light", name="rough leather armour", autoreq=true, ego_chance=-1000}
 		},
 		resolvers.inventory{ id=true, inven="QS_MAINHAND",
 			{type="weapon", subtype="sling", name="rough leather sling", autoreq=true, ego_chance=-1000},
 		},
+		resolvers.inventory{ id=true,
+			{type="ammo", subtype="shot", name="pouch of iron shot", autoreq=true, ego_chance=-1000},
+		},
 		resolvers.generic(function(e)
 			e.auto_shoot_talent = e.T_SHOOT
 		end),
diff --git a/game/modules/tome/data/chats/command-staff.lua b/game/modules/tome/data/chats/command-staff.lua
new file mode 100644
index 0000000000..afc5a16644
--- /dev/null
+++ b/game/modules/tome/data/chats/command-staff.lua
@@ -0,0 +1,269 @@
+-- ToME - Tales of Maj'Eyal
+-- Copyright (C) 2009, 2010, 2011 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
+
+
+
+local Dialog = require "engine.ui.Dialog"
+local DamageType = require "engine.DamageType"
+local o = version
+local src = game.player
+if o.factory_settings then
+	print("Just started the chat, and we apparently have o.factory_settings.")
+else
+	print("Just started the chat, and there's no o.factory_settings")
+	o.factory_settings = o.combat
+	o.unused_stats = 0
+	o.factory_settings.mins = {
+		dam = math.max(o.factory_settings.dam - 5 * (o.material_level or 1), 1),
+		critical_power = math.max(o.factory_settings.critical_power - 0.5, 1),
+		max_acc = o.factory_settings.max_acc - 25,
+	}
+	o.factory_settings.maxes = {
+		dam = o.factory_settings.dam + 5 * (o.material_level or 1),
+		critical_power = math.min(o.factory_settings.critical_power + 0.5, 3),
+		max_acc = 100,
+	}
+end
+
+local function intro(o)
+	local sentient_responses = {
+		default = [[Greetings. How can I help you?]],
+		aggressive = [[Hurry up and make with the foe-blasting.]],
+		fawning = [[O wise wielder, instruct me that I may better serve you.]],
+		penitent = [[Make amends, magic-user, for the harm ye have wrought is beyond compare.]],
+		telos = [[You really could have chosen a better home for me, you know. I was reasonably happy in my old crystal. This stick smells like armpit.]],
+	}
+	if o.no_command then
+		return [[It is not yet your place to command such a staff as this. To do so invites obliteration.]]
+	end
+	if o.combat.sentient then
+		return sentient_responses[o.combat.sentient] or sentient_responses["default"]
+	else
+		return [[Call on which aspect of the staff?]]
+	end
+end
+
+local function how_speak(o)
+	if not o.combat.sentient then return [[error!]] end
+	local sentient_responses = {
+		default = [[Oh, I was once a mighty Eldritch Channeler. Mighty and absentminded, as it turns out. Had a bit of a mishap with an Inverted Kugala's Soul-infusion technique. Long story short, my soul is now stuck in this stick, and the soul I was working with... well, I don't rightly know where he got to. But I hope we never meet him.]],
+		aggressive = [[Argh! Bollocksed up a tricky bit of soul magic and the fool that I was supposed to be imprisoning for all eternity flitted away. My body, like all the targets of my spells, intended or otherwise, got reduced to elementary particles. Fortunately, I had this soul-cage of a staff all prepped and ready for a stray soul, so I'm not completely gone. But enough chit-chat. Let's fry somebody.]],
+		fawning = [[My old master-- who, though a powerful enchanter, did not compare to you and your glory-- saw fit to imprison me in this fine staff to aid him in his work. Alas, he is long gone, but I despair not, for I have found a mighty new master.]],
+		penitent = [[I am a portion of the very spirit of the world that was ripped free during the Spellblaze. I speak that I might enlighten those who bear me.]],
+		telos = [[What's the good of immortality if you can't even speak? No archmage worth his salt is going to concoct some immoral life-after-death scheme without including some sort of capacity for making his opinions known. And, by the way, your energy manipulation techniques are on the same level as those of my average pair of shoes. Best study up if you don't want to die forgotten and incompetent.]],
+	}
+	return sentient_responses[o.combat.sentient] or sentient_responses["default"]
+end
+
+local function which_aspect(o)
+	if not o.combat.sentient then return [[error!]] end
+	local sentient_responses = {
+		default = [[Of course. Which aspect?]],
+		aggressive = [[I highly recommend the mage aspect and the fire element. You're not going to find anything better for turning a piece of meat into a cloud of vapor.]],
+		fawning = [[I live to serve-- though my use of the word 'live' is perhaps loose here.]],
+		penitent = [[Choose wisely. Powers beyond your comprehension will tolerate only so much interference in their carefully-laid natural order.]],
+		telos = [[Back in my day, we didn't need to go changing our staves around willy-nilly. We picked an element and stuck with it, by the gods.]],
+	}
+	return sentient_responses[o.combat.sentient] or sentient_responses["default"]
+end
+
+--unused for now:
+local function alter_combat(o)
+	if not o.combat.sentient then return [[error!]] end
+	local sentient_responses = {
+		default = [[Certainly. You should be impressed, by the way, that I can do such a thing. Most lesser practitioners of my art would have difficulties with this. What shall I change?]],
+		aggressive = [[Fine, as long as it leads to blasting something soon. What do you want me to change?]],
+	}
+	return sentient_responses[o.combat.sentient] or sentient_responses["default"]
+end
+
+local function is_sentient()
+	return o.combat.sentient
+end
+
+local function update_table(d_table_old, d_table_new, old_element, new_element, tab, v, is_greater)
+	if is_greater then
+		for i = 1, #d_table_old do
+			o.wielder[tab][d_table_old[i]] = o.wielder[tab][d_table_old[i]] - v
+			if o.wielder[tab][d_table_old[i]] == 0 then o.wielder[tab][d_table_old[i]] = nil end
+		end
+		for i = 1, #d_table_new do
+			o.wielder[tab][d_table_new[i]] = (o.wielder[tab][d_table_new[i]] or 0) + v
+		end
+	else
+		o.wielder[tab][old_element] = o.wielder[tab][old_element] - v
+		o.wielder[tab][new_element] = (o.wielder[tab][new_element] or 0) + v
+		if o.wielder[tab][old_element] == 0 then o.wielder[tab][old_element] = nil end
+	end
+
+end
+
+local function set_element(element, new_flavor, player)
+	state.set_element = true
+	local dam = o.combat.dam
+	local inven = player:getInven("MAINHAND")
+	local o = player:takeoffObject(inven, 1)
+	local dam_tables = {
+		magestaff = {engine.DamageType.FIRE, engine.DamageType.COLD, engine.DamageType.LIGHTNING, engine.DamageType.ARCANE},
+		starstaff = {engine.DamageType.LIGHT, engine.DamageType.DARKNESS, engine.DamageType.TEMPORAL},
+		earthstaff = {engine.DamageType.NATURE, engine.DamageType.BLIGHT, engine.DamageType.ACID},
+	}
+
+	update_table(dam_tables[o.flavor_name], dam_tables[new_flavor], o.combat.damtype, element, "inc_damage", dam, o.combat.is_greater)
+	if o.combat.of_warding then update_table(dam_tables[o.flavor_name], dam_tables[new_flavor], o.combat.damtype, element, "wards", 2, o.combat.is_greater) end
+	if o.combat.of_breaching then update_table(dam_tables[o.flavor_name], dam_tables[new_flavor], o.combat.damtype, element, "resists_pen", dam/2, o.combat.is_greater) end
+	if o.combat.of_retribution then update_table(dam_tables[o.flavor_name], dam_tables[new_flavor], o.combat.damtype, element, "elemental_retribution", 1, o.combat.is_greater) end
+
+	o.combat.damtype = element
+	if not o.unique then o.name = o.name:gsub(o.flavor_name, new_flavor) end
+	o.flavor_name = new_flavor
+	o:resolve()
+	o:resolve(nil, true)
+	player:addObject(inven, o)
+	print("(in chat's set_element) state.set_element is ", state.set_element)
+	coroutine.resume(co, true)
+	
+end
+
+newChat{ id="welcome",
+	text = intro(o),
+	answers = {
+		{"How is it that you speak?", cond = function() return is_sentient() and not o.no_command end, jump="how_speak"},
+		{"I'd like you to bring forth a different aspect.", cond = function() return is_sentient() and not o.no_command end, jump="which_aspect"},
+		{"I'd like to alter your basic properties.", cond = function() return is_sentient() and not o.no_command end, 
+			action = function()
+				coroutine.resume(co, true)
+				local SentientWeapon = require "mod.dialogs.SentientWeapon"
+				local ds = SentientWeapon.new({actor=game.player, o=o})
+				game:registerDialog(ds)
+			end,
+		},
+		{"[Mage]", cond = function() return not is_sentient() and not o.no_command end, jump="element_mage"},
+		{"[Star]", cond = function() return not is_sentient() and not o.no_command end, jump="element_star"},
+		{"[Earth]", cond = function() return not is_sentient() and not o.no_command end, jump="element_earth"},
+		{"Never mind"},
+	}
+}
+
+newChat{ id="element_mage",
+	text = [[Call forth which element?]],
+	answers = {
+		{"[Fire]", 
+			action = function()
+				set_element(DamageType.FIRE, "magestaff", game.player) 
+				game.level.map:particleEmitter(game.player.x, game.player.y, 1, "teleport") 
+			end,
+		},
+		{"[Lightning]", 
+			action = function() 
+				set_element(DamageType.LIGHTNING, "magestaff", game.player) 
+				game.level.map:particleEmitter(game.player.x, game.player.y, 1, "teleport") 
+			end,
+		},
+		{"[Cold]", 
+			action = function() 
+				set_element(DamageType.COLD, "magestaff", game.player) 
+				game.level.map:particleEmitter(game.player.x, game.player.y, 1, "teleport") 
+			end,
+		},
+		{"[Arcane]", 
+			action = function() 
+				set_element(DamageType.ARCANE, "magestaff", game.player) 
+				game.level.map:particleEmitter(game.player.x, game.player.y, 1, "teleport") 
+			end,
+		},
+		{"[Choose different aspect]", jump="welcome"},
+		{"Never mind"},
+	}
+}
+
+
+newChat{ id="element_star",
+	text = [[Call forth which element?]],
+	answers = {
+		{"[Light]", 
+			action = function() 
+				set_element(DamageType.LIGHT, "starstaff", game.player) 
+				game.level.map:particleEmitter(game.player.x, game.player.y, 1, "teleport") 
+			end,
+		},
+		{"[Darkness]", 
+			action = function() 
+				set_element(DamageType.DARKNESS, "starstaff", game.player) 
+				game.level.map:particleEmitter(game.player.x, game.player.y, 1, "teleport") 
+			end,
+		},
+		{"[Temporal]", 
+			action = function() 
+				set_element(DamageType.TEMPORAL, "starstaff", game.player) 
+				game.level.map:particleEmitter(game.player.x, game.player.y, 1, "teleport") 
+			end,
+		},
+		{"[Choose different aspect]", jump="welcome"},
+		{"Never mind"},
+	}
+}
+
+
+newChat{ id="element_earth",
+	text = [[Call forth which element?]],
+	answers = {
+		{"[Nature]", 
+			action = function() 
+				set_element(DamageType.NATURE, "earthstaff", game.player) 
+				game.level.map:particleEmitter(game.player.x, game.player.y, 1, "teleport") 
+			end,
+		},
+		{"[Blight]", 
+			action = function() 
+				set_element(DamageType.BLIGHT, "earthstaff", game.player) 
+				game.level.map:particleEmitter(game.player.x, game.player.y, 1, "teleport") 
+			end,
+		},
+		{"[Acid]", 
+			action = function() 
+				set_element(DamageType.ACID, "earthstaff", game.player) 
+				game.level.map:particleEmitter(game.player.x, game.player.y, 1, "teleport") 
+			end,
+		},
+		{"[Choose different aspect]", jump="welcome"},
+		{"Never mind"},
+	}
+}
+
+newChat{ id="how_speak",
+	text = how_speak(o),
+	answers = {
+		{"I see.", jump="welcome"},
+	}
+}
+
+newChat{ id="which_aspect",
+	text = which_aspect(o),
+	answers = {
+		{"[Mage]", jump="element_mage"},
+		{"[Star]", jump="element_star"},
+		{"[Earth]", jump="element_earth"},
+		{"Back up a second.", jump="welcome"},
+		{"Never mind"},
+	}
+}
+
+return "welcome"
+
diff --git a/game/modules/tome/data/chats/ward.lua b/game/modules/tome/data/chats/ward.lua
new file mode 100644
index 0000000000..9c6054c58c
--- /dev/null
+++ b/game/modules/tome/data/chats/ward.lua
@@ -0,0 +1,84 @@
+-- ToME - Tales of Maj'Eyal
+-- Copyright (C) 2009, 2010, 2011 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
+
+local DamageType = require "engine.DamageType"
+local src = version
+
+local function has_ward(which)
+	if not src.wards then return false end
+	if src.wards[which] and src.wards[which] ~= 0 then return true end
+	return false
+end
+
+local function set_ward(which, charges)
+	src:setEffect(src.EFF_WARD, 10, {nb=charges, d_type=which})
+	state.set_ward = true
+	--print("(in chat's set_ward) state.set_ward is ", state.set_ward)
+end
+
+newChat{ id="welcome",
+	text = [[Call forth which ward?]],
+	answers = {
+		{"Fire ["..(src.wards[DamageType.FIRE] or 0).."]", 
+			cond = function() return has_ward(DamageType.FIRE) end,
+			action = function() return set_ward(DamageType.FIRE, (src.wards[DamageType.FIRE] or 0)) end,
+		},
+		{"Lightning ["..(src.wards[DamageType.LIGHTNING] or 0).."]",
+			cond = function() return has_ward(DamageType.LIGHTNING) end,
+			action = function() return set_ward(DamageType.LIGHTNING, (src.wards[DamageType.LIGHTNING] or 0)) end,
+		},
+		{"Cold ["..(src.wards[DamageType.COLD] or 0).."]",
+			cond = function(who) return has_ward(DamageType.COLD) end,
+			action = function() return set_ward(DamageType.COLD, (src.wards[DamageType.COLD] or 0)) end,
+		},
+		{"Arcane ["..(src.wards[DamageType.ARCANE] or 0).."]",
+			cond = function(who) return has_ward(DamageType.ARCANE) end,
+			action = function() return set_ward(DamageType.ARCANE, (src.wards[DamageType.ARCANE] or 0)) end,
+		},
+		{"Light ["..(src.wards[DamageType.LIGHT] or 0).."]", 
+			cond = function() return has_ward(DamageType.LIGHT) end,
+			action = function() return set_ward(DamageType.LIGHT, (src.wards[DamageType.LIGHT] or 0)) end,
+		},
+		{"Darkness ["..(src.wards[DamageType.DARKNESS] or 0).."]", 
+			cond = function() return has_ward(DamageType.DARKNESS) end,
+			action = function() return set_ward(DamageType.DARKNESS, (src.wards[DamageType.DARKNESS] or 0)) end,
+		},
+		{"Temporal ["..(src.wards[DamageType.TEMPORAL] or 0).."]", 
+			cond = function() return has_ward(DamageType.TEMPORAL) end,
+			action = function() return set_ward(DamageType.TEMPORAL, (src.wards[DamageType.TEMPORAL] or 0)) end,
+		},
+		{"Nature ["..(src.wards[DamageType.NATURE] or 0).."]", 
+			cond = function() return has_ward(DamageType.NATURE) end,
+			action = function() return set_ward(DamageType.NATURE, (src.wards[DamageType.NATURE] or 0)) end,
+		},
+		{"Blight ["..(src.wards[DamageType.BLIGHT] or 0).."]", 
+			cond = function() return has_ward(DamageType.BLIGHT) end,
+			action = function() return set_ward(DamageType.BLIGHT, (src.wards[DamageType.BLIGHT] or 0)) end,
+		},
+		{"Acid ["..(src.wards[DamageType.ACID] or 0).."]", 
+			cond = function() return has_ward(DamageType.ACID) end,
+			action = function() return set_ward(DamageType.ACID, (src.wards[DamageType.ACID] or 0)) end,
+		},
+
+		{"Never mind"},
+	}
+}
+
+return "welcome"
+
diff --git a/game/modules/tome/data/damage_types.lua b/game/modules/tome/data/damage_types.lua
index 80864811de..7d0bccbccf 100644
--- a/game/modules/tome/data/damage_types.lua
+++ b/game/modules/tome/data/damage_types.lua
@@ -45,6 +45,19 @@ setDefaultProjector(function(src, x, y, type, dam, tmp, no_martyr)
 			t.on_damage(target, t, type)
 		end
 
+		-- Item-granted damage ward talent
+		--if target:attr("ward") then
+		if target:hasEffect(target.EFF_WARD) then
+			local e = target.tempeffect_def[target.EFF_WARD]
+			dam = e.absorb(type, dam, target.tmp[target.EFF_WARD], target, src)
+		end
+
+		-- Block talent from shields
+		if target:attr("block") then
+			local e = target.tempeffect_def[target.EFF_BLOCKING]
+			dam = e.do_block(type, dam, target.tmp[target.EFF_BLOCKING], target, src)
+		end
+
 		-- Increases damage
 		if src.inc_damage then
 			local inc = (src.inc_damage.all or 0) + (src.inc_damage[type] or 0)
@@ -58,7 +71,6 @@ setDefaultProjector(function(src, x, y, type, dam, tmp, no_martyr)
 					print("[PROJECTOR] after inc_damage_actor_type", dam + (dam * inc / 100))
 				end
 			end
-
 			dam = dam + (dam * inc / 100)
 		end
 
@@ -104,6 +116,12 @@ setDefaultProjector(function(src, x, y, type, dam, tmp, no_martyr)
 			end
 		end
 
+		-- Elemental Retribution causes the target to get buffed when taking certain kinds of damage
+		if target:knowTalent(target.T_ELEMENTAL_RETRIBUTION) and target ~= src and target.elemental_retribution and target.elemental_retribution[type] and target.elemental_retribution[type] > 0 then
+			local t = target:getTalentFromId(target.T_ELEMENTAL_RETRIBUTION)
+			t.do_retribution(target, t)
+		end
+
 		-- Static reduce damage for psionic kinetic shield
 		if target.isTalentActive and target:isTalentActive(target.T_KINETIC_SHIELD) then
 			local t = target:getTalentFromId(target.T_KINETIC_SHIELD)
@@ -283,7 +301,7 @@ setDefaultProjector(function(src, x, y, type, dam, tmp, no_martyr)
 		if dam > 0 and source_talent then
 			local t = source_talent
 
-			if src:attr("spellshock_on_damage") and target:checkHit(src:combatSpellpower(), target:combatPhysicalResist(), 0, 95, 15) and not target:hasEffect(target.EFF_SPELLSHOCKED) then
+			if src:attr("spellshock_on_damage") and target:checkHit(src:combatSpellpower(), target:combatPhysicalResist(), 0, src:getMaxAccuracy("spell"), 15) and not target:hasEffect(target.EFF_SPELLSHOCKED) then
 				target:crossTierEffect(target.EFF_SPELLSHOCKED, src:combatSpellpower())
 			end
 
@@ -328,19 +346,19 @@ local function tryDestroy(who, inven, dam, destroy_prop, proof_prop, msg)
 end
 
 newDamageType{
-	name = "physical", type = "PHYSICAL",
+	name = "physical", type = "PHYSICAL", text_color = "#WHITE#", color = colors.WHITE,
 	death_message = {"battered", "bludgeoned", "sliced", "maimed", "raked", "bled", "impaled", "dissected", "disembowelled", "decapitated", "stabbed", "pierced", "torn limb from limb", "crushed", "shattered", "smashed", "cleaved", "swiped", "struck", "mutilated", "tortured", "skewered", "squished", "mauled", "chopped into tiny pieces", "splattered", "ground", "minced", "punctured", "hacked apart", "eviscerated"},
 }
 
 -- Arcane is basic (usually) unresistable damage
 newDamageType{
-	name = "arcane", type = "ARCANE", text_color = "#PURPLE#",
+	name = "arcane", type = "ARCANE", text_color = "#PURPLE#", color = colors.PURPLE,
 	antimagic_resolve = true,
 	death_message = {"blasted", "energised", "mana-torn", "dweomered", "imploded"},
 }
 -- The elemental damages
 newDamageType{
-	name = "fire", type = "FIRE", text_color = "#LIGHT_RED#",
+	name = "fire", type = "FIRE", text_color = "#LIGHT_RED#", color = colors.LIGHT_RED,
 	antimagic_resolve = true,
 	projector = function(src, x, y, type, dam)
 		if src.fire_convert_to then
@@ -355,7 +373,7 @@ newDamageType{
 	death_message = {"burnt", "scorched", "blazed", "roasted", "flamed", "fried", "combusted", "toasted", "slowly cooked", "boiled"},
 }
 newDamageType{
-	name = "cold", type = "COLD", text_color = "#1133F3#",
+	name = "cold", type = "COLD", text_color = "#1133F3#", color = {r=0x11, g=0x33, b=0xF3},
 	antimagic_resolve = true,
 	projector = function(src, x, y, type, dam)
 		local realdam = DamageType.defaultProjector(src, x, y, type, dam)
@@ -367,7 +385,7 @@ newDamageType{
 	death_message = {"frozen", "chilled", "iced", "cooled", "frozen and shattered into a million little shards"},
 }
 newDamageType{
-	name = "lightning", type = "LIGHTNING", text_color = "#ROYAL_BLUE#",
+	name = "lightning", type = "LIGHTNING", text_color = "#ROYAL_BLUE#", color = colors.ROYAL_BLUE,
 	antimagic_resolve = true,
 	projector = function(src, x, y, type, dam)
 		local realdam = DamageType.defaultProjector(src, x, y, type, dam)
@@ -377,7 +395,7 @@ newDamageType{
 }
 -- Acid destroys potions
 newDamageType{
-	name = "acid", type = "ACID", text_color = "#GREEN#",
+	name = "acid", type = "ACID", text_color = "#GREEN#", color = colors.GREEN,
 	antimagic_resolve = true,
 	projector = function(src, x, y, type, dam)
 		local realdam = DamageType.defaultProjector(src, x, y, type, dam)
@@ -388,12 +406,12 @@ newDamageType{
 
 -- Nature & Blight: Opposing damage types
 newDamageType{
-	name = "nature", type = "NATURE", text_color = "#LIGHT_GREEN#",
+	name = "nature", type = "NATURE", text_color = "#LIGHT_GREEN#", color = colors.LIGHT_GREEN,
 	antimagic_resolve = true,
 	death_message = {"slimed", "splurged", "treehugged", "naturalised"},
 }
 newDamageType{
-	name = "blight", type = "BLIGHT", text_color = "#DARK_GREEN#",
+	name = "blight", type = "BLIGHT", text_color = "#DARK_GREEN#", color = colors.DARK_GREEN,
 	antimagic_resolve = true,
 	projector = function(src, x, y, type, dam, extra)
 		local realdam = DamageType.defaultProjector(src, x, y, type, dam)
@@ -413,21 +431,21 @@ newDamageType{
 
 -- Light damage
 newDamageType{
-	name = "light", type = "LIGHT", text_color = "#YELLOW#",
+	name = "light", type = "LIGHT", text_color = "#YELLOW#", color = colors.YELLOW,
 	antimagic_resolve = true,
 	death_message = {"radiated", "seared", "purified", "sun baked", "jerkied", "tanned"},
 }
 
 -- Darkness damage
 newDamageType{
-	name = "darkness", type = "DARKNESS", text_color = "#GREY#",
+	name = "darkness", type = "DARKNESS", text_color = "#GREY#", color = colors.GREY,
 	antimagic_resolve = true,
 	death_message = {"shadowed", "darkened", "swallowed by the void"},
 }
 
 -- Mind damage
 newDamageType{
-	name = "mind", type = "MIND", text_color = "#YELLOW#",
+	name = "mind", type = "MIND", text_color = "#YELLOW#", color = colors.YELLOW,
 	projector = function(src, x, y, type, dam)
 		local target = game.level.map(x, y, Map.ACTOR)
 		if target then
@@ -452,7 +470,7 @@ newDamageType{
 
 -- Temporal damage
 newDamageType{
-	name = "temporal", type = "TEMPORAL", text_color = "#LIGHT_STEEL_BLUE#",
+	name = "temporal", type = "TEMPORAL", text_color = "#LIGHT_STEEL_BLUE#", color = colors.LIGHT_STEEL_BLUE,
 	antimagic_resolve = true,
 	death_message = {"timewarped", "temporally distorted", "spaghettified across the whole of space and time", "paradoxed", "replaced by a time clone (and no one ever knew the difference)", "grandfathered", "time dilated"},
 }
@@ -820,7 +838,7 @@ newDamageType{
 		DamageType:get(DamageType.PHYSICAL).projector(src, x, y, DamageType.PHYSICAL, dam / 2)
 		local target = game.level.map(x, y, Map.ACTOR)
 		if target then
-			if target:checkHit(src:combatSpellpower(), target:combatPhysicalResist(), 0, 95, 15) and target:canBe("knockback") then
+			if target:checkHit(src:combatSpellpower(), target:combatPhysicalResist(), 0, src:getMaxAccuracy("spell"), 15) and target:canBe("knockback") then
 				target:knockback(srcx, srcy, 1)
 				target:crossTierEffect(target.EFF_OFFBALANCE, src:combatSpellpower())
 				game.logSeen(target, "%s is knocked back!", target.name:capitalize())
@@ -841,7 +859,7 @@ newDamageType{
 		if target and not tmp[target] then
 			tmp[target] = true
 			DamageType:get(DamageType.FIREBURN).projector(src, x, y, DamageType.FIREBURN, dam.dam)
-			if target:checkHit(src:combatSpellpower(), target:combatPhysicalResist(), 0, 95, 15) and target:canBe("knockback") then
+			if target:checkHit(src:combatSpellpower(), target:combatPhysicalResist(), 0, src:getMaxAccuracy("spell"), 15) and target:canBe("knockback") then
 				target:knockback(src.x, src.y, dam.dist)
 				target:crossTierEffect(target.EFF_OFFBALANCE, src:combatSpellpower())
 				game.logSeen(target, "%s is knocked back!", target.name:capitalize())
@@ -883,7 +901,7 @@ newDamageType{
 		if target and not tmp[target] then
 			tmp[target] = true
 			DamageType:get(DamageType.DARKNESS).projector(src, x, y, DamageType.DARKNESS, dam.dam)
-			if target:checkHit(src:combatSpellpower(), target:combatMentalResist(), 0, 95, 15) and target:canBe("knockback") then
+			if target:checkHit(src:combatSpellpower(), target:combatMentalResist(), 0, src:getMaxAccuracy("spell"), 15) and target:canBe("knockback") then
 				target:knockback(src.x, src.y, dam.dist)
 				target:crossTierEffect(target.EFF_BRAINLOCKED, src:combatSpellpower())
 				game.logSeen(target, "%s is knocked back!", target.name:capitalize())
@@ -904,7 +922,7 @@ newDamageType{
 		if target and not tmp[target] then
 			tmp[target] = true
 			realdam = DamageType:get(DamageType.PHYSICAL).projector(src, x, y, DamageType.PHYSICAL, dam)
-			if target:checkHit(src:combatSpellpower(), target:combatPhysicalResist(), 0, 95, 15) and target:canBe("knockback") then
+			if target:checkHit(src:combatSpellpower(), target:combatPhysicalResist(), 0, src:getMaxAccuracy("spell"), 15) and target:canBe("knockback") then
 				target:knockback(src.x, src.y, 3)
 				target:crossTierEffect(target.EFF_OFFBALANCE, src:combatSpellpower())
 				game.logSeen(target, "%s is knocked back!", target.name:capitalize())
@@ -1122,7 +1140,7 @@ newDamageType{
 			if src == target then
 				target:setEffect(target.EFF_TIME_PRISON, dam, {no_ct_effect=true})
 				target:setEffect(target.EFF_CONTINUUM_DESTABILIZATION, 100, {power=src:combatSpellpower(0.3), no_ct_effect=true})
-			elseif target:checkHit(src:combatSpellpower() - (target:attr("continuum_destabilization") or 0), target:combatSpellResist(), 0, 95, 15) then
+			elseif target:checkHit(src:combatSpellpower() - (target:attr("continuum_destabilization") or 0), target:combatSpellResist(), 0, src:getMaxAccuracy("spell"), 15) then
 				target:setEffect(target.EFF_TIME_PRISON, dam, {apply_power=src:combatSpellpower() - (target:attr("continuum_destabilization") or 0), apply_save="combatSpellResist", no_ct_effect=true})
 				target:setEffect(target.EFF_CONTINUUM_DESTABILIZATION, 100, {power=src:combatSpellpower(0.3), no_ct_effect=true})
 			else
@@ -1149,9 +1167,10 @@ newDamageType{
 
 -- Confusion
 newDamageType{
-	name = "% chances to confuse", type = "RANDOM_CONFUSION",
+	name = "confusion", type = "RANDOM_CONFUSION", text_color = "#YELLOW#",
 	projector = function(src, x, y, type, dam)
 		if _G.type(dam) == "number" then dam = {dam=dam} end
+		DamageType:get(DamageType.MIND).projector(src, x, y, DamageType.MIND, dam.dam)
 		local target = game.level.map(x, y, Map.ACTOR)
 		if target and rng.percent(dam.dam) then
 			if target:canBe("confusion") then
@@ -1256,6 +1275,26 @@ newDamageType{
 	end,
 }
 
+-- Drain all resources
+newDamageType{
+	name = "soul drain", type = "SOUL_DRAIN",
+	projector = function(src, x, y, type, dam)
+		if _G.type(dam) == "number" then dam = {dam=dam, drain=0.5} end
+		local realdam = DamageType:get(DamageType.BLIGHT).projector(src, x, y, DamageType.BLIGHT, dam.dam)
+		local target = game.level.map(x, y, Map.ACTOR)
+		if target and target ~= src and realdam > 0 then
+			target:incMana(-target:getMana()*0.5)
+			target:incVim(-target:getVim()*0.5)
+			target:incPositive(-target:getPositive()*0.5)
+			target:incNegative(-target:getNegative()*0.5)
+			target:incEquilibrium(target:getEquilibrium()*0.5)
+			target:incStamina(-target:getStamina()*0.5)
+			target:incHate(-target:getHate()*0.5)
+			target:incPsi(-target:getPsi()*0.5)
+		end
+	end,
+}
+
 -- Demonfire: heal demon; damage others
 newDamageType{
 	name = "demonfire", type = "DEMONFIRE",
@@ -1445,7 +1484,7 @@ newDamageType{
 		-- check knockback
 		if target and not target:attr("never_move") and not tmp[target] then
 			tmp[target] = true
-			if target:checkHit(src:combatSpellpower(), target:combatPhysicalResist(), 0, 95, 15) and target:canBe("knockback") then
+			if target:checkHit(src:combatSpellpower(), target:combatPhysicalResist(), 0, src:getMaxAccuracy("spell"), 15) and target:canBe("knockback") then
 				target:knockback(src.x, src.y, 2)
 				target:crossTierEffect(target.EFF_OFFBALANCE, src:combatSpellpower())
 				game.logSeen(target, "%s is knocked back!", target.name:capitalize())
@@ -1529,7 +1568,7 @@ newDamageType{
 			elseif target ~= src then
 				DamageType:get(DamageType.LIGHT).projector(src, x, y, DamageType.LIGHT, dam )
 				DamageType:get(DamageType.DARKNESS).projector(src, x, y, DamageType.DARKNESS, dam)
-				if target:checkHit(src:combatSpellpower(), target:combatPhysicalResist(), 0, 95, 15) and target:canBe("knockback") then
+				if target:checkHit(src:combatSpellpower(), target:combatPhysicalResist(), 0, src:getMaxAccuracy("spell"), 15) and target:canBe("knockback") then
 					target:knockback(src.x, src.y, 1)
 					target:crossTierEffect(target.EFF_OFFBALANCE, src:combatSpellpower())
 					game.logSeen(target, "%s is knocked back!", target.name:capitalize())
@@ -1669,7 +1708,7 @@ newDamageType{
 					game.logSeen(target, "%s resists the blindness!", target.name:capitalize())
 				end
 			elseif chance == 3 then
-				if target:checkHit(src:combatSpellpower(), target:combatPhysicalResist(), 0, 95, 15) and target:canBe("pin") then
+				if target:checkHit(src:combatSpellpower(), target:combatPhysicalResist(), 0, src:getMaxAccuracy("spell"), 15) and target:canBe("pin") then
 					target:setEffect(target.EFF_PINNED, 3, {apply_power=src:combatSpellpower()})
 				else
 					game.logSeen(target, "%s resists the pin!", target.name:capitalize())
diff --git a/game/modules/tome/data/general/npcs/ant.lua b/game/modules/tome/data/general/npcs/ant.lua
index 9f0a7dee30..34ffdf965c 100644
--- a/game/modules/tome/data/general/npcs/ant.lua
+++ b/game/modules/tome/data/general/npcs/ant.lua
@@ -34,7 +34,7 @@ newEntity{
 	stats = { str=12, dex=10, mag=3, con=13 },
 	energy = { mod=1 },
 	combat_armor = 1, combat_def = 1,
-	combat = { dam=resolvers.levelup(resolvers.rngavg(5,5), 1, 1), atk=15, apr=7, dammod={str=0.6}, sound="creatures/ants/ant_hit" },
+	combat = { dam=resolvers.levelup(resolvers.rngavg(5,5), 1, 1), atk=15, apr=7, dammod={str=resolvers.levelup(0.1, 5, 0.1, 0.6)}, sound="creatures/ants/ant_hit" },
 	infravision = 10,
 	max_life = resolvers.rngavg(10,20),
 	rank = 1,
diff --git a/game/modules/tome/data/general/npcs/aquatic_critter.lua b/game/modules/tome/data/general/npcs/aquatic_critter.lua
index d4161f3bd5..6501e4919a 100644
--- a/game/modules/tome/data/general/npcs/aquatic_critter.lua
+++ b/game/modules/tome/data/general/npcs/aquatic_critter.lua
@@ -30,7 +30,7 @@ newEntity{
 	ai = "dumb_talented_simple", ai_state = { ai_move="move_dmap", talent_in=1, },
 	stats = { str=12, dex=10, mag=3, con=13 },
 	combat_armor = 1, combat_def = 1,
-	combat = { dam=resolvers.levelup(resolvers.mbonus(36, 10), 1, 1), atk=15, apr=7, dammod={str=0.6} },
+	combat = { dam=resolvers.levelup(resolvers.mbonus(36, 10), 1, 1), atk=15, apr=7, dammod={str=resolvers.levelup(0.2, 5, 0.1, 0.6)} },
 	max_life = resolvers.rngavg(10,20), life_rating = 6,
 	infravision = 10,
 	rank = 1,
diff --git a/game/modules/tome/data/general/npcs/bear.lua b/game/modules/tome/data/general/npcs/bear.lua
index 27fcdd4666..3763f54932 100644
--- a/game/modules/tome/data/general/npcs/bear.lua
+++ b/game/modules/tome/data/general/npcs/bear.lua
@@ -41,7 +41,7 @@ newEntity{
 	size_category = 4,
 
 	combat_armor = 1, combat_def = 1,
-	combat = { dam=resolvers.levelup(resolvers.rngavg(12, 25), 1, 1), atk=10, apr=3, physspeed=2, dammod={str=0.8} },
+	combat = { dam=resolvers.levelup(resolvers.rngavg(12, 25), 1, 1), atk=10, apr=3, physspeed=2, dammod={str=resolvers.levelup(0.2, 5, 0.1, 1.1)} },
 	life_rating = 12,
 	resolvers.tmasteries{ ["technique/other"]=0.25 },
 
diff --git a/game/modules/tome/data/general/npcs/canine.lua b/game/modules/tome/data/general/npcs/canine.lua
index 0ee72d2d57..03b3a9242f 100644
--- a/game/modules/tome/data/general/npcs/canine.lua
+++ b/game/modules/tome/data/general/npcs/canine.lua
@@ -39,7 +39,7 @@ newEntity{
 	ai = "dumb_talented_simple", ai_state = { ai_move="move_dmap", talent_in=2, },
 	global_speed_base = 1.2,
 	stats = { str=10, dex=17, mag=3, con=7 },
-	combat = { dammod={str=0.6}, sound="creatures/wolves/wolf_attack_1" },
+	combat = { dammod={str=resolvers.levelup(0.2, 5, 0.1, 0.6)}, sound="creatures/wolves/wolf_attack_1" },
 	combat_armor = 1, combat_def = 1,
 }
 
diff --git a/game/modules/tome/data/general/npcs/cold-drake.lua b/game/modules/tome/data/general/npcs/cold-drake.lua
index f506fa7bb0..289c26f98e 100644
--- a/game/modules/tome/data/general/npcs/cold-drake.lua
+++ b/game/modules/tome/data/general/npcs/cold-drake.lua
@@ -51,7 +51,7 @@ newEntity{ base = "BASE_NPC_COLD_DRAKE",
 	rank = 1, size_category = 2,
 	max_life = resolvers.rngavg(40,60),
 	combat_armor = 5, combat_def = 0,
-	combat = { dam=resolvers.levelup(resolvers.rngavg(25,40), 1, 0.6), atk=resolvers.rngavg(25,50), apr=25, dammod={str=1.1} },
+	combat = { dam=resolvers.levelup(resolvers.rngavg(25,40), 1, 0.6), atk=resolvers.rngavg(25,50), apr=25, dammod={str=resolvers.levelup(0.2, 5, 0.1, 1.1)} },
 	on_melee_hit = {[DamageType.COLD]=resolvers.mbonus(7, 2)},
 
 	make_escort = {
diff --git a/game/modules/tome/data/general/npcs/feline.lua b/game/modules/tome/data/general/npcs/feline.lua
index ecdec4d5c3..bfc2f06901 100644
--- a/game/modules/tome/data/general/npcs/feline.lua
+++ b/game/modules/tome/data/general/npcs/feline.lua
@@ -29,7 +29,7 @@ newEntity{
 	global_speed_base = 1.25,
 	type = "animal", subtype="feline",
 	ai = "dumb_talented_simple", ai_state = { ai_move="move_dmap", talent_in=2, },
-
+	combat = {dammod={str=resolvers.levelup(0.1, 5, 0.1, 0.5), dex=resolvers.levelup(0.1, 5, 0.1, 0.5)}},
 	combat_physspeed = 2, -- Double attack per turn
 
 	resolvers.sustains_at_birth(),
@@ -44,7 +44,7 @@ newEntity{ base = "BASE_NPC_CAT",
 	max_life = resolvers.rngavg(40,80),
 	resists = { [DamageType.COLD] = 50 },
 	combat_armor = 0, combat_def = 8,
-	combat = { dam=resolvers.levelup(5, 1, 0.7), atk=12, apr=15, dammod={str=0.5, dex=0.5}},
+	combat = { dam=resolvers.levelup(5, 1, 0.7), atk=12, apr=15},
 	resolvers.talents{
 		[Talents.T_STEALTH]={base=1, every=6, max=5},
 		[Talents.T_RUSH]={base=1, every=8, max=3},
@@ -60,7 +60,7 @@ newEntity{ base = "BASE_NPC_CAT",
 	size_category=3,
 	max_life = resolvers.rngavg(60,100),
 	combat_armor = 3, combat_def = 8,
-	combat = { dam=resolvers.levelup(18, 1, 1), atk=12, apr=20, dammod={str=0.5, dex=0.5}},
+	combat = { dam=resolvers.levelup(18, 1, 1), atk=12, apr=20},
 	resolvers.talents{
 		[Talents.T_STEALTH]={base=1, every=6, max=5},
 		[Talents.T_RUSH]={base=1, every=8, max=3},
@@ -76,7 +76,7 @@ newEntity{ base = "BASE_NPC_CAT",
 	size_category=4,
 	max_life = resolvers.rngavg(70,110),
 	combat_armor = 3, combat_def = 8,
-	combat = { dam=resolvers.levelup(25, 1, 1), atk=12, apr=25, dammod={str=0.5, dex=0.5}},
+	combat = { dam=resolvers.levelup(25, 1, 1), atk=12, apr=25},
 	resolvers.talents{
 		[Talents.T_STEALTH]={base=2, every=6, max=5},
 		[Talents.T_RUSH]={base=2, every=8, max=5},
@@ -93,7 +93,7 @@ newEntity{ base = "BASE_NPC_CAT",
 	size_category=4,
 	max_life = resolvers.rngavg(80,120),
 	combat_armor = 3, combat_def = 8,
-	combat = { dam=resolvers.levelup(28, 1, 1), atk=12, apr=35, dammod={str=0.5, dex=0.5}},
+	combat = { dam=resolvers.levelup(28, 1, 1), atk=12, apr=35},
 	resolvers.talents{
 		[Talents.T_STEALTH]={base=3, every=6, max=5},
 		[Talents.T_RUSH]={base=3, every=8, max=5},
diff --git a/game/modules/tome/data/general/npcs/fire-drake.lua b/game/modules/tome/data/general/npcs/fire-drake.lua
index 6916668d37..5f763b21cb 100644
--- a/game/modules/tome/data/general/npcs/fire-drake.lua
+++ b/game/modules/tome/data/general/npcs/fire-drake.lua
@@ -51,7 +51,7 @@ newEntity{ base = "BASE_NPC_FIRE_DRAKE",
 	rank = 1, size_category = 2,
 	max_life = resolvers.rngavg(40,60),
 	combat_armor = 5, combat_def = 0,
-	combat = { dam=resolvers.levelup(resolvers.rngavg(25,40), 1, 0.6), atk=resolvers.rngavg(25,60), apr=25, dammod={str=1.1} },
+	combat = { dam=resolvers.levelup(resolvers.rngavg(25,40), 1, 0.6), atk=resolvers.rngavg(25,60), apr=25, dammod={str=resolvers.levelup(0.1, 5, 0.1, 1.1)} },
 	on_melee_hit = {[DamageType.FIRE]=resolvers.mbonus(7, 2)},
 
 	make_escort = {
diff --git a/game/modules/tome/data/general/npcs/ghoul.lua b/game/modules/tome/data/general/npcs/ghoul.lua
index d449de24ad..caf888b497 100644
--- a/game/modules/tome/data/general/npcs/ghoul.lua
+++ b/game/modules/tome/data/general/npcs/ghoul.lua
@@ -65,7 +65,7 @@ newEntity{ base = "BASE_NPC_GHOUL",
 	},
 	ai_state = { talent_in=4, },
 
-	combat = { dam=resolvers.levelup(10, 1, 1), atk=resolvers.levelup(5, 1, 1), apr=3, dammod={str=0.6} },
+	combat = { dam=resolvers.levelup(10, 1, 1), atk=resolvers.levelup(5, 1, 1), apr=3, dammod={str=resolvers.levelup(0.1, 5, 0.1, 0.6)} },
 }
 
 newEntity{ base = "BASE_NPC_GHOUL",
@@ -77,7 +77,7 @@ newEntity{ base = "BASE_NPC_GHOUL",
 	combat_armor = 2, combat_def = 8,
 	ai_state = { talent_in=3, },
 
-	combat = { dam=resolvers.levelup(17, 1, 1.1), atk=resolvers.levelup(6, 1, 1), apr=3, dammod={str=0.6} },
+	combat = { dam=resolvers.levelup(17, 1, 1.1), atk=resolvers.levelup(6, 1, 1), apr=3, dammod={str=resolvers.levelup(0.1, 5, 0.1, 0.6)} },
 
 	summon = {{type="undead", subtype="ghoul", name="ghoul", number=1, hasxp=false}, },
 	resolvers.talents{
diff --git a/game/modules/tome/data/general/npcs/gwelgoroth.lua b/game/modules/tome/data/general/npcs/gwelgoroth.lua
index b95c675fac..d927191631 100644
--- a/game/modules/tome/data/general/npcs/gwelgoroth.lua
+++ b/game/modules/tome/data/general/npcs/gwelgoroth.lua
@@ -25,7 +25,7 @@ newEntity{
 	blood_color = colors.AQUAMARINE,
 	display = "E", color=colors.AQUAMARINE,
 
-	combat = { dam=resolvers.levelup(resolvers.mbonus(40, 15), 1, 1.2), atk=15, apr=15, dammod={mag=0.8}, damtype=DamageType.LIGHTNING },
+	combat = { dam=resolvers.levelup(resolvers.mbonus(40, 15), 1, 1.2), atk=15, apr=15, dammod={mag=resolvers.levelup(0.1, 5, 0.1, 0.8)}, damtype=DamageType.LIGHTNING },
 
 	body = { INVEN = 10, MAINHAND=1, OFFHAND=1, BODY=1 },
 
diff --git a/game/modules/tome/data/general/npcs/multihued-drake.lua b/game/modules/tome/data/general/npcs/multihued-drake.lua
index 76c292d82a..10b6bb9601 100644
--- a/game/modules/tome/data/general/npcs/multihued-drake.lua
+++ b/game/modules/tome/data/general/npcs/multihued-drake.lua
@@ -52,7 +52,7 @@ newEntity{ base = "BASE_NPC_MULTIHUED_DRAKE",
 	max_life = resolvers.rngavg(60,80),
 	combat_armor = 5, combat_def = 0,
 	on_melee_hit = {[DamageType.FIRE]=resolvers.mbonus(7, 3), [DamageType.COLD]=resolvers.mbonus(7, 3)},
-	combat = { dam=resolvers.levelup(resolvers.rngavg(25,70), 1, 0.6), atk=resolvers.rngavg(25,70), apr=25, dammod={str=1.1} },
+	combat = { dam=resolvers.levelup(resolvers.rngavg(25,70), 1, 0.6), atk=resolvers.rngavg(25,70), apr=25, dammod={str=resolvers.levelup(0.2, 5, 0.1, 1.1)} },
 
 	resists = { [DamageType.PHYSICAL] = 20, [DamageType.FIRE] = 20, [DamageType.COLD] = 20, [DamageType.ACID] = 20, [DamageType.LIGHTNING] = 20, },
 
diff --git a/game/modules/tome/data/general/npcs/ritch.lua b/game/modules/tome/data/general/npcs/ritch.lua
index 8cd2cb9047..1486a20250 100644
--- a/game/modules/tome/data/general/npcs/ritch.lua
+++ b/game/modules/tome/data/general/npcs/ritch.lua
@@ -27,7 +27,7 @@ newEntity{
 	desc = [[Ritches are giant insects native to the arid wastes of the southern parts of the Far East.
 Vicious predators, they inject corrupting diseases into their foes, and their sharp claws cut through most armours.]],
 
-	combat = { dam=resolvers.levelup(resolvers.rngavg(30,35), 1, 1), atk=16, apr=70, damtype=DamageType.BLIGHT, dammod={dex=1.2} },
+	combat = { dam=resolvers.levelup(resolvers.rngavg(30,35), 1, 1), atk=16, apr=70, damtype=DamageType.BLIGHT, dammod={dex=resolvers.levelup(0.1, 5, 0.1, 1.2)} },
 
 	body = { INVEN = 10, MAINHAND=1, OFFHAND=1, BODY=1 },
 
diff --git a/game/modules/tome/data/general/npcs/sandworm.lua b/game/modules/tome/data/general/npcs/sandworm.lua
index 9b65cafae3..4080ccb958 100644
--- a/game/modules/tome/data/general/npcs/sandworm.lua
+++ b/game/modules/tome/data/general/npcs/sandworm.lua
@@ -26,7 +26,7 @@ newEntity{
 	level_range = {7, nil},
 	body = { INVEN = 10 },
 
-	combat = { dam=resolvers.levelup(resolvers.mbonus(25, 15), 1, 1), atk=15, apr=0, dammod={str=0.7} },
+	combat = { dam=resolvers.levelup(resolvers.mbonus(25, 15), 1, 1), atk=15, apr=0, dammod={str=resolvers.levelup(0.1, 5, 0.1, 0.7)} },
 
 	infravision = 10,
 	max_life = 40, life_rating = 5,
diff --git a/game/modules/tome/data/general/npcs/snow-giant.lua b/game/modules/tome/data/general/npcs/snow-giant.lua
index 19d986455b..a3f903758e 100644
--- a/game/modules/tome/data/general/npcs/snow-giant.lua
+++ b/game/modules/tome/data/general/npcs/snow-giant.lua
@@ -24,7 +24,7 @@ newEntity{
 	type = "giant", subtype = "ice",
 	display = "P", color=colors.WHITE,
 
-	combat = { dam=resolvers.levelup(resolvers.mbonus(50, 10), 1, 1), atk=15, apr=15, dammod={str=0.8} },
+	combat = { dam=resolvers.levelup(resolvers.mbonus(50, 10), 1, 1), atk=15, apr=15, dammod={str=resolvers.levelup(0.2, 5, 0.1, 0.8)} },
 
 	body = { INVEN = 10, MAINHAND=1, OFFHAND=1, BODY=1 },
 	resolvers.drops{chance=100, nb=1, {type="money"} },
diff --git a/game/modules/tome/data/general/npcs/spider.lua b/game/modules/tome/data/general/npcs/spider.lua
index c1cf8cbb1b..6fc8df7550 100644
--- a/game/modules/tome/data/general/npcs/spider.lua
+++ b/game/modules/tome/data/general/npcs/spider.lua
@@ -25,7 +25,7 @@ newEntity{
 	display = "S", color=colors.WHITE,
 	desc = [[Arachnophobia...]],
 
-	combat = { dam=resolvers.levelup(resolvers.mbonus(40, 70), 1, 0.9), atk=16, apr=9, damtype=DamageType.NATURE, dammod={dex=1.2} },
+	combat = { dam=resolvers.levelup(resolvers.mbonus(40, 70), 1, 0.9), atk=16, apr=9, damtype=DamageType.NATURE, dammod={dex=resolvers.levelup(0.2, 5, 0.1, 1.2)} },
 
 	body = { INVEN = 10, MAINHAND=1, OFFHAND=1, BODY=1 },
 
@@ -263,7 +263,7 @@ newEntity{ base = "BASE_NPC_SPIDER",
 
 	size_category = 1,
 
-	combat = { dam=resolvers.levelup(resolvers.mbonus(40, 70), 1, 0.9), atk=16, apr=9, damtype=DamageType.WASTING, dammod={dex=1.2} },
+	combat = { dam=resolvers.levelup(resolvers.mbonus(40, 70), 1, 0.9), atk=16, apr=9, damtype=DamageType.WASTING},
 
 	combat_armor = 5, combat_def = 10,
 	resists = { [DamageType.NATURE] = 20, [DamageType.LIGHT] = -20, [DamageType.TEMPORAL] = 20, },
@@ -285,7 +285,7 @@ newEntity{ base = "BASE_NPC_SPIDER",
 	life_rating = 13,
 	rank = 2,
 
-	combat = { dam=resolvers.levelup(resolvers.mbonus(40, 70), 1, 0.9), atk=16, apr=9, damtype=DamageType.WASTING, dammod={dex=1.2} },
+	combat = { dam=resolvers.levelup(resolvers.mbonus(40, 70), 1, 0.9), atk=16, apr=9, damtype=DamageType.WASTING},
 
 	combat_armor = 7, combat_def = 17,
 	resists = { [DamageType.NATURE] = 20, [DamageType.LIGHT] = -20, [DamageType.TEMPORAL] = 20, },
@@ -316,7 +316,7 @@ newEntity{ base = "BASE_NPC_SPIDER",
 	ai = "tactical",
 	ai_tactic = resolvers.tactic"melee", ai_state = { ai_move="move_dmap", talent_in=2, },
 
-	combat = { dam=resolvers.levelup(resolvers.mbonus(40, 70), 1, 0.9), atk=16, apr=9, damtype=DamageType.WASTING, dammod={dex=1.2} },
+	combat = { dam=resolvers.levelup(resolvers.mbonus(40, 70), 1, 0.9), atk=16, apr=9, damtype=DamageType.WASTING},
 
 	combat_armor = 7, combat_def = 17,
 	resists = { [DamageType.NATURE] = 20, [DamageType.LIGHT] = -20, [DamageType.TEMPORAL] = 20, },
@@ -354,7 +354,7 @@ newEntity{ base = "BASE_NPC_SPIDER",
 	ai = "tactical",
 	ai_tactic = resolvers.tactic"melee", ai_state = { ai_move="move_dmap", talent_in=1, },
 
-	combat = { dam=resolvers.levelup(resolvers.mbonus(100, 15), 1, 0.9), atk=16, apr=9, damtype=DamageType.WASTING, dammod={dex=1.2} },
+	combat = { dam=resolvers.levelup(resolvers.mbonus(100, 15), 1, 0.9), atk=16, apr=9, damtype=DamageType.WASTING},
 
 	combat_armor = 7, combat_def = 17,
 	resists = { [DamageType.NATURE] = 20, [DamageType.LIGHT] = -20, [DamageType.TEMPORAL] = 20, },
diff --git a/game/modules/tome/data/general/npcs/storm-drake.lua b/game/modules/tome/data/general/npcs/storm-drake.lua
index 5c812e0719..e6c324cfef 100644
--- a/game/modules/tome/data/general/npcs/storm-drake.lua
+++ b/game/modules/tome/data/general/npcs/storm-drake.lua
@@ -51,7 +51,7 @@ newEntity{ base = "BASE_NPC_STORM_DRAKE",
 	rank = 1, size_category = 2,
 	max_life = resolvers.rngavg(40,60),
 	combat_armor = 5, combat_def = 0,
-	combat = { dam=resolvers.levelup(resolvers.rngavg(25,40), 1, 0.6), atk=resolvers.rngavg(25,60), apr=25, dammod={str=1.1} },
+	combat = { dam=resolvers.levelup(resolvers.rngavg(25,40), 1, 0.6), atk=resolvers.rngavg(25,60), apr=25, dammod={str=resolvers.levelup(0.2, 5, 0.1, 1.1)} },
 	on_melee_hit = {[DamageType.LIGHTNING]=resolvers.mbonus(7, 2)},
 
 	make_escort = {
diff --git a/game/modules/tome/data/general/npcs/telugoroth.lua b/game/modules/tome/data/general/npcs/telugoroth.lua
index 96468426c9..244f948d4e 100644
--- a/game/modules/tome/data/general/npcs/telugoroth.lua
+++ b/game/modules/tome/data/general/npcs/telugoroth.lua
@@ -26,7 +26,7 @@ newEntity{
 	blood_color = colors.PURPLE,
 	display = "E", color=colors.YELLOW,
 
-	combat = { dam=resolvers.levelup(resolvers.mbonus(40, 15), 1, 1.2), atk=15, apr=15, dammod={mag=0.8}, damtype=DamageType.TEMPORAL, },
+	combat = { dam=resolvers.levelup(resolvers.mbonus(40, 15), 1, 1.2), atk=15, apr=15, dammod={mag=resolvers.levelup(0.1, 5, 0.1, 0.8)}, damtype=DamageType.TEMPORAL },
 
 	body = { INVEN = 10, MAINHAND=1, OFFHAND=1, BODY=1 },
 
@@ -44,7 +44,7 @@ newEntity{
 	resists = { [DamageType.TEMPORAL] = 100, },
 
 	negative_status_effect_immune = 1,
-	
+
 }
 
 newEntity{ base = "BASE_NPC_TELUGOROTH",
@@ -111,7 +111,7 @@ newEntity{ base = "BASE_NPC_TELUGOROTH",
 	ai = "dumb_talented_simple", ai_state = { talent_in=2, ai_move="move_snake" },
 
 	talent_cd_reduction = {[Talents.T_DUST_TO_DUST]=-3},
-	
+
 	resolvers.talents{
 		[Talents.T_ANOMALY_REARRANGE]=1,
 		[Talents.T_DUST_TO_DUST]={base=3, every=10, max=7},
@@ -132,7 +132,7 @@ newEntity{ base = "BASE_NPC_TELUGOROTH",
 	ai = "dumb_talented_simple", ai_state = { talent_in=2, ai_move="move_snake" },
 
 	talent_cd_reduction = {[Talents.T_DUST_TO_DUST]=-3},
-	
+
 	resolvers.talents{
 		[Talents.T_DIMENSIONAL_STEP]={base=5, every=10, max=9},
 		[Talents.T_ANOMALY_REARRANGE]=1,
@@ -156,7 +156,7 @@ newEntity{ base = "BASE_NPC_TELUGOROTH",
 	ai = "tactical", ai_state = { talent_in=2, ai_move="move_snake" },
 
 	talent_cd_reduction = {[Talents.T_DUST_TO_DUST]=-3},
-	
+
 	resolvers.talents{
 		[Talents.T_ANOMALY_TEMPORAL_STORM]=1,
 		[Talents.T_DUST_TO_DUST]={base=4, every=7},
diff --git a/game/modules/tome/data/general/npcs/troll.lua b/game/modules/tome/data/general/npcs/troll.lua
index fbffb3996e..b5f9a2a71d 100644
--- a/game/modules/tome/data/general/npcs/troll.lua
+++ b/game/modules/tome/data/general/npcs/troll.lua
@@ -27,7 +27,7 @@ newEntity{
 	sound_die = {"creatures/trolls/troll_die_%d", 1, 2},
 	sound_random = {"creatures/trolls/troll_growl_%d", 1, 4},
 
-	combat = { dam=resolvers.levelup(resolvers.mbonus(45, 10), 1, 1), atk=2, apr=6, physspeed=2, dammod={str=0.8}, sound="creatures/trolls/stomp" },
+	combat = { dam=resolvers.levelup(resolvers.mbonus(45, 10), 1, 1), atk=2, apr=6, physspeed=2, dammod={str=resolvers.levelup(0.2, 5, 0.1, 1.1)}, sound="creatures/trolls/stomp" },
 
 	body = { INVEN = 10, MAINHAND=1, OFFHAND=1, BODY=1 },
 	resolvers.drops{chance=20, nb=1, {} },
diff --git a/game/modules/tome/data/general/npcs/vampire.lua b/game/modules/tome/data/general/npcs/vampire.lua
index 1add4ef128..54cf10644c 100644
--- a/game/modules/tome/data/general/npcs/vampire.lua
+++ b/game/modules/tome/data/general/npcs/vampire.lua
@@ -25,7 +25,7 @@ newEntity{
 	display = "V", color=colors.WHITE,
 	desc = [[These ancient cursed beings often take the form of a bat and attack their prey.]],
 
-	combat = { dam=resolvers.levelup(resolvers.mbonus(30, 10), 1, 0.8), atk=10, apr=9, damtype=DamageType.DRAINLIFE, dammod={str=1.9} },
+	combat = { dam=resolvers.levelup(resolvers.mbonus(30, 10), 1, 0.8), atk=10, apr=9, damtype=DamageType.DRAINLIFE, dammod={str=resolvers.levelup(0.3, 5, 0.2, 1.9)} },
 
 	body = { INVEN = 10, MAINHAND=1, OFFHAND=1, BODY=1 },
 	drops = resolvers.drops{chance=20, nb=1, {} },
diff --git a/game/modules/tome/data/general/npcs/xorn.lua b/game/modules/tome/data/general/npcs/xorn.lua
index 92f0022b9d..58005e7e1d 100644
--- a/game/modules/tome/data/general/npcs/xorn.lua
+++ b/game/modules/tome/data/general/npcs/xorn.lua
@@ -25,7 +25,7 @@ newEntity{
 	display = "X", color=colors.UMBER,
 
 	blood_color = colors.UMBER,
-	combat = { dam=resolvers.levelup(resolvers.mbonus(46, 15), 1, 0.8), atk=15, apr=15, dammod={str=0.8} },
+	combat = { dam=resolvers.levelup(resolvers.mbonus(46, 15), 1, 0.8), atk=15, apr=15, dammod={str=resolvers.levelup(0.2, 5, 0.1, 0.8)} },
 
 	body = { INVEN = 10, MAINHAND=1, OFFHAND=1, BODY=1 },
 	resolvers.drops{chance=100, nb=1, {type="money"} },
diff --git a/game/modules/tome/data/general/objects/2haxes.lua b/game/modules/tome/data/general/objects/2haxes.lua
index 8c926212fe..118c8b849e 100644
--- a/game/modules/tome/data/general/objects/2haxes.lua
+++ b/game/modules/tome/data/general/objects/2haxes.lua
@@ -17,8 +17,11 @@
 -- Nicolas Casalini "DarkGod"
 -- darkgod@te4.org
 
+local Talents = require "engine.interface.ActorTalents"
+
 newEntity{
 	define_as = "BASE_BATTLEAXE",
+	flavor_names = {"battleaxe", "greataxe", "bardiche", "warcleaver"},
 	slot = "MAINHAND",
 	slot_forbid = "OFFHAND",
 	type = "weapon", subtype="battleaxe", image = resolvers.image_material("2haxe", "metal"),
@@ -28,7 +31,7 @@ newEntity{
 	encumber = 3,
 	rarity = 5,
 	metallic = true,
-	combat = { talented = "axe", damrange = 1.5, physspeed = 1, sound = {"actions/melee", pitch=0.6, vol=1.2}, sound_miss = {"actions/melee", pitch=0.6, vol=1.2} },
+	combat = { talented = "axe", damrange = 1, physspeed = 1, sound = {"actions/melee", pitch=0.6, vol=1.2}, sound_miss = {"actions/melee", pitch=0.6, vol=1.2} },
 	desc = [[Massive two-handed battleaxes.]],
 	twohanded = true,
 	randart_able = { attack=40, physical=80, spell=20, def=10, misc=10 },
@@ -42,10 +45,10 @@ newEntity{ base = "BASE_BATTLEAXE",
 	cost = 5,
 	material_level = 1,
 	combat = {
-		dam = resolvers.rngavg(6,12),
-		apr = 1,
-		physcrit = 4.5,
-		dammod = {str=1.2},
+		dam = resolvers.cbonus(8),
+		max_acc = resolvers.cbonus(85, 100, 1, 3),
+		critical_power = resolvers.cbonus(17, 29, 0.1),
+		dammod = {str=0.25},
 	},
 }
 
@@ -53,13 +56,13 @@ newEntity{ base = "BASE_BATTLEAXE",
 	name = "steel battleaxe", short_name = "steel",
 	level_range = {10, 20},
 	require = { stat = { str=16 }, },
-	cost = 10,
+	cost = 30,
 	material_level = 2,
 	combat = {
-		dam = resolvers.rngavg(15,23),
-		apr = 2,
-		physcrit = 5,
-		dammod = {str=1.2},
+		dam = resolvers.cbonus(16),
+		max_acc = resolvers.cbonus(85, 100, 1, 3.5),
+		critical_power = resolvers.cbonus(17, 29, 0.1, 3.5),
+		dammod = {str=0.5},
 	},
 }
 
@@ -67,13 +70,13 @@ newEntity{ base = "BASE_BATTLEAXE",
 	name = "dwarven-steel battleaxe", short_name = "d.steel",
 	level_range = {20, 30},
 	require = { stat = { str=24 }, },
-	cost = 15,
+	cost = 80,
 	material_level = 3,
 	combat = {
-		dam = resolvers.rngavg(28,35),
-		apr = 2,
-		physcrit = 6.5,
-		dammod = {str=1.2},
+		dam = resolvers.cbonus(32),
+		max_acc = resolvers.cbonus(85, 100, 1, 4),
+		critical_power = resolvers.cbonus(17, 29, 0.1, 4),
+		dammod = {str=0.75},
 	},
 }
 
@@ -81,13 +84,13 @@ newEntity{ base = "BASE_BATTLEAXE",
 	name = "stralite battleaxe", short_name = "stralite",
 	level_range = {30, 40},
 	require = { stat = { str=35 }, },
-	cost = 25,
+	cost = 120,
 	material_level = 4,
 	combat = {
-		dam = resolvers.rngavg(40,48),
-		apr = 3,
-		physcrit = 7.5,
-		dammod = {str=1.2},
+		dam = resolvers.cbonus(56),
+		max_acc = resolvers.cbonus(85, 100, 1, 4.5),
+		critical_power = resolvers.cbonus(17, 29, 0.1, 4.5),
+		dammod = {str=1},
 	},
 }
 
@@ -95,12 +98,12 @@ newEntity{ base = "BASE_BATTLEAXE",
 	name = "voratun battleaxe", short_name = "voratun",
 	level_range = {40, 50},
 	require = { stat = { str=48 }, },
-	cost = 35,
+	cost = 170,
 	material_level = 5,
 	combat = {
-		dam = resolvers.rngavg(54, 60),
-		apr = 4,
-		physcrit = 8,
-		dammod = {str=1.2},
+		dam = resolvers.cbonus(80),
+		max_acc = resolvers.cbonus(85, 100, 1, 5),
+		critical_power = resolvers.cbonus(17, 29, 0.1, 5),
+		dammod = {str=1.25},
 	},
 }
diff --git a/game/modules/tome/data/general/objects/2hmaces.lua b/game/modules/tome/data/general/objects/2hmaces.lua
index caa4e8eccc..e5586b418f 100644
--- a/game/modules/tome/data/general/objects/2hmaces.lua
+++ b/game/modules/tome/data/general/objects/2hmaces.lua
@@ -17,8 +17,11 @@
 -- Nicolas Casalini "DarkGod"
 -- darkgod@te4.org
 
+local Talents = require "engine.interface.ActorTalents"
+
 newEntity{
 	define_as = "BASE_GREATMAUL",
+	flavor_names = {"greatmaul", "sledge", "warhammer", "bonegrinder"},
 	slot = "MAINHAND",
 	slot_forbid = "OFFHAND",
 	type = "weapon", subtype="greatmaul",
@@ -28,7 +31,7 @@ newEntity{
 	encumber = 5,
 	rarity = 5,
 	metallic = true,
-	combat = { talented = "mace", damrange = 1.5, physspeed = 1, sound = {"actions/melee", pitch=0.6, vol=1.2}, sound_miss = {"actions/melee", pitch=0.6, vol=1.2} },
+	combat = { talented = "mace", damrange = 1, physspeed = 1, sound = {"actions/melee", pitch=0.6, vol=1.2}, sound_miss = {"actions/melee", pitch=0.6, vol=1.2} },
 	desc = [[Massive two-handed maul.]],
 	twohanded = true,
 	randart_able = { attack=40, physical=80, spell=20, def=10, misc=10 },
@@ -42,10 +45,10 @@ newEntity{ base = "BASE_GREATMAUL",
 	cost = 5,
 	material_level = 1,
 	combat = {
-		dam = resolvers.rngavg(10,16),
-		apr = 1,
-		physcrit = 0.5,
-		dammod = {str=1.2},
+		dam = resolvers.cbonus(12),
+		max_acc = resolvers.cbonus(80, 100, 1, 3),
+		critical_power = resolvers.cbonus(15, 27, 0.1, 3),
+		dammod = {str=0.25},
 	},
 }
 
@@ -53,13 +56,13 @@ newEntity{ base = "BASE_GREATMAUL",
 	name = "steel greatmaul", short_name = "steel",
 	level_range = {10, 20},
 	require = { stat = { str=16 }, },
-	cost = 10,
+	cost = 30,
 	material_level = 2,
 	combat = {
-		dam = resolvers.rngavg(22,30),
-		apr = 2,
-		physcrit = 1,
-		dammod = {str=1.2},
+		dam = resolvers.cbonus(24),
+		max_acc = resolvers.cbonus(80, 100, 1, 3.5),
+		critical_power = resolvers.cbonus(15, 27, 0.1, 3.5),
+		dammod = {str=0.5},
 	},
 }
 
@@ -67,13 +70,13 @@ newEntity{ base = "BASE_GREATMAUL",
 	name = "dwarven-steel greatmaul", short_name = "d.steel",
 	level_range = {20, 30},
 	require = { stat = { str=24 }, },
-	cost = 15,
+	cost = 80,
 	material_level = 3,
 	combat = {
-		dam = resolvers.rngavg(38,45),
-		apr = 2,
-		physcrit = 1.5,
-		dammod = {str=1.2},
+		dam = resolvers.cbonus(48),
+		max_acc = resolvers.cbonus(80, 100, 1, 4),
+		critical_power = resolvers.cbonus(15, 27, 0.1, 4),
+		dammod = {str=0.75},
 	},
 }
 
@@ -81,13 +84,13 @@ newEntity{ base = "BASE_GREATMAUL",
 	name = "stralite greatmaul", short_name = "stralite",
 	level_range = {30, 40},
 	require = { stat = { str=35 }, },
-	cost = 25,
+	cost = 120,
 	material_level = 4,
 	combat = {
-		dam = resolvers.rngavg(50,59),
-		apr = 3,
-		physcrit = 2.5,
-		dammod = {str=1.2},
+		dam = resolvers.cbonus(84),
+		max_acc = resolvers.cbonus(80, 100, 1, 4.5),
+		critical_power = resolvers.cbonus(15, 27, 0.1, 4.5),
+		dammod = {str=1},
 	},
 }
 
@@ -95,12 +98,12 @@ newEntity{ base = "BASE_GREATMAUL",
 	name = "voratun greatmaul", short_name = "voratun",
 	level_range = {40, 50},
 	require = { stat = { str=48 }, },
-	cost = 35,
+	cost = 170,
 	material_level = 5,
 	combat = {
-		dam = resolvers.rngavg(62, 72),
-		apr = 4,
-		physcrit = 3,
-		dammod = {str=1.2},
+		dam = resolvers.cbonus(120),
+		max_acc = resolvers.cbonus(80, 100, 1, 5),
+		critical_power = resolvers.cbonus(15, 27, 0.1, 5),
+		dammod = {str=1.25},
 	},
 }
diff --git a/game/modules/tome/data/general/objects/2hswords.lua b/game/modules/tome/data/general/objects/2hswords.lua
index 1697ce0369..3c0915573b 100644
--- a/game/modules/tome/data/general/objects/2hswords.lua
+++ b/game/modules/tome/data/general/objects/2hswords.lua
@@ -19,6 +19,7 @@
 
 newEntity{
 	define_as = "BASE_GREATSWORD",
+	flavor_names = {"greatsword", "broadsword", "claymore", "murderblade"},
 	slot = "MAINHAND",
 	slot_forbid = "OFFHAND",
 	type = "weapon", subtype="greatsword",
@@ -27,7 +28,7 @@ newEntity{
 	moddable_tile = resolvers.moddable_tile("sword"),
 	encumber = 3,
 	rarity = 5,
-	combat = { talented = "sword", damrange = 1.6, physspeed = 1, sound = {"actions/melee", pitch=0.6, vol=1.2}, sound_miss = {"actions/melee", pitch=0.6, vol=1.2} },
+	combat = { talented = "sword", damrange = 1, physspeed = 1, sound = {"actions/melee", pitch=0.6, vol=1.2}, sound_miss = {"actions/melee", pitch=0.6, vol=1.2} },
 	desc = [[Massive two-handed swords.]],
 	twohanded = true,
 	metallic = true,
@@ -42,10 +43,10 @@ newEntity{ base = "BASE_GREATSWORD",
 	cost = 5,
 	material_level = 1,
 	combat = {
-		dam = resolvers.rngavg(8,14),
-		apr = 1,
-		physcrit = 2.5,
-		dammod = {str=1.2},
+		dam = resolvers.cbonus(10),
+		max_acc = resolvers.cbonus(90, 100, 1, 3),
+		critical_power = resolvers.cbonus(13, 25, 0.1),
+		dammod = {str=0.25},
 	},
 }
 
@@ -53,13 +54,13 @@ newEntity{ base = "BASE_GREATSWORD",
 	name = "steel greatsword", short_name = "steel",
 	level_range = {10, 20},
 	require = { stat = { str=16 }, },
-	cost = 10,
+	cost = 30,
 	material_level = 2,
 	combat = {
-		dam = resolvers.rngavg(18,26),
-		apr = 2,
-		physcrit = 3,
-		dammod = {str=1.2},
+		dam = resolvers.cbonus(20),
+		max_acc = resolvers.cbonus(90, 100, 1, 3.5),
+		critical_power = resolvers.cbonus(13, 25, 0.1, 3.5),
+		dammod = {str=0.5},
 	},
 }
 
@@ -67,13 +68,13 @@ newEntity{ base = "BASE_GREATSWORD",
 	name = "dwarven-steel greatsword", short_name = "d.steel",
 	level_range = {20, 30},
 	require = { stat = { str=24 }, },
-	cost = 15,
+	cost = 80,
 	material_level = 3,
 	combat = {
-		dam = resolvers.rngavg(32,40),
-		apr = 2,
-		physcrit = 3.5,
-		dammod = {str=1.2},
+		dam = resolvers.cbonus(40),
+		max_acc = resolvers.cbonus(90, 100, 1, 4),
+		critical_power = resolvers.cbonus(13, 25, 0.1, 4),
+		dammod = {str=0.75},
 	},
 }
 
@@ -81,13 +82,13 @@ newEntity{ base = "BASE_GREATSWORD",
 	name = "stralite greatsword", short_name = "stralite",
 	level_range = {30, 40},
 	require = { stat = { str=35 }, },
-	cost = 25,
+	cost = 120,
 	material_level = 4,
 	combat = {
-		dam = resolvers.rngavg(45,52),
-		apr = 3,
-		physcrit = 4.5,
-		dammod = {str=1.2},
+		dam = resolvers.cbonus(70),
+		max_acc = resolvers.cbonus(90, 100, 1, 4.5),
+		critical_power = resolvers.cbonus(13, 25, 0.1, 4.5),
+		dammod = {str=1},
 	},
 }
 
@@ -95,12 +96,12 @@ newEntity{ base = "BASE_GREATSWORD",
 	name = "voratun greatsword", short_name = "voratun",
 	level_range = {40, 50},
 	require = { stat = { str=48 }, },
-	cost = 35,
+	cost = 170,
 	material_level = 5,
 	combat = {
-		dam = resolvers.rngavg(58, 66),
-		apr = 4,
-		physcrit = 5,
-		dammod = {str=1.2},
+		dam = resolvers.cbonus(100),
+		max_acc = resolvers.cbonus(90, 100, 1, 3, 5),
+		critical_power = resolvers.cbonus(13, 25, 0.1, 5),
+		dammod = {str=1.25},
 	},
 }
diff --git a/game/modules/tome/data/general/objects/2htridents.lua b/game/modules/tome/data/general/objects/2htridents.lua
index 51c58e9b6f..daa94e32d7 100644
--- a/game/modules/tome/data/general/objects/2htridents.lua
+++ b/game/modules/tome/data/general/objects/2htridents.lua
@@ -29,7 +29,7 @@ newEntity{
 	trident_rarity = 5, -- Special rarity field, converted to "rarity" when needed
 	metallic = true,
 	no_rust = true,
-	combat = { talented = "trident", damrange = 1.6, physspeed = 1, sound = {"actions/melee", pitch=0.6, vol=1.2}, sound_miss = {"actions/melee", pitch=0.6, vol=1.2} },
+	combat = { talented = "trident", damrange = 1, physspeed = 1, sound = {"actions/melee", pitch=0.6, vol=1.2}, sound_miss = {"actions/melee", pitch=0.6, vol=1.2} },
 	desc = [[A two-handed massive trident.
 Tridents require the exotic weapons mastery talent to use correctly.]],
 	twohanded = true,
@@ -44,10 +44,10 @@ newEntity{ base = "BASE_TRIDENT",
 	cost = 5,
 	material_level = 1,
 	combat = {
-		dam = resolvers.rngavg(6,10),
-		apr = 6,
-		physcrit = 1.5,
-		dammod = {str=1.2},
+		dam = resolvers.cbonus(10),
+		max_acc = resolvers.cbonus(90, 100, 1, 3),
+		critical_power = resolvers.cbonus(13, 25, 0.1),
+		dammod = {str=0.25},
 	},
 }
 
@@ -55,13 +55,13 @@ newEntity{ base = "BASE_TRIDENT",
 	name = "blue-steel trident", short_name = "b.steel",
 	level_range = {10, 20},
 	require = { stat = { str=16 }, },
-	cost = 10,
+	cost = 30,
 	material_level = 2,
 	combat = {
-		dam = resolvers.rngavg(11,19),
-		apr = 8,
-		physcrit = 2,
-		dammod = {str=1.2},
+		dam = resolvers.cbonus(20),
+		max_acc = resolvers.cbonus(90, 100, 1, 3.5),
+		critical_power = resolvers.cbonus(13, 25, 0.1, 3.5),
+		dammod = {str=0.5},
 	},
 }
 
@@ -69,13 +69,13 @@ newEntity{ base = "BASE_TRIDENT",
 	name = "deep-steel trident", short_name = "d.steel",
 	level_range = {20, 30},
 	require = { stat = { str=24 }, },
-	cost = 15,
+	cost = 80,
 	material_level = 3,
 	combat = {
-		dam = resolvers.rngavg(24,31),
-		apr = 10,
-		physcrit = 2.5,
-		dammod = {str=1.2},
+		dam = resolvers.cbonus(40),
+		max_acc = resolvers.cbonus(90, 100, 1, 4),
+		critical_power = resolvers.cbonus(13, 25, 0.1, 4),
+		dammod = {str=0.75},
 	},
 }
 
@@ -83,13 +83,13 @@ newEntity{ base = "BASE_TRIDENT",
 	name = "orite trident", short_name = "orite",
 	level_range = {30, 40},
 	require = { stat = { str=35 }, },
-	cost = 25,
+	cost = 120,
 	material_level = 4,
 	combat = {
-		dam = resolvers.rngavg(36,44),
-		apr = 13,
-		physcrit = 3.5,
-		dammod = {str=1.2},
+		dam = resolvers.cbonus(70),
+		max_acc = resolvers.cbonus(90, 100, 1, 4.5),
+		critical_power = resolvers.cbonus(13, 25, 0.1, 4.5),
+		dammod = {str=1},
 	},
 }
 
@@ -97,12 +97,12 @@ newEntity{ base = "BASE_TRIDENT",
 	name = "orichalcum trident", short_name = "orichalcum",
 	level_range = {40, 50},
 	require = { stat = { str=48 }, },
-	cost = 35,
+	cost = 170,
 	material_level = 5,
 	combat = {
-		dam = resolvers.rngavg(50, 56),
-		apr = 16,
-		physcrit = 4,
-		dammod = {str=1.2},
+		dam = resolvers.cbonus(100),
+		max_acc = resolvers.cbonus(90, 100, 1, 3, 5),
+		critical_power = resolvers.cbonus(13, 25, 0.1, 5),
+		dammod = {str=1.25},
 	},
 }
diff --git a/game/modules/tome/data/general/objects/axes.lua b/game/modules/tome/data/general/objects/axes.lua
index d46ce2719c..172fef4502 100644
--- a/game/modules/tome/data/general/objects/axes.lua
+++ b/game/modules/tome/data/general/objects/axes.lua
@@ -19,6 +19,7 @@
 
 newEntity{
 	define_as = "BASE_WARAXE",
+	flavor_names = {"handaxe", "waraxe", "broadaxe", "slaughteraxe"},
 	slot = "MAINHAND", dual_wieldable = true,
 	type = "weapon", subtype="waraxe",
 	add_name = " (#COMBAT#)",
@@ -27,7 +28,7 @@ newEntity{
 	encumber = 3,
 	rarity = 3,
 	metallic = true,
-	combat = { talented = "axe", damrange = 1.4, physspeed = 1, sound = {"actions/melee", pitch=0.6, vol=1.2}, sound_miss = {"actions/melee", pitch=0.6, vol=1.2}},
+	combat = { talented = "axe", damrange = 1, physspeed = 1, sound = {"actions/melee", pitch=0.6, vol=1.2}, sound_miss = {"actions/melee", pitch=0.6, vol=1.2}},
 	desc = [[One-handed war axes.]],
 	randart_able = { attack=40, physical=80, spell=20, def=10, misc=10 },
 	egos = "/data/general/objects/egos/weapon.lua", egos_chance = { prefix=resolvers.mbonus(40, 5), suffix=resolvers.mbonus(40, 5) },
@@ -40,10 +41,10 @@ newEntity{ base = "BASE_WARAXE",
 	cost = 5,
 	material_level = 1,
 	combat = {
-		dam = resolvers.rngavg(5,8),
-		apr = 2,
-		physcrit = 3.5,
-		dammod = {str=1},
+		dam = resolvers.cbonus(4),
+		max_acc = resolvers.cbonus(85, 100, 1, 3),
+		critical_power = resolvers.cbonus(17, 29, 0.1),
+		dammod = {str=0.2},
 	},
 }
 
@@ -51,13 +52,13 @@ newEntity{ base = "BASE_WARAXE",
 	name = "steel waraxe", short_name = "steel",
 	level_range = {10, 20},
 	require = { stat = { str=16 }, },
-	cost = 10,
+	cost = 30,
 	material_level = 2,
 	combat = {
-		dam = resolvers.rngavg(8,14),
-		apr = 3,
-		physcrit = 4,
-		dammod = {str=1},
+		dam = resolvers.cbonus(8),
+		max_acc = resolvers.cbonus(85, 100, 1, 3.5),
+		critical_power = resolvers.cbonus(17, 29, 0.1, 3.5),
+		dammod = {str=0.4},
 	},
 }
 
@@ -65,13 +66,13 @@ newEntity{ base = "BASE_WARAXE",
 	name = "dwarven-steel waraxe", short_name = "d.steel",
 	level_range = {20, 30},
 	require = { stat = { str=24 }, },
-	cost = 15,
+	cost = 80,
 	material_level = 3,
 	combat = {
-		dam = resolvers.rngavg(17,23),
-		apr = 4,
-		physcrit = 4.5,
-		dammod = {str=1},
+		dam = resolvers.cbonus(16),
+		max_acc = resolvers.cbonus(85, 100, 1, 4),
+		critical_power = resolvers.cbonus(17, 29, 0.1, 4),
+		dammod = {str=0.6},
 	},
 }
 
@@ -79,13 +80,13 @@ newEntity{ base = "BASE_WARAXE",
 	name = "stralite waraxe", short_name = "stralite",
 	level_range = {30, 40},
 	require = { stat = { str=35 }, },
-	cost = 25,
+	cost = 120,
 	material_level = 4,
 	combat = {
-		dam = resolvers.rngavg(28,35),
-		apr = 5,
-		physcrit = 6.5,
-		dammod = {str=1},
+		dam = resolvers.cbonus(28),
+		max_acc = resolvers.cbonus(85, 100, 1, 4.5),
+		critical_power = resolvers.cbonus(17, 29, 0.1, 4.5),
+		dammod = {str=0.8},
 	},
 }
 
@@ -93,12 +94,12 @@ newEntity{ base = "BASE_WARAXE",
 	name = "voratun waraxe", short_name = "voratun",
 	level_range = {40, 50},
 	require = { stat = { str=48 }, },
-	cost = 35,
+	cost = 170,
 	material_level = 5,
 	combat = {
-		dam = resolvers.rngavg(38,42),
-		apr = 6,
-		physcrit = 7,
+		dam = resolvers.cbonus(40),
+		max_acc = resolvers.cbonus(85, 100, 1, 5),
+		critical_power = resolvers.cbonus(17, 29, 0.1, 5),
 		dammod = {str=1},
 	},
 }
diff --git a/game/modules/tome/data/general/objects/boss-artifacts-far-east.lua b/game/modules/tome/data/general/objects/boss-artifacts-far-east.lua
index b948cb7b1a..192aa0c4bc 100644
--- a/game/modules/tome/data/general/objects/boss-artifacts-far-east.lua
+++ b/game/modules/tome/data/general/objects/boss-artifacts-far-east.lua
@@ -34,10 +34,11 @@ newEntity{ base = "BASE_KNIFE", define_as = "LIFE_DRINKER",
 	cost = 450,
 	material_level = 5,
 	combat = {
+		affects_spells = true,
 		dam = 42,
-		apr = 11,
-		physcrit = 18,
-		dammod = {mag=0.55,str=0.35},
+		max_acc = 100,
+		critical_power = 2.2,
+		dammod = {mag=0.6,str=0.4},
 	},
 	wielder = {
 		inc_damage={
diff --git a/game/modules/tome/data/general/objects/boss-artifacts.lua b/game/modules/tome/data/general/objects/boss-artifacts.lua
index 489843de2e..d845d40b54 100644
--- a/game/modules/tome/data/general/objects/boss-artifacts.lua
+++ b/game/modules/tome/data/general/objects/boss-artifacts.lua
@@ -34,11 +34,10 @@ It is said the Conclave created this weapon for their warmaster during the dark
 	cost = 2000,
 	material_level = 5,
 	combat = {
-		dam = 45,
-		apr = 10,
-		physcrit = 10,
+		dam = 70,
+		max_acc = 95,
+		critical_power = 1.5,
 		dammod = {str=1},
-		damrange = 1.4,
 		melee_project={[DamageType.ICE] = 45},
 	},
 	wielder = {
@@ -200,11 +199,10 @@ Tridents require the exotic weapons mastery talent to use correctly.]],
 	cost = 300,
 	material_level = 4,
 	combat = {
-		dam = 60,
-		apr = 4,
-		physcrit = 15,
-		dammod = {str=1.3},
-		damrange = 1.4,
+		dam = 90,
+		max_acc = 100,
+		critical_power = 2,
+		dammod = {str=1.1},
 		melee_project={
 			[DamageType.COLD] = 15,
 			[DamageType.NATURE] = 20,
@@ -374,10 +372,11 @@ newEntity{ base = "BASE_SHIELD",
 	cost = 350,
 	material_level = 5,
 	special_combat = {
-		dam = 45,
-		physcrit = 10,
+		dam = 55,
+		block = 250,
+		max_acc = 80,
+		critical_power = 1.5,
 		dammod = {str=1},
-		damrange = 1.4,
 		damtype = DamageType.ARCANE,
 	},
 	wielder = {
@@ -411,9 +410,10 @@ newEntity{ base = "BASE_SHIELD",
 
 	special_combat = {
 		dam = resolvers.rngavg(20,30),
-		physcrit = 2,
-		dammod = {str=1.5},
-		damrange = 1.4,
+		block = 60,
+		max_acc = 75,
+		critical_power = 1.5,
+		dammod = {str=0.4},
 	},
 	wielder = {
 		combat_armor = 10,
@@ -481,11 +481,10 @@ newEntity{ base = "BASE_WARAXE",
 	rarity = 290,
 	cost = 375,
 	combat = {
-		dam = 55,
-		apr = 15,
-		physcrit = 10,
+		dam = 60,
+		max_acc = 90,
+		critical_power = 2.8,
 		dammod = {str=1},
-		damrange = 1.2,
 		melee_project={[DamageType.BLIGHT] = 20},
 	},
 	wielder = {
@@ -498,29 +497,33 @@ newEntity{ base = "BASE_STAFF",
 	power_source = {arcane=true},
 	define_as = "STAFF_KOR", rarity=false, image = "object/artifact/staff_kors_fall.png",
 	unided_name = "dark staff",
+	flavor_name = "starstaff",
 	name = "Kor's Fall", unique=true,
 	desc = [[Made from the bones of many creatures, this staff glows with power. You can feel its evilness even from a distance.]],
 	require = { stat = { mag=25 }, },
+	material_level = 1,
 	level_range = {1, 10},
 	rarity = 200,
 	cost = 60,
+	modes = {"light", "darkness", "temporal"},
 	combat = {
+		is_greater = true,
 		dam = 10,
-		apr = 0,
-		physcrit = 1.5,
-		dammod = {mag=1.1},
+		max_acc = 90,
+		critical_power = 1.6,
+		dammod = {mag=0.2},
+		damtype = DamageType.DARKNESS,
 	},
 	wielder = {
 		see_invisible = 2,
 		combat_spellpower = 7,
 		combat_spellcrit = 8,
 		inc_damage={
-			[DamageType.FIRE] = 4,
-			[DamageType.COLD] = 4,
-			[DamageType.ACID] = 4,
-			[DamageType.LIGHTNING] = 4,
-			[DamageType.BLIGHT] = 4,
+			[DamageType.TEMPORAL] = 10,
+			[DamageType.DARKNESS] = 10,
+			[DamageType.LIGHT] = 10,
 		},
+		learn_talent = {[Talents.T_BLOODFLOW] = 2, [Talents.T_COMMAND_STAFF] = 2},
 	},
 }
 
@@ -550,23 +553,28 @@ newEntity{ base = "BASE_STAFF",
 	twohanded = false,
 	unided_name = "broken staff",
 	name = "Telos's Staff (Top Half)", unique=true,
+	flavor_name = "magestaff",
 	desc = [[The top part of Telos's broken staff.]],
 	require = { stat = { mag=35 }, },
 	level_range = {40, 50},
 	rarity = 210,
 	encumber = 2.5,
 	cost = 500,
+	material_level = 5,
+	modes = {"fire", "cold", "lightning", "arcane"},
 	combat = {
-		dam = 35,
-		apr = 0,
-		physcrit = 1.5,
-		dammod = {mag=1.0},
+		dam = 50,
+		max_acc = 85,
+		critical_power = 1.2,
+		dammod = {mag=0.3},
+		damtype = DamageType.ARCANE,
 	},
 	wielder = {
-		combat_spellpower = 30,
-		combat_spellcrit = 15,
+		combat_spellpower = 10,
 		combat_mentalresist = 8,
 		inc_stats = { [Stats.STAT_WIL] = 5, },
+		inc_damage = {[DamageType.ARCANE] = 50},
+		learn_talent = {[Talents.T_COMMAND_STAFF] = 5},
 	},
 }
 
@@ -675,11 +683,10 @@ newEntity{ base = "BASE_GREATMAUL",
 	metallic = false,
 	cost = 70,
 	combat = {
-		dam = 30,
-		apr = 7,
-		physcrit = 1.5,
-		dammod = {str=1.3},
-		damrange = 1.7,
+		dam = 40,
+		max_acc = 80,
+		critical_power = 1.5,
+		dammod = {str=0.5},
 	},
 
 	wielder = {
@@ -699,9 +706,11 @@ newEntity{ base = "BASE_SHIELD",
 	cost = 120,
 
 	special_combat = {
-		dam = 40,
-		physcrit = 9,
-		dammod = {str=1.2},
+		dam = 60,
+		block = 290,
+		max_acc = 95,
+		critical_power = 1.5,
+		dammod = {str=1},
 	},
 	wielder = {
 		combat_armor = 4,
@@ -726,9 +735,9 @@ newEntity{ base = "BASE_WHIP",
 	cost = 250,
 	material_level = 5,
 	combat = {
-		dam = resolvers.rngavg(40,45),
-		apr = 0,
-		physcrit = 9,
+		dam = resolvers.rngavg(50,55),
+		max_acc = 75,
+		critical_power = 3,
 		dammod = {dex=1},
 		damtype = DamageType.FIREKNOCKBACK,
 	},
@@ -755,10 +764,10 @@ newEntity{ base = "BASE_GREATSWORD",
 	cost = 300,
 	material_level = 5,
 	combat = {
-		dam = 60,
-		apr = 19,
-		physcrit = 4.5,
-		dammod = {str=1.2},
+		dam = 121,
+		max_acc = 100,
+		critical_power = 2,
+		dammod = {str=1.25},
 		special_on_hit = {desc="10% chance to send the wielder into a killing frenzy", fct=function(combat, who)
 			if not rng.percent(10) then return end
 			who:setEffect(who.EFF_FRENZY, 3, {crit=10, power=0.3, dieat=0.2})
@@ -820,11 +829,10 @@ newEntity{ base = "BASE_GLOVES", define_as = "FLAMEWROUGHT",
 		inc_damage = { [DamageType.FIRE]= 5, },
 		combat_armor = 2,
 		combat = {
-			dam = 5,
-			apr = 7,
-			physcrit = 1,
-			physspeed = -0.4,
-			dammod = {dex=0.4, str=-0.6, cun=0.4 },
+			dam = 8,
+			max_acc = 13,
+			critical_power = 0.4,
+			dammod = {dex=0.1, str=0, cun=0.1 },
 			melee_project={[DamageType.FIRE] = 10},
 		},
 	},
@@ -1005,9 +1013,9 @@ newEntity{ base = "BASE_WARAXE",
 	cost = 50,
 	combat = {
 		dam = 16,
-		apr = 3,
-		physcrit = 12,
-		dammod = {str=1},
+		max_acc = 85,
+		critical_power = 2.6,
+		dammod = {str=0.4},
 		talent_on_hit = { [Talents.T_GREATER_WEAPON_FOCUS] = {level=2, chance=10} },
 		melee_project={[DamageType.DRAINLIFE] = 10},
 	},
@@ -1071,10 +1079,10 @@ newEntity{ base = "BASE_BATTLEAXE",
 	cost = 650,
 	material_level = 4,
 	combat = {
-		dam = 72,
-		apr = 4,
-		physcrit = 8,
-		dammod = {str=1.2},
+		dam = 120,
+		max_acc = 80,
+		critical_power = 2,
+		dammod = {str=1},
 		melee_project={[DamageType.SLIME] = 50, [DamageType.ACID] = 50},
 	},
 	wielder = {
diff --git a/game/modules/tome/data/general/objects/bows.lua b/game/modules/tome/data/general/objects/bows.lua
index edd4a6c510..cf69ae4ea9 100644
--- a/game/modules/tome/data/general/objects/bows.lua
+++ b/game/modules/tome/data/general/objects/bows.lua
@@ -21,18 +21,19 @@ local Talents = require "engine.interface.ActorTalents"
 
 newEntity{
 	define_as = "BASE_LONGBOW",
+	flavor_names = {"shortbow", "longbow", "warbow", "warbow"},
 	slot = "MAINHAND",
 	slot_forbid = "OFFHAND",
 	type = "weapon", subtype="longbow",
+	add_name = " (#COMBAT_RANGED#)",
 	display = "}", color=colors.UMBER, image = resolvers.image_material("longbow", "wood"),
 	moddable_tile = resolvers.moddable_tile("bow"),
 	encumber = 4,
 	rarity = 5,
-	combat = { talented = "bow", sound = "actions/arrow", sound_miss = "actions/arrow",},
+	combat = { talented = "bow", sound = "actions/arrow", sound_miss = "actions/arrow", physspeed = 0.8,},
 	require = { talent = { Talents.T_SHOOT }, },
 	archery = "bow",
 	proj_image = resolvers.image_material("arrow", "wood"),
-	basic_ammo = { talented = "bow", damrange = 1.4  },
 	desc = [[Longbows are used to shoot arrows at your foes.]],
 	randart_able = { attack=40, physical=80, spell=20, def=10, misc=10 },
 	egos = "/data/general/objects/egos/bow.lua", egos_chance = { prefix=resolvers.mbonus(40, 5), suffix=resolvers.mbonus(40, 5) },
@@ -45,14 +46,10 @@ newEntity{ base = "BASE_LONGBOW",
 	cost = 5,
 	material_level = 1,
 	combat = {
+		dam = resolvers.cbonus(3, 6, 1, 1),
+		critical_power = resolvers.cbonus(18, 30, 0.1, 3),
 		range = 6,
-		physspeed = 0.8,
-	},
-	basic_ammo = {
-		dam = resolvers.rngavg(7,12),
-		apr = 5,
-		physcrit = 1,
-		dammod = {dex=0.7, str=0.5},
+		dammod = {dex=0.1},
 	},
 }
 
@@ -60,17 +57,13 @@ newEntity{ base = "BASE_LONGBOW",
 	name = "ash longbow", short_name = "ash",
 	level_range = {10, 20},
 	require = { stat = { dex=16 }, },
-	cost = 10,
+	cost = 30,
 	material_level = 2,
 	combat = {
+		dam = resolvers.cbonus(6),
+		critical_power = resolvers.cbonus(18, 30, 0.1, 3.5),
 		range = 7,
-		physspeed = 0.8,
-	},
-	basic_ammo = {
-		dam = resolvers.rngavg(15,22),
-		apr = 7,
-		physcrit = 1.5,
-		dammod = {dex=0.7, str=0.5},
+		dammod = {dex=0.2},
 	},
 }
 
@@ -78,17 +71,13 @@ newEntity{ base = "BASE_LONGBOW",
 	name = "yew longbow", short_name = "yew",
 	level_range = {20, 30},
 	require = { stat = { dex=24 }, },
-	cost = 15,
+	cost = 80,
 	material_level = 3,
 	combat = {
+		dam = resolvers.cbonus(12),
+		critical_power = resolvers.cbonus(18, 30, 0.1, 4),
 		range = 8,
-		physspeed = 0.8,
-	},
-	basic_ammo = {
-		dam = resolvers.rngavg(28,37),
-		apr = 10,
-		physcrit = 2,
-		dammod = {dex=0.7, str=0.5},
+		dammod = {dex=0.3},
 	},
 }
 
@@ -96,17 +85,13 @@ newEntity{ base = "BASE_LONGBOW",
 	name = "elven-wood longbow", short_name = "e.wood",
 	level_range = {30, 40},
 	require = { stat = { dex=35 }, },
-	cost = 25,
+	cost = 120,
 	material_level = 4,
 	combat = {
+		dam = resolvers.cbonus(21),
+		critical_power = resolvers.cbonus(18, 30, 0.1, 4.5),
 		range = 9,
-		physspeed = 0.8,
-	},
-	basic_ammo = {
-		dam = resolvers.rngavg(40,47),
-		apr = 14,
-		physcrit = 2.5,
-		dammod = {dex=0.7, str=0.5},
+		dammod = {dex=0.4},
 	},
 }
 
@@ -114,105 +99,106 @@ newEntity{ base = "BASE_LONGBOW",
 	name = "dragonbone longbow", short_name = "dragonbone",
 	level_range = {40, 50},
 	require = { stat = { dex=48 }, },
-	cost = 35,
+	cost = 170,
 	material_level = 5,
 	combat = {
+		dam = resolvers.cbonus(30),
+		critical_power = resolvers.cbonus(18, 30, 0.1, 5),
 		range = 10,
-		physspeed = 0.8,
-	},
-	basic_ammo = {
-		dam = resolvers.rngavg(50, 57),
-		apr = 18,
-		physcrit = 3,
-		dammod = {dex=0.7, str=0.5},
+		dammod = {dex=0.5},
 	},
 }
-
------------------- AMMO -------------------
+------------------ QUIVERS -------------------
 
 newEntity{
-	define_as = "BASE_ARROW",
+	define_as = "BASE_QUIVER",
 	slot = "QUIVER",
 	type = "ammo", subtype="arrow",
-	add_name = " (#COMBAT#)",
+	add_name = " (#COMBAT_QUIVER#)",
 	display = "{", color=colors.UMBER, image = resolvers.image_material("arrow", "wood"),
-	encumber = 0.03,
+	encumber = 3,
 	rarity = 11,
-	combat = { talented = "bow", damrange = 1.4},
+	combat = { talented = "bow", damrange = 1},
 	proj_image = resolvers.image_material("arrow", "wood"),
 	archery_ammo = "bow",
-	desc = [[Arrows are used with bows to pierce your foes to death.]],
-	generate_stack = resolvers.rngavg(100,200),
-	egos = "/data/general/objects/egos/ammo.lua", egos_chance = {100, resolvers.mbonus(30, 5)},
-	stacking = true,
+	desc = [[Arrows are used with bows to pierce your foes.]],
+	egos = "/data/general/objects/egos/ammo.lua",
+	egos_chance = { prefix=resolvers.mbonus(40, 5), suffix=resolvers.mbonus(40, 5) },
 }
 
-newEntity{ base = "BASE_ARROW",
-	name = "elm arrow", short_name = "elm",
+newEntity{ base = "BASE_QUIVER", define_as = "TEST_ELM_QUIVER",
+	name = "quiver of elm arrows", short_name = "elm",
 	level_range = {1, 10},
 	require = { stat = { dex=11 }, },
-	cost = 0.05,
+	cost = 5,
 	material_level = 1,
 	combat = {
-		dam = resolvers.rngavg(7,12),
-		apr = 5,
-		physcrit = 1,
-		dammod = {dex=0.7, str=0.5},
+		capacity = resolvers.cbonus(10),
+		dam = resolvers.cbonus(3, 6, 1, 1),
+		max_acc = resolvers.cbonus(85, 100, 1, 3),
+		dammod = {dex=0.1},
+		shots_left = 20,
 	},
+	--wielder = {learn_talent = {[Talents.T_RELOAD] = 1}},
 }
 
-newEntity{ base = "BASE_ARROW",
-	name = "ash arrow", short_name = "ash",
+newEntity{ base = "BASE_QUIVER",
+	name = "quiver of ash arrows", short_name = "ash",
 	level_range = {10, 20},
 	require = { stat = { dex=16 }, },
-	cost = 0.1,
+	cost = 30,
 	material_level = 2,
 	combat = {
-		dam = resolvers.rngavg(15,22),
-		apr = 7,
-		physcrit = 1.5,
-		dammod = {dex=0.7, str=0.5},
+		capacity = resolvers.cbonus(10, nil, nil, 3),
+		dam = resolvers.cbonus(6),
+		max_acc = resolvers.cbonus(85, 100, 1, 3.5),
+		dammod = {dex=0.2},
+		shots_left = 20,
 	},
 }
 
-newEntity{ base = "BASE_ARROW",
-	name = "yew arrow", short_name = "yew",
+newEntity{ base = "BASE_QUIVER",
+	name = "quiver of yew arrows", short_name = "yew",
 	level_range = {20, 30},
 	require = { stat = { dex=24 }, },
-	cost = 0.15,
+	cost = 80,
 	material_level = 3,
 	combat = {
-		dam = resolvers.rngavg(28,37),
-		apr = 10,
-		physcrit = 2,
-		dammod = {dex=0.7, str=0.5},
+		capacity = resolvers.cbonus(10, nil, nil, 3.5),
+		dam = resolvers.cbonus(12),
+		max_acc = resolvers.cbonus(85, 100, 1, 4),
+		dammod = {dex=0.3},
+		shots_left = 20,
 	},
 }
 
-newEntity{ base = "BASE_ARROW",
-	name = "elven-wood arrow", short_name = "e.wood",
+newEntity{ base = "BASE_QUIVER",
+	name = "quiver of elven-wood arrows", short_name = "e.wood",
 	level_range = {30, 40},
 	require = { stat = { dex=35 }, },
-	cost = 0.25,
+	cost = 120,
 	material_level = 4,
 	combat = {
-		dam = resolvers.rngavg(40,47),
-		apr = 14,
-		physcrit = 2.5,
-		dammod = {dex=0.7, str=0.5},
+		capacity = resolvers.cbonus(10, nil, nil, 4),
+		dam = resolvers.cbonus(21),
+		max_acc = resolvers.cbonus(85, 100, 1, 4.5),
+		dammod = {dex=0.4},
+		shots_left = 20,
 	},
 }
 
-newEntity{ base = "BASE_ARROW",
-	name = "dragonbone arrow", short_name = "dragonbone",
+newEntity{ base = "BASE_QUIVER",
+	name = "quiver of dragonbone arrows", short_name = "dragonbone",
 	level_range = {40, 50},
 	require = { stat = { dex=48 }, },
-	cost = 0.35,
+	cost = 170,
 	material_level = 5,
 	combat = {
-		dam = resolvers.rngavg(50, 57),
-		apr = 18,
-		physcrit = 3,
-		dammod = {dex=0.7, str=0.5},
+		capacity = resolvers.cbonus(10, nil, nil, 4.5),
+		dam = resolvers.cbonus(30),
+		max_acc = resolvers.cbonus(85, 100, 1, 5),
+		dammod = {dex=0.5},
+		shots_left = 20,
 	},
 }
+
diff --git a/game/modules/tome/data/general/objects/egos/ammo.lua b/game/modules/tome/data/general/objects/egos/ammo.lua
index e8dc03eef8..9548117691 100644
--- a/game/modules/tome/data/general/objects/egos/ammo.lua
+++ b/game/modules/tome/data/general/objects/egos/ammo.lua
@@ -17,81 +17,181 @@
 -- Nicolas Casalini "DarkGod"
 -- darkgod@te4.org
 
+local Talents = require("engine.interface.ActorTalents")
+
 newEntity{
-	power_source = {arcane=true},
-	name = "flaming ", prefix=true, instant_resolve=true,
-	keywords = {flaming=true},
+	power_source = {technique=true},
+	name = "quick-loading ", prefix=true, instant_resolve=true,
+	keywords = {quick=true},
 	level_range = {1, 50},
 	rarity = 5,
 	wielder = {
-		ranged_project={[DamageType.FIRE] = resolvers.mbonus_material(25, 4, function(e, v) return v * 0.1 * 0.64 end)},
+		learn_talent = {
+			[Talents.T_RELOAD] = resolvers.mbonus_material("learn_talent"),
+		}
 	},
 }
+
+newEntity{
+	power_source = {technique=true},
+	name = "high-capacity ", prefix=true, instant_resolve=true,
+	keywords = {capacity=true},
+	level_range = {1, 50},
+	rarity = 5,
+	combat = {
+		capacity = resolvers.mbonus_material("capacity"),
+	},
+	resolvers.genericlast(function(e) 
+		e.combat.shots_left = e.combat.capacity end),
+}
+
 newEntity{
 	power_source = {arcane=true},
-	name = "icy ", prefix=true, instant_resolve=true,
-	keywords = {icy=true},
-	level_range = {15, 50},
+	name = "self-loading ", prefix=true, instant_resolve=true,
+	keywords = {self=true},
+	level_range = {1, 50},
 	rarity = 5,
-	wielder = {
-		ranged_project={[DamageType.ICE] = resolvers.mbonus_material(15, 4, function(e, v) return v * 0.1 * 0.7 end)},
+	combat = {
+		ammo_regen = resolvers.mbonus_material("ammo_regen"),
 	},
+	resolvers.genericlast(function(e) 
+		e.combat.ammo_every = 6 - e.combat.ammo_regen 
+	end),
 }
+
 newEntity{
-	power_source = {nature=true},
-	name = "acidic ", prefix=true, instant_resolve=true,
-	keywords = {acidic=true},
+	power_source = {technique=true},
+	name = "battle-ranger's ", prefix=true, instant_resolve=true,
+	keywords = {ranger=true},
 	level_range = {1, 50},
 	rarity = 5,
+	greater_ego = 1,
+	combat = {
+		capacity = resolvers.mbonus_material("capacity"),
+	},
 	wielder = {
-		ranged_project={[DamageType.ACID] = resolvers.mbonus_material(25, 4, function(e, v) return v * 0.1 * 0.7 end)},
+		learn_talent = {
+			[Talents.T_RELOAD] = resolvers.mbonus_material("learn_talent"),
+		}
 	},
+	resolvers.genericlast(function(e) 
+		e.combat.shots_left = e.combat.capacity end),
 }
+
 newEntity{
 	power_source = {arcane=true},
-	name = "shocking ", prefix=true, instant_resolve=true,
-	keywords = {shocking=true},
+	name = "enchanted ", prefix=true, instant_resolve=true,
+	keywords = {enchanted=true},
 	level_range = {1, 50},
 	rarity = 5,
+	greater_ego = 1,
+	combat = {
+		ammo_regen = resolvers.mbonus_material("ammo_regen"),
+	},
 	wielder = {
-		ranged_project={[DamageType.LIGHTNING] = resolvers.mbonus_material(25, 4, function(e, v) return v * 0.1 * 0.7 end)},
+		learn_talent = {
+			[Talents.T_RELOAD] = resolvers.mbonus_material("learn_talent"),
+		}
+	},
+	resolvers.genericlast(function(e) 
+		e.combat.ammo_every = 6 - e.combat.ammo_regen 
+	end),
+}
+
+newEntity{
+	power_source = {arcane=true},
+	name = "sentry's ", prefix=true, instant_resolve=true,
+	keywords = {sentry=true},
+	level_range = {1, 50},
+	rarity = 5,
+	greater_ego = 1,
+	combat = {
+		ammo_regen = resolvers.mbonus_material("ammo_regen"),
+		capacity = resolvers.mbonus_material("capacity"),
 	},
+	resolvers.genericlast(function(e) 
+		e.combat.ammo_every = 6 - e.combat.ammo_regen 
+	end),
+	resolvers.genericlast(function(e) 
+		e.combat.shots_left = e.combat.capacity end),
 }
+
 newEntity{
 	power_source = {nature=true},
-	name = "poisonous ", prefix=true, instant_resolve=true,
-	keywords = {poisonous=true},
+	name = " of fire", suffix=true, instant_resolve=true,
+	keywords = {fire=true},
 	level_range = {1, 50},
 	rarity = 5,
-	wielder = {
-		ranged_project={[DamageType.POISON] = resolvers.mbonus_material(45, 6, function(e, v) return v * 0.1 * 0.5 end)},
+	combat = {
+		ranged_project={[DamageType.FIRE] = resolvers.mbonus_material("ranged_project", 1)},
+	},
+}
+newEntity{
+	power_source = {nature=true},
+	name = " of ice", suffix=true, instant_resolve=true,
+	keywords = {ice=true},
+	level_range = {15, 50},
+	rarity = 5,
+	combat = {
+		ranged_project={[DamageType.ICE] = resolvers.mbonus_material("ranged_project", 0.5)},
+	},
+}
+newEntity{
+	power_source = {nature=true},
+	name = " of acid", suffix=true, instant_resolve=true,
+	keywords = {cunning=true},
+	level_range = {1, 50},
+	rarity = 5,
+	combat = {
+		ranged_project={[DamageType.ACID] = resolvers.mbonus_material("ranged_project", 1)},
+	},
+}
+newEntity{
+	power_source = {nature=true},
+	name = " of lightning", suffix=true, instant_resolve=true,
+	keywords = {lightning=true},
+	level_range = {1, 50},
+	rarity = 5,
+	combat = {
+		ranged_project={[DamageType.LIGHTNING] = resolvers.mbonus_material("ranged_project", 1)},
 	},
 }
 
 newEntity{
 	power_source = {nature=true},
-	name = "slime-covered ", prefix=true, instant_resolve=true,
+	name = " of slime", suffix=true, instant_resolve=true,
 	keywords = {slime=true},
 	level_range = {10, 50},
 	rarity = 5,
-	wielder = {
-		ranged_project={[DamageType.SLIME] = resolvers.mbonus_material(45, 6, function(e, v) return v * 0.1 * 0.9 end)},
+	combat = {
+		ranged_project={[DamageType.SLIME] = resolvers.mbonus_material("ranged_project", 0.5)},
 	},
 }
 
 newEntity{
-	power_source = {arcane=true},
-	name = "elemental ", prefix=true, instant_resolve=true,
-	keywords = {elemental=true},
+	power_source = {technique=true},
+	name = " of accuracy", suffix=true, instant_resolve=true,
+	keywords = {accuracy=true},
+	level_range = {1, 50},
+	rarity = 3,
+	cost = 4,
+	combat = {max_acc = resolvers.mbonus_material("max_acc")},
+}
+
+newEntity{
+	power_source = {nature=true},
+	name = " of the elements", suffix=true, instant_resolve=true,
+	keywords = {elements=true},
 	level_range = {35, 50},
 	greater_ego = 1,
 	rarity = 25,
-	wielder = {
+	cost = 35,
+	combat = {
 		ranged_project={
-			[DamageType.FIRE] = resolvers.mbonus_material(25, 4, function(e, v) return v * 0.1 * 0.7 * 0.3 end),
-			[DamageType.ICE] = resolvers.mbonus_material(15, 4, function(e, v) return v * 0.1 * 0.7 * 0.3 end),
-			[DamageType.ACID] = resolvers.mbonus_material(25, 4, function(e, v) return v * 0.1 * 0.7 * 0.3 end),
-			[DamageType.LIGHTNING] = resolvers.mbonus_material(25, 4, function(e, v) return v * 0.1 * 0.7 * 0.3 end),
+			[DamageType.FIRE] = resolvers.mbonus_material("ranged_project", 0.5),
+			[DamageType.ICE] = resolvers.mbonus_material("ranged_project", 0.5),
+			[DamageType.ACID] = resolvers.mbonus_material("ranged_project", 0.5),
+			[DamageType.LIGHTNING] = resolvers.mbonus_material("ranged_project", 0.5),
 		},
 	},
 }
@@ -104,40 +204,78 @@ newEntity{
 	rarity = 7,
 	combat = {
 		travel_speed = 200,
-		atk = resolvers.mbonus_material(10, 3, function(e, v) return v * 0.1 * 0.5 end),
 	},
 }
 
 newEntity{
 	power_source = {technique=true},
-	name = " of annihilation", suffix=true,
-	keywords = {['annihil.']=true},
+	name = " of annihilation", suffix=true, instant_resolve=true,
+	keywords = {annihilation=true},
 	level_range = {1, 50},
 	greater_ego = 1,
 	cost = 1,
 	rarity = 15,
 	combat = {
-		physcrit = 100,
+		dam = resolvers.mbonus_material("dam", 4),
+		max_acc = resolvers.mbonus_material("max_acc", 3),
+		travel_speed = 200,
 	},
-	-- Powerful but does not come in much quantity
+	-- Powerful but comes in a small quiver/pouch
 	resolvers.generic(function(e)
-		e.generate_stack = rng.range(5, 10)
+		e.combat.capacity = math.ceil(e.combat.capacity/4)
+		e.combat.shots_left = e.combat.capacity
 	end),
 }
 
 newEntity{
-	power_source = {technique=true},
-	name = " of unerring flight", suffix=true,
-	keywords = {unerring=true},
+	power_source = {arcane=true},
+	name = " of corruption", suffix=true, instant_resolve=true,
+	keywords = {corruption=true},
+	level_range = {35, 50},
+	greater_ego = 1,
+	rarity = 20,
+	cost = 35,
+	combat = {
+		ranged_project={
+			[DamageType.BLIGHT] = resolvers.mbonus_material("ranged_project", 1, true),
+			[DamageType.DARKNESS] = resolvers.mbonus_material("ranged_project", 1, true),
+		},
+	},
+}
+
+newEntity{
+	power_source = {arcane=true},
+	name = " of paradox", suffix=true, instant_resolve=true,
+	keywords = {paradox=true},
 	level_range = {1, 50},
 	greater_ego = 1,
-	cost = 1,
+	rarity = 15,
+	cost = 30,
+	combat = {
+		ranged_project = {
+			[DamageType.TEMPORAL] = resolvers.mbonus_material("ranged_project", 2, true),
+			[DamageType.RANDOM_CONFUSION] = resolvers.mbonus_material("ranged_project", 1, true),
+		},
+	},
+}
+
+newEntity{
+	power_source = {nature=true},
+	name = " of sunrise", suffix=true,
+	keywords = {sunrise=true},
+	level_range = {1, 50},
+	greater_ego = 1,
+	cost = 30,
 	rarity = 15,
 	combat = {
-		atk = 500,
+		tg_type = "beam",
+		damtype = DamageType.LIGHT,
+		travel_speed = 300,
+		lite = true,
 	},
-	-- Powerful but does not come in much quantity
+	-- Powerful but comes in a small quiver/pouch
 	resolvers.generic(function(e)
-		e.generate_stack = rng.range(5, 10)
+		e.combat.capacity = math.ceil(e.combat.capacity/4)
+		e.combat.shots_left = e.combat.capacity
 	end),
 }
diff --git a/game/modules/tome/data/general/objects/egos/amulets.lua b/game/modules/tome/data/general/objects/egos/amulets.lua
index 0380a809f4..f920c3309a 100644
--- a/game/modules/tome/data/general/objects/egos/amulets.lua
+++ b/game/modules/tome/data/general/objects/egos/amulets.lua
@@ -33,7 +33,7 @@ newEntity{
 	rarity = 6,
 	cost = 4,
 	wielder = {
-		inc_stats = { [Stats.STAT_CUN] = resolvers.mbonus_material(8, 2) },
+		inc_stats = { [Stats.STAT_CUN] = resolvers.mbonus_material("inc_stats") },
 	},
 }
 newEntity{
@@ -44,7 +44,7 @@ newEntity{
 	rarity = 6,
 	cost = 4,
 	wielder = {
-		inc_stats = { [Stats.STAT_WIL] = resolvers.mbonus_material(8, 2) },
+		inc_stats = { [Stats.STAT_WIL] = resolvers.mbonus_material("inc_stats") },
 	},
 }
 newEntity{
@@ -122,8 +122,8 @@ newEntity{
 	cost = 5,
 	wielder = {
 		resists={
-			[DamageType.FIRE] = resolvers.mbonus_material(10, 5),
-			[DamageType.COLD] = resolvers.mbonus_material(10, 5),
+			[DamageType.FIRE] = resolvers.mbonus_material("resists"),
+			[DamageType.COLD] = resolvers.mbonus_material("resists"),
 		},
 	},
 }
@@ -137,9 +137,9 @@ newEntity{
 	cost = 5,
 	wielder = {
 		resists={
-			[DamageType.LIGHTNING] = resolvers.mbonus_material(10, 5),
+			[DamageType.LIGHTNING] = resolvers.mbonus_material("resists"),
 		},
-		stun_immune = resolvers.mbonus_material(20, 10, function(e, v) v=v/100 return 0, v end),
+		stun_immune = resolvers.mbonus_material("immunity"),
 	},
 }
 
@@ -152,9 +152,9 @@ newEntity{
 	cost = 5,
 	wielder = {
 		resists={
-			[DamageType.TEMPORAL] = resolvers.mbonus_material(10, 5),
+			[DamageType.TEMPORAL] = resolvers.mbonus_material("resists"),
 		},
-		teleport_immune = resolvers.mbonus_material(20, 10, function(e, v) v=v/100 return 0, v end),
+		teleport_immune = resolvers.mbonus_material("immunity"),
 	},
 }
 
@@ -166,8 +166,8 @@ newEntity{
 	rarity = 6,
 	cost = 5,
 	wielder = {
-		stun_immune = resolvers.mbonus_material(20, 10, function(e, v) v=v/100 return 0, v end),
-		knockback_immune = resolvers.mbonus_material(20, 10, function(e, v) v=v/100 return 0, v end),
+		stun_immune = resolvers.mbonus_material("immunity"),
+		knockback_immune = resolvers.mbonus_material("immunity"),
 	},
 }
 
@@ -179,8 +179,8 @@ newEntity{
 	rarity = 6,
 	cost = 5,
 	wielder = {
-		blind_immune = resolvers.mbonus_material(20, 10, function(e, v) v=v/100 return 0, v end),
-		confusion_immune = resolvers.mbonus_material(20, 10, function(e, v) v=v/100 return 0, v end),
+		blind_immune = resolvers.mbonus_material("immunity"),
+		confusion_immune = resolvers.mbonus_material("immunity"),
 	},
 }
 
@@ -193,10 +193,10 @@ newEntity{
 	cost = 9,
 	wielder = {
 		resists={
-			[DamageType.ACID] = resolvers.mbonus_material(10, 5),
+			[DamageType.ACID] = resolvers.mbonus_material("resists"),
 		},
-		poison_immune = resolvers.mbonus_material(10, 5, function(e, v) return 0, v/100 end),
-		disease_immune = resolvers.mbonus_material(10, 5, function(e, v) return 0, v/100 end),
+		poison_immune = resolvers.mbonus_material("immunity"),
+		disease_immune = resolvers.mbonus_material("immunity"),
 	},
 }
 
@@ -209,7 +209,7 @@ newEntity{
 	rarity = 6,
 	cost = 10,
 	wielder = {
-		fatigue = resolvers.mbonus_material(6, 4, function(e, v) return 0, -v end),
+		fatigue = resolvers.mbonus_material("fatigue"),
 	},
 }
 
@@ -223,15 +223,15 @@ newEntity{
 	cost = 30,
 	wielder = {
 		resists={
-			[DamageType.BLIGHT] = resolvers.mbonus_material(10, 5),
+			[DamageType.BLIGHT] = resolvers.mbonus_material("resists"),
 		},
 		inc_stats={
-			[Stats.STAT_CON] = resolvers.mbonus_material(4, 2),
+			[Stats.STAT_CON] = resolvers.mbonus_material("inc_stats"),
 		},
-		combat_physresist = resolvers.mbonus_material(5, 5),
-		max_life = resolvers.mbonus_material(50, 30),
-		life_regen = resolvers.mbonus_material(12, 3, function(e, v) v=v/10 return 0, v end),
-		max_stamina = resolvers.mbonus_material(20, 10),
+		combat_physresist = resolvers.mbonus_material("rare_resists"),
+		max_life = resolvers.mbonus_material("max_life"),
+		life_regen = resolvers.mbonus_material("life_regen"),
+		max_stamina = resolvers.mbonus_material("max_stamina"),
 	},
 }
 
@@ -245,10 +245,10 @@ newEntity{
 	rarity = 16,
 	cost = 40,
 	wielder = {
-		combat_physcrit = resolvers.mbonus_material(3, 3),
-		combat_critical_power = resolvers.mbonus_material(10, 10),
-		combat_atk = resolvers.mbonus_material(5, 5),
-		combat_apr = resolvers.mbonus_material(4, 4),
+		combat_physcrit = resolvers.mbonus_material("combat_physcrit"),
+	--	combat_critical_power = resolvers.mbonus_material("combat_critical_power"),
+		combat_atk = resolvers.mbonus_material("combat_atk", 2),
+		combat_apr = resolvers.mbonus_material("combat_apr"),
 	},
 }
 
@@ -262,10 +262,10 @@ newEntity{
 	rarity = 15,
 	cost = 30,
 	wielder = {
-		see_invisible = resolvers.mbonus_material(10, 5),
-		blind_immune = resolvers.mbonus_material(30, 10, function(e, v) v=v/100 return 0, v end),
-		infravision = resolvers.mbonus_material(2, 1),
-		trap_detect_power = resolvers.mbonus_material(15, 5),
+		see_invisible = resolvers.mbonus_material("see_invisible"),
+		blind_immune = resolvers.mbonus_material("immunity"),
+		infravision = resolvers.mbonus_material("infravision"),
+		trap_detect_power = resolvers.mbonus_material("trap_detect_power"),
 	},
 }
 
@@ -279,8 +279,8 @@ newEntity{
 	rarity = 18,
 	cost = 60,
 	wielder = {
-		healing_factor = resolvers.mbonus_material(20, 10, function(e, v) v=v/100 return 0, v end),
-		cut_immune = resolvers.mbonus_material(4, 4, function(e, v) v=v/10 return 0, v end),
+		healing_factor = resolvers.mbonus_material("healing_factor"),
+		cut_immune = resolvers.mbonus_material("immunity"),
 	},
 	max_power = 80, power_regen = 1,
 	use_talent = { id = Talents.T_HEAL, level = 3, power = 80 },
@@ -295,9 +295,9 @@ newEntity{
 	rarity = 16,
 	cost = 40,
 	wielder = {
-		combat_armor = resolvers.mbonus_material(3, 2),
-		combat_def = resolvers.mbonus_material(4, 4),
-		combat_physresist = resolvers.mbonus_material(20, 7),
+		combat_armor = resolvers.mbonus_material("combat_armor"),
+		combat_def = resolvers.mbonus_material("combat_def"),
+		combat_physresist = resolvers.mbonus_material("save"),
 	},
 }
 
@@ -310,9 +310,9 @@ newEntity{
 	rarity = 20,
 	cost = 90,
 	wielder = {
-		combat_dam = resolvers.mbonus_material(5, 5),
-		inc_damage = { [DamageType.PHYSICAL] = resolvers.mbonus_material(5, 5) },
-		combat_physspeed = 0.1,
+		combat_dam = resolvers.mbonus_material("combat_dam", 2),
+		--inc_damage = { [DamageType.PHYSICAL] = resolvers.mbonus_material("inc_damage") },
+		combat_physspeed = resolvers.mbonus_material("combat_physspeed"),
 	},
 }
 
@@ -326,13 +326,13 @@ newEntity{
 	rarity = 16,
 	cost = 40,
 	wielder = {
-		combat_spellpower = resolvers.mbonus_material(3, 3),
-		combat_spellcrit = resolvers.mbonus_material(3, 3),
+		combat_spellpower = resolvers.mbonus_material("combat_spellpower"),
+		combat_spellcrit = resolvers.mbonus_material("combat_spellcrit"),
 		inc_damage = {
-			[DamageType.FIRE] = resolvers.mbonus_material(4, 4),
-			[DamageType.COLD] = resolvers.mbonus_material(4, 4),
-			[DamageType.ACID] = resolvers.mbonus_material(4, 4),
-			[DamageType.LIGHTNING] = resolvers.mbonus_material(4, 4),
+			[DamageType.FIRE] = resolvers.mbonus_material("inc_damage"),
+			[DamageType.COLD] = resolvers.mbonus_material("inc_damage"),
+			[DamageType.ACID] = resolvers.mbonus_material("inc_damage"),
+			[DamageType.LIGHTNING] = resolvers.mbonus_material("inc_damage"),
 		},
 	},
 }
@@ -348,14 +348,14 @@ newEntity{
 
 	wielder = {
 		resists={
-			[DamageType.ARCANE] = resolvers.mbonus_material(20, 10, function(e, v) return 0, -v end),
+			[DamageType.ARCANE] = resolvers.mbonus_material("rare_resists", -1),
 		},
 		inc_stats = {
-			[Stats.STAT_STR] = resolvers.mbonus_material(6, 4),
-			[Stats.STAT_DEX] = resolvers.mbonus_material(6, 4),
-			[Stats.STAT_WIL] = resolvers.mbonus_material(6, 4),
+			[Stats.STAT_STR] = resolvers.mbonus_material("inc_stats", 2),
+			[Stats.STAT_DEX] = resolvers.mbonus_material("inc_stats", 2),
+			[Stats.STAT_WIL] = resolvers.mbonus_material("inc_stats", 2),
 		},
-		combat_spellresist = resolvers.mbonus_material(10, 5, function(e, v) return 0, -v end),
+		combat_spellresist = resolvers.mbonus_material("save", -1),
 
 	},
 }
@@ -370,12 +370,10 @@ newEntity{
 	cost = 30,
 	wielder = {
 		inc_stats = {
-			[Stats.STAT_CUN] = resolvers.mbonus_material(5, 1),
+			[Stats.STAT_CUN] = resolvers.mbonus_material("inc_stats"),
 		},
-		confusion_immune = resolvers.mbonus_material(15, 10, function(e, v) v=v/100 return 0, v end),
-		combat_mentalresist = resolvers.mbonus_material(10, 5),
-		combat_spellresist = resolvers.mbonus_material(10, 5),
-
+		confusion_immune = resolvers.mbonus_material("immunity"),
+		combat_mentalresist = resolvers.mbonus_material("save"),
 	},
 }
 
@@ -388,10 +386,10 @@ newEntity{
 	rarity = 15,
 	cost = 30,
 	wielder = {
-		combat_mentalresist = resolvers.mbonus_material(10, 5),
-		combat_physresist = resolvers.mbonus_material(10, 5),
-		combat_spellresist = resolvers.mbonus_material(10, 5),
-		combat_def = resolvers.mbonus_material(10, 5),
+		combat_mentalresist = resolvers.mbonus_material("save"),
+		combat_physresist = resolvers.mbonus_material("save"),
+		combat_spellresist = resolvers.mbonus_material("save"),
+		combat_def = resolvers.mbonus_material("combat_def"),
 	},
 }
 
@@ -405,10 +403,10 @@ newEntity{
 	cost = 30,
 	wielder = {
 		inc_stats = {
-			[Stats.STAT_CON] = resolvers.mbonus_material(7, 3),
-			[Stats.STAT_CUN] = resolvers.mbonus_material(7, 3),
+			[Stats.STAT_CON] = resolvers.mbonus_material("inc_stats"),
+			[Stats.STAT_CUN] = resolvers.mbonus_material("inc_stats"),
 		},
-		combat_armor = resolvers.mbonus_material(7, 3),
+		combat_armor = resolvers.mbonus_material("combat_armor"),
 	},
 }
 
@@ -422,7 +420,7 @@ newEntity{
 	cost = 30,
 	wielder = {
 		inc_stats = {
-			[Stats.STAT_LCK] = resolvers.mbonus_material(12, 8),
+			[Stats.STAT_LCK] = resolvers.mbonus_material("inc_stats", 2),
 		},
 	},
 }
@@ -437,18 +435,35 @@ newEntity{
 	cost = 90,
 	wielder = {
 		resists={
-			[DamageType.FIRE] = resolvers.mbonus_material(10, 5, function(e, v) return 0, -v end),
-			[DamageType.MIND] = resolvers.mbonus_material(10, 5, function(e, v) return 0, -v end),
+			[DamageType.FIRE] = resolvers.mbonus_material("resists", -1),
+			[DamageType.MIND] = resolvers.mbonus_material("rare_resists", -1),
 		},
-		combat_spellpower = resolvers.mbonus_material(10, 5),
-		combat_critical_power = resolvers.mbonus_material(30, 10),
+		combat_spellpower = resolvers.mbonus_material("combat_spellpower"),
+		--combat_critical_power = resolvers.mbonus_material("combat_critical_power"),
 		inc_damage = {
-			[DamageType.FIRE] = resolvers.mbonus_material(10, 5),
-			[DamageType.MIND] = resolvers.mbonus_material(10, 5),
+			[DamageType.FIRE] = resolvers.mbonus_material("inc_damage", 2),
+			[DamageType.MIND] = resolvers.mbonus_material("inc_damage", 2),
 		},
 	},
 }
-
+--[=[
+newEntity{
+	power_source = {nature=true},
+	name = " of lifeblood", suffix=true, instant_resolve=true,
+	level_range = {40, 50},
+	greater_ego = 1,
+	rarity = 30,
+	cost = 100,
+	wielder = {
+		resists={
+			[DamageType.LIGHT] = resolvers.mbonus_material("resists", -1),
+			[DamageType.DARKNESS] = resolvers.mbonus_material("resists"),
+		},
+		resource_leech_chance = resolvers.mbonus_material("resource_leech_chance"),
+		resource_leech_value = resolvers.mbonus_material("resource_leech_value"),
+	},
+}
+]=]
 newEntity{
 	power_source = {technique=true},
 	name = " of seduction", suffix=true, instant_resolve=true,
@@ -459,10 +474,10 @@ newEntity{
 	cost = 50,
 	wielder = {
 		inc_stats = {
-			[Stats.STAT_WIL] = resolvers.mbonus_material(5, 1),
+			[Stats.STAT_WIL] = resolvers.mbonus_material("inc_stats"),
 		},
-		max_stamina = resolvers.mbonus_material(30, 10),
-		stamina_regen_on_hit = resolvers.mbonus_material(23, 7, function(e, v) v=v/10 return 0, v end),
+		max_stamina = resolvers.mbonus_material("max_stamina"),
+		stamina_regen_on_hit = resolvers.mbonus_material("stamina_regen_on_hit"),
 	},
 }
 
@@ -476,10 +491,10 @@ newEntity{
 	cost = 70,
 	wielder = {
 		inc_stats = {
-			[Stats.STAT_MAG] = resolvers.mbonus_material(5, 1),
+			[Stats.STAT_MAG] = resolvers.mbonus_material("inc_stats"),
 		},
-		max_mana = resolvers.mbonus_material(40, 20),
-		mana_regen = resolvers.mbonus_material(50, 10, function(e, v) v=v/100 return 0, v end),
+		max_mana = resolvers.mbonus_material("max_mana"),
+		mana_regen = resolvers.mbonus_material("mana_regen"),
 
 	},
 }
@@ -494,13 +509,10 @@ newEntity{
 	cost = 40,
 	wielder = {
 		resists={
-			[DamageType.LIGHT] = resolvers.mbonus_material(10, 5),
+			[DamageType.LIGHT] = resolvers.mbonus_material("resists"),
 		},
 		on_melee_hit = {
-			[DamageType.LIGHT] = resolvers.mbonus_material(10, 5),
-		},
-		melee_project={
-			[DamageType.LIGHT] = resolvers.mbonus_material(10, 5),
+			[DamageType.LIGHT] = resolvers.mbonus_material("on_melee_hit", 2),
 		},
 	},
-}
\ No newline at end of file
+}
diff --git a/game/modules/tome/data/general/objects/egos/armor.lua b/game/modules/tome/data/general/objects/egos/armor.lua
index 577c3228e3..0d637cab4b 100644
--- a/game/modules/tome/data/general/objects/egos/armor.lua
+++ b/game/modules/tome/data/general/objects/egos/armor.lua
@@ -28,7 +28,7 @@ newEntity{
 	rarity = 5,
 	cost = 6,
 	wielder = {
-		resists={[DamageType.FIRE] = resolvers.mbonus_material(30, 10)},
+		resists={[DamageType.FIRE] = resolvers.mbonus_material("resists")},
 	},
 }
 newEntity{
@@ -39,7 +39,7 @@ newEntity{
 	rarity = 5,
 	cost = 6,
 	wielder = {
-		resists={[DamageType.COLD] = resolvers.mbonus_material(30, 10)},
+		resists={[DamageType.COLD] = resolvers.mbonus_material("resists")},
 	},
 }
 newEntity{
@@ -50,7 +50,7 @@ newEntity{
 	rarity = 5,
 	cost = 6,
 	wielder = {
-		resists={[DamageType.ACID] = resolvers.mbonus_material(30, 10)},
+		resists={[DamageType.ACID] = resolvers.mbonus_material("resists")},
 	},
 }
 newEntity{
@@ -61,7 +61,7 @@ newEntity{
 	rarity = 5,
 	cost = 6,
 	wielder = {
-		resists={[DamageType.LIGHTNING] = resolvers.mbonus_material(30, 10)},
+		resists={[DamageType.LIGHTNING] = resolvers.mbonus_material("resists")},
 	},
 }
 newEntity{
@@ -72,7 +72,7 @@ newEntity{
 	rarity = 5,
 	cost = 6,
 	wielder = {
-		resists={[DamageType.NATURE] = resolvers.mbonus_material(30, 10)},
+		resists={[DamageType.NATURE] = resolvers.mbonus_material("nature")},
 	},
 }
 
@@ -84,8 +84,8 @@ newEntity{
 	rarity = 7,
 	cost = 6,
 	wielder = {
-		stun_immune = resolvers.mbonus_material(20, 10, function(e, v) v=v/100 return 0, v end),
-		knockback_immune = resolvers.mbonus_material(20, 20, function(e, v) v=v/100 return 0, v end),
+		stun_immune = resolvers.mbonus_material("immunity"),
+		knockback_immune = resolvers.mbonus_material("immunity"),
 	},
 }
 
@@ -98,8 +98,8 @@ newEntity{
 	cost = 7,
 	wielder = {
 		resists={
-			[DamageType.LIGHT] = resolvers.mbonus_material(10, 10),
-			[DamageType.DARKNESS] = resolvers.mbonus_material(10, 10),
+			[DamageType.LIGHT] = resolvers.mbonus_material("resists"),
+			[DamageType.DARKNESS] = resolvers.mbonus_material("resists"),
 		},
 	},
 }
@@ -112,22 +112,7 @@ newEntity{
 	rarity = 6,
 	cost = 7,
 	wielder = {
-		on_melee_hit={[DamageType.PHYSICAL] = resolvers.mbonus_material(10, 10)},
-	},
-}
-
-newEntity{
-	power_source = {arcane=true},
-	name = "searing ", prefix=true, instant_resolve=true,
-	keywords = {searing=true},
-	level_range = {10, 50},
-	rarity = 10,
-	cost = 7,
-	wielder = {
-		melee_project={
-			[DamageType.FIRE] = resolvers.mbonus_material(8, 8),
-			[DamageType.ACID] = resolvers.mbonus_material(8, 8),
-		},
+		on_melee_hit={[DamageType.PHYSICAL] = resolvers.mbonus_material("on_melee_hit")},
 	},
 }
 
@@ -139,7 +124,7 @@ newEntity{
 	rarity = 10,
 	cost = 15,
 	wielder = {
-		stamina_regen = resolvers.mbonus_material(50, 20, function(e, v) v=v/100 return 0, v end),
+		stamina_regen = resolvers.mbonus_material("stamina_regen", 2),
 	},
 }
 
@@ -152,14 +137,13 @@ newEntity{
 	rarity = 18,
 	cost = 15,
 	wielder = {
-		melee_project={[DamageType.LIGHT] = resolvers.mbonus_material(10, 4),},
 		resists={
-			[DamageType.BLIGHT] = resolvers.mbonus_material(20, 10),
-			[DamageType.DARKNESS] = resolvers.mbonus_material(20, 10),
+			[DamageType.BLIGHT] = resolvers.mbonus_material("resists"),
+			[DamageType.DARKNESS] = resolvers.mbonus_material("resists"),
 		},
 		inc_stats = {
-			[Stats.STAT_WIL] = resolvers.mbonus_material(5, 1),
-			[Stats.STAT_LCK] = resolvers.mbonus_material(10, 1),
+			[Stats.STAT_WIL] = resolvers.mbonus_material("inc_stats"),
+			[Stats.STAT_LCK] = resolvers.mbonus_material("inc_stats"),
 		},
 	},
 }
@@ -173,8 +157,8 @@ newEntity{
 	cost = 5,
 	wielder = {
 		resists={
-			[DamageType.FIRE] = resolvers.mbonus_material(10, 5),
-			[DamageType.COLD] = resolvers.mbonus_material(10, 5),
+			[DamageType.FIRE] = resolvers.mbonus_material("resists"),
+			[DamageType.COLD] = resolvers.mbonus_material("resists"),
 		},
 	},
 }
@@ -190,9 +174,9 @@ newEntity{
 	cost = 10,
 	wielder = {
 		resists={
-			[DamageType.LIGHTNING] = resolvers.mbonus_material(10, 5),
+			[DamageType.LIGHTNING] = resolvers.mbonus_material("resists"),
 		},
-		stun_immune = resolvers.mbonus_material(2, 2, function(e, v) v=v/10 return 0, v end),
+		stun_immune = resolvers.mbonus_material("immunity"),
 	},
 }
 
@@ -205,9 +189,9 @@ newEntity{
 	cost = 10,
 	wielder = {
 		resists={
-			[DamageType.TEMPORAL] = resolvers.mbonus_material(10, 5),
+			[DamageType.TEMPORAL] = resolvers.mbonus_material("resists"),
 		},
-		teleport_immune = resolvers.mbonus_material(2, 2, function(e, v) v=v/10 return 0, v end),
+		teleport_immune = resolvers.mbonus_material("immunity"),
 	},
 }
 
@@ -220,8 +204,8 @@ newEntity{
 	cost = 5,
 	wielder = {
 		resists={
-			[DamageType.ACID] = resolvers.mbonus_material(10, 5),
-			[DamageType.POISON] = resolvers.mbonus_material(10, 5),
+			[DamageType.ACID] = resolvers.mbonus_material("resists"),
+			[DamageType.POISON] = resolvers.mbonus_material("resists"),
 		},
 	},
 }
@@ -236,10 +220,10 @@ newEntity{
 	cost = 35,
 	wielder = {
 		inc_stats = {
-			[Stats.STAT_CON] = resolvers.mbonus_material(5, 2),
-			[Stats.STAT_STR] = resolvers.mbonus_material(5, 2),
+			[Stats.STAT_CON] = resolvers.mbonus_material("inc_stats"),
+			[Stats.STAT_STR] = resolvers.mbonus_material("inc_stats"),
 		},
-		max_life=resolvers.mbonus_material(70, 30),
+		max_life=resolvers.mbonus_material("max_life"),
 	},
 }
 
@@ -254,13 +238,11 @@ newEntity{
 	cost = 47,
 	wielder = {
 		resists={
-			[DamageType.ACID] = resolvers.mbonus_material(8, 5),
-			[DamageType.LIGHTNING] = resolvers.mbonus_material(8, 5),
-			[DamageType.FIRE] = resolvers.mbonus_material(8, 5),
-			[DamageType.COLD] = resolvers.mbonus_material(8, 5),
-			[DamageType.PHYSICAL] = resolvers.mbonus_material(8, 5),
+			[DamageType.ACID] = resolvers.mbonus_material("resists"),
+			[DamageType.FIRE] = resolvers.mbonus_material("resists"),
+			[DamageType.COLD] = resolvers.mbonus_material("resists"),
 		},
-		combat_armor = resolvers.mbonus_material(5, 5),
+		combat_armor = resolvers.mbonus_material("combat_armor"),
 	},
 }
 
@@ -274,7 +256,7 @@ newEntity{
 	rarity = 9,
 	cost = 10,
 	wielder = {
-		max_life = resolvers.mbonus_material(40, 40),
+		max_life = resolvers.mbonus_material("max_life", 2),
 	},
 }
 
@@ -290,13 +272,12 @@ newEntity{
 	cost = 35,
 	wielder = {
 		resists={
-			[DamageType.ACID] = resolvers.mbonus_material(8, 5),
-			[DamageType.LIGHTNING] = resolvers.mbonus_material(8, 5),
-			[DamageType.FIRE] = resolvers.mbonus_material(8, 5),
-			[DamageType.COLD] = resolvers.mbonus_material(8, 5),
+			[DamageType.ACID] = resolvers.mbonus_material("resists"),
+			[DamageType.LIGHTNING] = resolvers.mbonus_material("resists"),
+			[DamageType.COLD] = resolvers.mbonus_material("resists"),
 		},
 		inc_stats = {
-			[Stats.STAT_DEX] = resolvers.mbonus_material(6, 2),
+			[Stats.STAT_DEX] = resolvers.mbonus_material("inc_stats"),
 		},
 	},
 }
@@ -310,9 +291,9 @@ newEntity{
 	rarity = 16,
 	cost = 30,
 	wielder = {
-		max_life=resolvers.mbonus_material(60, 40),
-		life_regen = resolvers.mbonus_material(15, 5, function(e, v) v=v/10 return 0, v end),
-		healing_factor = resolvers.mbonus_material(20, 10, function(e, v) v=v/100 return 0, v end),
+		max_life=resolvers.mbonus_material("max_life"),
+		life_regen = resolvers.mbonus_material("life_regen"),
+		healing_factor = resolvers.mbonus_material("healing_factor"),
 	},
 }
 
@@ -325,9 +306,9 @@ newEntity{
 	rarity = 16,
 	cost = 30,
 	wielder = {
-		combat_dam = resolvers.mbonus_material(5, 5),
-		combat_physcrit = resolvers.mbonus_material(3, 3),
-		combat_critical_power = resolvers.mbonus_material(10, 10),
+		combat_dam = resolvers.mbonus_material("combat_dam", 2),
+		combat_physcrit = resolvers.mbonus_material("combat_physcrit"),
+		--combat_critical_power = resolvers.mbonus_material("combat_critical_power"),
 	},
 }
 
@@ -340,10 +321,10 @@ newEntity{
 	rarity = 16,
 	cost = 30,
 	wielder = {
-		stun_immune = resolvers.mbonus_material(20, 10, function(e, v) v=v/100 return 0, v end),
-		pin_immune = resolvers.mbonus_material(20, 10, function(e, v) v=v/100 return 0, v end),
-		combat_armor = resolvers.mbonus_material(6, 4),
-		fatigue = resolvers.mbonus_material(6, 4, function(e, v) return 0, -v end),
+		stun_immune = resolvers.mbonus_material("immunity"),
+		pin_immune = resolvers.mbonus_material("immunity"),
+		combat_armor = resolvers.mbonus_material("combat_armor"),
+		fatigue = resolvers.mbonus_material("fatigue"),
 	},
 }
 
@@ -357,11 +338,11 @@ newEntity{
 	cost = 40,
 	wielder = {
 		inc_stats = {
-			[Stats.STAT_STR] = resolvers.mbonus_material(7, 3),
-			[Stats.STAT_DEX] = resolvers.mbonus_material(7, 3),
+			[Stats.STAT_STR] = resolvers.mbonus_material("inc_stats"),
+			[Stats.STAT_DEX] = resolvers.mbonus_material("inc_stats"),
 		},
-		disarm_immune = resolvers.mbonus_material(25, 15, function(e, v) v=v/100 return 0, v end),
-		combat_physresist = resolvers.mbonus_material(15, 5),
+		disarm_immune = resolvers.mbonus_material("immunity"),
+		combat_physresist = resolvers.mbonus_material("save"),
 	},
 }
 
@@ -375,12 +356,12 @@ newEntity{
 	cost = 30,
 	wielder = {
 		inc_stats = {
-			[Stats.STAT_CON] = resolvers.mbonus_material(5, 1),
+			[Stats.STAT_CON] = resolvers.mbonus_material("inc_stats"),
 		},
-		poison_immune = resolvers.mbonus_material(15, 10, function(e, v) v=v/100 return 0, v end),
-		disease_immune = resolvers.mbonus_material(15, 10, function(e, v) v=v/100 return 0, v end),
-		life_regen = resolvers.mbonus_material(30, 5, function(e, v) v=v/10 return 0, v end),
-		fatigue = resolvers.mbonus_material(6, 4, function(e, v) return 0, -v end),
+		poison_immune = resolvers.mbonus_material("immunity"),
+		disease_immune = resolvers.mbonus_material("immunity"),
+		life_regen = resolvers.mbonus_material("life_regen"),
+		fatigue = resolvers.mbonus_material("fatigue"),
 	},
 }
 
@@ -394,12 +375,12 @@ newEntity{
 	cost = 80,
 	wielder = {
 		inc_stats = {
-			[Stats.STAT_WIL] = resolvers.mbonus_material(7, 3),
+			[Stats.STAT_WIL] = resolvers.mbonus_material("inc_stats"),
 		},
-		combat_armor = resolvers.mbonus_material(7, 3),
-		combat_physcrit = resolvers.mbonus_material(5, 1),
-		combat_spellcrit = resolvers.mbonus_material(5, 1),
-		combat_atk = resolvers.mbonus_material(10, 5),
+		combat_armor = resolvers.mbonus_material("combat_armor"),
+		combat_physcrit = resolvers.mbonus_material("combat_physcrit"),
+		combat_spellcrit = resolvers.mbonus_material("combat_spellcrit"),
+		combat_atk = resolvers.mbonus_material("combat_atk"),
 	},
 }
 
@@ -413,12 +394,12 @@ newEntity{
 	cost = 30,
 	wielder = {
 		inc_stats = {
-			[Stats.STAT_CUN] = resolvers.mbonus_material(5, 1),
+			[Stats.STAT_CUN] = resolvers.mbonus_material("inc_stats"),
 		},
-		blind_immune = resolvers.mbonus_material(15, 10, function(e, v) v=v/100 return 0, v end),
-		confusion_immune = resolvers.mbonus_material(15, 10, function(e, v) v=v/100 return 0, v end),
-		combat_mentalresist = resolvers.mbonus_material(10, 5),
-		combat_spellresist = resolvers.mbonus_material(10, 5),
+		blind_immune = resolvers.mbonus_material("immunity"),
+		confusion_immune = resolvers.mbonus_material("immunity"),
+		combat_mentalresist = resolvers.mbonus_material("save"),
+		combat_spellresist = resolvers.mbonus_material("save"),
 	},
 }
 
@@ -433,12 +414,12 @@ newEntity{
 	max_power = 80, power_regen = 1,
 	use_talent = { id = Talents.T_SECOND_WIND, level = 5, power = 80 },
 	wielder = {
-		max_life = resolvers.mbonus_material(60, 40, function(e, v) return 0, -v end),
-		combat_armor = resolvers.mbonus_material(7, 3, function(e, v) return 0, -v end),
+		max_life = resolvers.mbonus_material("max_life", -1),
+		combat_armor = resolvers.mbonus_material("combat_armor", -1),
 
-		combat_physcrit = resolvers.mbonus_material(7, 3),
-		combat_apr = resolvers.mbonus_material(15, 5),
-		combat_def = resolvers.mbonus_material(10, 5),
+		combat_physcrit = resolvers.mbonus_material("combat_physcrit"),
+		combat_apr = resolvers.mbonus_material("combat_apr"),
+		combat_def = resolvers.mbonus_material("combat_def", 2),
 	},
 }
 
@@ -452,11 +433,11 @@ newEntity{
 	cost = 40,
 	wielder = {
 		inc_stats = {
-			[Stats.STAT_CUN] = resolvers.mbonus_material(5, 1),
+			[Stats.STAT_CUN] = resolvers.mbonus_material("inc_stats"),
 		},
-		combat_mentalresist = resolvers.mbonus_material(10, 5),
-		combat_armor = resolvers.mbonus_material(7, 3),
-		combat_def = resolvers.mbonus_material(10, 5),
+		combat_mentalresist = resolvers.mbonus_material("save"),
+		combat_armor = resolvers.mbonus_material("combat_armor"),
+		combat_def = resolvers.mbonus_material("combat_def"),
 	},
 }
 
@@ -472,9 +453,9 @@ newEntity{
 	use_talent = { id = Talents.T_TRACK, level = 2, power = 80 },
 	wielder = {
 		inc_stats = {
-			[Stats.STAT_STR] = resolvers.mbonus_material(6, 4),
+			[Stats.STAT_STR] = resolvers.mbonus_material("inc_stats"),
 		},
-		lite = resolvers.mbonus_material(1, 1),
+		lite = resolvers.mbonus_material("lite"),
 	},
 }
 
@@ -488,10 +469,10 @@ newEntity{
 	cost = 20,
 	wielder = {
 		resists={
-			[DamageType.ACID] = resolvers.mbonus_material(10, 5),
-			[DamageType.COLD] = resolvers.mbonus_material(10, 5),
+			[DamageType.ACID] = resolvers.mbonus_material("resists"),
+			[DamageType.COLD] = resolvers.mbonus_material("resists"),
 		},
-		combat_armor = resolvers.mbonus_material(5, 1),
+		combat_armor = resolvers.mbonus_material("combat_armor"),
 		can_breath = {water=1},
 	},
 }
@@ -506,11 +487,11 @@ newEntity{
 	cost = 100,
 	wielder = {
 		inc_stats = {
-			[Stats.STAT_STR] = resolvers.mbonus_material(7, 3),
-			[Stats.STAT_MAG] = resolvers.mbonus_material(7, 3),
+			[Stats.STAT_STR] = resolvers.mbonus_material("inc_stats"),
+			[Stats.STAT_MAG] = resolvers.mbonus_material("inc_stats"),
 		},
-		combat_physcrit = resolvers.mbonus_material(3, 2),
-		combat_spellcrit = resolvers.mbonus_material(3, 2),
-		combat_dam = resolvers.mbonus_material(7, 3),
+		combat_physcrit = resolvers.mbonus_material("combat_physcrit"),
+		combat_spellcrit = resolvers.mbonus_material("combat_spellcrit"),
+		combat_dam = resolvers.mbonus_material("combat_dam"),
 	},
 }
diff --git a/game/modules/tome/data/general/objects/egos/belt.lua b/game/modules/tome/data/general/objects/egos/belt.lua
index cf60d94297..68fef5634b 100644
--- a/game/modules/tome/data/general/objects/egos/belt.lua
+++ b/game/modules/tome/data/general/objects/egos/belt.lua
@@ -30,8 +30,8 @@ newEntity{
 	rarity = 5,
 	cost = 6,
 	wielder = {
-		max_encumber = resolvers.mbonus_material(40, 20),
-		fatigue = resolvers.mbonus_material(6, 4, function(e, v) return 0, -v end),
+		max_encumber = resolvers.mbonus_material("max_encumber"),
+		fatigue = resolvers.mbonus_material("fatigue"),
 	},
 }
 
@@ -43,7 +43,7 @@ newEntity{
 	rarity = 10,
 	cost = 40,
 	wielder = {
-		combat_def = resolvers.mbonus_material(10, 5),
+		combat_def = resolvers.mbonus_material("combat_def"),
 	},
 	max_power = 120, power_regen = 1,
 	use_power = { name = "create a temporary shield that absorbs damage", power = 100, use = function(self, who)
@@ -62,7 +62,7 @@ newEntity{
 	rarity = 5,
 	cost = 6,
 	wielder = {
-		combat_spellpower = resolvers.mbonus_material(10, 2),
+		combat_spellpower = resolvers.mbonus_material("combat_spellpower"),
 	},
 }
 
@@ -74,7 +74,7 @@ newEntity{
 	rarity = 5,
 	cost = 6,
 	wielder = {
-		combat_dam = resolvers.mbonus_material(10, 2),
+		combat_dam = resolvers.mbonus_material("combat_dam"),
 	},
 }
 
@@ -86,7 +86,7 @@ newEntity{
 	rarity = 8,
 	cost = 6,
 	wielder = {
-		life_regen = resolvers.mbonus_material(10, 2, function(e, v) return 0, v/10 end),
+		life_regen = resolvers.mbonus_material("life_regen"),
 	},
 }
 
@@ -98,7 +98,7 @@ newEntity{
 	rarity = 6,
 	cost = 5,
 	wielder = {
-		max_life = resolvers.mbonus_material(40, 30),
+		max_life = resolvers.mbonus_material("max_life"),
 	},
 }
 
@@ -110,8 +110,8 @@ newEntity{
 	rarity = 9,
 	cost = 10,
 	wielder = {
-		combat_def_ranged = resolvers.mbonus_material(8, 2),
-		inc_stealth = resolvers.mbonus_material(10, 5),
+		combat_def_ranged = resolvers.mbonus_material("combat_def_ranged"),
+		inc_stealth = resolvers.mbonus_material("inc_stealth"),
 	},
 }
 
@@ -124,8 +124,8 @@ newEntity{
 	cost = 5,
 	wielder = {
 		resists={
-			[DamageType.FIRE] = resolvers.mbonus_material(10, 5),
-			[DamageType.COLD] = resolvers.mbonus_material(10, 5),
+			[DamageType.FIRE] = resolvers.mbonus_material("resists"),
+			[DamageType.COLD] = resolvers.mbonus_material("resists"),
 		},
 	},
 }
@@ -139,9 +139,9 @@ newEntity{
 	cost = 5,
 	wielder = {
 		resists={
-			[DamageType.LIGHTNING] = resolvers.mbonus_material(10, 5),
+			[DamageType.LIGHTNING] = resolvers.mbonus_material("resists"),
 		},
-		stun_immune = resolvers.mbonus_material(20, 10, function(e, v) v=v/100 return 0, v end),
+		stun_immune = resolvers.mbonus_material("immunity"),
 	},
 }
 
@@ -154,9 +154,9 @@ newEntity{
 	cost = 5,
 	wielder = {
 		resists={
-			[DamageType.TEMPORAL] = resolvers.mbonus_material(10, 5),
+			[DamageType.TEMPORAL] = resolvers.mbonus_material("resists"),
 		},
-		teleport_immune = resolvers.mbonus_material(20, 10, function(e, v) v=v/100 return 0, v end),
+		teleport_immune = resolvers.mbonus_material("immunity"),
 	},
 }
 
@@ -168,8 +168,8 @@ newEntity{
 	rarity = 6,
 	cost = 5,
 	wielder = {
-		stun_immune = resolvers.mbonus_material(20, 10, function(e, v) v=v/100 return 0, v end),
-		knockback_immune = resolvers.mbonus_material(20, 10, function(e, v) v=v/100 return 0, v end),
+		stun_immune = resolvers.mbonus_material("immunity"),
+		knockback_immune = resolvers.mbonus_material("immunity"),
 	},
 }
 
@@ -182,10 +182,10 @@ newEntity{
 	cost = 9,
 	wielder = {
 		resists={
-			[DamageType.ACID] = resolvers.mbonus_material(10, 5),
+			[DamageType.ACID] = resolvers.mbonus_material("resists"),
 		},
-		poison_immune = resolvers.mbonus_material(10, 5, function(e, v) return 0, v/100 end),
-		disease_immune = resolvers.mbonus_material(10, 5, function(e, v) return 0, v/100 end),
+		poison_immune = resolvers.mbonus_material("immunity"),
+		disease_immune = resolvers.mbonus_material("immunity"),
 	},
 }
 
@@ -197,7 +197,7 @@ newEntity{
 	rarity = 9,
 	cost = 9,
 	wielder = {
-		confusion_immune = resolvers.mbonus_material(15, 10, function(e, v) v=v/100 return 0, v end),
+		confusion_immune = resolvers.mbonus_material("immunity"),
 	},
 }
 
@@ -211,10 +211,10 @@ newEntity{
 	cost = 50,
 	wielder = {
 		inc_stats = {
-			[Stats.STAT_MAG] = resolvers.mbonus_material(3, 3),
-			[Stats.STAT_WIL] = resolvers.mbonus_material(3, 3),
+			[Stats.STAT_MAG] = resolvers.mbonus_material("inc_stats"),
+			[Stats.STAT_WIL] = resolvers.mbonus_material("inc_stats"),
 		},
-		combat_spellcrit = resolvers.mbonus_material(3, 3),
+		combat_spellcrit = resolvers.mbonus_material("combat_spellcrit"),
 	},
 }
 
@@ -227,11 +227,11 @@ newEntity{
 	rarity = 15,
 	cost = 30,
 	wielder = {
-		disarm_bonus = resolvers.mbonus_material(25, 5),
-		trap_detect_power = resolvers.mbonus_material(25, 5),
-		infravision = resolvers.mbonus_material(2, 2),
+		disarm_bonus = resolvers.mbonus_material("disarm_bonus"),
+		trap_detect_power = resolvers.mbonus_material("trap_detect_power"),
+		infravision = resolvers.mbonus_material("infravision"),
 		inc_stats = {
-			[Stats.STAT_DEX] = resolvers.mbonus_material(3, 3),
+			[Stats.STAT_DEX] = resolvers.mbonus_material("inc_stats"),
 		},
 	},
 }
@@ -246,10 +246,10 @@ newEntity{
 	cost = 50,
 	wielder = {
 		resists={
-			[DamageType.ACID] = resolvers.mbonus_material(5, 5),
-			[DamageType.LIGHTNING] = resolvers.mbonus_material(5, 5),
-			[DamageType.FIRE] = resolvers.mbonus_material(5, 5),
-			[DamageType.COLD] = resolvers.mbonus_material(5, 5),
+			[DamageType.ACID] = resolvers.mbonus_material("resists"),
+			[DamageType.LIGHTNING] = resolvers.mbonus_material("resists"),
+			[DamageType.FIRE] = resolvers.mbonus_material("resists"),
+			[DamageType.COLD] = resolvers.mbonus_material("resists"),
 		},
 	},
 }
@@ -264,10 +264,10 @@ newEntity{
 	cost = 50,
 	wielder = {
 		inc_stats = {
-			[Stats.STAT_STR] = resolvers.mbonus_material(3, 3),
-			[Stats.STAT_CON] = resolvers.mbonus_material(3, 3),
+			[Stats.STAT_STR] = resolvers.mbonus_material("inc_stats"),
+			[Stats.STAT_CON] = resolvers.mbonus_material("inc_stats"),
 		},
-		pin_immune = resolvers.mbonus_material(20, 10, function(e, v) v=v/100 return 0, v end),
+		pin_immune = resolvers.mbonus_material("immunity"),
 	},
 }
 
@@ -282,8 +282,8 @@ newEntity{
 	cost = 60,
 	wielder = {
 		size_category = 1,
-		combat_dam = resolvers.mbonus_material(5, 5),
-		combat_critical_power = resolvers.mbonus_material(10, 10),
+		combat_dam = resolvers.mbonus_material("combat_dam", 2),
+	--	combat_critical_power = resolvers.mbonus_material("combat_critical_power"),
 
 	},
 }
@@ -298,10 +298,10 @@ newEntity{
 	cost = 60,
 	wielder = {
 		inc_stats = {
-			[Stats.STAT_CUN] = resolvers.mbonus_material(3, 3),
+			[Stats.STAT_CUN] = resolvers.mbonus_material("inc_stats"),
 		},
-		combat_atk = resolvers.mbonus_material(5, 5),
-		combat_physcrit = resolvers.mbonus_material(3, 3),
+		combat_atk = resolvers.mbonus_material("combat_atk"),
+		combat_physcrit = resolvers.mbonus_material("combat_physcrit"),
 	},
 }
 
@@ -315,9 +315,9 @@ newEntity{
 	rarity = 20,
 	cost = 60,
 	wielder = {
-		combat_armor = resolvers.mbonus_material(6, 4),
-		combat_def = resolvers.mbonus_material(4, 4),
-		combat_physresist = resolvers.mbonus_material(20, 7),
+		combat_armor = resolvers.mbonus_material("combat_armor"),
+		combat_def = resolvers.mbonus_material("combat_def"),
+		combat_physresist = resolvers.mbonus_material("save", 2),
 	},
 }
 
@@ -330,18 +330,29 @@ newEntity{
 	rarity = 40,
 	cost = 100,
 	wielder = {
-		resists={
-			[DamageType.PHYSICAL] = resolvers.mbonus_material(15, 5, function(e, v) return 0, -v end),
-		},
-		inc_damage = {
-			[DamageType.PHYSICAL] = resolvers.mbonus_material(20, 5),
-		},
+		combat_dam = resolvers.mbonus_material("combat_dam"),
 		resists_pen = {
-			[DamageType.PHYSICAL] = resolvers.mbonus_material(15, 5),
+			[DamageType.PHYSICAL] = resolvers.mbonus_material("resists_pen", 2),
 		},
 	},
 }
-
+--[=[
+newEntity{
+	power_source = {nature=true},
+	name = "draining ", prefix=true, instant_resolve=true,
+	level_range = {45, 50},
+	greater_ego = 1,
+	rarity = 40,
+	cost = 100,
+	wielder = {
+		resource_leech_chance = resolvers.mbonus_material("resource_leech_chance"),
+		resource_leech_value = resolvers.mbonus_material("resource_leech_value"),
+		on_melee_hit = {
+			[DamageType.BLIGHT] = resolvers.mbonus_material("on_melee_hit"),
+		},
+	},
+}
+]=]
 newEntity{
 	power_source = {arcane=true},
 	name = "nightruned ", prefix=true, instant_resolve=true,
@@ -352,11 +363,11 @@ newEntity{
 	cost = 60,
 	wielder = {
 		resists={
-			[DamageType.LIGHT] = resolvers.mbonus_material(10, 5),
-			[DamageType.DARKNESS] = resolvers.mbonus_material(10, 5),
+			[DamageType.LIGHT] = resolvers.mbonus_material("resists"),
+			[DamageType.DARKNESS] = resolvers.mbonus_material("resists"),
 		},
-		blind_immune = resolvers.mbonus_material(20, 15, function(e, v) v=v/100 return 0, v end),
-		see_invisible = resolvers.mbonus_material(20, 5),
+		blind_immune = resolvers.mbonus_material("immunity"),
+		see_invisible = resolvers.mbonus_material("immunity"),
 	},
 }
 
@@ -369,16 +380,13 @@ newEntity{
 	rarity = 35,
 	cost = 70,
 	wielder = {
-
 		inc_stats = {
-			[Stats.STAT_STR] = resolvers.mbonus_material(3, 1),
-			[Stats.STAT_DEX] = resolvers.mbonus_material(3, 1),
-			[Stats.STAT_WIL] = resolvers.mbonus_material(3, 1),
-			[Stats.STAT_CUN] = resolvers.mbonus_material(3, 1),
+			[Stats.STAT_STR] = resolvers.mbonus_material("inc_stats"),
+			[Stats.STAT_DEX] = resolvers.mbonus_material("inc_stats"),
+			[Stats.STAT_WIL] = resolvers.mbonus_material("inc_stats"),
+			[Stats.STAT_CUN] = resolvers.mbonus_material("inc_stats"),
 		},
-		combat_mentalresist = resolvers.mbonus_material(3, 3),
-		combat_physresist = resolvers.mbonus_material(3, 3),
-		combat_spellresist = resolvers.mbonus_material(3, 3),
+		combat_spellresist = resolvers.mbonus_material("save"),
 	},
 }
 
@@ -392,10 +400,10 @@ newEntity{
 	cost = 40,
 	wielder = {
 		inc_stats = {
-			[Stats.STAT_MAG] = resolvers.mbonus_material(5, 1),
+			[Stats.STAT_MAG] = resolvers.mbonus_material("inc_stats"),
 		},
-		max_mana = resolvers.mbonus_material(40, 20),
-		mana_regen = resolvers.mbonus_material(50, 10, function(e, v) v=v/100 return 0, v end),
+		max_mana = resolvers.mbonus_material("max_mana"),
+		mana_regen = resolvers.mbonus_material("mana_regen"),
 	},
 }
 
@@ -409,14 +417,14 @@ newEntity{
 	cost = 70,
 	wielder = {
 		inc_stats = {
-			[Stats.STAT_CON] = resolvers.mbonus_material(6, 4),
+			[Stats.STAT_CON] = resolvers.mbonus_material("inc_stats"),
 		},
-		stun_immune = resolvers.mbonus_material(17, 5, function(e, v) v=v/100 return 0, v end),
-		knockback_immune = resolvers.mbonus_material(17, 5, function(e, v) v=v/100 return 0, v end),
-		pin_immune = resolvers.mbonus_material(17, 5, function(e, v) v=v/100 return 0, -v end),
-		blind_immune = resolvers.mbonus_material(17, 5, function(e, v) v=v/100 return 0, -v end),
-		confusion_immune = resolvers.mbonus_material(17, 5, function(e, v) v=v/100 return 0, v end),
-		max_stamina = resolvers.mbonus_material(30, 10),
+		stun_immune = resolvers.mbonus_material("immunity"),
+		knockback_immune = resolvers.mbonus_material("immunity"),
+		pin_immune = resolvers.mbonus_material("immunity", -1),
+		blind_immune = resolvers.mbonus_material("immunity", -1),
+		confusion_immune = resolvers.mbonus_material("immunity"),
+		max_stamina = resolvers.mbonus_material("max_stamina"),
 	},
 }
 
@@ -429,10 +437,10 @@ newEntity{
 	rarity = 15,
 	cost = 40,
 	wielder = {
-		disarm_immune = resolvers.mbonus_material(15, 5, function(e, v) v=v/100 return 0, v end),
-		confusion_immune = resolvers.mbonus_material(15, 5, function(e, v) v=v/100 return 0, v end),
-		combat_critical_power = resolvers.mbonus_material(10, 5),
-		combat_dam = resolvers.mbonus_material(3, 3),
+		disarm_immune = resolvers.mbonus_material("immunity"),
+		confusion_immune = resolvers.mbonus_material("immunity"),
+		--combat_critical_power = resolvers.mbonus_material("combat_critical_power"),
+		combat_dam = resolvers.mbonus_material("combat_dam"),
 	},
 }
 
@@ -446,12 +454,12 @@ newEntity{
 	cost = 60,
 	wielder = {
 		resists={
-			[DamageType.PHYSICAL] = resolvers.mbonus_material(7, 3),
+			[DamageType.PHYSICAL] = resolvers.mbonus_material("resists"),
 		},
 		inc_stats = {
-			[Stats.STAT_WIL] = resolvers.mbonus_material(5, 1),
+			[Stats.STAT_WIL] = resolvers.mbonus_material("inc_stats"),
 		},
-		max_life = resolvers.mbonus_material(70, 40),
+		max_life = resolvers.mbonus_material("max_life"),
 	},
 }
 
@@ -465,10 +473,10 @@ newEntity{
 	cost = 30,
 	wielder = {
 		resists={
-			[DamageType.BLIGHT] = resolvers.mbonus_material(10, 5),
+			[DamageType.BLIGHT] = resolvers.mbonus_material("resists"),
 		},
 		inc_stats = {
-			[Stats.STAT_STR] = resolvers.mbonus_material(5, 1),
+			[Stats.STAT_STR] = resolvers.mbonus_material("inc_stats"),
 		},
 		can_breath = {water=1},
 	},
@@ -484,10 +492,8 @@ newEntity{
 	cost = 40,
 	wielder = {
 		inc_stats = {
-			[Stats.STAT_CON] = resolvers.mbonus_material(5, 1),
+			[Stats.STAT_CON] = resolvers.mbonus_material("inc_stats", 2),
 		},
-		combat_mentalresist = resolvers.mbonus_material(7, 3),
-		combat_physresist = resolvers.mbonus_material(7, 3),
-		combat_spellresist = resolvers.mbonus_material(7, 3),
+		combat_physresist = resolvers.mbonus_material("save", 2),
 	},
 }
diff --git a/game/modules/tome/data/general/objects/egos/boots.lua b/game/modules/tome/data/general/objects/egos/boots.lua
index 0895bbaeb9..728542497f 100644
--- a/game/modules/tome/data/general/objects/egos/boots.lua
+++ b/game/modules/tome/data/general/objects/egos/boots.lua
@@ -52,7 +52,7 @@ newEntity{
 	rarity = 5,
 	cost = 6,
 	wielder = {
-		combat_def_ranged = resolvers.mbonus_material(8, 2),
+		combat_def_ranged = resolvers.mbonus_material("combat_def_ranged"),
 	},
 }
 
@@ -65,7 +65,7 @@ newEntity{
 	rarity = 20,
 	cost = 60,
 	wielder = {
-		movement_speed = 0.2,
+		movement_speed = resolvers.mbonus_material("movement_speed"),
 	},
 }
 
@@ -81,8 +81,8 @@ newEntity{
 	use_talent = { id = Talents.T_RUSH, level = 2, power = 80 },
 	wielder = {
 		inc_stats = {
-			[Stats.STAT_STR] = resolvers.mbonus_material(2, 2),
-			[Stats.STAT_CON] = resolvers.mbonus_material(2, 2),
+			[Stats.STAT_STR] = resolvers.mbonus_material("inc_stats"),
+			[Stats.STAT_CON] = resolvers.mbonus_material("inc_stats"),
 		},
 	},
 }
@@ -100,8 +100,8 @@ newEntity{
 	use_talent = { id = Talents.T_DISENGAGE, level = 2, power = 80 },
 	wielder = {
 		inc_stats = {
-			[Stats.STAT_DEX] = resolvers.mbonus_material(2, 2),
-			[Stats.STAT_CUN] = resolvers.mbonus_material(2, 2),
+			[Stats.STAT_DEX] = resolvers.mbonus_material("inc_stats"),
+			[Stats.STAT_CUN] = resolvers.mbonus_material("inc_stats"),
 		},
 	},
 }
@@ -114,8 +114,8 @@ newEntity{
 	rarity = 12,
 	cost = 12,
 	wielder = {
-		stun_immune = resolvers.mbonus_material(20, 10, function(e, v) v=v/100 return 0, v end),
-		knockback_immune = resolvers.mbonus_material(20, 10, function(e, v) v=v/100 return 0, v end),
+		stun_immune = resolvers.mbonus_material("immunity"),
+		knockback_immune = resolvers.mbonus_material("immunity"),
 	},
 }
 
@@ -127,8 +127,8 @@ newEntity{
 	rarity = 9,
 	cost = 7,
 	wielder = {
-		max_stamina = resolvers.mbonus_material(30, 10),
-		stamina_regen = resolvers.mbonus_material(10, 3, function(e, v) v=v/10 return 0, v end),
+		max_stamina = resolvers.mbonus_material("max_stamina"),
+		stamina_regen = resolvers.mbonus_material("stamina_regen"),
 	},
 }
 
@@ -140,7 +140,7 @@ newEntity{
 	rarity = 5,
 	cost = 6,
 	wielder = {
-		max_encumber = resolvers.mbonus_material(30, 20),
+		max_encumber = resolvers.mbonus_material("max_encumber"),
 	},
 }
 
@@ -153,7 +153,7 @@ newEntity{
 	rarity = 5,
 	cost = 6,
 	wielder = {
-		combat_spellpower = resolvers.mbonus_material(3, 3),
+		combat_spellpower = resolvers.mbonus_material("combat_spellpower"),
 	},
 }
 
@@ -165,7 +165,7 @@ newEntity{
 	rarity = 5,
 	cost = 6,
 	wielder = {
-		combat_armor = resolvers.mbonus_material(6, 4),
+		combat_armor = resolvers.mbonus_material("combat_armor"),
 	},
 }
 
@@ -176,7 +176,7 @@ newEntity{
 	rarity = 5,
 	cost = 6,
 	wielder = {
-		infravision = resolvers.mbonus_material(2, 1),
+		infravision = resolvers.mbonus_material("infravision"),
 	},
 }
 
@@ -189,10 +189,10 @@ newEntity{
 	rarity = 18,
 	cost = 60,
 	wielder = {
-		healing_factor = resolvers.mbonus_material(20, 10, function(e, v) v=v/100 return 0, v end),
-		cut_immune = resolvers.mbonus_material(2, 2, function(e, v) v=v/10 return 0, v end),
-		life_regen = resolvers.mbonus_material(10, 5, function(e, v) v=v/10 return 0, v end),
-		poison_immune = resolvers.mbonus_material(10, 10, function(e, v) return 0, v/100 end),
+		healing_factor = resolvers.mbonus_material("healing_factor"),
+		cut_immune = resolvers.mbonus_material("immunity"),
+		life_regen = resolvers.mbonus_material("life_regen"),
+		poison_immune = resolvers.mbonus_material("immunity"),
 
 	},
 }
@@ -206,9 +206,9 @@ newEntity{
 	rarity = 20,
 	cost = 70,
 	wielder = {
-		fatigue = resolvers.mbonus_material(6, 4, function(e, v) return 0, -v end),
-		max_life=resolvers.mbonus_material(30, 30),
-		movement_speed = 0.1,
+		fatigue = resolvers.mbonus_material("fatigue"),
+		max_life = resolvers.mbonus_material("max_life"),
+		movement_speed = resolvers.mbonus_material("movement_speed"),
 	},
 }
 
@@ -221,9 +221,9 @@ newEntity{
 	rarity = 15,
 	cost = 20,
 	wielder = {
-		combat_dam = resolvers.mbonus_material(3, 3),
-		combat_apr = resolvers.mbonus_material(3, 3),
-		pin_immune = resolvers.mbonus_material(20, 10, function(e, v) v=v/100 return 0, v end),
+		combat_dam = resolvers.mbonus_material("combat_dam"),
+		combat_apr = resolvers.mbonus_material("combat_apr"),
+		pin_immune = resolvers.mbonus_material("immunity"),
 	},
 }
 
@@ -238,14 +238,14 @@ newEntity{
 	max_power = 80, power_regen = 1,
 	wielder = {
 		resists={
-			[DamageType.NATURE] = resolvers.mbonus_material(20, 10, function(e, v) return 0, -v end),
-			[DamageType.LIGHT] = resolvers.mbonus_material(20, 10, function(e, v) return 0, -v end),
+			[DamageType.NATURE] = resolvers.mbonus_material("resists", -1),
+			[DamageType.LIGHT] = resolvers.mbonus_material("resists", -1),
 		},
 		inc_stats = {
-			[Stats.STAT_WIL] = resolvers.mbonus_material(7, 3),
+			[Stats.STAT_WIL] = resolvers.mbonus_material("inc_stats", 2),
 		},
-		pin_immune = resolvers.mbonus_material(50, 40, function(e, v) v=v/100 return 0, v end),
-		combat_spellpower = resolvers.mbonus_material(7, 3),
+		pin_immune = resolvers.mbonus_material("immunity", 2),
+		combat_spellpower = resolvers.mbonus_material("combat_spellpower"),
 	},
 }
 
@@ -259,11 +259,11 @@ newEntity{
 	cost = 30,
 	wielder = {
 		inc_stats = {
-			[Stats.STAT_CON] = resolvers.mbonus_material(5, 1),
+			[Stats.STAT_CON] = resolvers.mbonus_material("inc_stats"),
 		},
-		blind_immune = resolvers.mbonus_material(15, 5, function(e, v) v=v/100 return 0, v end),
-		confusion_immune = resolvers.mbonus_material(15, 5, function(e, v) v=v/100 return 0, v end),
-		disease_immune = resolvers.mbonus_material(15, 5, function(e, v) v=v/100 return 0, v end),
+		blind_immune = resolvers.mbonus_material("immunity"),
+		confusion_immune = resolvers.mbonus_material("immunity"),
+		disease_immune = resolvers.mbonus_material("immunity"),
 	},
 }
 
@@ -277,12 +277,12 @@ newEntity{
 	cost = 60,
 	wielder = {
 		resists={
-			[DamageType.ACID] = resolvers.mbonus_material(10, 5),
-			[DamageType.LIGHTNING] = resolvers.mbonus_material(10, 5),
-			[DamageType.FIRE] = resolvers.mbonus_material(10, 5),
-			[DamageType.COLD] = resolvers.mbonus_material(10, 5),
+			[DamageType.ACID] = resolvers.mbonus_material("resists"),
+			[DamageType.LIGHTNING] = resolvers.mbonus_material("resists"),
+			[DamageType.FIRE] = resolvers.mbonus_material("resists"),
+			[DamageType.COLD] = resolvers.mbonus_material("resists"),
 		},
-		combat_armor = resolvers.mbonus_material(7, 3),
+		combat_armor = resolvers.mbonus_material("combat_armor"),
 	},
 }
 
@@ -295,9 +295,9 @@ newEntity{
 	rarity = 30,
 	cost = 60,
 	wielder = {
-		max_mana = resolvers.mbonus_material(40, 20),
-		mana_regen = resolvers.mbonus_material(50, 10, function(e, v) v=v/100 return 0, v end),
-		combat_spellcrit = resolvers.mbonus_material(4, 1),
+		max_mana = resolvers.mbonus_material("max_mana"),
+		mana_regen = resolvers.mbonus_material("mana_regen"),
+		combat_spellcrit = resolvers.mbonus_material("combat_spellcrit"),
 	},
 }
 
@@ -311,11 +311,11 @@ newEntity{
 	cost = 70,
 	wielder = {
 		resists={
-			[DamageType.LIGHTNING] = resolvers.mbonus_material(15, 5),
+			[DamageType.LIGHTNING] = resolvers.mbonus_material("resists"),
 		},
-		stun_immune = resolvers.mbonus_material(15, 10, function(e, v) v=v/100 return 0, v end),
-		pin_immune = resolvers.mbonus_material(15, 10, function(e, v) v=v/100 return 0, v end),
-		confusion_immune = resolvers.mbonus_material(15, 10, function(e, v) v=v/100 return 0, v end),
+		stun_immune = resolvers.mbonus_material("immunity"),
+		pin_immune = resolvers.mbonus_material("immunity"),
+		confusion_immune = resolvers.mbonus_material("immunity"),
 	},
 }
 
@@ -331,15 +331,29 @@ newEntity{
 	use_talent = { id = Talents.T_HEAVE, level = 4, power = 40 },
 	wielder = {
 		inc_stats = {
-			[Stats.STAT_STR] = resolvers.mbonus_material(7, 3),
+			[Stats.STAT_STR] = resolvers.mbonus_material("inc_stats", 2),
 		},
-		knockback_immune = resolvers.mbonus_material(15, 10, function(e, v) v=v/100 return 0, v end),
-		pin_immune = resolvers.mbonus_material(15, 10, function(e, v) v=v/100 return 0, v end),
-		poison_immune = resolvers.mbonus_material(15, 10, function(e, v) v=v/100 return 0, -v end),
-		disease_immune = resolvers.mbonus_material(15, 10, function(e, v) v=v/100 return 0, -v end),
+		knockback_immune = resolvers.mbonus_material("immunity"),
+		pin_immune = resolvers.mbonus_material("immunity"),
+		poison_immune = resolvers.mbonus_material("immunity", -1),
+		disease_immune = resolvers.mbonus_material("immunity", -1),
 	},
 }
-
+--[=[
+newEntity{
+	power_source = {nature=true},
+	name = " of voracity", suffix=true, instant_resolve=true,
+	level_range = {20, 50},
+	greater_ego = 1,
+	rarity = 20,
+	cost = 40,
+	wielder = {
+		resource_leech_chance = resolvers.mbonus_material("resource_leech_chance"),
+		resource_leech_value = resolvers.mbonus_material("resource_leech_value"),
+		max_life = resolvers.mbonus_material("max_life", -1),
+	},
+}
+]=]
 newEntity{
 	power_source = {technique=true},
 	name = " of invasion", suffix=true, instant_resolve=true,
@@ -349,11 +363,11 @@ newEntity{
 	rarity = 30,
 	cost = 40,
 	wielder = {
-		disarm_immune = resolvers.mbonus_material(15, 10, function(e, v) v=v/100 return 0, v end),
-		combat_physcrit = resolvers.mbonus_material(4, 1),
-		combat_dam = resolvers.mbonus_material(3, 3),
+		disarm_immune = resolvers.mbonus_material("immunity"),
+		combat_physcrit = resolvers.mbonus_material("combat_physcrit"),
+		combat_dam = resolvers.mbonus_material("combat_dam"),
 		resists_pen = {
-			[DamageType.PHYSICAL] = resolvers.mbonus_material(10, 5),
+			[DamageType.PHYSICAL] = resolvers.mbonus_material("resists"),
 		},
 	},
 }
@@ -370,7 +384,7 @@ newEntity{
 	use_talent = { id = Talents.T_METAFLOW, level = 2, power = 80 },
 	wielder = {
 		inc_stats = {
-			[Stats.STAT_MAG] = resolvers.mbonus_material(5, 1),
+			[Stats.STAT_MAG] = resolvers.mbonus_material("inc_stats"),
 		},
 	},
 }
@@ -386,8 +400,8 @@ newEntity{
 	max_power = 80, power_regen = 1,
 	use_talent = { id = Talents.T_EVASION, level = 2, power = 80 },
 	wielder = {
-		combat_mentalresist = resolvers.mbonus_material(7, 1),
-		combat_physresist = resolvers.mbonus_material(7, 1),
-		combat_spellresist = resolvers.mbonus_material(7, 1),
+		combat_mentalresist = resolvers.mbonus_material("save"),
+		combat_physresist = resolvers.mbonus_material("save"),
+		combat_spellresist = resolvers.mbonus_material("save"),
 	},
 }
diff --git a/game/modules/tome/data/general/objects/egos/bow.lua b/game/modules/tome/data/general/objects/egos/bow.lua
index 04fc09a96c..8fd7b1f26d 100644
--- a/game/modules/tome/data/general/objects/egos/bow.lua
+++ b/game/modules/tome/data/general/objects/egos/bow.lua
@@ -19,74 +19,7 @@
 local Talents = require("engine.interface.ActorTalents")
 local Stats = require("engine.interface.ActorStats")
 
---load("/data/general/objects/egos/charged-attack.lua")
-
-newEntity{
-	power_source = {technique=true},
-	name = " of power", suffix=true, instant_resolve=true,
-	keywords = {power=true},
-	level_range = {1, 50},
-	rarity = 3,
-	cost = 6,
-	combat={apr = resolvers.mbonus_material(15, 1)},
-}
-
-newEntity{
-	power_source = {technique=true},
-	name = "mighty ", prefix=true, instant_resolve=true,
-	keywords = {mighty=true},
-	level_range = {1, 50},
-	rarity = 3,
-	cost = 4,
-	wielder = {
-		inc_damage={ [DamageType.PHYSICAL] = resolvers.mbonus_material(25, 8), },
-	},
-}
-
-newEntity{
-	power_source = {technique=true},
-	name = "steady ", prefix=true, instant_resolve=true,
-	keywords = {steady=true},
-	level_range = {20, 50},
-	rarity = 9,
-	cost = 10,
-	wielder = {
-		talent_cd_reduction={[Talents.T_STEADY_SHOT]=1},
-	},
-}
-
-newEntity{
-	power_source = {technique=true},
-	name = " of dexterity (#STATBONUS#)", suffix=true, instant_resolve=true,
-	keywords = {dexterity=true},
-	level_range = {20, 50},
-	rarity = 7,
-	cost = 7,
-	wielder = {
-		inc_stats = { [Stats.STAT_DEX] = resolvers.mbonus_material(6, 2) },
-	},
-}
-
-newEntity{
-	power_source = {technique=true},
-	name = " of speed", suffix=true, instant_resolve=true,
-	keywords = {speed=true},
-	level_range = {20, 50},
-	rarity = 7,
-	cost = 7,
-	combat={physspeed = -0.1},
-}
-
-newEntity{
-	power_source = {technique=true},
-	name = " of great speed", suffix=true, instant_resolve=true,
-	keywords = {['g.speed']=true},
-	level_range = {40, 50},
-	greater_ego = 1,
-	rarity = 10,
-	cost = 60,
-	combat={physspeed = -0.2},
-}
+load("/data/general/objects/egos/ranged.lua")
 
 newEntity{
 	power_source = {technique=true},
@@ -96,12 +29,14 @@ newEntity{
 	greater_ego = 1,
 	rarity = 24,
 	cost = 40,
+	combat = {
+		critical_power = resolvers.mbonus_material("critical_power"),
+	},
 	wielder = {
-		talent_cd_reduction={
-			[Talents.T_STEADY_SHOT]=1,
-			[Talents.T_PINNING_SHOT]=1,
-			[Talents.T_VOLLEY_OF_ARROWS]=2,
+		learn_talent = {
+			[Talents.T_STEADY_SHOT] = resolvers.mbonus_material("learn_talent"),
+			[Talents.T_PINNING_SHOT] = resolvers.mbonus_material("learn_talent"),
+			[Talents.T_VOLLEY_OF_ARROWS] = resolvers.mbonus_material("learn_talent"),
 		},
-		inc_damage={ [DamageType.PHYSICAL] = resolvers.mbonus_material(14, 8), },
 	},
 }
diff --git a/game/modules/tome/data/general/objects/egos/cloak.lua b/game/modules/tome/data/general/objects/egos/cloak.lua
index 7319200a4c..72cee57b24 100644
--- a/game/modules/tome/data/general/objects/egos/cloak.lua
+++ b/game/modules/tome/data/general/objects/egos/cloak.lua
@@ -30,7 +30,7 @@ newEntity{
 	rarity = 5,
 	cost = 6,
 	wielder = {
-		inc_stealth = resolvers.mbonus_material(20, 5),
+		inc_stealth = resolvers.mbonus_material("inc_stealth"),
 	},
 }
 
@@ -42,7 +42,7 @@ newEntity{
 	rarity = 6,
 	cost = 7,
 	wielder = {
-		resists={[DamageType.COLD] = resolvers.mbonus_material(20, 10)},
+		resists={[DamageType.COLD] = resolvers.mbonus_material("resists")},
 	},
 }
 
@@ -54,7 +54,7 @@ newEntity{
 	rarity = 6,
 	cost = 7,
 	wielder = {
-		combat_armor = resolvers.mbonus_material(8, 5),
+		combat_armor = resolvers.mbonus_material("combat_armor"),
 	},
 }
 
@@ -67,8 +67,8 @@ newEntity{
 	cost = 10,
 	wielder = {
 		inc_stats = {
-			[Stats.STAT_DEX] = resolvers.mbonus_material(3, 1),
-			[Stats.STAT_CUN] = resolvers.mbonus_material(3, 1),
+			[Stats.STAT_DEX] = resolvers.mbonus_material("inc_stats", 0.5),
+			[Stats.STAT_CUN] = resolvers.mbonus_material("inc_stats", 0.5),
 			},
 	},
 }
@@ -82,8 +82,8 @@ newEntity{
 	cost = 10,
 	wielder = {
 		inc_stats = {
-			[Stats.STAT_MAG] = resolvers.mbonus_material(3, 1),
-			[Stats.STAT_WIL] = resolvers.mbonus_material(3, 1),
+			[Stats.STAT_MAG] = resolvers.mbonus_material("inc_stats", 0.5),
+			[Stats.STAT_WIL] = resolvers.mbonus_material("inc_stats", 0.5),
 			},
 	},
 }
@@ -97,8 +97,8 @@ newEntity{
 	cost = 10,
 	wielder = {
 		inc_stats = {
-			[Stats.STAT_STR] = resolvers.mbonus_material(3, 1),
-			[Stats.STAT_CON] = resolvers.mbonus_material(3, 1),
+			[Stats.STAT_STR] = resolvers.mbonus_material("inc_stats", 0.5),
+			[Stats.STAT_CON] = resolvers.mbonus_material("inc_stats", 0.5),
 			},
 	},
 }
@@ -111,7 +111,7 @@ newEntity{
 	rarity = 6,
 	cost = 7,
 	wielder = {
-		resists={[DamageType.ACID] = resolvers.mbonus_material(15, 10)},
+		resists={[DamageType.ACID] = resolvers.mbonus_material("resists")},
 	},
 }
 
@@ -126,13 +126,13 @@ newEntity{
 	cost = 25,
 	wielder = {
 		resists={
-			[DamageType.FIRE] = resolvers.mbonus_material(15, 10),
-			[DamageType.LIGHT] = resolvers.mbonus_material(15, 10),
+			[DamageType.FIRE] = resolvers.mbonus_material("resists"),
+			[DamageType.LIGHT] = resolvers.mbonus_material("resists"),
 		},
-		confusion_immune = -0.2,
-		combat_def = resolvers.mbonus_material(6, 4),
+		confusion_immune = resolvers.mbonus_material("immunity", -1),
+		combat_def = resolvers.mbonus_material("combat_def"),
 		lite = -1,
-		inc_stealth = resolvers.mbonus_material(10, 5),
+		inc_stealth = resolvers.mbonus_material("inc_stealth"),
 	},
 }
 
@@ -145,7 +145,7 @@ newEntity{
 	rarity = 7,
 	cost = 6,
 	wielder = {
-		max_life=resolvers.mbonus_material(30, 30),
+		max_life=resolvers.mbonus_material("max_life"),
 	},
 }
 
@@ -157,8 +157,8 @@ newEntity{
 	rarity = 7,
 	cost = 6,
 	wielder = {
-		stun_immune = resolvers.mbonus_material(20, 10, function(e, v) v=v/100 return 0, v end),
-		knockback_immune = resolvers.mbonus_material(20, 10, function(e, v) v=v/100 return 0, v end),
+		stun_immune = resolvers.mbonus_material("immunity"),
+		knockback_immune = resolvers.mbonus_material("immunity"),
 	},
 }
 
@@ -170,7 +170,7 @@ newEntity{
 	rarity = 5,
 	cost = 6,
 	wielder = {
-		combat_def = resolvers.mbonus_material(4, 4),
+		combat_def = resolvers.mbonus_material("combat_def"),
 	},
 }
 
@@ -182,7 +182,7 @@ newEntity{
 	rarity = 10,
 	cost = 10,
 	wielder = {
-		fatigue = resolvers.mbonus_material(5, 2, function(e, v) return 0, -v end),
+		fatigue = resolvers.mbonus_material("fatigue"),
 	},
 }
 
@@ -196,11 +196,11 @@ newEntity{
 	cost = 50,
 	wielder = {
 		inc_stats = {
-			[Stats.STAT_MAG] = resolvers.mbonus_material(2, 2),
-			[Stats.STAT_WIL] = resolvers.mbonus_material(2, 2),
-			[Stats.STAT_CUN] = resolvers.mbonus_material(2, 2),
+			[Stats.STAT_MAG] = resolvers.mbonus_material("inc_stats", 0.5),
+			[Stats.STAT_WIL] = resolvers.mbonus_material("inc_stats", 0.5),
+			[Stats.STAT_CUN] = resolvers.mbonus_material("inc_stats", 0.5),
 			},
-		combat_spellcrit = resolvers.mbonus_material(3, 3),
+		combat_spellcrit = resolvers.mbonus_material("combat_spellcrit"),
 	},
 }
 
@@ -213,9 +213,9 @@ newEntity{
 	rarity = 16,
 	cost = 50,
 	wielder = {
-		pin_immune = resolvers.mbonus_material(3, 2, function(e, v) v=v/10 return 0, v end),
-		knockback_immune = resolvers.mbonus_material(3, 2, function(e, v) v=v/10 return 0, v end),
-		confusion_immune = resolvers.mbonus_material(3, 2, function(e, v) v=v/10 return 0, v end),
+		pin_immune = resolvers.mbonus_material("immunity"),
+		knockback_immune = resolvers.mbonus_material("immunity"),
+		confusion_immune = resolvers.mbonus_material("immunity"),
 	},
 }
 
@@ -228,10 +228,10 @@ newEntity{
 	rarity = 18,
 	cost = 60,
 	wielder = {
-		healing_factor = resolvers.mbonus_material(20, 10, function(e, v) v=v/100 return 0, v end),
-		cut_immune = resolvers.mbonus_material(2, 2, function(e, v) v=v/10 return 0, v end),
-		life_regen = resolvers.mbonus_material(10, 5, function(e, v) v=v/10 return 0, v end),
-		poison_immune = resolvers.mbonus_material(10, 10, function(e, v) return 0, v/100 end),
+		healing_factor = resolvers.mbonus_material("healing_factor"),
+		--cut_immune = resolvers.mbonus_material("immunity"),
+		life_regen = resolvers.mbonus_material("life_regen"),
+		poison_immune = resolvers.mbonus_material("immunity"),
 
 	},
 }
@@ -246,10 +246,10 @@ newEntity{
 	cost = 20,
 	wielder = {
 		inc_stats = {
-			[Stats.STAT_WIL] = resolvers.mbonus_material(2, 2),
-			[Stats.STAT_CUN] = resolvers.mbonus_material(2, 2),
+			[Stats.STAT_WIL] = resolvers.mbonus_material("inc_stats"),
+			[Stats.STAT_CUN] = resolvers.mbonus_material("inc_stats"),
 			},
-		silence_immune = resolvers.mbonus_material(3, 2, function(e, v) v=v/10 return 0, v end),
+		silence_immune = resolvers.mbonus_material("immunity"),
 	},
 }
 
@@ -263,10 +263,10 @@ newEntity{
 	cost = 60,
 	wielder = {
 		resists={
-			[DamageType.ACID] = resolvers.mbonus_material(5, 5),
-			[DamageType.LIGHTNING] = resolvers.mbonus_material(5, 5),
-			[DamageType.FIRE] = resolvers.mbonus_material(5, 5),
-			[DamageType.COLD] = resolvers.mbonus_material(5, 5),
+			[DamageType.ACID] = resolvers.mbonus_material("resists"),
+			[DamageType.LIGHTNING] = resolvers.mbonus_material("resists"),
+			[DamageType.FIRE] = resolvers.mbonus_material("resists"),
+			[DamageType.COLD] = resolvers.mbonus_material("resists"),
 		},
 	},
 }
@@ -281,15 +281,15 @@ newEntity{
 	cost = 80,
 	wielder = {
 		inc_stats = {
-			[Stats.STAT_STR] = resolvers.mbonus_material(5, 1),
-			[Stats.STAT_DEX] = resolvers.mbonus_material(5, 1),
-			[Stats.STAT_CON] = resolvers.mbonus_material(5, 1),
+			[Stats.STAT_STR] = resolvers.mbonus_material("inc_stats"),
+			[Stats.STAT_DEX] = resolvers.mbonus_material("inc_stats"),
+			[Stats.STAT_CON] = resolvers.mbonus_material("inc_stats"),
 		},
-		combat_spellresist = resolvers.mbonus_material(20, 10, function(e, v) return 0, -v end),
-		stamina_regen = resolvers.mbonus_material(12, 3, function(e, v) v=v/10 return 0, -v end),
-		mana_regen = resolvers.mbonus_material(50, 10, function(e, v) v=v/100 return 0, -v end),
+		combat_spellresist = resolvers.mbonus_material("save", -1),
+		stamina_regen = resolvers.mbonus_material("stamina_regen", -1),
+		mana_regen = resolvers.mbonus_material("mana_regen", -1),
 		talents_types_mastery = {
-			["technique/combat-training"] = resolvers.mbonus_material(2, 2, function(e, v) v=v/10 return 0, v end),
+			["technique/combat-training"] = resolvers.mbonus_material("talent_types_mastery"),
 		},
 	},
 }
@@ -303,11 +303,11 @@ newEntity{
 	rarity = 15,
 	cost = 30,
 	wielder = {
-		blind_immune = resolvers.mbonus_material(10, 5, function(e, v) v=v/100 return 0, v end),
-		confusion_immune = resolvers.mbonus_material(10, 5, function(e, v) v=v/100 return 0, v end),
-		combat_mentalresist = resolvers.mbonus_material(4, 1),
-		combat_physresist = resolvers.mbonus_material(4, 1),
-		combat_spellresist = resolvers.mbonus_material(4, 1),
+		blind_immune = resolvers.mbonus_material("immunity"),
+		confusion_immune = resolvers.mbonus_material("immunity"),
+		combat_mentalresist = resolvers.mbonus_material("save"),
+		combat_physresist = resolvers.mbonus_material("save"),
+		combat_spellresist = resolvers.mbonus_material("save"),
 	},
 }
 
@@ -321,13 +321,13 @@ newEntity{
 	cost = 40,
 	wielder = {
 		inc_stats = {
-			[Stats.STAT_STR] = resolvers.mbonus_material(5, 1),
-			[Stats.STAT_CON] = resolvers.mbonus_material(5, 1),
+			[Stats.STAT_STR] = resolvers.mbonus_material("inc_stats"),
+			[Stats.STAT_CON] = resolvers.mbonus_material("inc_stats"),
 		},
-		combat_mentalresist = resolvers.mbonus_material(4, 1),
-		combat_physresist = resolvers.mbonus_material(4, 1),
-		combat_spellresist = resolvers.mbonus_material(4, 1),
-		max_life = resolvers.mbonus_material(70, 40),
+		combat_mentalresist = resolvers.mbonus_material("save"),
+		combat_physresist = resolvers.mbonus_material("save"),
+		combat_spellresist = resolvers.mbonus_material("save"),
+		max_life = resolvers.mbonus_material("max_life"),
 	},
 }
 
@@ -341,14 +341,31 @@ newEntity{
 	cost = 40,
 	wielder = {
 		inc_stats = {
-			[Stats.STAT_DEX] = resolvers.mbonus_material(5, 1),
-			[Stats.STAT_CUN] = resolvers.mbonus_material(5, 1),
+			[Stats.STAT_DEX] = resolvers.mbonus_material("inc_stats"),
+			[Stats.STAT_CUN] = resolvers.mbonus_material("inc_stats"),
 		},
-		combat_atk = resolvers.mbonus_material(7, 3),
-		combat_apr = resolvers.mbonus_material(7, 3),
+		combat_atk = resolvers.mbonus_material("combat_atk"),
+		combat_apr = resolvers.mbonus_material("combat_apr"),
 	},
 }
-
+--[=[
+newEntity{
+	power_source = {nature=true},
+	name = "parasitic ", prefix=true, instant_resolve=true,
+	level_range = {30, 50},
+	greater_ego = 1,
+	rarity = 30,
+	cost = 60,
+	wielder = {
+		inc_stats = {
+			[Stats.STAT_CON] = resolvers.mbonus_material("inc_stats", -2),
+		},
+		poison_immune = resolvers.mbonus_material("immunity"),
+		resource_leech_chance = resolvers.mbonus_material("resource_leech_chance"),
+		resource_leech_value = resolvers.mbonus_material("resource_leech_value"),
+	},
+}
+]=]
 newEntity{
 	power_source = {technique=true},
 	name = " of the guardian", suffix=true, instant_resolve=true,
@@ -358,11 +375,11 @@ newEntity{
 	rarity = 35,
 	cost = 40,
 	wielder = {
-		combat_mentalresist = resolvers.mbonus_material(10, 5),
-		combat_physresist = resolvers.mbonus_material(10, 5),
-		combat_spellresist = resolvers.mbonus_material(10, 5),
-		combat_armor = resolvers.mbonus_material(7, 3),
-		combat_def = resolvers.mbonus_material(10, 5),
+		combat_mentalresist = resolvers.mbonus_material("save"),
+		combat_physresist = resolvers.mbonus_material("save"),
+		combat_spellresist = resolvers.mbonus_material("save"),
+		combat_armor = resolvers.mbonus_material("combat_armor"),
+		combat_def = resolvers.mbonus_material("combat_def"),
 	},
 }
 
@@ -375,9 +392,9 @@ newEntity{
 	rarity = 35,
 	cost = 70,
 	wielder = {
-		max_mana = resolvers.mbonus_material(80, 20),
-		combat_spellpower = resolvers.mbonus_material(7, 3),
-		combat_spellcrit = resolvers.mbonus_material(3, 3),
+		max_mana = resolvers.mbonus_material("max_mana"),
+		combat_spellpower = resolvers.mbonus_material("combat_spellpower"),
+		combat_spellcrit = resolvers.mbonus_material("combat_spellcrit"),
 	},
 }
 
@@ -390,10 +407,10 @@ newEntity{
 	rarity = 15,
 	cost = 30,
 	wielder = {
-		disarm_immune = resolvers.mbonus_material(15, 5, function(e, v) v=v/100 return 0, v end),
-		confusion_immune = resolvers.mbonus_material(15, 5, function(e, v) v=v/100 return 0, v end),
-		combat_physcrit = resolvers.mbonus_material(4, 1),
-		combat_dam = resolvers.mbonus_material(4, 1),
+		disarm_immune = resolvers.mbonus_material("immunity"),
+		--confusion_immune = resolvers.mbonus_material("immunity"),
+		combat_physcrit = resolvers.mbonus_material("combat_physcrit"),
+		combat_dam = resolvers.mbonus_material("combat_dam"),
 	},
 }
 
@@ -408,8 +425,8 @@ newEntity{
 	max_power = 80, power_regen = 1,
 	use_talent = { id = Talents.T_BLINDING_SPEED, level = 3, power = 80 },
 	wielder = {
-		max_life = resolvers.mbonus_material(70, 40),
-		fatigue = resolvers.mbonus_material(6, 4, function(e, v) return 0, -v end),
+		max_life = resolvers.mbonus_material("max_life"),
+		fatigue = resolvers.mbonus_material("fatigue"),
 	},
 }
 
@@ -422,9 +439,9 @@ newEntity{
 	rarity = 35,
 	cost = 70,
 	wielder = {
-		combat_critical_power = resolvers.mbonus_material(30, 10),
-		combat_atk = resolvers.mbonus_material(10, 5),
-		combat_apr = resolvers.mbonus_material(10, 5),
-		inc_stealth = resolvers.mbonus_material(10, 5),
+		--combat_critical_power = resolvers.mbonus_material("combat_critical_power"),
+		combat_atk = resolvers.mbonus_material("combat_atk"),
+		combat_apr = resolvers.mbonus_material("combat_apr"),
+		inc_stealth = resolvers.mbonus_material("inc_stealth"),
 	},
 }
\ No newline at end of file
diff --git a/game/modules/tome/data/general/objects/egos/digger.lua b/game/modules/tome/data/general/objects/egos/digger.lua
index 1c41b21e1d..b35121137b 100644
--- a/game/modules/tome/data/general/objects/egos/digger.lua
+++ b/game/modules/tome/data/general/objects/egos/digger.lua
@@ -38,7 +38,7 @@ newEntity{
 	rarity = 6,
 	cost = 10,
 	wielder = {
-		inc_stats = { [Stats.STAT_STR] = resolvers.mbonus_material(4, 1) },
+		inc_stats = { [Stats.STAT_STR] = resolvers.mbonus_material("inc_stats") },
 	},
 }
 
@@ -51,10 +51,10 @@ newEntity{
 	rarity = 20,
 	cost = 20,
 	wielder = {
-		lite = 1,
+		lite = resolvers.mbonus_material("lite"),
 		inc_stats = {
-			[Stats.STAT_STR] = resolvers.mbonus_material(3, 1),
-			[Stats.STAT_CON] = resolvers.mbonus_material(3, 1),
+			[Stats.STAT_STR] = resolvers.mbonus_material("inc_stats"),
+			[Stats.STAT_CON] = resolvers.mbonus_material("inc_stats"),
 			},
 	},
 }
@@ -67,7 +67,7 @@ newEntity{
 	rarity = 6,
 	cost = 5,
 	wielder = {
-		fatigue = resolvers.mbonus_material(6, 4, function(e, v) return 0, -v end),
+		fatigue = resolvers.mbonus_material("fatigue"),
 	},
 }
 
@@ -79,7 +79,7 @@ newEntity{
 	rarity = 6,
 	cost = 5,
 	wielder = {
-		infravision = resolvers.mbonus_material(2, 1),
+		infravision = resolvers.mbonus_material("infravision"),
 	},
 }
 
@@ -91,7 +91,7 @@ newEntity{
 	rarity = 6,
 	cost = 5,
 	wielder = {
-		resists = { [DamageType.NATURE] = resolvers.mbonus_material(5, 10), },
+		resists = { [DamageType.NATURE] = resolvers.mbonus_material("resists"), },
 	},
 }
 
@@ -104,8 +104,8 @@ newEntity{
 	rarity = 15,
 	cost = 15,
 	wielder = {
-		max_life = resolvers.mbonus_material(20, 20),
-		max_stamina = resolvers.mbonus_material(15, 15),
+		max_life = resolvers.mbonus_material("max_life"),
+		max_stamina = resolvers.mbonus_material("max_stamina"),
 	},
 	resolvers.generic(function(e) e.digspeed = math.ceil(e.digspeed / 3) end),
 }
@@ -120,8 +120,8 @@ newEntity{
 	cost = 15,
 	wielder = {
 		resists={
-			[DamageType.FIRE] = resolvers.mbonus_material(5, 5),
-			[DamageType.DARKNESS] = resolvers.mbonus_material(5, 5),
+			[DamageType.FIRE] = resolvers.mbonus_material("resists"),
+			[DamageType.DARKNESS] = resolvers.mbonus_material("resists"),
 		},
 	},
 	resolvers.generic(function(e) e.digspeed = math.ceil(e.digspeed / 3) end),
@@ -136,9 +136,9 @@ newEntity{
 	rarity = 20,
 	cost = 70,
 	wielder = {
-		combat_dam = resolvers.mbonus_material(5, 5),
-		combat_apr = resolvers.mbonus_material(4, 4),
-		combat_critical_power = resolvers.mbonus_material(10, 10),
+		combat_dam = resolvers.mbonus_material("combat_dam", 2),
+		combat_apr = resolvers.mbonus_material("combat_apr"),
+		--combat_critical_power = resolvers.mbonus_material("combat_critical_power"),
 	},
 	resolvers.generic(function(e) e.digspeed = math.ceil(e.digspeed / 3) end),
 }
@@ -153,9 +153,9 @@ newEntity{
 	cost = 15,
 	wielder = {
 		inc_stats = {
-			[Stats.STAT_CUN] = resolvers.mbonus_material(2, 2),
+			[Stats.STAT_CUN] = resolvers.mbonus_material("inc_stats"),
 			},
-		confusion_immune = resolvers.mbonus_material(3, 2, function(e, v) v=v/10 return 0, v end),
+		confusion_immune = resolvers.mbonus_material("immunity"),
 	},
 	resolvers.generic(function(e) e.digspeed = math.ceil(e.digspeed / 3) end),
 }
@@ -169,8 +169,8 @@ newEntity{
 	rarity = 15,
 	cost = 15,
 	wielder = {
-		combat_def = resolvers.mbonus_material(4, 4),
-		combat_armor = resolvers.mbonus_material(3, 2),
+		combat_def = resolvers.mbonus_material("combat_def"),
+		combat_armor = resolvers.mbonus_material("combat_armor"),
 	},
 	resolvers.generic(function(e) e.digspeed = math.ceil(e.digspeed / 3) end),
 }
@@ -186,10 +186,10 @@ newEntity{
 	resolvers.generic(function(e) e.digspeed = math.ceil(e.digspeed / 2) end),
 	wielder = {
 		inc_stats = {
-			[Stats.STAT_STR] = resolvers.mbonus_material(7, 3),
+			[Stats.STAT_STR] = resolvers.mbonus_material("inc_stats", 2),
 		},
-		combat_physcrit = resolvers.mbonus_material(5, 1),
-		healing_factor = resolvers.mbonus_material(20, 10, function(e, v) v=v/100 return 0, -v end),
+		combat_physcrit = resolvers.mbonus_material("combat_physcrit"),
+		healing_factor = resolvers.mbonus_material("healing_factor", -1),
 	},
 }
 
@@ -203,10 +203,10 @@ newEntity{
 	cost = 40,
 	wielder = {
 		inc_stats = {
-			[Stats.STAT_CUN] = resolvers.mbonus_material(5, 1),
+			[Stats.STAT_CUN] = resolvers.mbonus_material("inc_stats"),
 		},
-		max_mana = resolvers.mbonus_material(40, 20),
-		combat_spellcrit = resolvers.mbonus_material(4, 1),
+		max_mana = resolvers.mbonus_material("max_mana"),
+		combat_spellcrit = resolvers.mbonus_material("combat_spellcrit"),
 	},
 }
 
@@ -221,7 +221,7 @@ newEntity{
 	resolvers.generic(function(e) e.digspeed = math.ceil(e.digspeed / 3) end),
 	wielder = {
 		resists_pen = {
-			[DamageType.PHYSICAL] = resolvers.mbonus_material(10, 5),
+			[DamageType.PHYSICAL] = resolvers.mbonus_material("resists_pen"),
 		},
 	},
 }
@@ -237,10 +237,10 @@ newEntity{
 	resolvers.generic(function(e) e.digspeed = math.ceil(e.digspeed / 2) end),
 	wielder = {
 		inc_stats = {
-			[Stats.STAT_CUN] = resolvers.mbonus_material(5, 1),
+			[Stats.STAT_CUN] = resolvers.mbonus_material("inc_stats"),
 		},
-		combat_atk = resolvers.mbonus_material(7, 3),
-		infravision = resolvers.mbonus_material(2, 1),
+		combat_atk = resolvers.mbonus_material("combat_atk"),
+		infravision = resolvers.mbonus_material("infravision"),
 	},
 }
 
@@ -254,13 +254,29 @@ newEntity{
 	cost = 60,
 	resolvers.generic(function(e) e.digspeed = math.ceil(e.digspeed / 2) end),
 	wielder = {
-		combat_mentalresist = resolvers.mbonus_material(7, 3),
-		combat_physresist = resolvers.mbonus_material(7, 3),
-		combat_spellresist = resolvers.mbonus_material(7, 3),
-		max_life = resolvers.mbonus_material(70, 40),
+		combat_mentalresist = resolvers.mbonus_material("save"),
+		--combat_physresist = resolvers.mbonus_material("save"),
+		--combat_spellresist = resolvers.mbonus_material("save"),
+		max_life = resolvers.mbonus_material("max_life"),
 	},
 }
-
+--[=[
+newEntity{
+	power_source = {technique=true},
+	name = " of avarice", suffix=true, instant_resolve=true,
+	level_range = {40, 50},
+	greater_ego = 1,
+	rarity = 45,
+	cost = 60,
+	resolvers.generic(function(e) e.digspeed = math.ceil(e.digspeed / 2) end),
+	wielder = {
+		blind_immune = resolvers.mbonus_material("immunity", -1),
+		combat_mentalresist = resolvers.mbonus_material("save", -1),
+		resource_leech_chance = resolvers.mbonus_material("resource_leech_chance"),
+		resource_leech_value = resolvers.mbonus_material("resource_leech_value"),
+	},	
+}
+]=]
 newEntity{
 	power_source = {arcane=true},
 	name = " of quickening", suffix=true, instant_resolve=true,
@@ -285,10 +301,10 @@ newEntity{
 	resolvers.generic(function(e) e.digspeed = math.ceil(e.digspeed / 2) end),
 	wielder = {
 		inc_stats = {
-			[Stats.STAT_DEX] = resolvers.mbonus_material(5, 1),
+			[Stats.STAT_DEX] = resolvers.mbonus_material("inc_stats"),
 		},
-		pin_immune = resolvers.mbonus_material(15, 10, function(e, v) v=v/100 return 0, v end),
-		combat_dam = resolvers.mbonus_material(7, 3),
+		pin_immune = resolvers.mbonus_material("immunity"),
+		combat_dam = resolvers.mbonus_material("combat_dam"),
 	},
 }
 
@@ -303,11 +319,11 @@ newEntity{
 	resolvers.generic(function(e) e.digspeed = math.ceil(e.digspeed / 2) end),
 	wielder = {
 		resists={
-			[DamageType.DARKNESS] = resolvers.mbonus_material(10, 5),
+			[DamageType.DARKNESS] = resolvers.mbonus_material("resists"),
 		},
-		blind_immune = resolvers.mbonus_material(15, 10, function(e, v) v=v/100 return 0, v end),
-		confusion_immune = resolvers.mbonus_material(15, 10, function(e, v) v=v/100 return 0, v end),
-		infravision = resolvers.mbonus_material(2, 1),
+		blind_immune = resolvers.mbonus_material("immunity"),
+		confusion_immune = resolvers.mbonus_material("immunity"),
+		infravision = resolvers.mbonus_material("infravision"),
 	},
 }
 
@@ -324,8 +340,8 @@ newEntity{
 	resolvers.generic(function(e) e.digspeed = math.ceil(e.digspeed / 2) end),
 	wielder = {
 		inc_stats = {
-			[Stats.STAT_STR] = resolvers.mbonus_material(5, 1),
+			[Stats.STAT_STR] = resolvers.mbonus_material("inc_stats"),
 		},
-		combat_apr = resolvers.mbonus_material(10, 5),
+		combat_apr = resolvers.mbonus_material("combat_apr"),
 	},
 }
diff --git a/game/modules/tome/data/general/objects/egos/gloves.lua b/game/modules/tome/data/general/objects/egos/gloves.lua
index b0f5000ae9..a971768b67 100644
--- a/game/modules/tome/data/general/objects/egos/gloves.lua
+++ b/game/modules/tome/data/general/objects/egos/gloves.lua
@@ -28,7 +28,7 @@ newEntity{
 	rarity = 5,
 	cost = 6,
 	wielder = {
-		disarm_bonus = resolvers.mbonus_material(25, 5),
+		disarm_bonus = resolvers.mbonus_material("disarm_bonus"),
 		combat = {
 			talent_on_hit = { [Talents.T_DISARM] = {level=2, chance=10} },
 		},
@@ -43,27 +43,25 @@ newEntity{
 	rarity = 9,
 	cost = 15,
 	wielder = {
-		combat_spellcrit = resolvers.mbonus_material(15, 5),
-		combat_physcrit = resolvers.mbonus_material(15, 5),
-		combat = {
-			physcrit = resolvers.mbonus_material(10, 4),
-		},
+		combat_spellcrit = resolvers.mbonus_material("combat_spellcrit"),
+		combat_physcrit = resolvers.mbonus_material("combat_physcrit"),
+		combat_mindcrit = resolvers.mbonus_material("combat_mindcrit"),
 	},
 }
 
 newEntity{
 	power_source = {technique=true},
-	name = " of mighty criticals", suffix=true, instant_resolve=true,
+	name = " of might", suffix=true, instant_resolve=true,
 	keywords = {critical=true},
 	level_range = {30, 50},
 	greater_ego = 1,
 	rarity = 12,
 	cost = 25,
 	wielder = {
-		combat_critical_power = resolvers.mbonus_material(35, 5),
+		combat_dam = resolvers.mbonus_material("combat_dam"),
 		combat = {
-			physcrit = resolvers.mbonus_material(10, 4),
-			dam = resolvers.mbonus_material(7, 3),
+			critical_power = resolvers.mbonus_material("critical_power"),
+			dam = resolvers.mbonus_material("dam"),
 			talent_on_hit = { [Talents.T_HAYMAKER] = {level=1, chance=10} },
 		},
 	},
@@ -71,30 +69,30 @@ newEntity{
 
 newEntity{
 	power_source = {technique=true},
-	name = " of attack", suffix=true, instant_resolve=true,
-	keywords = {attack=true},
+	name = " of precision", suffix=true, instant_resolve=true,
+	keywords = {precision=true},
 	level_range = {1, 50},
 	rarity = 5,
 	cost = 5,
 	wielder = {
-		combat_atk = resolvers.mbonus_material(15, 10),
+		combat_atk = resolvers.mbonus_material("combat_atk"),
 		combat = {
-			atk = resolvers.mbonus_material(10, 4),
+			max_acc = resolvers.mbonus_material("max_acc"),
 		},
 	},
 }
 
 newEntity{
 	power_source = {technique=true},
-	name = " of damage", suffix=true, instant_resolve=true,
-	keywords = {damage=true},
+	name = " of power", suffix=true, instant_resolve=true,
+	keywords = {power=true},
 	level_range = {10, 50},
 	rarity = 7,
 	cost = 10,
 	wielder = {
-		combat_dam = resolvers.mbonus_material(15, 5),
+		combat_dam = resolvers.mbonus_material("combat_dam"),
 		combat = {
-			dam = resolvers.mbonus_material(7, 3),
+			dam = resolvers.mbonus_material("dam"),
 		},
 	},
 }
@@ -107,10 +105,10 @@ newEntity{
 	rarity = 3,
 	cost = 5,
 	wielder = {
-		inc_damage={ [DamageType.FIRE] = resolvers.mbonus_material(8, 3), },
-		resists = { [DamageType.FIRE] = resolvers.mbonus_material(5, 5), },
+		inc_damage={ [DamageType.FIRE] = resolvers.mbonus_material("inc_damage"), },
+		resists = { [DamageType.FIRE] = resolvers.mbonus_material("resists"), },
 		combat = {
-			melee_project={[ DamageType.FIRE] = resolvers.mbonus_material(25, 4) },
+			melee_project={[ DamageType.FIRE] = resolvers.mbonus_material("melee_project") },
 		},
 	},
 }
@@ -123,10 +121,10 @@ newEntity{
 	rarity = 3,
 	cost = 5,
 	wielder = {
-		inc_damage={ [DamageType.COLD] = resolvers.mbonus_material(8, 3), },
-		resists = { [DamageType.COLD] = resolvers.mbonus_material(5, 5), },
+		inc_damage={ [DamageType.COLD] = resolvers.mbonus_material("inc_damage"), },
+		resists = { [DamageType.COLD] = resolvers.mbonus_material("resists"), },
 		combat = {
-			melee_project={ [DamageType.ICE] = resolvers.mbonus_material(15, 4) },
+			melee_project={ [DamageType.ICE] = resolvers.mbonus_material("melee_project") },
 		},
 	},
 }
@@ -139,10 +137,10 @@ newEntity{
 	rarity = 3,
 	cost = 5,
 	wielder = {
-		inc_damage={ [DamageType.ACID] = resolvers.mbonus_material(8, 3), },
-		resists = { [DamageType.ACID] = resolvers.mbonus_material(5, 5), },
+		inc_damage={ [DamageType.ACID] = resolvers.mbonus_material("inc_damage"), },
+		resists = { [DamageType.ACID] = resolvers.mbonus_material("resists"), },
 		combat = {
-			melee_project={ [DamageType.ACID] = resolvers.mbonus_material(25, 4) },
+			melee_project={ [DamageType.ACID] = resolvers.mbonus_material("melee_project") },
 		},
 	},
 }
@@ -155,10 +153,10 @@ newEntity{
 	rarity = 3,
 	cost = 5,
 	wielder = {
-		inc_damage={ [DamageType.LIGHTNING] = resolvers.mbonus_material(8, 3), },
-		resists = { [DamageType.LIGHTNING] = resolvers.mbonus_material(5, 5), },
+		inc_damage={ [DamageType.LIGHTNING] = resolvers.mbonus_material("inc_damage"), },
+		resists = { [DamageType.LIGHTNING] = resolvers.mbonus_material("resists"), },
 		combat = {
-			melee_project={ [DamageType.LIGHTNING] = resolvers.mbonus_material(25, 4) },
+			melee_project={ [DamageType.LIGHTNING] = resolvers.mbonus_material("melee_project") },
 		},
 	},
 }
@@ -171,10 +169,10 @@ newEntity{
 	rarity = 3,
 	cost = 5,
 	wielder = {
-		inc_damage={ [DamageType.TEMPORAL] = resolvers.mbonus_material(8, 3), },
-		resists = { [DamageType.TEMPORAL] = resolvers.mbonus_material(5, 5), },
+		inc_damage={ [DamageType.TEMPORAL] = resolvers.mbonus_material("inc_damage"), },
+		resists = { [DamageType.TEMPORAL] = resolvers.mbonus_material("resists"), },
 		combat = {
-			melee_project={ [DamageType.TEMPORAL] = resolvers.mbonus_material(15, 4) },
+			melee_project={ [DamageType.TEMPORAL] = resolvers.mbonus_material("melee_project") },
 		},
 	},
 }
@@ -187,10 +185,10 @@ newEntity{
 	rarity = 3,
 	cost = 5,
 	wielder = {
-		inc_damage={ [DamageType.NATURE] = resolvers.mbonus_material(8, 3), },
-		resists = { [DamageType.NATURE] = resolvers.mbonus_material(5, 5), },
+		inc_damage={ [DamageType.NATURE] = resolvers.mbonus_material("inc_damage"), },
+		resists = { [DamageType.NATURE] = resolvers.mbonus_material("resists"), },
 		combat = {
-			melee_project={ [DamageType.SLIME] = resolvers.mbonus_material(25, 4) },
+			melee_project={ [DamageType.SLIME] = resolvers.mbonus_material("melee_project") },
 		},
 	},
 }
@@ -203,25 +201,10 @@ newEntity{
 	rarity = 3,
 	cost = 5,
 	wielder = {
-		inc_damage={ [DamageType.BLIGHT] = resolvers.mbonus_material(8, 3), },
-		resists = { [DamageType.BLIGHT] = resolvers.mbonus_material(5, 5), },
-		combat = {
-			melee_project={ [DamageType.BLIGHT] = resolvers.mbonus_material(25, 4) },
-		},
-	},
-}
-
-newEntity{
-	power_source = {technique=true},
-	name = "powerful ", prefix=true, instant_resolve=true,
-	keywords = {powerful=true},
-	level_range = {1, 50},
-	rarity = 3,
-	cost = 5,
-	wielder = {
-		inc_damage={ [DamageType.PHYSICAL] = resolvers.mbonus_material(8, 3), },
+		inc_damage={ [DamageType.BLIGHT] = resolvers.mbonus_material("inc_damage"), },
+		resists = { [DamageType.BLIGHT] = resolvers.mbonus_material("resists"), },
 		combat = {
-			melee_project={ [DamageType.PHYSICAL] = resolvers.mbonus_material(25, 4) },
+			melee_project={ [DamageType.BLIGHT] = resolvers.mbonus_material("melee_project") },
 		},
 	},
 }
@@ -234,10 +217,9 @@ newEntity{
 	rarity = 6,
 	cost = 4,
 	wielder = {
-		inc_stats = { [Stats.STAT_STR] = resolvers.mbonus_material(4, 2) },
+		inc_stats = { [Stats.STAT_STR] = resolvers.mbonus_material("inc_stats") },
 		combat = {
-			dam = resolvers.mbonus_material(5, 1),
-			melee_project={ [DamageType.PHYSICAL] = resolvers.mbonus_material(15, 4) },
+			dam = resolvers.mbonus_material("dam"),
 		},
 	},
 }
@@ -250,10 +232,9 @@ newEntity{
 	rarity = 6,
 	cost = 4,
 	wielder = {
-		inc_stats = { [Stats.STAT_DEX] = resolvers.mbonus_material(4, 2) },
+		inc_stats = { [Stats.STAT_DEX] = resolvers.mbonus_material("inc_stats") },
 		combat = {
-			physcrit = resolvers.mbonus_material(8, 4),
-			atk = resolvers.mbonus_material(8, 4),
+			max_acc = resolvers.mbonus_material("max_acc"),
 		},
 	},
 }
@@ -266,9 +247,9 @@ newEntity{
 	rarity = 6,
 	cost = 4,
 	wielder = {
-		inc_stats = { [Stats.STAT_MAG] = resolvers.mbonus_material(4, 2) },
+		inc_stats = { [Stats.STAT_MAG] = resolvers.mbonus_material("inc_stats") },
 		combat = {
-			melee_project={ [DamageType.ARCANE] = resolvers.mbonus_material(15, 4) },
+			melee_project={ [DamageType.ARCANE] = resolvers.mbonus_material("melee_project") },
 		},
 	},
 }
@@ -281,9 +262,9 @@ newEntity{
 	rarity = 9,
 	cost = 15,
 	wielder = {
-		talents_types_mastery = { ["technique/grappling"] = 0.2},
-		inc_stats = { [Stats.STAT_STR] = resolvers.mbonus_material(2, 2) },
-		disarm_immune = resolvers.mbonus_material(4, 4, function(e, v) v=v/10 return 0, v end),
+		talents_types_mastery = { ["technique/grappling"] = resolvers.mbonus_material("talents_types_mastery")},
+		inc_stats = { [Stats.STAT_STR] = resolvers.mbonus_material("inc_stats") },
+		disarm_immune = resolvers.mbonus_material("immunity"),
 		combat = {
 			talent_on_hit = { [Talents.T_MAIM] = {level=2, chance=10} },
 		},
@@ -300,11 +281,9 @@ newEntity{
 	cost = 25,
 	wielder = {
 		resists={
-			[DamageType.NATURE] = resolvers.mbonus_material(5, 5),
+			[DamageType.NATURE] = resolvers.mbonus_material("resists"),
 		},
-		combat_mentalresist = resolvers.mbonus_material(7, 3),
-		combat_physresist = resolvers.mbonus_material(7, 3),
-		combat_spellresist = resolvers.mbonus_material(7, 3),
+		combat_physresist = resolvers.mbonus_material("save", 2),
 		combat = {
 			talent_on_hit = { [Talents.T_HEALING_NEXUS] = {level=1, chance=10} },
 		},
@@ -321,13 +300,12 @@ newEntity{
 	cost = 35,
 	wielder = {
 		inc_stats = {
-			[Stats.STAT_STR] = resolvers.mbonus_material(3, 2),
-			[Stats.STAT_DEX] = resolvers.mbonus_material(3, 2),
+			[Stats.STAT_STR] = resolvers.mbonus_material("inc_stats"),
+			[Stats.STAT_DEX] = resolvers.mbonus_material("inc_stats"),
 			},
-		combat_apr = resolvers.mbonus_material(4, 4),
+		combat_apr = resolvers.mbonus_material("combat_apr"),
 		combat = {
-			physcrit = resolvers.mbonus_material(10, 4),
-			melee_project={ [DamageType.PHYSICAL] = resolvers.mbonus_material(25, 4) },
+			critical_power = resolvers.mbonus_material("critical_power"),
 			talent_on_hit = { [Talents.T_BATTLE_CALL] = {level=1, chance=10} },
 		},
 	},
@@ -343,9 +321,9 @@ newEntity{
 	rarity = 18,
 	cost = 25,
 	wielder = {
-		life_regen = resolvers.mbonus_material(15, 5, function(e, v) v=v/10 return 0, v end),
-		mana_regen = resolvers.mbonus_material(30, 10, function(e, v) v=v/100 return 0, v end),
-		stamina_regen = resolvers.mbonus_material(10, 3, function(e, v) v=v/10 return 0, v end),
+		life_regen = resolvers.mbonus_material("life_regen"),
+		mana_regen = resolvers.mbonus_material("mana_regen"),
+		stamina_regen = resolvers.mbonus_material("stamina_regen"),
 		combat = {
 			talent_on_hit = { [Talents.T_SECOND_WIND] = {level=1, chance=10} },
 		},
@@ -362,14 +340,13 @@ newEntity{
 	cost = 75,
 	wielder = {
 		resists={
-			[DamageType.FIRE] = resolvers.mbonus_material(10, 5),
-			[DamageType.COLD] = resolvers.mbonus_material(10, 5),
+			[DamageType.FIRE] = resolvers.mbonus_material("resists"),
+			[DamageType.COLD] = resolvers.mbonus_material("resists"),
 		},
-		max_life=resolvers.mbonus_material(40, 40),
-		combat_armor = resolvers.mbonus_material(3, 3),
+		max_life=resolvers.mbonus_material("max_life"),
+		combat_armor = resolvers.mbonus_material("combat_armor"),
 		combat = {
-			dam = resolvers.mbonus_material(7, 3),
-			atk = resolvers.mbonus_material(10, 2),
+			dam = resolvers.mbonus_material("combat_dam"),
 			talent_on_hit = { [Talents.T_BATTLE_SHOUT] = {level=1, chance=10} },
 		},
 	},
@@ -385,17 +362,17 @@ newEntity{
 	cost = 35,
 	wielder = {
 		inc_stats = {
-			[Stats.STAT_MAG] = resolvers.mbonus_material(3, 2),
-			[Stats.STAT_WIL] = resolvers.mbonus_material(3, 2),
+			[Stats.STAT_MAG] = resolvers.mbonus_material("inc_stats"),
+			[Stats.STAT_WIL] = resolvers.mbonus_material("inc_stats"),
 			},
-		blind_immune = resolvers.mbonus_material(15, 10, function(e, v) v=v/100 return 0, v end),
-		confusion_immune = resolvers.mbonus_material(15, 10, function(e, v) v=v/100 return 0, v end),
+		blind_immune = resolvers.mbonus_material("immunity"),
+		confusion_immune = resolvers.mbonus_material("immunity"),
 		combat = {
 			melee_project={
-				[DamageType.FIRE] = resolvers.mbonus_material(25, 4),
-				[DamageType.ICE] = resolvers.mbonus_material(15, 4),
-				[DamageType.ACID] = resolvers.mbonus_material(25, 4),
-				[DamageType.LIGHTNING] = resolvers.mbonus_material(25, 4),
+				[DamageType.FIRE] = resolvers.mbonus_material("melee_project", 0.5),
+				[DamageType.ICE] = resolvers.mbonus_material("melee_project", 0.5),
+				[DamageType.ACID] = resolvers.mbonus_material("melee_project", 0.5),
+				[DamageType.LIGHTNING] = resolvers.mbonus_material("melee_project", 0.5),
 			},
 			talent_on_hit = { [Talents.T_STONE_TOUCH] = {level=1, chance=10} },
 		},
@@ -413,13 +390,12 @@ newEntity{
 	cost = 35,
 	wielder = {
 		inc_stats = {
-			[Stats.STAT_DEX] = resolvers.mbonus_material(3, 2),
-			[Stats.STAT_CUN] = resolvers.mbonus_material(3, 2),
+			[Stats.STAT_DEX] = resolvers.mbonus_material("inc_stats"),
+			[Stats.STAT_CUN] = resolvers.mbonus_material("inc_stats"),
 		},
-		combat_atk = resolvers.mbonus_material(5, 5),
+		combat_atk = resolvers.mbonus_material("combat_atk"),
 		combat = {
-			apr = resolvers.mbonus_material(8, 1),
-			atk = resolvers.mbonus_material(10, 2),
+			max_acc = resolvers.mbonus_material("max_acc"),
 		},
 	},
 }
@@ -435,14 +411,13 @@ newEntity{
 	wielder = {
 		talent_cd_reduction={ [Talents.T_DOUBLE_STRIKE]=1,	},
 		inc_stats = {
-			[Stats.STAT_STR] = resolvers.mbonus_material(3, 2),
-			[Stats.STAT_DEX] = resolvers.mbonus_material(3, 2),
-			[Stats.STAT_CUN] = resolvers.mbonus_material(3, 2),
+			[Stats.STAT_STR] = resolvers.mbonus_material("inc_stats"),
+			[Stats.STAT_DEX] = resolvers.mbonus_material("inc_stats"),
+			[Stats.STAT_CUN] = resolvers.mbonus_material("inc_stats"),
 		},
 		combat = {
-			physcrit = resolvers.mbonus_material(10, 4),
-			atk = resolvers.mbonus_material(10, 2),
-			physspeed = -0.1,
+			critical_power = resolvers.mbonus_material("critical_power"),
+			physspeed = resolvers.mbonus_material("combat_physspeed"),
 		},
 	},
 }
@@ -457,14 +432,14 @@ newEntity{
 	cost = 90,
 	wielder = {
 		resists={
-			[DamageType.PHYSICAL] = resolvers.mbonus_material(7, 3),
+			[DamageType.PHYSICAL] = resolvers.mbonus_material("rare_resists"),
 		},
 		inc_stats = {
-			[Stats.STAT_DEX] = resolvers.mbonus_material(5, 1, function(e, v) return 0, -v end),
-			[Stats.STAT_CON] = resolvers.mbonus_material(5, 1),
+			[Stats.STAT_DEX] = resolvers.mbonus_material("inc_stats", -1),
+			[Stats.STAT_CON] = resolvers.mbonus_material("inc_stats"),
 		},
-		combat_armor = resolvers.mbonus_material(7, 3),
-		combat_atk = resolvers.mbonus_material(10, 5, function(e, v) return 0, -v end),
+		combat_armor = resolvers.mbonus_material("combat_armor"),
+		combat_atk = resolvers.mbonus_material("combat_atk", -1),
 		combat = {
 			talent_on_hit = { [Talents.T_UNSTOPPABLE] = {level=1, chance=5} },
 		},
@@ -483,13 +458,13 @@ newEntity{
 	use_talent = { id = Talents.T_DISPERSE_MAGIC, level = 3, power = 80 },
 	wielder = {
 		resists={
-			[DamageType.ARCANE] = resolvers.mbonus_material(7, 3),
+			[DamageType.ARCANE] = resolvers.mbonus_material("rare_resists"),
 		},
 		inc_stats = {
-			[Stats.STAT_MAG] = resolvers.mbonus_material(7, 3),
+			[Stats.STAT_MAG] = resolvers.mbonus_material("inc_stats"),
 		},
 		combat = {
-			melee_project={  [DamageType.ARCANE] = resolvers.mbonus_material(15, 4), },
+			melee_project={  [DamageType.ARCANE] = resolvers.mbonus_material("melee_project"), },
 			talent_on_hit = { [Talents.T_MANATHRUST] = {level=3, chance=10} },
 		},
 	},
@@ -505,16 +480,15 @@ newEntity{
 	cost = 60,
 	wielder = {
 		resists={
-			[DamageType.BLIGHT] = resolvers.mbonus_material(10, 5),
+			[DamageType.BLIGHT] = resolvers.mbonus_material("resists"),
 		},
-		poison_immune = resolvers.mbonus_material(15, 10, function(e, v) v=v/100 return 0, v end),
-		disease_immune = resolvers.mbonus_material(15, 10, function(e, v) v=v/100 return 0, v end),
-		combat_atk = resolvers.mbonus_material(7, 3),
-		combat_dam = resolvers.mbonus_material(7, 1),
+		poison_immune = resolvers.mbonus_material("immunity"),
+		disease_immune = resolvers.mbonus_material("immunity"),
+		combat_dam = resolvers.mbonus_material("combat_dam"),
 		combat = {
 			melee_project={
-				[DamageType.SLIME] = resolvers.mbonus_material(15, 3),
-				[DamageType.ACID] = resolvers.mbonus_material(24, 4),
+				[DamageType.SLIME] = resolvers.mbonus_material("melee_project"),
+				[DamageType.ACID] = resolvers.mbonus_material("melee_project"),
 			},
 		},
 	},
@@ -532,13 +506,11 @@ newEntity{
 	use_talent = { id = Talents.T_JUGGERNAUT, level = 4, power = 80 },
 	wielder = {
 		inc_stats = {
-			[Stats.STAT_CON] = resolvers.mbonus_material(5, 1),
+			[Stats.STAT_CON] = resolvers.mbonus_material("inc_stats"),
 		},
-		combat_mentalresist = resolvers.mbonus_material(7, 3),
-		combat_physresist = resolvers.mbonus_material(7, 3),
-		combat_spellresist = resolvers.mbonus_material(7, 3),
+		combat_physresist = resolvers.mbonus_material("save"),
+		combat_spellresist = resolvers.mbonus_material("save"),
 		combat = {
-			melee_project={ [DamageType.PHYSICAL] = resolvers.mbonus_material(25, 4), },
 			talent_on_hit = { [Talents.T_JUGGERNAUT] = {level=1, chance=10} },
 		},
 	},
@@ -556,13 +528,12 @@ newEntity{
 	use_talent = { id = Talents.T_TRACK, level = 2, power = 80 },
 	wielder = {
 		inc_stats = {
-			[Stats.STAT_DEX] = resolvers.mbonus_material(5, 1),
+			[Stats.STAT_DEX] = resolvers.mbonus_material("inc_stats"),
 		},
-		combat_atk = resolvers.mbonus_material(7, 3),
+		combat_atk = resolvers.mbonus_material("combat_atk"),
 		combat = {
-			physcrit = resolvers.mbonus_material(8, 4),
-			atk = resolvers.mbonus_material(8, 4),
-			inc_damage_type = {animal=25},
+			max_acc = resolvers.mbonus_material("max_acc"),
+			inc_damage_type = {animal=resolvers.mbonus_material("inc_damage_type"),},
 		},
 	},
 }
@@ -577,15 +548,15 @@ newEntity{
 	cost = 40,
 	wielder = {
 		resists={
-			[DamageType.DARKNESS] = resolvers.mbonus_material(10, 5),
+			[DamageType.DARKNESS] = resolvers.mbonus_material("resists"),
 		},
 		inc_stats = {
-			[Stats.STAT_CUN] = resolvers.mbonus_material(5, 1),
+			[Stats.STAT_CUN] = resolvers.mbonus_material("inc_stats"),
 		},
-		blind_immune = resolvers.mbonus_material(15, 10, function(e, v) v=v/100 return 0, v end),
-		infravision = resolvers.mbonus_material(1, 1),
+		blind_immune = resolvers.mbonus_material("immunity"),
+		infravision = resolvers.mbonus_material("infravision"),
 		combat = {
-			melee_project={ [DamageType.DARKNESS] = resolvers.mbonus_material(25, 4), },
+			melee_project={ [DamageType.DARKNESS] = resolvers.mbonus_material("melee_project"), },
 			talent_on_hit = { [Talents.T_SHADOWSTEP] = {level=3, chance=10} },
 		},
 	},
@@ -601,12 +572,12 @@ newEntity{
 	cost = 30,
 	wielder = {
 		inc_stats = {
-			[Stats.STAT_WIL] = resolvers.mbonus_material(5, 1),
+			[Stats.STAT_WIL] = resolvers.mbonus_material("inc_stats"),
 		},
-		combat_spellpower = resolvers.mbonus_material(7, 1),
-		combat_spellcrit = resolvers.mbonus_material(4, 1),
+		combat_spellpower = resolvers.mbonus_material("combat_spellpower"),
+		combat_spellcrit = resolvers.mbonus_material("combat_spellcrit"),
 		combat = {
-			melee_project={  [DamageType.ARCANE] = resolvers.mbonus_material(15, 4), },
+			melee_project={  [DamageType.ARCANE] = resolvers.mbonus_material("melee_project"), },
 			talent_on_hit = { [Talents.T_ELEMENTAL_BOLT] = {level=3, chance=10} },
 		},
 	},
@@ -621,18 +592,21 @@ newEntity{
 	rarity = 50,
 	cost = 100,
 	wielder = {
-		melee_project = {
-			[DamageType.ACID] = resolvers.mbonus_material(7, 3),
-			[DamageType.LIGHTNING] = resolvers.mbonus_material(7, 3),
-			[DamageType.FIRE] = resolvers.mbonus_material(7, 3),
-			[DamageType.COLD] = resolvers.mbonus_material(7, 3),
+		learn_talent = {
+			[Talents.T_WARD] = resolvers.mbonus_material("learn_talent"),
+		},
+		wards = {
+			[DamageType.ACID] = resolvers.mbonus_material("wards"),
+			[DamageType.LIGHTNING] = resolvers.mbonus_material("wards"),
+			[DamageType.FIRE] = resolvers.mbonus_material("wards"),
+			[DamageType.COLD] = resolvers.mbonus_material("wards"),	
 		},
 		combat = {
 			melee_project={
-				[DamageType.FIRE] = resolvers.mbonus_material(25, 4),
-				[DamageType.ICE] = resolvers.mbonus_material(15, 4),
-				[DamageType.ACID] = resolvers.mbonus_material(25, 4),
-				[DamageType.LIGHTNING] = resolvers.mbonus_material(25, 4),
+				[DamageType.FIRE] = resolvers.mbonus_material("melee_project"),
+				[DamageType.ICE] = resolvers.mbonus_material("melee_project"),
+				[DamageType.ACID] = resolvers.mbonus_material("melee_project"),
+				[DamageType.LIGHTNING] = resolvers.mbonus_material("melee_project"),
 			},
 		},
 	},
@@ -648,13 +622,13 @@ newEntity{
 	cost = 60,
 	wielder = {
 		inc_stats = {
-			[Stats.STAT_DEX] = resolvers.mbonus_material(7, 3),
+			[Stats.STAT_DEX] = resolvers.mbonus_material("inc_stats"),
 		},
-		stun_immune = resolvers.mbonus_material(15, 10, function(e, v) v=v/100 return 0, v end),
-		knockback_immune = resolvers.mbonus_material(15, 10, function(e, v) v=v/100 return 0, v end),
-		pin_immune = resolvers.mbonus_material(15, 10, function(e, v) v=v/100 return 0, v end),
+		stun_immune = resolvers.mbonus_material("immunity"),
+		knockback_immune = resolvers.mbonus_material("immunity"),
+		pin_immune = resolvers.mbonus_material("immunity"),
 		combat = {
-			melee_project={ [DamageType.PHYSICAL] = resolvers.mbonus_material(25, 4), },
+			critical_power = resolvers.mbonus_material("critical_power"),
 			talent_on_hit = { [Talents.T_SET_UP] = {level=1, chance=10} },
 		},
 	},
diff --git a/game/modules/tome/data/general/objects/egos/heavy-armor.lua b/game/modules/tome/data/general/objects/egos/heavy-armor.lua
index 610797ba9d..b6c5080b4d 100644
--- a/game/modules/tome/data/general/objects/egos/heavy-armor.lua
+++ b/game/modules/tome/data/general/objects/egos/heavy-armor.lua
@@ -30,7 +30,7 @@ newEntity{
 	rarity = 8,
 	cost = 7,
 	wielder = {
-		combat_armor = resolvers.mbonus_material(12, 3),
+		combat_armor = resolvers.mbonus_material("combat_armor"),
 	},
 }
 
@@ -44,16 +44,16 @@ newEntity{
 	cost = 80,
 	wielder = {
 		resists={
-			[DamageType.FIRE] = resolvers.mbonus_material(10, 5),
-			[DamageType.LIGHT] = resolvers.mbonus_material(10, 10, function(e, v) return 0, -v end),
-			[DamageType.DARKNESS] = resolvers.mbonus_material(10, 5),
+			[DamageType.FIRE] = resolvers.mbonus_material("resists"),
+			[DamageType.LIGHT] = resolvers.mbonus_material("resists", -1),
+			[DamageType.DARKNESS] = resolvers.mbonus_material("resists"),
 		},
 		inc_stats = {
-			[Stats.STAT_CON] = resolvers.mbonus_material(5, 5),
+			[Stats.STAT_CON] = resolvers.mbonus_material("inc_stats", 2),
 		},
-		combat_mentalresist = resolvers.mbonus_material(5, 5),
-		combat_physresist = resolvers.mbonus_material(5, 5),
-		combat_spellresist = resolvers.mbonus_material(5, 5),
-		fatigue = resolvers.mbonus_material(10, 5),
-	},	
-}
\ No newline at end of file
+		combat_mentalresist = resolvers.mbonus_material("save", 2),
+		--combat_physresist = resolvers.mbonus_material(5, 5),
+		--combat_spellresist = resolvers.mbonus_material(5, 5),
+		fatigue = resolvers.mbonus_material("fatigue", -1),
+	},
+}
diff --git a/game/modules/tome/data/general/objects/egos/helm.lua b/game/modules/tome/data/general/objects/egos/helm.lua
index 20bec90f79..3324c1431a 100644
--- a/game/modules/tome/data/general/objects/egos/helm.lua
+++ b/game/modules/tome/data/general/objects/egos/helm.lua
@@ -33,7 +33,7 @@ newEntity{
 	rarity = 6,
 	cost = 4,
 	wielder = {
-		inc_stats = { [Stats.STAT_STR] = resolvers.mbonus_material(8, 2) },
+		inc_stats = { [Stats.STAT_STR] = resolvers.mbonus_material("inc_stats") },
 	},
 }
 newEntity{
@@ -44,7 +44,7 @@ newEntity{
 	rarity = 6,
 	cost = 4,
 	wielder = {
-		inc_stats = { [Stats.STAT_CON] = resolvers.mbonus_material(8, 2) },
+		inc_stats = { [Stats.STAT_CON] = resolvers.mbonus_material("inc_stats") },
 	},
 }
 newEntity{
@@ -55,7 +55,7 @@ newEntity{
 	rarity = 6,
 	cost = 4,
 	wielder = {
-		inc_stats = { [Stats.STAT_DEX] = resolvers.mbonus_material(8, 2) },
+		inc_stats = { [Stats.STAT_DEX] = resolvers.mbonus_material("inc_stats") },
 	},
 }
 newEntity{
@@ -78,9 +78,9 @@ newEntity{
 	rarity = 10,
 	cost = 10,
 	wielder = {
-		inc_stats = { [Stats.STAT_WIL] = resolvers.mbonus_material(2, 1) },
-		disease_immune = resolvers.mbonus_material(15, 10, function(e, v) return 0, v/100 end),
-		stun_immune = resolvers.mbonus_material(2, 2, function(e, v) v=v/10 return 0, v end),
+		inc_stats = { [Stats.STAT_WIL] = resolvers.mbonus_material("inc_stats") },
+		disease_immune = resolvers.mbonus_material("immunity"),
+		stun_immune = resolvers.mbonus_material("immunity"),
 	},
 }
 newEntity{
@@ -92,8 +92,8 @@ newEntity{
 	cost = 7,
 	wielder = {
 		resists={
-			[DamageType.LIGHT] = resolvers.mbonus_material(10, 10),
-			[DamageType.DARKNESS] = resolvers.mbonus_material(10, 10),
+			[DamageType.LIGHT] = resolvers.mbonus_material("resists"),
+			[DamageType.DARKNESS] = resolvers.mbonus_material("resists"),
 		},
 	},
 }
@@ -107,9 +107,9 @@ newEntity{
 	rarity = 18,
 	cost = 25,
 	wielder = {
-		combat_atk = resolvers.mbonus_material(4, 2),
-		combat_def = resolvers.mbonus_material(4, 2),
-		inc_stats = { [Stats.STAT_CUN] = 4, },
+		combat_atk = resolvers.mbonus_material("combat_atk"),
+		combat_def = resolvers.mbonus_material("combat_def"),
+		inc_stats = { [Stats.STAT_CUN] = resolvers.mbonus_material("inc_stats") },
 	},
 }
 
@@ -133,9 +133,9 @@ newEntity{
 	rarity = 10,
 	cost = 20,
 	wielder = {
-		stamina_regen_on_hit = resolvers.mbonus_material(23, 7, function(e, v) v=v/10 return 0, v end),
-		equilibrium_regen_on_hit = resolvers.mbonus_material(23, 7, function(e, v) v=v/10 return 0, v end),
-		mana_regen_on_hit = resolvers.mbonus_material(23, 7, function(e, v) v=v/10 return 0, v end),
+		stamina_regen_on_hit = resolvers.mbonus_material("stamina_regen_on_hit"),
+		equilibrium_regen_on_hit = resolvers.mbonus_material("equilibrium_regen_on_hit"),
+		mana_regen_on_hit = resolvers.mbonus_material("mana_regen_on_hit"),
 	},
 }
 
@@ -147,8 +147,8 @@ newEntity{
 	rarity = 6,
 	cost = 5,
 	wielder = {
-		infravision = resolvers.mbonus_material(3, 1),
-		combat_armor = resolvers.mbonus_material(5, 1),
+		infravision = resolvers.mbonus_material("infravision"),
+		combat_armor = resolvers.mbonus_material("combat_armor"),
 	},
 }
 
@@ -161,8 +161,8 @@ newEntity{
 	cost = 5,
 	wielder = {
 		resists={
-			[DamageType.FIRE] = resolvers.mbonus_material(10, 5),
-			[DamageType.COLD] = resolvers.mbonus_material(10, 5),
+			[DamageType.FIRE] = resolvers.mbonus_material("resists"),
+			[DamageType.COLD] = resolvers.mbonus_material("resists"),
 		},
 	},
 }
@@ -176,9 +176,9 @@ newEntity{
 	cost = 5,
 	wielder = {
 		resists={
-			[DamageType.LIGHTNING] = resolvers.mbonus_material(10, 5),
+			[DamageType.LIGHTNING] = resolvers.mbonus_material("resists"),
 		},
-		stun_immune = resolvers.mbonus_material(20, 10, function(e, v) v=v/100 return 0, v end),
+		stun_immune = resolvers.mbonus_material("immunity"),
 	},
 }
 
@@ -191,9 +191,9 @@ newEntity{
 	cost = 5,
 	wielder = {
 		resists={
-			[DamageType.TEMPORAL] = resolvers.mbonus_material(10, 5),
+			[DamageType.TEMPORAL] = resolvers.mbonus_material("resists"),
 		},
-		teleport_immune = resolvers.mbonus_material(20, 10, function(e, v) v=v/100 return 0, v end),
+		teleport_immune = resolvers.mbonus_material("immunity"),
 	},
 }
 
@@ -205,8 +205,8 @@ newEntity{
 	rarity = 6,
 	cost = 5,
 	wielder = {
-		stun_immune = resolvers.mbonus_material(20, 10, function(e, v) v=v/100 return 0, v end),
-		knockback_immune = resolvers.mbonus_material(20, 10, function(e, v) v=v/100 return 0, v end),
+		stun_immune = resolvers.mbonus_material("immunity"),
+		knockback_immune = resolvers.mbonus_material("immunity"),
 	},
 }
 
@@ -219,10 +219,10 @@ newEntity{
 	cost = 9,
 	wielder = {
 		resists={
-			[DamageType.ACID] = resolvers.mbonus_material(10, 5),
+			[DamageType.ACID] = resolvers.mbonus_material("resists"),
 		},
-		poison_immune = resolvers.mbonus_material(10, 5, function(e, v) return 0, v/100 end),
-		disease_immune = resolvers.mbonus_material(10, 5, function(e, v) return 0, v/100 end),
+		poison_immune = resolvers.mbonus_material("immunity"),
+		disease_immune = resolvers.mbonus_material("immunity"),
 	},
 }
 
@@ -236,10 +236,10 @@ newEntity{
 	rarity = 15,
 	cost = 20,
 	wielder = {
-		combat_spellcrit = resolvers.mbonus_material(3, 3),
+		combat_spellcrit = resolvers.mbonus_material("combat_spellcrit"),
 		inc_stats = {
-			[Stats.STAT_MAG] = resolvers.mbonus_material(3, 2),
-			[Stats.STAT_WIL] = resolvers.mbonus_material(3, 2),
+			[Stats.STAT_MAG] = resolvers.mbonus_material("inc_stats"),
+			[Stats.STAT_WIL] = resolvers.mbonus_material("inc_stats"),
 			},
 	},
 }
@@ -254,10 +254,10 @@ newEntity{
 	rarity = 15,
 	cost = 20,
 	wielder = {
-		combat_physcrit = resolvers.mbonus_material(3, 3),
+		combat_physcrit = resolvers.mbonus_material("combat_physcrit"),
 		inc_stats = {
-			[Stats.STAT_STR] = resolvers.mbonus_material(3, 2),
-			[Stats.STAT_CON] = resolvers.mbonus_material(3, 2),
+			[Stats.STAT_STR] = resolvers.mbonus_material("inc_stats"),
+			[Stats.STAT_CON] = resolvers.mbonus_material("inc_stats"),
 			},
 	},
 }
@@ -271,10 +271,10 @@ newEntity{
 	rarity = 13,
 	cost = 20,
 	wielder = {
-		combat_apr = resolvers.mbonus_material(4, 4),
+		combat_apr = resolvers.mbonus_material("combat_apr"),
 		inc_stats = {
-			[Stats.STAT_DEX] = resolvers.mbonus_material(3, 2),
-			[Stats.STAT_CUN] = resolvers.mbonus_material(3, 2),
+			[Stats.STAT_DEX] = resolvers.mbonus_material("inc_stats"),
+			[Stats.STAT_CUN] = resolvers.mbonus_material("inc_stats"),
 			},
 	},
 }
@@ -288,10 +288,10 @@ newEntity{
 	rarity = 17,
 	cost = 50,
 	wielder = {
-		combat_dam = resolvers.mbonus_material(6, 6),
-		pin_immune = resolvers.mbonus_material(3, 3, function(e, v) v=v/10 return 0, v end),
+		combat_dam = resolvers.mbonus_material("combat_dam"),
+		pin_immune = resolvers.mbonus_material("immunity"),
 		inc_stats = {
-			[Stats.STAT_WIL] = resolvers.mbonus_material(4, 3),
+			[Stats.STAT_WIL] = resolvers.mbonus_material("inc_stats"),
 			},
 	},
 }
@@ -305,9 +305,9 @@ newEntity{
 	rarity = 17,
 	cost = 50,
 	wielder = {
-		combat_armor = resolvers.mbonus_material(5, 4),
-		combat_def = resolvers.mbonus_material(4, 4),
-		combat_physresist = resolvers.mbonus_material(7, 3),
+		combat_armor = resolvers.mbonus_material("combat_armor"),
+		combat_def = resolvers.mbonus_material("combat_def"),
+		combat_physresist = resolvers.mbonus_material("save"),
 	},
 }
 
@@ -321,10 +321,10 @@ newEntity{
 	cost = 50,
 	wielder = {
 		resists={
-			[DamageType.ACID] = resolvers.mbonus_material(10, 5),
-			[DamageType.LIGHTNING] = resolvers.mbonus_material(10, 5),
-			[DamageType.FIRE] = resolvers.mbonus_material(10, 5),
-			[DamageType.COLD] = resolvers.mbonus_material(10, 5),
+			[DamageType.ACID] = resolvers.mbonus_material("resists"),
+			[DamageType.LIGHTNING] = resolvers.mbonus_material("resists"),
+			[DamageType.FIRE] = resolvers.mbonus_material("resists"),
+			[DamageType.COLD] = resolvers.mbonus_material("resists"),
 		},
 	},
 }
@@ -339,15 +339,15 @@ newEntity{
 	cost = 80,
 	wielder = {
 		resists={
-			[DamageType.LIGHT] = resolvers.mbonus_material(25, 15, function(e, v) return 0, -v end),
+			[DamageType.LIGHT] = resolvers.mbonus_material("resists", -1),
 		},
 		inc_stats = {
-			[Stats.STAT_STR] = resolvers.mbonus_material(4, 1),
-			[Stats.STAT_DEX] = resolvers.mbonus_material(4, 1),
-			[Stats.STAT_CON] = resolvers.mbonus_material(4, 1),
-			[Stats.STAT_CUN] = resolvers.mbonus_material(4, 1),
+			[Stats.STAT_STR] = resolvers.mbonus_material("inc_stats"),
+			[Stats.STAT_DEX] = resolvers.mbonus_material("inc_stats"),
+			[Stats.STAT_CON] = resolvers.mbonus_material("inc_stats"),
+			[Stats.STAT_CUN] = resolvers.mbonus_material("inc_stats"),
 		},
-		life_regen = resolvers.mbonus_material(30, 5, function(e, v) v=v/10 return 0, v end),
+		life_regen = resolvers.mbonus_material("life_regen"),
 	},
 }
 
@@ -361,11 +361,11 @@ newEntity{
 	cost = 40,
 	wielder = {
 		resists={
-			[DamageType.MIND] = resolvers.mbonus_material(15, 5),
+			[DamageType.MIND] = resolvers.mbonus_material("rare_resists"),
 		},
-		blind_immune = resolvers.mbonus_material(15, 10, function(e, v) v=v/100 return 0, v end),
-		confusion_immune = resolvers.mbonus_material(15, 10, function(e, v) v=v/100 return 0, v end),
-		combat_mentalresist = resolvers.mbonus_material(7, 3),
+		blind_immune = resolvers.mbonus_material("immunity"),
+		confusion_immune = resolvers.mbonus_material("immunity"),
+		combat_mentalresist = resolvers.mbonus_material("save"),
 	},
 }
 
@@ -379,11 +379,11 @@ newEntity{
 	cost = 30,
 	wielder = {
 		inc_stats = {
-			[Stats.STAT_STR] = resolvers.mbonus_material(5, 1),
-			[Stats.STAT_WIL] = resolvers.mbonus_material(5, 1),
+			[Stats.STAT_STR] = resolvers.mbonus_material("inc_stats"),
+			[Stats.STAT_WIL] = resolvers.mbonus_material("inc_stats"),
 		},
-		confusion_immune = resolvers.mbonus_material(15, 10, function(e, v) v=v/100 return 0, v end),
-		lite = resolvers.mbonus_material(1, 1),
+		confusion_immune = resolvers.mbonus_material("immunity"),
+		lite = resolvers.mbonus_material("lite"),
 	},
 }
 
@@ -397,12 +397,12 @@ newEntity{
 	cost = 80,
 	wielder = {
 		resists={
-			[DamageType.NATURE] = resolvers.mbonus_material(10, 5),
+			[DamageType.NATURE] = resolvers.mbonus_material("resists"),
 		},
-		poison_immune = resolvers.mbonus_material(15, 10, function(e, v) v=v/100 return 0, v end),
-		disease_immune = resolvers.mbonus_material(15, 10, function(e, v) v=v/100 return 0, v end),
-		max_life = resolvers.mbonus_material(70, 40),
-		healing_factor = resolvers.mbonus_material(20, 10, function(e, v) v=v/100 return 0, v end),
+		poison_immune = resolvers.mbonus_material("immunity"),
+		disease_immune = resolvers.mbonus_material("immunity"),
+		max_life = resolvers.mbonus_material("max_life"),
+		healing_factor = resolvers.mbonus_material("healing_factor"),
 	},
 }
 
@@ -416,12 +416,12 @@ newEntity{
 	cost = 40,
 	wielder = {
 		resists={
-			[DamageType.DARKNESS] = resolvers.mbonus_material(10, 5),
+			[DamageType.DARKNESS] = resolvers.mbonus_material("resists"),
 		},
 		inc_stats = {
-			[Stats.STAT_DEX] = resolvers.mbonus_material(7, 3),
+			[Stats.STAT_DEX] = resolvers.mbonus_material("inc_stats"),
 		},
-		infravision = resolvers.mbonus_material(3, 1),
+		infravision = resolvers.mbonus_material("infravision"),
 	},
 }
 
@@ -435,16 +435,16 @@ newEntity{
 	cost = 100,
 	wielder = {
 		inc_stats = {
-			[Stats.STAT_CON] = resolvers.mbonus_material(10, 5, function(e, v) return 0, -v end),
-			[Stats.STAT_MAG] = resolvers.mbonus_material(5, 3),
-			[Stats.STAT_WIL] = resolvers.mbonus_material(5, 3),
+			[Stats.STAT_CON] = resolvers.mbonus_material("inc_stats", -1),
+			[Stats.STAT_MAG] = resolvers.mbonus_material("inc_stats"),
+			[Stats.STAT_WIL] = resolvers.mbonus_material("inc_stats"),
 		},
-		combat_spellcrit = resolvers.mbonus_material(4, 1),
+		combat_spellcrit = resolvers.mbonus_material("combat_spellcrit"),
 		inc_damage = {
-			[DamageType.BLIGHT] = resolvers.mbonus_material(15, 5),
-			[DamageType.ARCANE] = resolvers.mbonus_material(15, 5),
+			[DamageType.BLIGHT] = resolvers.mbonus_material("inc_damage"),
+			[DamageType.ARCANE] = resolvers.mbonus_material("inc_damage"),
 		},
-		healing_factor = resolvers.mbonus_material(20, 10, function(e, v) v=v/100 return 0, -v end),
+		healing_factor = resolvers.mbonus_material("healing_factor", -1),
 	},
 }
 
@@ -458,10 +458,10 @@ newEntity{
 	cost = 40,
 	wielder = {
 		inc_stats = {
-			[Stats.STAT_LCK] = resolvers.mbonus_material(7, 3),
+			[Stats.STAT_LCK] = resolvers.mbonus_material("inc_stats"),
 		},
-		combat_physcrit = resolvers.mbonus_material(4, 1),
-		combat_spellcrit = resolvers.mbonus_material(4, 1),
+		combat_physcrit = resolvers.mbonus_material("combat_physcrit"),
+		combat_spellcrit = resolvers.mbonus_material("combat_spellcrit"),
 	},
 }
 
@@ -477,10 +477,10 @@ newEntity{
 	use_talent = { id = Talents.T_CIRCLE_OF_SANCTITY, level = 4, power = 80 },
 	wielder = {
 		resists={
-			[DamageType.BLIGHT] = resolvers.mbonus_material(10, 5),
-			[DamageType.DARKNESS] = resolvers.mbonus_material(10, 5),
+			[DamageType.BLIGHT] = resolvers.mbonus_material("resists"),
+			[DamageType.DARKNESS] = resolvers.mbonus_material("resists"),
 		},
-		confusion_immune = resolvers.mbonus_material(15, 10, function(e, v) v=v/100 return 0, v end),
+		confusion_immune = resolvers.mbonus_material("immunity"),
 	},
 }
 
@@ -496,9 +496,26 @@ newEntity{
 	use_talent = { id = Talents.T_BATTLE_CRY, level = 2, power = 80 },
 	wielder = {
 		inc_stats = {
-			[Stats.STAT_STR] = resolvers.mbonus_material(5, 1),
+			[Stats.STAT_STR] = resolvers.mbonus_material("inc_stats", 2),
 		},
-		combat_mentalresist = resolvers.mbonus_material(7, 3),
-		combat_physresist = resolvers.mbonus_material(7, 3),
+		--combat_mentalresist = resolvers.mbonus_material("save"),
+		combat_physresist = resolvers.mbonus_material("save"),
 	},
 }
+--[=[
+newEntity{
+	power_source = {technique=true},
+	name = " of hoarding", suffix=true, instant_resolve=true,
+	level_range = {40, 50},
+	greater_ego = 1,
+	rarity = 40,
+	cost = 40,
+	wielder = {
+		inc_stats = {
+			[Stats.STAT_CUN] = resolvers.mbonus_material("inc_stats"),
+		},
+		resource_leech_chance = resolvers.mbonus_material("resource_leech_chance"),
+		resource_leech_value = resolvers.mbonus_material("resource_leech_value"),
+	},
+}
+]=]
diff --git a/game/modules/tome/data/general/objects/egos/light-armor.lua b/game/modules/tome/data/general/objects/egos/light-armor.lua
index 085bded9bc..4384612ca7 100644
--- a/game/modules/tome/data/general/objects/egos/light-armor.lua
+++ b/game/modules/tome/data/general/objects/egos/light-armor.lua
@@ -31,7 +31,7 @@ newEntity{
 	rarity = 12,
 	cost = 14,
 	wielder = {
-		life_regen = resolvers.mbonus_material(60, 15, function(e, v) v=v/10 return 0, v end),
+		life_regen = resolvers.mbonus_material("life_regen", 4),
 	},
 }
 
@@ -44,8 +44,8 @@ newEntity{
 	rarity = 22,
 	cost = 35,
 	wielder = {
-		combat_def_ranged = resolvers.mbonus_material(8, 2),
-		movement_speed = 0.1,
-		inc_stats = { [Stats.STAT_DEX] = resolvers.mbonus_material(3, 2), },
+		--combat_def_ranged = resolvers.mbonus_material("combat_def_ranged"),
+		movement_speed = resolvers.mbonus_material("movement_speed"),
+		inc_stats = { [Stats.STAT_DEX] = resolvers.mbonus_material("inc_stats"), },
 	},
 }
diff --git a/game/modules/tome/data/general/objects/egos/light-boots.lua b/game/modules/tome/data/general/objects/egos/light-boots.lua
index caa2757e28..b4b517c9bd 100644
--- a/game/modules/tome/data/general/objects/egos/light-boots.lua
+++ b/game/modules/tome/data/general/objects/egos/light-boots.lua
@@ -31,6 +31,6 @@ newEntity{
 	rarity = 5,
 	cost = 6,
 	wielder = {
-		inc_stealth = resolvers.mbonus_material(10, 5),
+		inc_stealth = resolvers.mbonus_material("inc_stealth"),
 	},
 }
diff --git a/game/modules/tome/data/general/objects/egos/lite.lua b/game/modules/tome/data/general/objects/egos/lite.lua
index a8063f571c..98746e115e 100644
--- a/game/modules/tome/data/general/objects/egos/lite.lua
+++ b/game/modules/tome/data/general/objects/egos/lite.lua
@@ -30,7 +30,7 @@ newEntity{
 	rarity = 5,
 	cost = 1,
 	wielder = {
-		lite=1,
+		lite = resolvers.mbonus_material("lite"),
 	},
 }
 
@@ -42,7 +42,7 @@ newEntity{
 	rarity = 5,
 	cost = 1,
 	wielder = {
-		blind_immune=resolvers.mbonus_material(3, 3, function(e, v) v=v/10 return 0, v end),
+		blind_immune = resolvers.mbonus_material("immunity"),
 	},
 }
 
@@ -55,9 +55,9 @@ newEntity{
 	rarity = 9,
 	cost = 10,
 	wielder = {
-		blind_immune=resolvers.mbonus_material(3, 3, function(e, v) v=v/10 return 0, v end),
-		combat_spellresist = 15,
-		lite=1,
+		blind_immune = resolvers.mbonus_material("immunity"),
+		combat_spellresist = resolvers.mbonus_material("save"),
+		lite = resolvers.mbonus_material("lite"),
 	},
 }
 
@@ -69,7 +69,7 @@ newEntity{
 	rarity = 5,
 	cost = 4,
 	wielder = {
-		on_melee_hit={[DamageType.FIRE] = resolvers.mbonus_material(20, 10)},
+		on_melee_hit={[DamageType.FIRE] = resolvers.mbonus_material("on_melee_hit")},
 	},
 }
 
@@ -81,9 +81,9 @@ newEntity{
 	rarity = 7,
 	cost = 10,
 	wielder = {
-		lite = 1,
-		see_invisible = resolvers.mbonus_material(20, 5),
-		trap_detect_power = resolvers.mbonus_material(15, 10),
+		lite = resolvers.mbonus_material("lite"),
+		see_invisible = resolvers.mbonus_material("see_invisible"),
+		trap_detect_power = resolvers.mbonus_material("trap_detect_power"),
 	},
 }
 
@@ -95,7 +95,7 @@ newEntity{
 	rarity = 7,
 	cost = 10,
 	wielder = {
-		confusion_immune = resolvers.mbonus_material(3, 2, function(e, v) v=v/10 return 0, v end),
+		confusion_immune = resolvers.mbonus_material("immunity"),
 	},
 }
 
@@ -107,7 +107,7 @@ newEntity{
 	rarity = 7,
 	cost = 10,
 	wielder = {
-		max_life=resolvers.mbonus_material(40, 40),
+		max_life=resolvers.mbonus_material("max_life"),
 	},
 }
 
@@ -120,7 +120,7 @@ newEntity{
 	cost = 10,
 	wielder = {
 		inc_stats = {
-			[Stats.STAT_CUN] = resolvers.mbonus_material(4, 3),
+			[Stats.STAT_CUN] = resolvers.mbonus_material("inc_stats"),
 		},
 	},
 }
@@ -133,8 +133,8 @@ newEntity{
 	rarity = 9,
 	cost = 12,
 	wielder = {
-		lite = -2,
-		infravision = resolvers.mbonus_material(2, 1),
+		lite = resolvers.mbonus_material("lite", -1),
+		infravision = resolvers.mbonus_material("infravision"),
 	},
 }
 
@@ -146,7 +146,7 @@ newEntity{
 	rarity = 9,
 	cost = 12,
 	wielder = {
-		stun_immune = resolvers.mbonus_material(20, 10, function(e, v) v=v/100 return 0, v end),
+		stun_immune = resolvers.mbonus_material("immunity"),
 	},
 }
 
@@ -158,7 +158,7 @@ newEntity{
 	rarity = 9,
 	cost = 12,
 	wielder = {
-		healing_factor = resolvers.mbonus_material(20, 10, function(e, v) v=v/100 return 0, v end),
+		healing_factor = resolvers.mbonus_material("healing_factor"),
 	},
 }
 
@@ -170,7 +170,7 @@ newEntity{
 	rarity = 9,
 	cost = 12,
 	wielder = {
-		combat_mentalresist = resolvers.mbonus_material(15, 5),
+		combat_mentalresist = resolvers.mbonus_material("save"),
 	},
 }
 
@@ -184,10 +184,10 @@ newEntity{
 	cost = 30,
 	wielder = {
 		resists={
-			[DamageType.LIGHT] = resolvers.mbonus_material(10, 5),
-			[DamageType.DARKNESS] = resolvers.mbonus_material(10, 5),
+			[DamageType.LIGHT] = resolvers.mbonus_material("resists"),
+			[DamageType.DARKNESS] = resolvers.mbonus_material("resists"),
 		},
-		blind_immune = resolvers.mbonus_material(30, 10, function(e, v) v=v/100 return 0, v end),
+		blind_immune = resolvers.mbonus_material("immunity"),
 	},
 }
 
@@ -200,10 +200,10 @@ newEntity{
 	rarity = 10,
 	cost = 50,
 	wielder = {
-		combat_dam = resolvers.mbonus_material(5, 5),
-		combat_physcrit = resolvers.mbonus_material(3, 3),
+		combat_dam = resolvers.mbonus_material("combat_dam"),
+		combat_physcrit = resolvers.mbonus_material("combat_physcrit"),
 		inc_stats = {
-			[Stats.STAT_WIL] = resolvers.mbonus_material(4, 3),
+			[Stats.STAT_WIL] = resolvers.mbonus_material("inc_stats"),
 			},
 	},
 }
@@ -218,9 +218,9 @@ newEntity{
 	cost = 50,
 	encumber = -1,
 	wielder = {
-		lite = 2,
+		lite = resolvers.mbonus_material("lite"),
 		inc_stats = {
-			[Stats.STAT_MAG] = resolvers.mbonus_material(3, 3),
+			[Stats.STAT_MAG] = resolvers.mbonus_material("inc_stats"),
 			},
 	},
 }
@@ -234,10 +234,10 @@ newEntity{
 	rarity = 10,
 	cost = 50,
 	wielder = {
-		combat_def = resolvers.mbonus_material(4, 4),
-		combat_mentalresist = resolvers.mbonus_material(10, 5),
-		combat_physresist = resolvers.mbonus_material(10, 5),
-		combat_spellresist = resolvers.mbonus_material(10, 5),
+		combat_def = resolvers.mbonus_material("combat_def", 2),
+		--combat_mentalresist = resolvers.mbonus_material("save"),
+		combat_physresist = resolvers.mbonus_material("save"),
+		--combat_spellresist = resolvers.mbonus_material("save"),
 	},
 }
 
@@ -250,9 +250,9 @@ newEntity{
 	rarity = 10,
 	cost = 50,
 	wielder = {
-		combat_spellpower = resolvers.mbonus_material(3, 3),
-		combat_spellcrit = resolvers.mbonus_material(3, 3),
-		see_invisible = resolvers.mbonus_material(10, 5),
+		combat_spellpower = resolvers.mbonus_material("combat_spellpower"),
+		combat_spellcrit = resolvers.mbonus_material("combat_spellcrit"),
+		see_invisible = resolvers.mbonus_material("see_invisible"),
 	},
 }
 
@@ -266,11 +266,11 @@ newEntity{
 	cost = 40,
 	wielder = {
 		inc_stats = {
-			[Stats.STAT_LCK] = resolvers.mbonus_material(5, 5, function(e, v) return 0, -v end),
-			[Stats.STAT_DEX] = resolvers.mbonus_material(9, 1),
-			[Stats.STAT_CON] = resolvers.mbonus_material(9, 1),
-			[Stats.STAT_WIL] = resolvers.mbonus_material(5, 5, function(e, v) return 0, -v end),
-			[Stats.STAT_CUN] = resolvers.mbonus_material(9, 1),
+			[Stats.STAT_LCK] = resolvers.mbonus_material("inc_stats", -1),
+			[Stats.STAT_DEX] = resolvers.mbonus_material("inc_stats", 2),
+			[Stats.STAT_CON] = resolvers.mbonus_material("inc_stats"),
+			[Stats.STAT_WIL] = resolvers.mbonus_material("inc_stats", -1),
+			[Stats.STAT_CUN] = resolvers.mbonus_material("inc_stats", 2),
 		},
 	},	
 }
@@ -284,10 +284,10 @@ newEntity{
 	rarity = 30,
 	cost = 40,
 	wielder = {
-		stun_immune = resolvers.mbonus_material(15, 10, function(e, v) v=v/100 return 0, v end),
-		knockback_immune = resolvers.mbonus_material(15, 10, function(e, v) v=v/100 return 0, v end),
-		pin_immune = resolvers.mbonus_material(15, 10, function(e, v) v=v/100 return 0, v end),
-		lite = resolvers.mbonus_material(1, 1),
+		stun_immune = resolvers.mbonus_material("immunity"),
+		knockback_immune = resolvers.mbonus_material("immunity"),
+		pin_immune = resolvers.mbonus_material("immunity"),
+		lite = resolvers.mbonus_material("lite"),
 	},	
 }
 
@@ -300,10 +300,10 @@ newEntity{
 	rarity = 20,
 	cost = 40,
 	wielder = {
-		combat_spellpower = resolvers.mbonus_material(6, 1),
+		combat_spellpower = resolvers.mbonus_material("combat_spellpower"),
 		inc_damage = {
-			[DamageType.LIGHT] = resolvers.mbonus_material(10, 5),
-			[DamageType.DARKNESS] = resolvers.mbonus_material(10, 5),
+			[DamageType.LIGHT] = resolvers.mbonus_material("inc_damage"),
+			[DamageType.DARKNESS] = resolvers.mbonus_material("inc_damage"),
 		},
 	},	
 }
@@ -317,11 +317,11 @@ newEntity{
 	rarity = 20,
 	cost = 40,
 	wielder = {
-		combat_apr = resolvers.mbonus_material(10, 5),
+		combat_apr = resolvers.mbonus_material("combat_apr"),
 		resists_pen = { 
-			[DamageType.PHYSICAL] = resolvers.mbonus_material(10, 5),
+			[DamageType.PHYSICAL] = resolvers.mbonus_material("resists_pen"),
 		},
-		lite = resolvers.mbonus_material(1, 1),
+		lite = resolvers.mbonus_material("lite"),
 	},	
 }
 
@@ -335,11 +335,11 @@ newEntity{
 	cost = 20,
 	wielder = {
 		inc_stats = {
-			[Stats.STAT_CON] = resolvers.mbonus_material(5, 1),
+			[Stats.STAT_CON] = resolvers.mbonus_material("inc_stats"),
 		},
-		poison_immune = resolvers.mbonus_material(15, 10, function(e, v) v=v/100 return 0, v end),
-		disease_immune = resolvers.mbonus_material(15, 10, function(e, v) v=v/100 return 0, v end),
-		life_regen = resolvers.mbonus_material(27, 3, function(e, v) v=v/10 return 0, v end),
+		poison_immune = resolvers.mbonus_material("immunity"),
+		disease_immune = resolvers.mbonus_material("immunity"),
+		life_regen = resolvers.mbonus_material("life_regen"),
 	},	
 }
 
@@ -354,11 +354,11 @@ newEntity{
 	max_power = 80, power_regen = 1,
 	use_talent = { id = Talents.T_ARCANE_EYE, level = 2, power = 80 },
 	wielder = {
-		blind_immune = resolvers.mbonus_material(15, 10, function(e, v) v=v/100 return 0, -v end),
-		confusion_immune = resolvers.mbonus_material(15, 10, function(e, v) v=v/100 return 0, -v end),
+		blind_immune = resolvers.mbonus_material("immunity", -1),
+		confusion_immune = resolvers.mbonus_material("immunity", -1),
 		inc_damage = {
-			[DamageType.LIGHTNING] = resolvers.mbonus_material(15, 5),
-			[DamageType.FIRE] = resolvers.mbonus_material(15, 5),
+			[DamageType.LIGHTNING] = resolvers.mbonus_material("inc_damage"),
+			[DamageType.FIRE] = resolvers.mbonus_material("inc_damage"),
 		},
 	},	
 }
@@ -385,13 +385,13 @@ newEntity{
 	cost = 40,
 	wielder = {
 		resists={
-			[DamageType.LIGHT] = resolvers.mbonus_material(7, 3),
-			[DamageType.DARKNESS] = resolvers.mbonus_material(7, 3),
+			[DamageType.LIGHT] = resolvers.mbonus_material("resists"),
+			[DamageType.DARKNESS] = resolvers.mbonus_material("resists"),
 		},
 
 		resists_pen = { 
-			[DamageType.LIGHT] = resolvers.mbonus_material(7, 3),
-			[DamageType.DARKNESS] = resolvers.mbonus_material(7, 3),
+			[DamageType.LIGHT] = resolvers.mbonus_material("resists_pen"),
+			[DamageType.DARKNESS] = resolvers.mbonus_material("resists_pen"),
 		},
 	},	
 }
@@ -407,7 +407,7 @@ newEntity{
 	max_power = 80, power_regen = 1,
 	use_talent = { id = Talents.T_MOONLIGHT_RAY, level = 4, power = 80 },
 	wielder = {
-		combat_spellpower = resolvers.mbonus_material(7, 3),
+		combat_spellpower = resolvers.mbonus_material("combat_spellpower"),
 	},	
 }
 
@@ -423,7 +423,7 @@ newEntity{
 	use_talent = { id = Talents.T_GLYPH_OF_REPULSION, level = 3, power = 80 },
 	wielder = {
 		inc_stats = {
-			[Stats.STAT_MAG] = resolvers.mbonus_material(5, 1),
+			[Stats.STAT_MAG] = resolvers.mbonus_material("inc_stats"),
 		},
 	},	
 }
diff --git a/game/modules/tome/data/general/objects/egos/massive-armor.lua b/game/modules/tome/data/general/objects/egos/massive-armor.lua
index 3e132f18a0..eb7f0abe49 100644
--- a/game/modules/tome/data/general/objects/egos/massive-armor.lua
+++ b/game/modules/tome/data/general/objects/egos/massive-armor.lua
@@ -29,23 +29,23 @@ newEntity{
 	keywords = {dragon=true},
 	level_range = {20, 50},
 	greater_ego = 1,
-	rarity = 20,
+	rarity = 40,
 	cost = 60,
 	wielder = {
 		resists={
-			[DamageType.ACID] = resolvers.mbonus_material(10, 5),
-			[DamageType.LIGHTNING] = resolvers.mbonus_material(10, 5),
-			[DamageType.FIRE] = resolvers.mbonus_material(10, 5),
-			[DamageType.COLD] = resolvers.mbonus_material(10, 5),
-			[DamageType.PHYSICAL] = resolvers.mbonus_material(10, 5),
+			[DamageType.ACID] = resolvers.mbonus_material("resists"),
+			[DamageType.LIGHTNING] = resolvers.mbonus_material("resists"),
+			[DamageType.FIRE] = resolvers.mbonus_material("resists"),
+			[DamageType.COLD] = resolvers.mbonus_material("resists"),
+			[DamageType.PHYSICAL] = resolvers.mbonus_material("resists"),
 	},
 		inc_stats = {
-			[Stats.STAT_CON] = resolvers.mbonus_material(5, 1),
-			[Stats.STAT_STR] = resolvers.mbonus_material(5, 1),
+			[Stats.STAT_CON] = resolvers.mbonus_material("inc_stats"),
+			[Stats.STAT_STR] = resolvers.mbonus_material("inc_stats"),
 		},
-		stun_immune = resolvers.mbonus_material(20, 20, function(e, v) v=v/100 return 0, v end),
-		knockback_immune = resolvers.mbonus_material(20, 20, function(e, v) v=v/100 return 0, v end),
-		disarm_immune = resolvers.mbonus_material(20, 20, function(e, v) v=v/100 return 0, v end),
+		stun_immune = resolvers.mbonus_material("immunity"),
+		knockback_immune = resolvers.mbonus_material("immunity"),
+		disarm_immune = resolvers.mbonus_material("immunity"),
 		talent_cd_reduction={[Talents.T_RUSH]=5},
 	},
 }
@@ -59,6 +59,6 @@ newEntity{
 	rarity = 8,
 	cost = 7,
 	wielder = {
-		combat_armor = resolvers.mbonus_material(12, 3),
+		combat_armor = resolvers.mbonus_material("combat_armor"),
 	},
 }
diff --git a/game/modules/tome/data/general/objects/egos/ranged.lua b/game/modules/tome/data/general/objects/egos/ranged.lua
new file mode 100644
index 0000000000..fb579a3551
--- /dev/null
+++ b/game/modules/tome/data/general/objects/egos/ranged.lua
@@ -0,0 +1,277 @@
+-- ToME - Tales of Maj'Eyal
+-- Copyright (C) 2009, 2010, 2011 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
+local Talents = require("engine.interface.ActorTalents")
+local Stats = require("engine.interface.ActorStats")
+
+
+
+newEntity{
+	power_source = {technique=true},
+	name = " of power", suffix=true, instant_resolve=true,
+	keywords = {power=true},
+	level_range = {1, 50},
+	rarity = 3,
+	cost = 6,
+	combat={apr = resolvers.mbonus_material("combat_apr", 4)},
+}
+
+newEntity{
+	power_source = {technique=true},
+	name = "mighty ", prefix=true, instant_resolve=true,
+	keywords = {mighty=true},
+	level_range = {1, 50},
+	rarity = 3,
+	cost = 4,
+	combat = {
+		dam = resolvers.mbonus_material("dam"),
+	},
+}
+
+newEntity{
+	power_source = {technique=true},
+	name = "steady ", prefix=true, instant_resolve=true,
+	keywords = {steady=true},
+	level_range = {1, 50},
+	rarity = 9,
+	cost = 10,
+	wielder = {
+		learn_talent = {
+			[Talents.T_STEADY_SHOT] = resolvers.mbonus_material("learn_talent"),
+		},
+	},
+}
+
+newEntity{
+	power_source = {technique=true},
+	name = " of crippling", suffix=true, instant_resolve=true,
+	keywords = {crippling=true},
+	level_range = {1, 50},
+	rarity = 7,
+	cost = 7,
+	combat = {
+		critical_power = resolvers.mbonus_material("critical_power"),
+	}
+}
+
+newEntity{
+	power_source = {technique=true},
+	name = " of speed", suffix=true, instant_resolve=true,
+	keywords = {speed=true},
+	level_range = {20, 50},
+	rarity = 7,
+	cost = 7,
+	combat = {
+		physspeed = resolvers.mbonus_material("physspeed", -1),
+	},
+}
+
+newEntity{
+	power_source = {technique=true},
+	name = "tracker's ", prefix=true, instant_resolve=true,
+	keywords = {tracker=true},
+	level_range = {1, 50},
+	rarity = 9,
+	cost = 10,
+	wielder = {
+		learn_talent = {
+			[Talents.T_TRACK] = resolvers.mbonus_material("learn_talent"),
+		},
+	},
+}
+
+newEntity{
+	power_source = {technique=true},
+	name = " of range", suffix=true, instant_resolve=true,
+	keywords = {range=true},
+	level_range = {1, 50},
+	rarity = 9,
+	cost = 10,
+	resolvers.generic(function(e)
+		e.combat.range = e.combat.range + 1
+	end),
+}
+
+newEntity{
+	power_source = {technique=true},
+	name = "swiftstrike ", prefix=true, instant_resolve=true,
+	keywords = {swiftstrike=true},
+	level_range = {1, 50},
+	rarity = 9,
+	cost = 10,
+	combat = {travel_speed = 200,},
+}
+
+newEntity{
+	power_source = {technique=true},
+	name = " of true flight", suffix=true, instant_resolve=true,
+	keywords = {flight=true},
+	level_range = {30, 50},
+	greater_ego = 1,
+	rarity = 20,
+	cost = 40,
+	combat = {
+		critical_power = resolvers.mbonus_material("critical_power"),
+		travel_speed = 200
+	},
+	resolvers.generic(function(e)
+		e.combat.range = e.combat.range + 1
+	end),
+}
+
+newEntity{
+	power_source = {technique=true},
+	name = "penetrating ", prefix=true, instant_resolve=true,
+	keywords = {penetrating=true},
+	level_range = {30, 50},
+	greater_ego = 1,
+	rarity = 20,
+	cost = 40,
+	combat = {
+		apr = resolvers.mbonus_material("combat_apr", 4),
+	},
+	wielder = {
+		resists_pen = {
+			[DamageType.PHYSICAL] = resolvers.mbonus_material("resists_pen", 2),
+		},
+		learn_talent = {
+			[Talents.T_PIERCING_ARROW] = resolvers.mbonus_material("learn_talent"),
+		},
+	},
+}
+
+newEntity{
+	power_source = {technique=true},
+	name = "phase-shifting ", prefix=true, instant_resolve=true,
+	keywords = {phase=true},
+	level_range = {10, 50},
+	greater_ego = 1,
+	rarity = 30,
+	cost = 80,
+	combat = {
+		tg_type = "beam",
+	},
+	resolvers.generic(function(e)
+		e.combat.dam = 0
+		e.combat.dammod = {dex=0}
+	end),
+}
+
+newEntity{
+	power_source = {technique=true},
+	name = " of concussion", suffix=true, instant_resolve=true,
+	keywords = {concussion=true},
+	level_range = {10, 50},
+	greater_ego = 1,
+	rarity = 40,
+	cost = 40,
+	resolvers.generic(function(e)
+		e.combat.concussion = (e.combat.critical_power - 1) * 100
+	end),
+}
+
+newEntity{
+	power_source = {arcane=true},
+	name = " of spellstriking", suffix=true, instant_resolve=true,
+	keywords = {spellstrike=true},
+	level_range = {20, 50},
+	greater_ego = 1,
+	rarity = 20,
+	cost = 30,
+	combat = {
+		affects_spells = true,
+		talent_on_hit = { 
+			[Talents.T_DISPERSE_MAGIC] = {
+				level=3, 
+				chance = resolvers.mbonus_material("talent_on_hit_chance"),
+				} ,
+			},
+	},
+	resolvers.generic(function(e)
+		e.combat.dammod.mag = e.combat.dammod.dex
+	end),
+}
+
+newEntity{
+	power_source = {arcane=true},
+	name = " of torment", suffix=true, instant_resolve=true,
+	keywords = {torment=true},
+	level_range = {1, 50},
+	rarity = 18,
+	cost = 22,
+	combat = {
+		special_on_hit = {desc="30% chance to torment the target", fct=function(combat, who, target)
+			if not rng.percent(30) then return end
+			local eff = rng.table{"stun", "blind", "pin", "confusion", "silence"}
+			if not target:canBe(eff) then return end
+			if not target:checkHit(who:combatAttack(combat), target:combatPhysicalResist(), 15) then return end
+			if eff == "stun" then target:setEffect(target.EFF_STUNNED, 3, {})
+			elseif eff == "blind" then target:setEffect(target.EFF_BLINDED, 3, {})
+			elseif eff == "pin" then target:setEffect(target.EFF_PINNED, 3, {})
+			elseif eff == "confusion" then target:setEffect(target.EFF_CONFUSED, 3, {power=60})
+			elseif eff == "silence" then target:setEffect(target.EFF_SILENCED, 3, {})
+			end
+		end},
+	},
+}
+
+newEntity{
+	power_source = {nature=true},
+	name = "voracious ", prefix=true, instant_resolve=true,
+	keywords = {voracious=true},
+	level_range = {1, 50},
+	greater_ego = 1,
+	rarity = 60,
+	cost = 40,
+	wielder = {
+		resource_leech_chance = resolvers.mbonus_material("resource_leech_chance"),
+		resource_leech_value = resolvers.mbonus_material("resource_leech_value", 2),
+	},
+	max_power = 20, power_regen = 1,
+	use_talent = { id = Talents.T_THERMAL_LEECH, level = 5, power = 20 },
+}
+
+newEntity{
+	power_source = {technique=true},
+	name = " of savagery", suffix=true, instant_resolve=true,
+	keywords = {savage=true},
+	level_range = {30, 50},
+	greater_ego = 1,
+	rarity = 20,
+	cost = 40,
+	wielder = {
+		learn_talent = {
+			[Talents.T_SAVAGERY] = resolvers.mbonus_material("learn_talent_5"),
+		},
+	},
+}
+
+newEntity{
+	power_source = {technique=true},
+	name = " of sacrifice", suffix=true, instant_resolve=true,
+	keywords = {sacrifice=true},
+	level_range = {20, 50},
+	greater_ego = 1,
+	rarity = 20,
+	cost = 40,
+	max_power = 30, power_regen = 1,
+	use_talent = { id = Talents.T_LIFE_TAP, level = 5, power = 30 },
+	combat = {
+		dam = resolvers.mbonus_material("dam", 2, true),
+	},
+}
diff --git a/game/modules/tome/data/general/objects/egos/rings.lua b/game/modules/tome/data/general/objects/egos/rings.lua
index 5da83654c7..242b818378 100644
--- a/game/modules/tome/data/general/objects/egos/rings.lua
+++ b/game/modules/tome/data/general/objects/egos/rings.lua
@@ -33,7 +33,7 @@ newEntity{
 	rarity = 4,
 	cost = 2,
 	wielder = {
-		see_invisible = resolvers.mbonus_material(20, 5),
+		see_invisible = resolvers.mbonus_material("see_invisible"),
 	},
 }
 
@@ -45,7 +45,7 @@ newEntity{
 	rarity = 10,
 	cost = 8,
 	wielder = {
-		life_regen = resolvers.mbonus_material(30, 5, function(e, v) v=v/10 return 0, v end),
+		life_regen = resolvers.mbonus_material("life_regen"),
 	},
 }
 
@@ -57,117 +57,120 @@ newEntity{
 	rarity = 8,
 	cost = 3,
 	wielder = {
-		mana_regen = resolvers.mbonus_material(30, 10, function(e, v) v=v/100 return 0, v end),
+		mana_regen = resolvers.mbonus_material("mana_regen"),
 	},
 }
 
 newEntity{
 	power_source = {arcane=true},
-	name = " of fire (#RESIST#)", suffix=true, instant_resolve=true,
+	name = " of fire (#DAMBONUS#)", suffix=true, instant_resolve=true,
 	keywords = {fire=true},
 	level_range = {10, 40},
 	rarity = 6,
 	cost = 2,
 	wielder = {
-		inc_damage = { [DamageType.FIRE] = resolvers.mbonus_material(10, 10) },
-		resists = {},
+		inc_damage = { [DamageType.FIRE] = resolvers.mbonus_material("inc_damage") },
+		wards = {[DamageType.FIRE] = resolvers.mbonus_material("wards")},
+		learn_talent = {[Talents.T_WARD] = resolvers.mbonus_material("learn_talent")},
 	},
-	resolvers.genericlast(function(e) e.wielder.resists[engine.DamageType.FIRE] = (e.wielder.resists[engine.DamageType.FIRE] or 0) + e.wielder.inc_damage[engine.DamageType.FIRE] end),
 }
 
 newEntity{
 	power_source = {arcane=true},
-	name = " of time (#RESIST#)", suffix=true, instant_resolve=true,
+	name = " of time (#DAMBONUS#)", suffix=true, instant_resolve=true,
 	keywords = {time=true},
 	level_range = {10, 40},
 	rarity = 6,
 	cost = 2,
 	wielder = {
-		inc_damage = { [DamageType.TEMPORAL] = resolvers.mbonus_material(10, 10) },
-		resists = {},
+		inc_damage = { [DamageType.TEMPORAL] = resolvers.mbonus_material("inc_damage") },
+		wards = {[DamageType.TEMPORAL] = resolvers.mbonus_material("wards")},
+		learn_talent = {[Talents.T_WARD] = resolvers.mbonus_material("learn_talent")},
 	},
-	resolvers.genericlast(function(e) e.wielder.resists[engine.DamageType.TEMPORAL] = (e.wielder.resists[engine.DamageType.TEMPORAL] or 0) + e.wielder.inc_damage[engine.DamageType.TEMPORAL] end),
 }
 
 newEntity{
 	power_source = {arcane=true},
-	name = " of frost (#RESIST#)", suffix=true, instant_resolve=true,
+	name = " of frost (#DAMBONUS#)", suffix=true, instant_resolve=true,
 	keywords = {frost=true},
 	level_range = {10, 40},
 	rarity = 6,
 	cost = 2,
 	wielder = {
-		inc_damage = { [DamageType.COLD] = resolvers.mbonus_material(10, 10) },
-		resists = {},
+		inc_damage = { [DamageType.COLD] = resolvers.mbonus_material("inc_damage") },
+		wards = {[DamageType.COLD] = resolvers.mbonus_material("wards")},
+		learn_talent = {[Talents.T_WARD] = resolvers.mbonus_material("learn_talent")},
 	},
-	resolvers.genericlast(function(e) e.wielder.resists[engine.DamageType.COLD] = (e.wielder.resists[engine.DamageType.COLD] or 0) + e.wielder.inc_damage[engine.DamageType.COLD] end),
 }
 
 newEntity{
 	power_source = {nature=true},
-	name = " of nature (#RESIST#)", suffix=true, instant_resolve=true,
+	name = " of nature (#DAMBONUS#)", suffix=true, instant_resolve=true,
 	keywords = {nature=true},
 	level_range = {10, 40},
 	rarity = 6,
 	cost = 2,
 	wielder = {
-		inc_damage = { [DamageType.NATURE] = resolvers.mbonus_material(10, 10) },
-		resists = {},
+		inc_damage = { [DamageType.NATURE] = resolvers.mbonus_material("inc_damage") },
+		wards = {[DamageType.NATURE] = resolvers.mbonus_material("wards")},
+		learn_talent = {[Talents.T_WARD] = resolvers.mbonus_material("learn_talent")},
 	},
-	resolvers.genericlast(function(e) e.wielder.resists[engine.DamageType.NATURE] = (e.wielder.resists[engine.DamageType.NATURE] or 0) + e.wielder.inc_damage[engine.DamageType.NATURE] end),
 }
 
 newEntity{
 	power_source = {arcane=true},
-	name = " of lightning (#RESIST#)", suffix=true, instant_resolve=true,
+	name = " of lightning (#DAMBONUS#)", suffix=true, instant_resolve=true,
 	keywords = {lightning=true},
 	level_range = {10, 40},
 	rarity = 6,
 	cost = 2,
 	wielder = {
-		inc_damage = { [DamageType.LIGHTNING] = resolvers.mbonus_material(10, 10) },
-		resists = {},
+		inc_damage = { [DamageType.LIGHTNING] = resolvers.mbonus_material("inc_damage") },
+		wards = {[DamageType.LIGHTNING] = resolvers.mbonus_material("wards")},
+		learn_talent = {[Talents.T_WARD] = resolvers.mbonus_material("learn_talent")},
 	},
-	resolvers.genericlast(function(e) e.wielder.resists[engine.DamageType.LIGHTNING] = (e.wielder.resists[engine.DamageType.LIGHTNING] or 0) + e.wielder.inc_damage[engine.DamageType.LIGHTNING] end),
+
 }
 
 newEntity{
 	power_source = {nature=true},
-	name = " of corrosion (#RESIST#)", suffix=true, instant_resolve=true,
+	name = " of corrosion (#DAMBONUS#)", suffix=true, instant_resolve=true,
 	keywords = {corrosion=true},
 	level_range = {10, 40},
 	rarity = 6,
 	cost = 2,
 	wielder = {
-		inc_damage = { [DamageType.ACID] = resolvers.mbonus_material(10, 10) },
-		resists = {},
+		inc_damage = { [DamageType.ACID] = resolvers.mbonus_material("inc_damage") },
+		wards = {[DamageType.ACID] = resolvers.mbonus_material("wards")},
+		learn_talent = {[Talents.T_WARD] = resolvers.mbonus_material("learn_talent")},
 	},
-	resolvers.genericlast(function(e) e.wielder.resists[engine.DamageType.ACID] = (e.wielder.resists[engine.DamageType.ACID] or 0) + e.wielder.inc_damage[engine.DamageType.ACID] end),
+
 }
 
 newEntity{
 	power_source = {arcane=true},
-	name = " of blight (#RESIST#)", suffix=true, instant_resolve=true,
+	name = " of blight (#DAMBONUS#)", suffix=true, instant_resolve=true,
 	keywords = {blight=true},
 	level_range = {10, 40},
 	rarity = 6,
 	cost = 2,
 	wielder = {
-		inc_damage = { [DamageType.BLIGHT] = resolvers.mbonus_material(10, 10) },
-		resists = {},
+		inc_damage = { [DamageType.BLIGHT] = resolvers.mbonus_material("inc_damage") },
+		wards = {[DamageType.BLIGHT] = resolvers.mbonus_material("wards")},
+		learn_talent = {[Talents.T_WARD] = resolvers.mbonus_material("learn_talent")},
 	},
-	resolvers.genericlast(function(e) e.wielder.resists[engine.DamageType.BLIGHT] = (e.wielder.resists[engine.DamageType.BLIGHT] or 0) + e.wielder.inc_damage[engine.DamageType.BLIGHT] end),
 }
 
 newEntity{
 	power_source = {nature=true},
-	name = " of massacre (#DAMBONUS#)", suffix=true, instant_resolve=true,
+	name = " of massacre", suffix=true, instant_resolve=true,
 	keywords = {massacre=true},
 	level_range = {6, 50},
 	rarity = 4,
 	cost = 4,
 	wielder = {
-		inc_damage = { [DamageType.PHYSICAL] = resolvers.mbonus_material(15, 5) },
+		combat_dam = resolvers.mbonus_material("combat_dam", 2),
+		--inc_damage = { [DamageType.PHYSICAL] = resolvers.mbonus_material("inc_damage") },
 	},
 }
 
@@ -179,7 +182,9 @@ newEntity{ define_as = "RING_ARCANE_POWER",
 	rarity = 4,
 	cost = 4,
 	wielder = {
-		inc_damage = { [DamageType.ARCANE] = resolvers.mbonus_material(15, 5) },
+		inc_damage = { [DamageType.ARCANE] = resolvers.mbonus_material("inc_damage") },
+		wards = {[DamageType.ARCANE] = resolvers.mbonus_material("wards")},
+		learn_talent = {[Talents.T_WARD] = resolvers.mbonus_material("learn_talent")},
 	},
 }
 
@@ -187,13 +192,14 @@ newEntity{
 	power_source = {technique=true},
 	name = "savior's ", prefix=true, instant_resolve=true,
 	keywords = {savior=true},
+	greater_ego = 1,
 	level_range = {1, 50},
 	rarity = 10,
 	cost = 10,
 	wielder = {
-		combat_mentalresist = resolvers.mbonus_material(10, 5),
-		combat_physresist = resolvers.mbonus_material(10, 5),
-		combat_spellresist = resolvers.mbonus_material(10, 5),
+		combat_mentalresist = resolvers.mbonus_material("save"),
+		combat_physresist = resolvers.mbonus_material("save"),
+		combat_spellresist = resolvers.mbonus_material("save"),
 	},
 }
 
@@ -205,7 +211,7 @@ newEntity{
 	rarity = 7,
 	cost = 6,
 	wielder = {
-		inc_stats = { [Stats.STAT_STR] = resolvers.mbonus_material(8, 2) },
+		inc_stats = { [Stats.STAT_STR] = resolvers.mbonus_material("inc_stats") },
 	},
 	resolvers.genericlast(function(e) e.wielder.combat_def = (e.wielder.combat_def or 0) + e.wielder.inc_stats[engine.interface.ActorStats.STAT_STR] end),
 }
@@ -218,7 +224,7 @@ newEntity{
 	rarity = 7,
 	cost = 6,
 	wielder = {
-		inc_stats = { [Stats.STAT_CON] = resolvers.mbonus_material(8, 2) },
+		inc_stats = { [Stats.STAT_CON] = resolvers.mbonus_material("inc_stats") },
 	},
 	resolvers.genericlast(function(e) e.wielder.combat_physresist = (e.wielder.combat_physresist or 0) + e.wielder.inc_stats[engine.interface.ActorStats.STAT_CON] end),
 }
@@ -231,7 +237,7 @@ newEntity{
 	rarity = 7,
 	cost = 6,
 	wielder = {
-		inc_stats = { [Stats.STAT_DEX] = resolvers.mbonus_material(8, 2) },
+		inc_stats = { [Stats.STAT_DEX] = resolvers.mbonus_material("inc_stats") },
 	},
 	resolvers.genericlast(function(e) e.wielder.combat_atk = (e.wielder.combat_atk or 0) + e.wielder.inc_stats[engine.interface.ActorStats.STAT_DEX] end),
 }
@@ -244,7 +250,7 @@ newEntity{ define_as = "RING_MAGIC",
 	rarity = 7,
 	cost = 6,
 	wielder = {
-		inc_stats = { [Stats.STAT_MAG] = resolvers.mbonus_material(8, 2) },
+		inc_stats = { [Stats.STAT_MAG] = resolvers.mbonus_material("inc_stats") },
 	},
 	resolvers.genericlast(function(e) e.wielder.combat_spellresist = (e.wielder.combat_spellresist or 0) + e.wielder.inc_stats[engine.interface.ActorStats.STAT_MAG] end),
 }
@@ -257,8 +263,8 @@ newEntity{
 	rarity = 7,
 	cost = 6,
 	wielder = {
-		max_encumber = resolvers.mbonus_material(20, 20),
-		fatigue = resolvers.mbonus_material(6, 4, function(e, v) return 0, -v end),
+		max_encumber = resolvers.mbonus_material("max_encumber"),
+		fatigue = resolvers.mbonus_material("fatigue"),
 	},
 }
 
@@ -271,10 +277,10 @@ newEntity{
 	rarity = 12,
 	cost = 20,
 	wielder = {
-		lite = -2,
+		lite = resolvers.mbonus_material("lite", -1),
 		inc_stats = {
-			[Stats.STAT_DEX] = resolvers.mbonus_material(6, 4),
-			[Stats.STAT_CUN] = resolvers.mbonus_material(6, 4),
+			[Stats.STAT_DEX] = resolvers.mbonus_material("inc_stats"),
+			[Stats.STAT_CUN] = resolvers.mbonus_material("inc_stats"),
 	},
 	},
 }
@@ -288,10 +294,10 @@ newEntity{
 	rarity = 12,
 	cost = 20,
 	wielder = {
-		combat_dam = resolvers.mbonus_material(10, 5),
+		combat_dam = resolvers.mbonus_material("combat_dam"),
 		inc_stats = {
-			[Stats.STAT_STR] = resolvers.mbonus_material(6, 4),
-			[Stats.STAT_CON] = resolvers.mbonus_material(6, 4),
+			[Stats.STAT_STR] = resolvers.mbonus_material("inc_stats"),
+			[Stats.STAT_CON] = resolvers.mbonus_material("inc_stats"),
 	},
 	},
 }
@@ -305,10 +311,10 @@ newEntity{
 	rarity = 12,
 	cost = 20,
 	wielder = {
-		mana_regen = resolvers.mbonus_material(30, 10, function(e, v) v=v/100 return 0, v end),
+		mana_regen = resolvers.mbonus_material("mana_regen"),
 		inc_stats = {
-			[Stats.STAT_MAG] = resolvers.mbonus_material(4, 4),
-			[Stats.STAT_WIL] = resolvers.mbonus_material(4, 4),
+			[Stats.STAT_MAG] = resolvers.mbonus_material("inc_stats"),
+			[Stats.STAT_WIL] = resolvers.mbonus_material("inc_stats"),
 			},
 	},
 }
@@ -322,9 +328,9 @@ newEntity{
 	rarity = 12,
 	cost = 50,
 	wielder = {
-		pin_immune = resolvers.mbonus_material(2, 2, function(e, v) v=v/10 return 0, v end),
-		knockback_immune = resolvers.mbonus_material(2, 2, function(e, v) v=v/10 return 0, v end),
-		disarm_immune = resolvers.mbonus_material(2, 2, function(e, v) v=v/10 return 0, v end),
+		pin_immune = resolvers.mbonus_material("immunity"),
+		knockback_immune = resolvers.mbonus_material("immunity"),
+		disarm_immune = resolvers.mbonus_material("immunity"),
 	},
 }
 
@@ -338,9 +344,9 @@ newEntity{
 	rarity = 12,
 	cost = 50,
 	wielder = {
-		combat_spellpower = resolvers.mbonus_material(3, 3),
-		combat_spellcrit = resolvers.mbonus_material(3, 3),
-		inc_damage = { [DamageType.ARCANE] = resolvers.mbonus_material(15, 5) },
+		combat_spellpower = resolvers.mbonus_material("combat_spellpower"),
+		combat_spellcrit = resolvers.mbonus_material("combat_spellcrit"),
+		inc_damage = { [DamageType.ARCANE] = resolvers.mbonus_material("inc_damage") },
 	},
 }
 
@@ -353,9 +359,9 @@ newEntity{
 	rarity = 12,
 	cost = 50,
 	wielder = {
-		max_life=resolvers.mbonus_material(60, 40),
-		life_regen = resolvers.mbonus_material(15, 5, function(e, v) v=v/10 return 0, v end),
-		healing_factor = resolvers.mbonus_material(20, 10, function(e, v) v=v/100 return 0, v end),
+		max_life=resolvers.mbonus_material("max_life"),
+		life_regen = resolvers.mbonus_material("life_regen"),
+		healing_factor = resolvers.mbonus_material("healing_factor"),
 	},
 }
 
@@ -364,12 +370,13 @@ newEntity{
 	name = "painweaver's ", prefix=true, instant_resolve=true,
 	keywords = {painweaver=true},
 	level_range = {5, 35},
+	greater_ego = 1,
 	rarity = 20,
 	cost = 60,
 	wielder = {
-		healing_factor = resolvers.mbonus_material(30, 5, function(e, v) v=v/10 return 0, -v end),
-		combat_spellpower = resolvers.mbonus_material(15, 5),
-		combat_dam = resolvers.mbonus_material(15, 5),
+		healing_factor = resolvers.mbonus_material("healing_factor", -1),
+		combat_spellpower = resolvers.mbonus_material("combat_spellpower", 2),
+		combat_dam = resolvers.mbonus_material("combat_dam", 2),
 	},
 }
 
@@ -383,13 +390,10 @@ newEntity{
 	cost = 60,
 	wielder = {
 		inc_damage = {
-			[DamageType.FIRE] = resolvers.mbonus_material(10, 5),
-		},
-		melee_project = {
-			[DamageType.FIRE] = resolvers.mbonus_material(10, 5),
+			[DamageType.FIRE] = resolvers.mbonus_material("inc_damage"),
 		},
 		resists_pen = {
-			[DamageType.FIRE] = resolvers.mbonus_material(10, 5),
+			[DamageType.FIRE] = resolvers.mbonus_material("resists_pen"),
 		},
 	},
 }
@@ -404,12 +408,12 @@ newEntity{
 	cost = 40,
 	wielder = {
 		resists={
-			[DamageType.ARCANE] = resolvers.mbonus_material(7, 3),
+			[DamageType.ARCANE] = resolvers.mbonus_material("rare_resists"),
 		},
 		inc_damage = {
-			[DamageType.ARCANE] = resolvers.mbonus_material(20, 5),
+			[DamageType.ARCANE] = resolvers.mbonus_material("inc_damage"),
 		},
-		lite = resolvers.mbonus_material(1, 1),
+		lite = resolvers.mbonus_material("lite"),
 	},
 }
 
@@ -423,10 +427,10 @@ newEntity{
 	cost = 40,
 	wielder = {
 		inc_stats = {
-			[Stats.STAT_CON] = resolvers.mbonus_material(5, 1),
+			[Stats.STAT_CON] = resolvers.mbonus_material("inc_stats"),
 		},
-		combat_spellresist = resolvers.mbonus_material(7, 3),
-		max_stamina = resolvers.mbonus_material(30, 10),
+		combat_spellresist = resolvers.mbonus_material("combat_spellresist"),
+		max_stamina = resolvers.mbonus_material("max_stamina"),
 	},
 }
 
@@ -440,11 +444,11 @@ newEntity{
 	cost = 40,
 	wielder = {
 		resists={
-			[DamageType.NATURE] = resolvers.mbonus_material(10, 5),
+			[DamageType.NATURE] = resolvers.mbonus_material("resists"),
 		},
-		poison_immune = resolvers.mbonus_material(15, 10, function(e, v) v=v/100 return 0, v end),
-		disease_immune = resolvers.mbonus_material(15, 10, function(e, v) v=v/100 return 0, v end),
-		combat_physresist = resolvers.mbonus_material(7, 3),
+		poison_immune = resolvers.mbonus_material("immunity"),
+		disease_immune = resolvers.mbonus_material("immunity"),
+		combat_physresist = resolvers.mbonus_material("save"),
 	},
 }
 
@@ -458,13 +462,10 @@ newEntity{
 	cost = 60,
 	wielder = {
 		inc_damage = {
-			[DamageType.COLD] = resolvers.mbonus_material(10, 5),
-		},
-		melee_project = {
-			[DamageType.COLD] = resolvers.mbonus_material(10, 5),
+			[DamageType.COLD] = resolvers.mbonus_material("inc_damage"),
 		},
 		resists_pen = {
-			[DamageType.COLD] = resolvers.mbonus_material(10, 5),
+			[DamageType.COLD] = resolvers.mbonus_material("resists_pen"),
 		},
 	},
 }
@@ -481,11 +482,11 @@ newEntity{
 	use_talent = { id = Talents.T_BLEEDING_EDGE, level = 4, power = 80 },
 	wielder = {
 		inc_stats = {
-			[Stats.STAT_CUN] = resolvers.mbonus_material(9, 1),
+			[Stats.STAT_CUN] = resolvers.mbonus_material("inc_stats", 2),
 		},
-		combat_mentalresist = resolvers.mbonus_material(5, 5, function(e, v) return 0, -v end),
-		combat_physresist = resolvers.mbonus_material(5, 5, function(e, v) return 0, -v end),
-		combat_spellresist = resolvers.mbonus_material(5, 5, function(e, v) return 0, -v end),
+		combat_mentalresist = resolvers.mbonus_material("save", -1),
+		combat_physresist = resolvers.mbonus_material("save", -1),
+		combat_spellresist = resolvers.mbonus_material("save", -1),
 	},
 }
 
@@ -499,10 +500,10 @@ newEntity{
 	cost = 60,
 	wielder = {
 		resists={
-			[DamageType.ACID] = resolvers.mbonus_material(10, 5),
-			[DamageType.LIGHTNING] = resolvers.mbonus_material(10, 5),
-			[DamageType.FIRE] = resolvers.mbonus_material(10, 5),
-			[DamageType.COLD] = resolvers.mbonus_material(10, 5),
+			[DamageType.ACID] = resolvers.mbonus_material("resists"),
+			[DamageType.LIGHTNING] = resolvers.mbonus_material("resists"),
+			[DamageType.FIRE] = resolvers.mbonus_material("resists"),
+			[DamageType.COLD] = resolvers.mbonus_material("resists"),
 		},
 	},
 }
@@ -519,7 +520,7 @@ newEntity{
 	use_talent = { id = Talents.T_GREATER_WEAPON_FOCUS, level = 4, power = 80 },
 	wielder = {
 		resists_pen = {
-			[DamageType.PHYSICAL] = resolvers.mbonus_material(10, 5),
+			[DamageType.PHYSICAL] = resolvers.mbonus_material("resists_pen"),
 		},
 	},
 }
@@ -535,8 +536,8 @@ newEntity{
 	max_power = 80, power_regen = 1,
 	use_talent = { id = Talents.T_DISENGAGE, level = 2, power = 40 },
 	wielder = {
-		combat_apr = resolvers.mbonus_material(7, 3),
-		combat_def = resolvers.mbonus_material(7, 3),
+		combat_apr = resolvers.mbonus_material("combat_apr"),
+		combat_def = resolvers.mbonus_material("combat_def"),
 	},
 }
 
@@ -551,10 +552,10 @@ newEntity{
 	max_power = 80, power_regen = 1,
 	use_talent = { id = Talents.T_BLINDING_SPEED, level = 4, power = 80 },
 	wielder = {
-		movement_speed = resolvers.mbonus_material(12, 3, function(e, v) v=v/100 return 0, v end),
+		movement_speed = resolvers.mbonus_material("movement_speed"),
 	},
 }
-
+--[=[
 newEntity{
 	power_source = {arcane=true},
 	name = " of blasting", suffix=true, instant_resolve=true,
@@ -565,9 +566,9 @@ newEntity{
 	cost = 60,
 	wielder = {
 		melee_project = {
-			[DamageType.LIGHTNING] = resolvers.mbonus_material(12, 3),
-			[DamageType.PHYSICAL] = resolvers.mbonus_material(12, 3),
+			[DamageType.LIGHTNING] = resolvers.mbonus_material("melee_project"),
+			[DamageType.PHYSICAL] = resolvers.mbonus_material("melee_project"),
 		},
 	},
 }
-
+]=]
diff --git a/game/modules/tome/data/general/objects/egos/robe.lua b/game/modules/tome/data/general/objects/egos/robe.lua
index d56fb14041..527b88a027 100644
--- a/game/modules/tome/data/general/objects/egos/robe.lua
+++ b/game/modules/tome/data/general/objects/egos/robe.lua
@@ -31,7 +31,7 @@ newEntity{
 	rarity = 5,
 	cost = 6,
 	wielder = {
-		resists={[DamageType.FIRE] = resolvers.mbonus_material(30, 10)},
+		resists={[DamageType.FIRE] = resolvers.mbonus_material("resists")},
 	},
 }
 newEntity{
@@ -42,7 +42,7 @@ newEntity{
 	rarity = 5,
 	cost = 6,
 	wielder = {
-		resists={[DamageType.COLD] = resolvers.mbonus_material(30, 10)},
+		resists={[DamageType.COLD] = resolvers.mbonus_material("resists")},
 	},
 }
 newEntity{
@@ -53,7 +53,7 @@ newEntity{
 	rarity = 5,
 	cost = 6,
 	wielder = {
-		resists={[DamageType.ACID] = resolvers.mbonus_material(30, 10)},
+		resists={[DamageType.ACID] = resolvers.mbonus_material("resists")},
 	},
 }
 newEntity{
@@ -64,7 +64,7 @@ newEntity{
 	rarity = 5,
 	cost = 6,
 	wielder = {
-		resists={[DamageType.LIGHTNING] = resolvers.mbonus_material(30, 10)},
+		resists={[DamageType.LIGHTNING] = resolvers.mbonus_material("resists")},
 	},
 }
 newEntity{
@@ -75,7 +75,7 @@ newEntity{
 	rarity = 5,
 	cost = 6,
 	wielder = {
-		resists={[DamageType.NATURE] = resolvers.mbonus_material(30, 10)},
+		resists={[DamageType.NATURE] = resolvers.mbonus_material("resists")},
 	},
 }
 
@@ -87,7 +87,7 @@ newEntity{
 	rarity = 7,
 	cost = 6,
 	wielder = {
-		max_mana = resolvers.mbonus_material(100, 10),
+		max_mana = resolvers.mbonus_material("max_mana", 2),
 	},
 }
 
@@ -99,7 +99,7 @@ newEntity{
 	rarity = 7,
 	cost = 6,
 	wielder = {
-		on_melee_hit={[DamageType.SLIME] = resolvers.mbonus_material(7, 3)},
+		on_melee_hit={[DamageType.SLIME] = resolvers.mbonus_material("on_hit_melee")},
 	},
 }
 
@@ -113,16 +113,15 @@ newEntity{
 	cost = 15,
 	wielder = {
 		inc_damage = {
-			[DamageType.ARCANE] = resolvers.mbonus_material(15, 5),
-			[DamageType.FIRE] = resolvers.mbonus_material(15, 5),
-			[DamageType.COLD] = resolvers.mbonus_material(15, 5),
-			[DamageType.ACID] = resolvers.mbonus_material(15, 5),
-			[DamageType.LIGHTNING] = resolvers.mbonus_material(15, 5),
-			[DamageType.NATURE] = resolvers.mbonus_material(15, 5),
-			[DamageType.BLIGHT] = resolvers.mbonus_material(15, 5),
-			[DamageType.PHYSICAL] = resolvers.mbonus_material(15, 5),
+			[DamageType.ARCANE] = resolvers.mbonus_material("inc_damage"),
+			[DamageType.FIRE] = resolvers.mbonus_material("inc_damage"),
+			[DamageType.COLD] = resolvers.mbonus_material("inc_damage"),
+			[DamageType.ACID] = resolvers.mbonus_material("inc_damage"),
+			[DamageType.LIGHTNING] = resolvers.mbonus_material("inc_damage"),
+			[DamageType.NATURE] = resolvers.mbonus_material("inc_damage"),
+			[DamageType.BLIGHT] = resolvers.mbonus_material("inc_damage"),
 		},
-		combat_spellpower = resolvers.mbonus_material(4, 3),
+		--combat_spellpower = resolvers.mbonus_material("combat_spellpower"),
 	},
 }
 
@@ -134,7 +133,7 @@ newEntity{
 	rarity = 7,
 	cost = 6,
 	wielder = {
-		combat_spellpower = resolvers.mbonus_material(4, 2),
+		combat_spellpower = resolvers.mbonus_material("combat_spellpower"),
 	},
 }
 
@@ -146,7 +145,7 @@ newEntity{
 	rarity = 7,
 	cost = 6,
 	wielder = {
-		combat_armor = resolvers.mbonus_material(6, 2),
+		combat_armor = resolvers.mbonus_material("combat_armor"),
 	},
 }
 
@@ -158,7 +157,7 @@ newEntity{
 	rarity = 7,
 	cost = 6,
 	wielder = {
-		combat_spellcrit = resolvers.mbonus_material(4, 2),
+		combat_spellcrit = resolvers.mbonus_material("combat_spellcrit"),
 	},
 }
 
@@ -170,7 +169,7 @@ newEntity{
 	rarity = 10,
 	cost = 10,
 	wielder = {
-		mana_regen = resolvers.mbonus_material(30, 10, function(e, v) v=v/100 return 0, v end),
+		mana_regen = resolvers.mbonus_material("mana_regen"),
 	},
 }
 
@@ -184,15 +183,15 @@ newEntity{
 	cost = 50,
 	wielder = {
 		resists={
-			[DamageType.FIRE] = resolvers.mbonus_material(10, 5),
-			[DamageType.ACID] = resolvers.mbonus_material(10, 5),
+			[DamageType.FIRE] = resolvers.mbonus_material("resists"),
+			[DamageType.ACID] = resolvers.mbonus_material("resists"),
 		},
-		inc_stats = {
-			[Stats.STAT_MAG] = resolvers.mbonus_material(4, 4),
-			},
+--		inc_stats = {
+--			[Stats.STAT_MAG] = resolvers.mbonus_material("inc_stats"),
+--			},
 		inc_damage = {
-			[DamageType.FIRE] = resolvers.mbonus_material(15, 5),
-			[DamageType.ACID] = resolvers.mbonus_material(15, 5),
+			[DamageType.FIRE] = resolvers.mbonus_material("inc_damage"),
+			[DamageType.ACID] = resolvers.mbonus_material("inc_damage"),
 		},
 	},
 }
@@ -207,15 +206,15 @@ newEntity{
 	cost = 50,
 	wielder = {
 		resists={
-			[DamageType.TEMPORAL] = resolvers.mbonus_material(10, 5),
-			[DamageType.PHYSICAL] = resolvers.mbonus_material(10, 5),
+			[DamageType.TEMPORAL] = resolvers.mbonus_material("resists"),
+			[DamageType.PHYSICAL] = resolvers.mbonus_material("rare_resists"),
 		},
 		inc_stats = {
 			[Stats.STAT_MAG] = resolvers.mbonus_material(4, 4),
 			},
 		inc_damage = {
-			[DamageType.TEMPORAL] = resolvers.mbonus_material(15, 5),
-			[DamageType.PHYSICAL] = resolvers.mbonus_material(15, 5),
+			[DamageType.TEMPORAL] = resolvers.mbonus_material("inc_damage"),
+			--[DamageType.PHYSICAL] = resolvers.mbonus_material("inc_damage"),
 		},
 	},
 }
@@ -230,15 +229,15 @@ newEntity{
 	cost = 50,
 	wielder = {
 		resists={
-			[DamageType.COLD] = resolvers.mbonus_material(10, 5),
-			[DamageType.LIGHTNING] = resolvers.mbonus_material(10, 5),
+			[DamageType.COLD] = resolvers.mbonus_material("resists"),
+			[DamageType.LIGHTNING] = resolvers.mbonus_material("resists"),
 		},
-		inc_stats = {
-			[Stats.STAT_WIL] = resolvers.mbonus_material(4, 4),
-			},
+--		inc_stats = {
+--			[Stats.STAT_WIL] = resolvers.mbonus_material("inc_stats"),
+--			},
 		inc_damage = {
-			[DamageType.COLD] = resolvers.mbonus_material(15, 5),
-			[DamageType.LIGHTNING] = resolvers.mbonus_material(15, 5),
+			[DamageType.COLD] = resolvers.mbonus_material("inc_damage"),
+			[DamageType.LIGHTNING] = resolvers.mbonus_material("inc_damage"),
 		},
 	},
 }
@@ -253,13 +252,13 @@ newEntity{
 	cost = 50,
 	wielder = {
 		resists={
-			[DamageType.LIGHT] = resolvers.mbonus_material(10, 5),
-			[DamageType.DARKNESS] = resolvers.mbonus_material(10, 5),
+			[DamageType.LIGHT] = resolvers.mbonus_material("resists"),
+			[DamageType.DARKNESS] = resolvers.mbonus_material("resists"),
 		},
-		lite = 1,
+		lite = resolvers.mbonus_material("lite"),
 		inc_damage = {
-			[DamageType.LIGHT] = resolvers.mbonus_material(15, 5),
-			[DamageType.DARKNESS] = resolvers.mbonus_material(15, 5),
+			[DamageType.LIGHT] = resolvers.mbonus_material("inc_damage"),
+			[DamageType.DARKNESS] = resolvers.mbonus_material("inc_damage"),
 		},
 	},
 }
@@ -273,12 +272,11 @@ newEntity{
 	rarity = 20,
 	cost = 60,
 	wielder = {
-
 		inc_stats = {
-			[Stats.STAT_MAG] = resolvers.mbonus_material(4, 2),
-			[Stats.STAT_WIL] = resolvers.mbonus_material(4, 2),
-			[Stats.STAT_CUN] = resolvers.mbonus_material(4, 2),
-			[Stats.STAT_CON] = resolvers.mbonus_material(4, 2),
+			[Stats.STAT_MAG] = resolvers.mbonus_material("inc_stats"),
+			[Stats.STAT_WIL] = resolvers.mbonus_material("inc_stats"),
+			[Stats.STAT_CUN] = resolvers.mbonus_material("inc_stats"),
+			--[Stats.STAT_CON] = resolvers.mbonus_material(4, 2),
 			},
 
 	},
@@ -293,10 +291,10 @@ newEntity{
 	rarity = 20,
 	cost = 60,
 	wielder = {
-		combat_spellpower = resolvers.mbonus_material(3, 3),
-		combat_spellcrit = resolvers.mbonus_material(3, 3),
-		max_mana = resolvers.mbonus_material(60, 40),
-		mana_regen = resolvers.mbonus_material(30, 10, function(e, v) v=v/100 return 0, v end),
+		combat_spellpower = resolvers.mbonus_material("combat_spellpower"),
+		combat_spellcrit = resolvers.mbonus_material("combat_spellcrit"),
+		max_mana = resolvers.mbonus_material("max_mana"),
+		mana_regen = resolvers.mbonus_material("mana_regen"),
 
 	},
 }
@@ -310,11 +308,11 @@ newEntity{
 	rarity = 20,
 	cost = 60,
 	wielder = {
-		max_life=resolvers.mbonus_material(60, 40),
-		life_regen = resolvers.mbonus_material(15, 5, function(e, v) v=v/10 return 0, v end),
-		healing_factor = resolvers.mbonus_material(20, 10, function(e, v) v=v/100 return 0, v end),
+		max_life=resolvers.mbonus_material("max_life"),
+		life_regen = resolvers.mbonus_material("life_regen"),
+		healing_factor = resolvers.mbonus_material("healing_factor"),
 		resists={
-			[DamageType.BLIGHT] = resolvers.mbonus_material(15, 5),
+			[DamageType.BLIGHT] = resolvers.mbonus_material("resists"),
 		},
 
 	},
@@ -330,21 +328,37 @@ newEntity{
 	cost = 40,
 	wielder = {
 		resists={
-			[DamageType.FIRE] = resolvers.mbonus_material(10, 5),
-			[DamageType.COLD] = resolvers.mbonus_material(10, 5, function(e, v) return 0, -v end),
-			[DamageType.BLIGHT] = resolvers.mbonus_material(10, 5),
-			[DamageType.NATURE] = resolvers.mbonus_material(10, 5, function(e, v) return 0, -v end),
-			[DamageType.PHYSICAL] = resolvers.mbonus_material(10, 5),
-			[DamageType.ARCANE] = resolvers.mbonus_material(10, 5, function(e, v) return 0, -v end),
+			[DamageType.FIRE] = resolvers.mbonus_material("resists"),
+			[DamageType.COLD] = resolvers.mbonus_material("resists", -1),
+			[DamageType.BLIGHT] = resolvers.mbonus_material("resists"),
+			[DamageType.NATURE] = resolvers.mbonus_material("resists", -1),
+			[DamageType.PHYSICAL] = resolvers.mbonus_material("rare_resists"),
+			[DamageType.ARCANE] = resolvers.mbonus_material("resists", -1),
 		},
-		resists_pen = { 
-			[DamageType.FIRE] = resolvers.mbonus_material(15, 5),
-			[DamageType.BLIGHT] = resolvers.mbonus_material(15, 5),
-			[DamageType.PHYSICAL] = resolvers.mbonus_material(15, 5),
+		resists_pen = {
+			[DamageType.FIRE] = resolvers.mbonus_material("resists_pen", 2),
+			[DamageType.BLIGHT] = resolvers.mbonus_material("resists_pen", 2),
+			[DamageType.PHYSICAL] = resolvers.mbonus_material("resists_pen", 2),
 		},
-	},	
+	},
 }
-
+--[=[
+newEntity{
+	power_source = {nature=true},
+	name = " of gathering", suffix=true, instant_resolve=true,
+	level_range = {20, 50},
+	greater_ego = 1,
+	rarity = 40,
+	cost = 80,
+	wielder = {
+		resists={
+			[DamageType.NATURE] = resolvers.mbonus_material("resists"),
+		},
+		resource_leech_chance = resolvers.mbonus_material("resource_leech_chance"),
+		resource_leech_value = resolvers.mbonus_material("resource_leech_value"),
+	},
+}
+]=]
 newEntity{
 	power_source = {arcane=true},
 	name = " of explosions", suffix=true, instant_resolve=true,
@@ -357,10 +371,10 @@ newEntity{
 	use_talent = { id = Talents.T_GLYPH_OF_EXPLOSION, level = 4, power = 80 },
 	wielder = {
 		resists={
-			[DamageType.FIRE] = resolvers.mbonus_material(10, 5),
+			[DamageType.FIRE] = resolvers.mbonus_material("resists"),
 		},
-		combat_armor = resolvers.mbonus_material(7, 3),
-	},	
+		combat_armor = resolvers.mbonus_material("combat_armor"),
+	},
 }
 
 newEntity{
@@ -373,12 +387,12 @@ newEntity{
 	cost = 40,
 	wielder = {
 		on_melee_hit = {
-			[DamageType.ACID] = resolvers.mbonus_material(10, 5),
-			[DamageType.LIGHTNING] = resolvers.mbonus_material(10, 5),
-			[DamageType.FIRE] = resolvers.mbonus_material(10, 5),
-			[DamageType.COLD] = resolvers.mbonus_material(10, 5),
+			[DamageType.ACID] = resolvers.mbonus_material("on_melee_hit"),
+			[DamageType.LIGHTNING] = resolvers.mbonus_material("on_melee_hit"),
+			[DamageType.FIRE] = resolvers.mbonus_material("on_melee_hit"),
+			[DamageType.COLD] = resolvers.mbonus_material("on_melee_hit"),
 		},
-	},	
+	},
 }
 
 newEntity{
@@ -393,9 +407,9 @@ newEntity{
 	use_talent = { id = Talents.T_NOVA, level = 4, power = 6 },
 	wielder = {
 		resists={
-			[DamageType.LIGHTNING] = resolvers.mbonus_material(20, 5),
+			[DamageType.LIGHTNING] = resolvers.mbonus_material("resists"),
 		},
-	},	
+	},
 }
 
 newEntity{
@@ -408,16 +422,16 @@ newEntity{
 	cost = 60,
 	wielder = {
 		resists={
-			[DamageType.PHYSICAL] = resolvers.mbonus_material(15, 5, function(e, v) return 0, -v end),
-			[DamageType.ARCANE] = resolvers.mbonus_material(7, 3),
+			[DamageType.PHYSICAL] = resolvers.mbonus_material("rare_resists", -1),
+			[DamageType.ARCANE] = resolvers.mbonus_material("rara_resists"),
 		},
 		inc_stats = {
-			[Stats.STAT_MAG] = resolvers.mbonus_material(7, 3),
+			[Stats.STAT_MAG] = resolvers.mbonus_material("inc_stats"),
 		},
-		combat_mentalresist = resolvers.mbonus_material(10, 5),
-		combat_physresist = resolvers.mbonus_material(10, 5),
-		combat_spellresist = resolvers.mbonus_material(10, 5),
-	},	
+		combat_mentalresist = resolvers.mbonus_material("save"),
+		--combat_physresist = resolvers.mbonus_material(10, 5),
+		combat_spellresist = resolvers.mbonus_material("save"),
+	},
 }
 
 newEntity{
@@ -430,11 +444,11 @@ newEntity{
 	cost = 30,
 	wielder = {
 		inc_stats = {
-			[Stats.STAT_CUN] = resolvers.mbonus_material(5, 1),
+			[Stats.STAT_CUN] = resolvers.mbonus_material("inc_stats"),
 		},
-		blind_immune = resolvers.mbonus_material(15, 10, function(e, v) v=v/100 return 0, v end),
-		combat_spellpower = resolvers.mbonus_material(7, 3),
-	},	
+		blind_immune = resolvers.mbonus_material("immunity"),
+		combat_spellpower = resolvers.mbonus_material("combat_spellpower"),
+	},
 }
 
 newEntity{
@@ -447,13 +461,13 @@ newEntity{
 	cost = 40,
 	wielder = {
 		inc_stats = {
-			[Stats.STAT_MAG] = resolvers.mbonus_material(9, 1),
+			[Stats.STAT_MAG] = resolvers.mbonus_material("inc_stats"),
 		},
-		confusion_immune = resolvers.mbonus_material(15, 10, function(e, v) v=v/100 return 0, v end),
-		melee_project = {
-			[DamageType.TEMPORAL] = resolvers.mbonus_material(10, 5),
+		confusion_immune = resolvers.mbonus_material("immunity"),
+		on_melee_hit = {
+			[DamageType.TEMPORAL] = resolvers.mbonus_material("on_melee_hit"),
 		},
-	},	
+	},
 }
 
 newEntity{
@@ -466,12 +480,12 @@ newEntity{
 	cost = 80,
 	wielder = {
 		resists={
-			[DamageType.BLIGHT] = resolvers.mbonus_material(35, 5),
+			[DamageType.BLIGHT] = resolvers.mbonus_material("resists"),
 		},
-		combat_mentalresist = resolvers.mbonus_material(15, 5),
-		combat_armor = resolvers.mbonus_material(7, 3),
-		combat_spellpower = resolvers.mbonus_material(7, 3),
-	},	
+		combat_mentalresist = resolvers.mbonus_material("save", 2),
+		--combat_armor = resolvers.mbonus_material("combat_armor"),
+		combat_spellpower = resolvers.mbonus_material("combat_spellpower"),
+	},
 }
 
 newEntity{
@@ -484,9 +498,9 @@ newEntity{
 	cost = 60,
 	wielder = {
 		inc_stats = {
-			[Stats.STAT_CUN] = resolvers.mbonus_material(9, 1),
+			[Stats.STAT_CUN] = resolvers.mbonus_material("inc_stats", 2),
 		},
-		combat_spellcrit = resolvers.mbonus_material(4, 1),
-		combat_critical_power = resolvers.mbonus_material(30, 10),
-	},	
-}
\ No newline at end of file
+		combat_spellcrit = resolvers.mbonus_material("combat_spellcrit"),
+		--combat_critical_power = resolvers.mbonus_material("combat_critical_power"),
+	},
+}
diff --git a/game/modules/tome/data/general/objects/egos/shield.lua b/game/modules/tome/data/general/objects/egos/shield.lua
index cd021b5019..2a021d0819 100644
--- a/game/modules/tome/data/general/objects/egos/shield.lua
+++ b/game/modules/tome/data/general/objects/egos/shield.lua
@@ -32,7 +32,7 @@ newEntity{
 	rarity = 5,
 	cost = 4,
 	wielder = {
-		resists={[DamageType.FIRE] = resolvers.mbonus_material(20, 10)},
+		resists={[DamageType.FIRE] = resolvers.mbonus_material("resists")},
 	},
 }
 newEntity{
@@ -43,7 +43,7 @@ newEntity{
 	rarity = 5,
 	cost = 4,
 	wielder = {
-		resists={[DamageType.COLD] = resolvers.mbonus_material(20, 10)},
+		resists={[DamageType.COLD] = resolvers.mbonus_material("resists")},
 	},
 }
 newEntity{
@@ -54,7 +54,7 @@ newEntity{
 	rarity = 5,
 	cost = 4,
 	wielder = {
-		resists={[DamageType.ACID] = resolvers.mbonus_material(20, 10)},
+		resists={[DamageType.ACID] = resolvers.mbonus_material("resists")},
 	},
 }
 newEntity{
@@ -65,7 +65,7 @@ newEntity{
 	rarity = 5,
 	cost = 4,
 	wielder = {
-		resists={[DamageType.LIGHTNING] = resolvers.mbonus_material(20, 10)},
+		resists={[DamageType.LIGHTNING] = resolvers.mbonus_material("resists")},
 	},
 }
 newEntity{
@@ -76,11 +76,10 @@ newEntity{
 	rarity = 5,
 	cost = 4,
 	wielder = {
-		resists={[DamageType.NATURE] = resolvers.mbonus_material(20, 10)},
+		resists={[DamageType.NATURE] = resolvers.mbonus_material("resists")},
 	},
 }
 
-
 newEntity{
 	power_source = {arcane=true},
 	name = "flaming ", prefix=true, instant_resolve=true,
@@ -89,7 +88,7 @@ newEntity{
 	rarity = 8,
 	cost = 8,
 	wielder = {
-		on_melee_hit={[DamageType.FIRE] = resolvers.mbonus_material(10, 10)},
+		on_melee_hit={[DamageType.FIRE] = resolvers.mbonus_material("on_melee_hit")},
 	},
 }
 newEntity{
@@ -100,7 +99,7 @@ newEntity{
 	rarity = 8,
 	cost = 10,
 	wielder = {
-		on_melee_hit={[DamageType.ICE] = resolvers.mbonus_material(10, 10)},
+		on_melee_hit={[DamageType.COLD] = resolvers.mbonus_material("on_melee_hit")},
 	},
 }
 newEntity{
@@ -111,7 +110,7 @@ newEntity{
 	rarity = 8,
 	cost = 8,
 	wielder = {
-		on_melee_hit={[DamageType.ACID] = resolvers.mbonus_material(10, 10)},
+		on_melee_hit={[DamageType.ACID] = resolvers.mbonus_material("on_melee_hit")},
 	},
 }
 newEntity{
@@ -122,7 +121,7 @@ newEntity{
 	rarity = 8,
 	cost = 8,
 	wielder = {
-		on_melee_hit={[DamageType.LIGHTNING] = resolvers.mbonus_material(10, 10)},
+		on_melee_hit={[DamageType.LIGHTNING] = resolvers.mbonus_material("on_melee_hit")},
 	},
 }
 
@@ -134,7 +133,7 @@ newEntity{
 	rarity = 10,
 	cost = 10,
 	wielder = {
-		max_life=resolvers.mbonus_material(60, 40),
+		max_life=resolvers.mbonus_material("max_life"),
 	},
 }
 
@@ -146,7 +145,7 @@ newEntity{
 	rarity = 10,
 	cost = 10,
 	wielder = {
-		combat_def=resolvers.mbonus_material(11, 4),
+		combat_def=resolvers.mbonus_material("combat_def", 2),
 	},
 }
 
@@ -154,13 +153,14 @@ newEntity{
 	power_source = {nature=true},
 	name = "reflective ", prefix=true, instant_resolve=true,
 	keywords = {reflective=true},
-	level_range = {10, 50},
-	rarity = 10,
-	cost = 10,
+	level_range = {1, 50},
+	greater_ego = 1,
+	rarity = 30,
+	cost = 50,
+	special_combat = {reflective=true},
 	wielder = {
 		resists={
-			[DamageType.LIGHT] = resolvers.mbonus_material(10, 10),
-			[DamageType.DARKNESS] = resolvers.mbonus_material(10, 10),
+			[DamageType.LIGHT] = resolvers.mbonus_material("resists"),
 		},
 	},
 }
@@ -173,7 +173,7 @@ newEntity{
 	rarity = 8,
 	cost = 8,
 	wielder = {
-		on_melee_hit={[DamageType.LIGHT] = resolvers.mbonus_material(10, 10)},
+		on_melee_hit={[DamageType.LIGHT] = resolvers.mbonus_material("on_melee_hit")},
 	},
 }
 
@@ -185,10 +185,56 @@ newEntity{
 	greater_ego = 1,
 	rarity = 16,
 	cost = 20,
+	special_combat = {
+		critical_power = resolvers.mbonus_material("critical_power"),
+		dam = resolvers.mbonus_material("dam"),
+	},
 	wielder = {
-		pin_immune = resolvers.mbonus_material(20, 10, function(e, v) v=v/100 return 0, v end),
-		combat_dam = resolvers.mbonus_material(5, 5),
-		combat_physcrit = resolvers.mbonus_material(3, 3),
+		combat_dam = resolvers.mbonus_material("combat_dam"),
+	},
+}
+
+newEntity{
+	power_source = {technique=true},
+	name = "spiked ", prefix=true, instant_resolve=true,
+	keywords = {spiked=true},
+	level_range = {1, 50},
+	rarity = 5,
+	cost = 4,
+	special_combat = {
+		dam = resolvers.mbonus_material("dam"),
+	},
+	wielder = {
+		on_melee_hit={[DamageType.PHYSICAL] = resolvers.mbonus_material("on_melee_hit")},
+	},
+}
+
+newEntity{
+	power_source = {technique=true},
+	name = "reinforced ", prefix=true, instant_resolve=true,
+	keywords = {reinforced=true},
+	level_range = {1, 50},
+	rarity = 5,
+	cost = 4,
+	special_combat = {
+		block = resolvers.mbonus_material("block"),
+	},
+}
+
+newEntity{
+	power_source = {technique=true},
+	name = "brutal ", prefix=true, instant_resolve=true,
+	keywords = {brutal=true},
+	greater_ego = 1,
+	level_range = {1, 50},
+	rarity = 16,
+	cost = 20,
+	special_combat = {
+		dam = resolvers.mbonus_material("dam"),
+		block = resolvers.mbonus_material("block"),
+	},
+	wielder = {
+		on_melee_hit={[DamageType.PHYSICAL] = resolvers.mbonus_material("on_melee_hit")},
 	},
 }
 
@@ -202,10 +248,10 @@ newEntity{
 	cost = 20,
 	wielder = {
 		resists={
-			[DamageType.ACID] = resolvers.mbonus_material(8, 5),
-			[DamageType.LIGHTNING] = resolvers.mbonus_material(8, 5),
-			[DamageType.FIRE] = resolvers.mbonus_material(8, 5),
-			[DamageType.COLD] = resolvers.mbonus_material(8, 5),
+			[DamageType.ACID] = resolvers.mbonus_material("resists"),
+			[DamageType.LIGHTNING] = resolvers.mbonus_material("resists"),
+			[DamageType.FIRE] = resolvers.mbonus_material("resists"),
+			[DamageType.COLD] = resolvers.mbonus_material("resists"),
 		},
 	},
 }
@@ -220,10 +266,10 @@ newEntity{
 	cost = 20,
 	wielder = {
 		resists={
-			[DamageType.DARKNESS] = resolvers.mbonus_material(10, 10),
+			[DamageType.DARKNESS] = resolvers.mbonus_material("resists"),
 		},
-		on_melee_hit={[DamageType.DARKNESS] = resolvers.mbonus_material(10, 10)},
-		infravision = resolvers.mbonus_material(2, 1),
+		on_melee_hit={[DamageType.DARKNESS] = resolvers.mbonus_material("on_melee_hit", 2)},
+		infravision = resolvers.mbonus_material("infravision"),
 	},
 }
 
@@ -235,12 +281,12 @@ newEntity{
 	greater_ego = 1,
 	rarity = 18,
 	cost = 40,
+	special_combat = {
+		block = resolvers.mbonus_material("block"),
+	},
 	wielder = {
-		combat_armor = resolvers.mbonus_material(8, 4),
-		stun_immune = resolvers.mbonus_material(3, 2, function(e, v) v=v/10 return 0, v end),
-		inc_stats = {
-			[Stats.STAT_CON] = resolvers.mbonus_material(4, 3),
-			},
+		combat_armor = resolvers.mbonus_material("combat_armor"),
+		stun_immune = resolvers.mbonus_material("immunity"),
 	},
 }
 
@@ -252,11 +298,12 @@ newEntity{
 	greater_ego = 1,
 	rarity = 15,
 	cost = 18,
+	special_combat = {spellplated = true},
 	wielder = {
-		combat_mentalresist = resolvers.mbonus_material(10, 5),
-		combat_spellresist = resolvers.mbonus_material(10, 5),
+		combat_mentalresist = resolvers.mbonus_material("save"),
+		combat_spellresist = resolvers.mbonus_material("save"),
 		inc_stats = {
-			[Stats.STAT_WIL] = resolvers.mbonus_material(4, 2),
+			[Stats.STAT_WIL] = resolvers.mbonus_material("inc_stats"),
 			},
 	},
 }
@@ -269,12 +316,10 @@ newEntity{
 	greater_ego = 1,
 	rarity = 17,
 	cost = 30,
+	special_combat = {bloodruned = true},
 	wielder = {
-		life_regen = resolvers.mbonus_material(15, 5, function(e, v) v=v/10 return 0, v end),
-		healing_factor = resolvers.mbonus_material(20, 10, function(e, v) v=v/100 return 0, v end),
-		inc_stats = {
-			[Stats.STAT_CON] = resolvers.mbonus_material(4, 3),
-			},
+		life_regen = resolvers.mbonus_material("life_regen"),
+		healing_factor = resolvers.mbonus_material("healing_factor"),
 	},
 }
 
@@ -287,20 +332,15 @@ newEntity{
 	rarity = 30,
 	cost = 60,
 	encumber = 15,
+	special_combat = {block = resolvers.mbonus_material("block")},
 	wielder = {
 		resists={
-			[DamageType.ARCANE] = resolvers.mbonus_material(7, 3),
-		},
-		inc_stats = {
-			[Stats.STAT_MAG] = resolvers.mbonus_material(5, 1),
+			[DamageType.ARCANE] = resolvers.mbonus_material("rare_resists"),
 		},
 		on_melee_hit = {
-			[DamageType.ARCANE] = resolvers.mbonus_material(10, 5),
+			[DamageType.ARCANE] = resolvers.mbonus_material("on_melee_hit"),
 		},
-		melee_project = {
-			[DamageType.ARCANE] = resolvers.mbonus_material(10, 5),
-		},
-		fatigue = resolvers.mbonus_material(6, 4, function(e, v) return 0, v end),
+		fatigue = resolvers.mbonus_material("fatigue"),
 	},
 }
 
@@ -312,14 +352,16 @@ newEntity{
 	greater_ego = 1,
 	rarity = 15,
 	cost = 30,
+	special_combat = {
+		melee_project = {
+			[DamageType.NATURE] = resolvers.mbonus_material("melee_project"),
+		},
+	},
 	wielder = {
 		resists={
-			[DamageType.NATURE] = resolvers.mbonus_material(10, 5),
-		},
-		max_life = resolvers.mbonus_material(70, 40),
-		melee_project = {
-			[DamageType.NATURE] = resolvers.mbonus_material(10, 5),
+			[DamageType.NATURE] = resolvers.mbonus_material("resists"),
 		},
+		max_life = resolvers.mbonus_material("max_life", 2),
 	},
 }
 
@@ -331,90 +373,90 @@ newEntity{
 	greater_ego = 1,
 	rarity = 30,
 	cost = 60,
+	special_combat = {
+		dam = resolvers.mbonus_material("dam"),
+		melee_project = {
+			[DamageType.FIRE] = resolvers.mbonus_material("melee_project"),
+		},
+	},
 	wielder = {
 		resists={
-			[DamageType.FIRE] = resolvers.mbonus_material(10, 5),
-		},
-		inc_stats = {
-			[Stats.STAT_STR] = resolvers.mbonus_material(5, 1),
+			[DamageType.FIRE] = resolvers.mbonus_material("resists"),
 		},
 		on_melee_hit = {
-			[DamageType.FIRE] = resolvers.mbonus_material(10, 5),
-		},
-		melee_project = {
-			[DamageType.FIRE] = resolvers.mbonus_material(10, 5),
+			[DamageType.FIRE] = resolvers.mbonus_material("on_melee_hit"),
 		},
 	},
 }
 
 newEntity{
-	power_source = {technique=true},
+	power_source = {nature=true},
 	name = "crackling ", prefix=true, instant_resolve=true,
 	keywords = {crackling=true},
 	level_range = {30, 50},
 	greater_ego = 1,
 	rarity = 30,
 	cost = 60,
+	special_combat = {
+		dam = resolvers.mbonus_material("dam"),
+		melee_project = {
+			[DamageType.LIGHTNING] = resolvers.mbonus_material("melee_project"),
+		},
+	},
 	wielder = {
 		resists={
-			[DamageType.LIGHTNING] = resolvers.mbonus_material(10, 5),
-		},
-		inc_stats = {
-			[Stats.STAT_DEX] = resolvers.mbonus_material(5, 1),
+			[DamageType.LIGHTNING] = resolvers.mbonus_material("resists"),
 		},
 		on_melee_hit = {
-			[DamageType.LIGHTNING] = resolvers.mbonus_material(10, 5),
-		},
-		melee_project = {
-			[DamageType.LIGHTNING] = resolvers.mbonus_material(10, 5),
+			[DamageType.LIGHTNING] = resolvers.mbonus_material("on_melee_hit"),
 		},
 	},
 }
 
 newEntity{
-	power_source = {technique=true},
+	power_source = {nature=true},
 	name = "corrosive ", prefix=true, instant_resolve=true,
 	keywords = {corrosive=true},
 	level_range = {30, 50},
 	greater_ego = 1,
 	rarity = 30,
 	cost = 60,
+	special_combat = {
+		dam = resolvers.mbonus_material("dam"),
+		melee_project = {
+			[DamageType.ACID] = resolvers.mbonus_material("melee_project"),
+		},
+	},
 	wielder = {
 		resists={
-			[DamageType.ACID] = resolvers.mbonus_material(10, 5),
-		},
-		inc_stats = {
-			[Stats.STAT_CON] = resolvers.mbonus_material(5, 1),
+			[DamageType.ACID] = resolvers.mbonus_material("resists"),
 		},
 		on_melee_hit = {
-			[DamageType.ACID] = resolvers.mbonus_material(10, 5),
-		},
-		melee_project = {
-			[DamageType.ACID] = resolvers.mbonus_material(10, 5),
+			[DamageType.ACID] = resolvers.mbonus_material("on_melee_hit"),
 		},
 	},
 }
 
 newEntity{
-	power_source = {technique=true},
+	power_source = {nature=true},
 	name = "wintry ", prefix=true, instant_resolve=true,
 	keywords = {wintry=true},
 	level_range = {30, 50},
 	greater_ego = 1,
 	rarity = 30,
 	cost = 60,
+	special_combat = {
+		dam = resolvers.mbonus_material("dam"),
+		melee_project = {
+			[DamageType.COLD] = resolvers.mbonus_material("melee_project"),
+		},
+	},
 	wielder = {
 		resists={
-			[DamageType.COLD] = resolvers.mbonus_material(10, 5),
-		},
-		inc_stats = {
-			[Stats.STAT_WIL] = resolvers.mbonus_material(5, 1),
+			[DamageType.COLD] = resolvers.mbonus_material("resists"),
 		},
 		on_melee_hit = {
-			[DamageType.COLD] = resolvers.mbonus_material(10, 5),
-		},
-		melee_project = {
-			[DamageType.COLD] = resolvers.mbonus_material(10, 5),
+			[DamageType.COLD] = resolvers.mbonus_material("on_melee_hit"),
 		},
 	},
 }
@@ -427,10 +469,10 @@ newEntity{
 	greater_ego = 1,
 	rarity = 25,
 	cost = 40,
-	max_power = 80, power_regen = 1,
-	use_talent = { id = Talents.T_DISPLACEMENT_SHIELD, level = 5, power = 80 },
+	max_power = 40, power_regen = 1,
+	use_talent = { id = Talents.T_DISPLACEMENT_SHIELD, level = resolvers.mbonus_material("learn_talent_5"), power = 40 },
 	wielder = {
-		combat_def = resolvers.mbonus_material(10, 5),
+		combat_def = resolvers.mbonus_material("combat_def", 2),
 	},
 }
 
@@ -442,11 +484,9 @@ newEntity{
 	greater_ego = 1,
 	rarity = 25,
 	cost = 40,
-	max_power = 80, power_regen = 1,
-	use_talent = { id = Talents.T_EARTHEN_BARRIER, level = 5, power = 80 },
-	wielder = {
-		combat_armor = resolvers.mbonus_material(7, 3),
-	},
+	special_combat = {block = resolvers.mbonus_material("block")},
+	max_power = 30, power_regen = 1,
+	use_talent = { id = Talents.T_EARTHEN_BARRIER, level = resolvers.mbonus_material("learn_talent_5"), power = 30 },
 }
 
 newEntity{
@@ -458,11 +498,11 @@ newEntity{
 	rarity = 10,
 	cost = 20,
 	max_power = 10, power_regen = 1,
-	use_talent = { id = Talents.T_ILLUMINATE, level = 2, power = 6 },
+	use_talent = { id = Talents.T_ILLUMINATE, level = resolvers.mbonus_material("learn_talent_5"), power = 10 },
 	wielder = {
 		resists={
-			[DamageType.LIGHT] = resolvers.mbonus_material(10, 5),
-			[DamageType.DARKNESS] = resolvers.mbonus_material(10, 5),
+			[DamageType.LIGHT] = resolvers.mbonus_material("resists"),
+			[DamageType.DARKNESS] = resolvers.mbonus_material("resists"),
 		},
 	},
 }
@@ -475,14 +515,17 @@ newEntity{
 	greater_ego = 1,
 	rarity = 20,
 	cost = 40,
-	max_power = 80, power_regen = 1,
-	use_talent = { id = Talents.T_TIME_SHIELD, level = 5, power = 80 },
+	max_power = 20, power_regen = 1,
+	use_talent = { id = Talents.T_TIME_SHIELD, level = resolvers.mbonus_material("learn_talent_5"), power = 20 },
+	special_combat = {
+		dam = resolvers.mbonus_material("dam"),
+		melee_project = {
+			[DamageType.TEMPORAL] = resolvers.mbonus_material("melee_project"),
+		},
+	},
 	wielder = {
 		resists={
-			[DamageType.TEMPORAL] = resolvers.mbonus_material(10, 5),
-		},
-		melee_project = {
-			[DamageType.TEMPORAL] = resolvers.mbonus_material(7, 3),
+			[DamageType.TEMPORAL] = resolvers.mbonus_material("resists"),
 		},
 	},
 }
@@ -491,17 +534,11 @@ newEntity{
 	power_source = {nature=true},
 	name = " of harmony", suffix=true, instant_resolve=true,
 	keywords = {harmony=true},
-	level_range = {30, 50},
-	greater_ego = 1,
-	rarity = 30,
-	cost = 60,
-	max_power = 80, power_regen = 1,
-	use_talent = { id = Talents.T_WATERS_OF_LIFE, level = 4, power = 80 },
-	wielder = {
-		talents_types_mastery = {
-			["wild-gift/harmony"] = resolvers.mbonus_material(2, 2, function(e, v) v=v/10 return 0, v end),
-		},
-	},
+	level_range = {1, 50},
+	rarity = 5,
+	cost = 5,
+	max_power = 30, power_regen = 1,
+	use_talent = { id = Talents.T_WATERS_OF_LIFE, level = resolvers.mbonus_material("learn_talent_5"), power = 30 },
 }
 
 newEntity{
@@ -512,11 +549,6 @@ newEntity{
 	greater_ego = 1,
 	rarity = 10,
 	cost = 20,
-	max_power = 80, power_regen = 1,
-	use_talent = { id = Talents.T_BARRIER, level = 4, power = 80 },
-	wielder = {
-		inc_stats = {
-			[Stats.STAT_WIL] = resolvers.mbonus_material(5, 1),
-		},
-	},
-}
\ No newline at end of file
+	max_power = 20, power_regen = 1,
+	use_talent = { id = Talents.T_BARRIER, level = resolvers.mbonus_material("learn_talent_5"), power = 20 },
+}
diff --git a/game/modules/tome/data/general/objects/egos/sling.lua b/game/modules/tome/data/general/objects/egos/sling.lua
index 8e541d87d6..a76eb05a9e 100644
--- a/game/modules/tome/data/general/objects/egos/sling.lua
+++ b/game/modules/tome/data/general/objects/egos/sling.lua
@@ -19,74 +19,7 @@
 local Talents = require("engine.interface.ActorTalents")
 local Stats = require("engine.interface.ActorStats")
 
---load("/data/general/objects/egos/charged-attack.lua")
-
-newEntity{
-	power_source = {technique=true},
-	name = " of power", suffix=true, instant_resolve=true,
-	keywords = {power=true},
-	level_range = {1, 50},
-	rarity = 3,
-	cost = 6,
-	combat={apr = resolvers.mbonus_material(15, 1)},
-}
-
-newEntity{
-	power_source = {technique=true},
-	name = "mighty ", prefix=true, instant_resolve=true,
-	keywords = {mighty=true},
-	level_range = {1, 50},
-	rarity = 3,
-	cost = 4,
-	wielder = {
-		inc_damage={ [DamageType.PHYSICAL] = resolvers.mbonus_material(25, 8), },
-	},
-}
-
-newEntity{
-	power_source = {technique=true},
-	name = "steady ", prefix=true, instant_resolve=true,
-	keywords = {steady=true},
-	level_range = {20, 50},
-	rarity = 9,
-	cost = 10,
-	wielder = {
-		talent_cd_reduction={[Talents.T_STEADY_SHOT]=1},
-	},
-}
-
-newEntity{
-	power_source = {technique=true},
-	name = " of dexterity (#STATBONUS#)", suffix=true, instant_resolve=true,
-	keywords = {dex=true},
-	level_range = {20, 50},
-	rarity = 7,
-	cost = 7,
-	wielder = {
-		inc_stats = { [Stats.STAT_DEX] = resolvers.mbonus_material(6, 2) },
-	},
-}
-
-newEntity{
-	power_source = {technique=true},
-	name = " of speed", suffix=true, instant_resolve=true,
-	keywords = {speed=true},
-	level_range = {20, 50},
-	rarity = 7,
-	cost = 7,
-	combat={physspeed = -0.1},
-}
-
-newEntity{
-	power_source = {technique=true},
-	name = " of great speed", suffix=true, instant_resolve=true,
-	keywords = {SPEED=true},
-	level_range = {40, 50},
-	greater_ego = 1,
-	rarity = 10,
-	cost = 60,
-	combat={physspeed = -0.2},
-}
+load("/data/general/objects/egos/ranged.lua")
 
 newEntity{
 	power_source = {technique=true},
@@ -96,12 +29,14 @@ newEntity{
 	greater_ego = 1,
 	rarity = 24,
 	cost = 40,
+	combat = {
+		dam = resolvers.mbonus_material("dam"),
+	},
 	wielder = {
-		talent_cd_reduction={
-			[Talents.T_STEADY_SHOT]=1,
-			[Talents.T_PINNING_SHOT]=1,
-			[Talents.T_MULTISHOT]=2,
+		learn_talent={
+			[Talents.T_STEADY_SHOT] = resolvers.mbonus_material("learn_talent"),
+			[Talents.T_PINNING_SHOT] = resolvers.mbonus_material("learn_talent"),
+			[Talents.T_MULTISHOT] = resolvers.mbonus_material("learn_talent"),
 		},
-		inc_damage={ [DamageType.PHYSICAL] = resolvers.mbonus_material(14, 8), },
 	},
 }
diff --git a/game/modules/tome/data/general/objects/egos/staves.lua b/game/modules/tome/data/general/objects/egos/staves.lua
index 0f6b6ed8cf..eb1395d2f8 100644
--- a/game/modules/tome/data/general/objects/egos/staves.lua
+++ b/game/modules/tome/data/general/objects/egos/staves.lua
@@ -26,488 +26,437 @@ local Talents = require "engine.interface.ActorTalents"
 
 newEntity{
 	power_source = {arcane=true},
-	name = " of power", suffix=true, instant_resolve=true,
-	keywords = {power=true},
+	name = " of warding", suffix=true, instant_resolve=true,
+	keywords = {warding=true},
 	level_range = {1, 50},
-	rarity = 4,
-	cost = 8,
+	rarity = 10,
+	cost = 20,
 	wielder = {
-		combat_spellpower = resolvers.mbonus_material(30, 3),
+		learn_talent = {
+			[Talents.T_WARD] = resolvers.mbonus_material("learn_talent"),
+		},
+		wards = {},
 	},
+	combat = {of_warding = true},
+	resolvers.genericlast(function(e)
+		for d, v in pairs(e.wielder.inc_damage) do
+			e.wielder.wards[d] = 2
+		end
+	end),
 }
 
 newEntity{
-	power_source = {arcane=true},
-	name = "shimmering ", prefix=true, instant_resolve=true,
-	keywords = {shimmering=true},
-	level_range = {1, 50},
-	rarity = 3,
-	cost = 8,
+	power_source = {technique=true},
+	name = " of savagery", suffix=true, instant_resolve=true,
+	keywords = {savagery=true},
+	level_range = {30, 50},
+	greater_ego = 1,
+	rarity = 20,
+	cost = 40,
 	wielder = {
-		max_mana = resolvers.mbonus_material(70, 40),
+		learn_talent = {
+			[Talents.T_SAVAGERY] = resolvers.mbonus_material("learn_talent_5"),
+		},
 	},
 }
 
-
 newEntity{
 	power_source = {arcane=true},
-	name = " of might", suffix=true, instant_resolve=true,
-	keywords = {might=true},
-	level_range = {1, 50},
-	rarity = 3,
-	cost = 8,
+	name = " of draining", suffix=true, instant_resolve=true,
+	keywords = {draining=true},
+	level_range = {30, 50},
+	greater_ego = 1,
+	rarity = 20,
+	cost = 40,
 	wielder = {
-		combat_spellcrit = resolvers.mbonus_material(15, 4),
+		learn_talent = {
+			[Talents.T_SOUL_DRAIN] = resolvers.mbonus_material("learn_talent_5"),
+		},
 	},
 }
 
 newEntity{
 	power_source = {arcane=true},
-	name = " of wizardry", suffix=true, instant_resolve=true,
-	keywords = {wizardry=true},
-	level_range = {30, 50},
-	greater_ego = 1,
-	rarity = 18,
-	cost = 45,
+	name = " of retribution", suffix=true, instant_resolve=true,
+	keywords = {retribution=true},
+	level_range = {1, 50},
+	rarity = 10,
+	cost = 20,
 	wielder = {
-		combat_spellpower = resolvers.mbonus_material(30, 3),
-		max_mana = resolvers.mbonus_material(100, 10),
-		inc_stats = { [Stats.STAT_MAG] = resolvers.mbonus_material(5, 1), [Stats.STAT_WIL] = resolvers.mbonus_material(5, 1) },
+		learn_talent = {
+			[Talents.T_ELEMENTAL_RETRIBUTION] = resolvers.mbonus_material("learn_talent_5"),
+		},
+		elemental_retribution = {},
 	},
+	combat = {of_retribution = true},
+	resolvers.genericlast(function(e)
+		for d, v in pairs(e.wielder.inc_damage) do
+			e.wielder.elemental_retribution[d] = 1
+		end
+	end),
 }
 
 newEntity{
 	power_source = {arcane=true},
-	name = "magma ", prefix=true, instant_resolve=true,
-	keywords = {magma=true},
+	name = " of breaching", suffix=true, instant_resolve=true,
+	keywords = {breaching=true},
 	level_range = {1, 50},
-	rarity = 3,
-	cost = 5,
+	greater_ego = 1,
+	rarity = 20,
+	cost = 40,
 	wielder = {
-		inc_damage={ [DamageType.FIRE] = resolvers.mbonus_material(25, 8), },
+		resists_pen = {},
 	},
+	combat = {of_breaching = true},
+	resolvers.genericlast(function(e)
+		for d, v in pairs(e.wielder.inc_damage) do
+			e.wielder.resists_pen[d] = v/2
+		end
+	end),
 }
 
 newEntity{
 	power_source = {arcane=true},
-	name = "temporal ", prefix=true, instant_resolve=true,
-	keywords = {temporal=true},
+	name = "potent ", prefix=true, instant_resolve=true,
+	keywords = {potent=true},
 	level_range = {1, 50},
 	rarity = 3,
-	cost = 5,
-	wielder = {
-		inc_damage={ [DamageType.TEMPORAL] = resolvers.mbonus_material(25, 8), },
+	cost = 4,
+	combat = {
+		dam = resolvers.mbonus_material("dam"),
 	},
+	resolvers.genericlast(function(e)
+		e.wielder.inc_damage[e.combat.damtype] = e.combat.dam
+		if e.combat.of_breaching then
+			for d, v in pairs(e.wielder.inc_damage) do
+				e.wielder.resists_pen[d] = math.ceil(e.combat.dam/2)
+			end
+		end
+	end),
 }
 
 newEntity{
-	power_source = {arcane=true},
-	name = "icy ", prefix=true, instant_resolve=true,
-	keywords = {icy=true},
+	power_source = {technique=true},
+	name = "cruel ", prefix=true, instant_resolve=true,
+	keywords = {cruel=true},
 	level_range = {1, 50},
 	rarity = 3,
-	cost = 5,
-	wielder = {
-		inc_damage={ [DamageType.COLD] = resolvers.mbonus_material(25, 8), },
+	cost = 4,
+	combat = {
+		critical_power = resolvers.mbonus_material("critical_power"),
 	},
 }
 
 newEntity{
 	power_source = {arcane=true},
-	name = "acidic ", prefix=true, instant_resolve=true,
-	keywords = {acidic=true},
+	name = "tuned ", prefix=true, instant_resolve=true,
+	keywords = {tuned=true},
 	level_range = {1, 50},
 	rarity = 3,
-	cost = 5,
-	wielder = {
-		inc_damage={ [DamageType.ACID] = resolvers.mbonus_material(25, 8), },
+	cost = 4,
+	combat = {
+		max_acc = resolvers.mbonus_material("max_acc"),
 	},
 }
 
 newEntity{
 	power_source = {arcane=true},
-	name = "crackling ", prefix=true, instant_resolve=true,
-	keywords = {crackling=true},
+	name = "evoker's ", prefix=true, instant_resolve=true,
+	keywords = {evoker=true},
 	level_range = {1, 50},
-	rarity = 3,
-	cost = 5,
-	wielder = {
-		inc_damage={ [DamageType.LIGHTNING] = resolvers.mbonus_material(25, 8), },
+	greater_ego = 1,
+	rarity = 20,
+	cost = 25,
+	combat = {
+		dam = resolvers.mbonus_material("dam"),
+		critical_power = resolvers.mbonus_material("critical_power"),
 	},
+	resolvers.genericlast(function(e)
+		e.wielder.inc_damage[e.combat.damtype] = e.combat.dam
+		if e.combat.of_breaching then
+			for d, v in pairs(e.wielder.inc_damage) do
+				e.wielder.resists_pen[d] = math.ceil(e.combat.dam/2)
+			end
+		end
+	end),
 }
 
 newEntity{
-	power_source = {nature=true},
-	name = "naturalist's ", prefix=true, instant_resolve=true,
-	keywords = {naturalist=true},
+	power_source = {arcane=true},
+	name = "ritualist's ", prefix=true, instant_resolve=true,
+	keywords = {ritualist=true},
 	level_range = {1, 50},
-	rarity = 3,
-	cost = 5,
-	wielder = {
-		inc_damage={ [DamageType.NATURE] = resolvers.mbonus_material(25, 8), },
+	greater_ego = 1,
+	rarity = 20,
+	cost = 25,
+	combat = {
+		dam = resolvers.mbonus_material("dam"),
+		max_acc = resolvers.mbonus_material("max_acc"),
 	},
+	resolvers.genericlast(function(e)
+		e.wielder.inc_damage[e.combat.damtype] = e.combat.dam
+		if e.combat.of_breaching then
+			for d, v in pairs(e.wielder.inc_damage) do
+				e.wielder.resists_pen[d] = math.ceil(e.combat.dam/2)
+			end
+		end
+	end),
 }
 
 newEntity{
-	power_source = {arcane=true},
-	name = "blighted ", prefix=true, instant_resolve=true,
-	keywords = {blighted=true},
+	power_source = {technique=true},
+	name = "sadist's ", prefix=true, instant_resolve=true,
+	keywords = {sadist=true},
 	level_range = {1, 50},
-	rarity = 3,
-	cost = 5,
-	wielder = {
-		inc_damage={ [DamageType.BLIGHT] = resolvers.mbonus_material(25, 8), },
+	greater_ego = 1,
+	rarity = 20,
+	cost = 25,
+	combat = {
+		max_acc = resolvers.mbonus_material("max_acc"),
+		critical_power = resolvers.mbonus_material("critical_power"),
 	},
 }
 
 newEntity{
-	power_source = {nature=true},
-	name = "sunbathed ", prefix=true, instant_resolve=true,
-	keywords = {sunbathed=true},
+	power_source = {arcane=true},
+	name = "greater ", prefix=true, instant_resolve=true,
+	keywords = {greater=true},
 	level_range = {1, 50},
-	rarity = 3,
-	cost = 5,
-	wielder = {
-		inc_damage={ [DamageType.LIGHT] = resolvers.mbonus_material(25, 8), },
-	},
+	greater_ego = 1,
+	rarity = 20,
+	cost = 25,
+	combat = {is_greater = true,},
+	resolvers.generic(function(e)
+		local dam_tables = {
+			magestaff = {engine.DamageType.FIRE, engine.DamageType.COLD, engine.DamageType.LIGHTNING, engine.DamageType.ARCANE},
+			starstaff = {engine.DamageType.LIGHT, engine.DamageType.DARKNESS, engine.DamageType.TEMPORAL},
+			earthstaff = {engine.DamageType.NATURE, engine.DamageType.BLIGHT, engine.DamageType.ACID},
+		}
+		local d_table = dam_tables[e.flavor_name]
+		for i = 1, #d_table do
+			e.wielder.inc_damage[d_table[i]] = e.combat.dam
+		end
+	end),
 }
 
 newEntity{
 	power_source = {nature=true},
-	name = "shadow ", prefix=true, instant_resolve=true,
-	keywords = {shadow=true},
+	name = " of blood", suffix=true, instant_resolve=true,
+	keywords = {blood=true},
 	level_range = {1, 50},
-	rarity = 3,
-	cost = 5,
+	rarity = 10,
+	cost = 10,
 	wielder = {
-		inc_damage={ [DamageType.DARKNESS] = resolvers.mbonus_material(25, 8), },
+		learn_talent = {
+			[Talents.T_BLOODFLOW] = resolvers.mbonus_material("learn_talent_5"),
+		},
 	},
 }
 
 newEntity{
-	power_source = {arcane=true},
-	name = " of divination", suffix=true, instant_resolve=true,
-	keywords = {divination=true},
+	power_source = {nature=true},
+	name = "parasitic ", prefix=true, instant_resolve=true,
+	keywords = {parasitic=true},
 	level_range = {1, 50},
-	rarity = 8,
-	cost = 8,
+	greater_ego = 1,
+	rarity = 60,
+	cost = 40,
 	wielder = {
-		talents_types_mastery = {
-			["spell/divination"] = resolvers.mbonus_material(2, 2, function(e, v) v=v/10 return 0, v end),
-		},
+		resource_leech_chance = resolvers.mbonus_material("resource_leech_chance"),
+		resource_leech_value = resolvers.mbonus_material("resource_leech_value"),
 	},
 }
 
 newEntity{
 	power_source = {arcane=true},
-	name = " of conveyance", suffix=true, instant_resolve=true,
-	keywords = {conveyance=true},
+	name = " of channeling", suffix=true, instant_resolve=true,
+	keywords = {channeling=true},
 	level_range = {1, 50},
 	rarity = 10,
-	cost = 10,
+	cost = 20,
 	wielder = {
-		talents_types_mastery = {
-			["spell/conveyance"] = resolvers.mbonus_material(2, 2, function(e, v) v=v/10 return 0, v end),
+		learn_talent = {
+			[Talents.T_CHANNEL_STAFF] = resolvers.mbonus_material("learn_talent"),
 		},
 	},
-	max_power = 120, power_regen = 1,
-	use_power = { name = "teleport you anywhere on the level, randomly", power = 70, use = function(self, who)
-		game.level.map:particleEmitter(who.x, who.y, 1, "teleport")
-		who:teleportRandom(who.x, who.y, 200)
-		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}
 }
 
 newEntity{
 	power_source = {nature=true},
-	name = " of illumination", suffix=true, instant_resolve=true,
-	keywords = {illumination=true},
+	name = "sentient ", prefix=true, instant_resolve=true,
+	keywords = {sentient=true},
 	level_range = {1, 50},
-	rarity = 8,
-	cost = 8,
-	wielder = {
-		lite = 1,
+	greater_ego = 1,
+	rarity = 60,
+	cost = 200,
+	combat = {
+		sentient = resolvers.rngtable{"default", "aggressive", "fawning"},
 	},
-	max_power = 80, power_regen = 1,
-	use_talent = { id = Talents.T_ILLUMINATE, level = 2, power = 10 },
 }
 
 newEntity{
 	power_source = {arcane=true},
-	name = " of blasting", suffix=true, instant_resolve=true,
-	keywords = {blasting=true},
+	name = " of wizardry", suffix=true, instant_resolve=true,
+	keywords = {wizardry=true},
 	level_range = {30, 50},
 	greater_ego = 1,
 	rarity = 18,
 	cost = 45,
 	wielder = {
-		combat_spellpower = resolvers.mbonus_material(12, 3),
-		combat_spellcrit = resolvers.mbonus_material(4, 2),
-		inc_damage = {
-			[DamageType.FIRE] = resolvers.mbonus_material(15, 5),
-			[DamageType.LIGHTNING] = resolvers.mbonus_material(15, 5),
+		learn_talent = {
+			[Talents.T_ELEMENTAL_RETRIBUTION] = resolvers.mbonus_material("learn_talent_5"),
+			[Talents.T_METAFLOW] = resolvers.mbonus_material("learn_talent"),
+			[Talents.T_COMMAND_STAFF] = resolvers.mbonus_material("learn_talent"),
 		},
+		elemental_retribution = {},
 	},
-	max_power = 80, power_regen = 1,
-	use_talent = { id = Talents.T_BLASTWAVE, level = 2, power = 80 },
+	combat = {
+		of_retribution = true,
+		max_acc = resolvers.mbonus_material("max_acc"),
+	},
+	resolvers.genericlast(function(e)
+		for d, v in pairs(e.wielder.inc_damage) do
+			e.wielder.elemental_retribution[d] = 1
+		end
+	end),
 }
 
-
 newEntity{
 	power_source = {arcane=true},
-	name = " of warding", suffix=true, instant_resolve=true,
-	keywords = {warding=true},
-	level_range = {30, 50},
-	greater_ego = 1,
+	name = "shadowy ", prefix=true, instant_resolve=true,
+	keywords = {shadowy=true},
+	level_range = {1, 50},
 	rarity = 20,
-	cost = 45,
+	cost = 20,
 	wielder = {
-		combat_spellpower = resolvers.mbonus_material(12, 3),
-		stun_immune = resolvers.mbonus_material(3, 3, function(e, v) v=v/10 return 0, v end),
-		combat_def = resolvers.mbonus_material(16, 4),
-		resists={
-			[DamageType.ARCANE] = resolvers.mbonus_material(5, 5),
+		learn_talent = {
+			[Talents.T_FEARSCAPE_FOG] = resolvers.mbonus_material("learn_talent"),
 		},
 	},
-	max_power = 80, power_regen = 1,
-	use_talent = { id = Talents.T_DISPLACEMENT_SHIELD, level = 4, power = 80 },
-}
-
--- TODO: Make into an artifact effect and remove
-newEntity{
-	power_source = {arcane=true},
-	name = " of channeling", suffix=true, instant_resolve=true,
-	keywords = {channeling=true},
-	level_range = {30, 50},
-	greater_ego = 1,
-	rarity = 38,
-	cost = 45,
-	wielder = {
-		combat_spellpower = resolvers.mbonus_material(12, 3),
-		mana_regen = resolvers.mbonus_material(30, 10, function(e, v) v=v/100 return 0, v end),
-	},
-	max_power = 80, power_regen = 1,
-	use_talent = { id = Talents.T_METAFLOW, level = 3, power = 80 },
 }
 
 newEntity{
 	power_source = {nature=true},
-	name = "lifebinding ", prefix=true, instant_resolve=true,
-	keywords = {lifebinding=true},
-	level_range = {30, 50},
-	greater_ego = 1,
-	rarity = 16,
-	cost = 35,
-	wielder = {
-		combat_spellpower = resolvers.mbonus_material(7, 3),
-		life_regen = resolvers.mbonus_material(15, 5, function(e, v) v=v/10 return 0, v end),
-		healing_factor = resolvers.mbonus_material(20, 10, function(e, v) v=v/100 return 0, v end),
-		inc_stats = {
-			[Stats.STAT_CON] = resolvers.mbonus_material(4, 3),
-			},
-	},
-}
-
-newEntity{
-	power_source = {arcane=true},
-	name = "infernal ", prefix=true, instant_resolve=true,
-	keywords = {infernal=true},
-	level_range = {30, 50},
-	greater_ego = 1,
-	rarity = 16,
-	cost = 35,
+	name = " of perception", suffix=true, instant_resolve=true,
+	keywords = {perception=true},
+	level_range = {1, 50},
+	rarity = 3,
+	cost = 4,
 	wielder = {
-		combat_spellpower = resolvers.mbonus_material(7, 3),
-		see_invisible = resolvers.mbonus_material(15, 5),
-		inc_damage = {
-			[DamageType.FIRE] = resolvers.mbonus_material(20, 5),
-			[DamageType.BLIGHT] = resolvers.mbonus_material(20, 5),
+		learn_talent = {
+			[Talents.T_PERCEPTION] = resolvers.mbonus_material("learn_talent_5"),
 		},
 	},
 }
 
 newEntity{
 	power_source = {arcane=true},
-	name = "chronomancer's ", prefix=true, instant_resolve=true,
-	keywords = {chronomancer=true},
-	level_range = {30, 50},
-	greater_ego = 1,
-	rarity = 16,
-	cost = 35,
+	name = " of conveyance", suffix=true, instant_resolve=true,
+	keywords = {conveyance=true},
+	level_range = {1, 50},
+	rarity = 10,
+	cost = 10,
 	wielder = {
-		combat_spellpower = resolvers.mbonus_material(7, 3),
-		movement_speed = 0.1,
-		inc_damage = {
-			[DamageType.TEMPORAL] = resolvers.mbonus_material(20, 5),
+		talents_types_mastery = {
+			["spell/conveyance"] = resolvers.mbonus_material("talents_types_mastery"),
 		},
 	},
-
+	max_power = 120, power_regen = 1,
+	use_power = { name = "teleport you anywhere on the level, randomly", power = 70, use = function(self, who)
+		game.level.map:particleEmitter(who.x, who.y, 1, "teleport")
+		who:teleportRandom(who.x, who.y, 200)
+		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}
 }
 
 newEntity{
 	power_source = {nature=true},
-	name = "abyssal ", prefix=true, instant_resolve=true,
-	keywords = {abyssal=true},
-	level_range = {30, 50},
-	greater_ego = 1,
-	rarity = 40,
-	cost = 80,
+	name = " of illumination", suffix=true, instant_resolve=true,
+	keywords = {illumination=true},
+	level_range = {1, 50},
+	rarity = 3,
+	cost = 4,
 	wielder = {
-		inc_damage = {
-			[DamageType.COLD] = resolvers.mbonus_material(25, 5),
-			[DamageType.DARKNESS] = resolvers.mbonus_material(25, 5),
-		},
-		resists_pen = {
-			[DamageType.COLD] = resolvers.mbonus_material(15, 5),
-			[DamageType.DARKNESS] = resolvers.mbonus_material(15, 5),
-		},
+		lite = resolvers.mbonus_material("lite"),
 	},
+	max_power = 20, power_regen = 1,
+	use_talent = { id = Talents.T_ILLUMINATE, level = resolvers.mbonus_material("learn_talent_5"), power = 10 },
 }
 
 newEntity{
 	power_source = {arcane=true},
-	name = "magelord's ", prefix=true, instant_resolve=true,
-	keywords = {magelord=true},
-	level_range = {10, 50},
+	name = " of blasting", suffix=true, instant_resolve=true,
+	keywords = {blasting=true},
+	level_range = {30, 50},
 	greater_ego = 1,
-	rarity = 40,
-	cost = 60,
-	wielder = {
-		max_mana = resolvers.mbonus_material(100, 20),
-		combat_spellpower = resolvers.mbonus_material(20, 5),
+	rarity = 18,
+	cost = 45,
+	combat = {
+		critical_power = resolvers.mbonus_material("critical_power"),
 	},
+	max_power = 80, power_regen = 1,
+	use_talent = { id = Talents.T_BLASTWAVE, level = resolvers.mbonus_material("learn_talent_5"), power = 50 },
 }
 
-newEntity{
-	power_source = {arcane=true},
-	name = "polar ", prefix=true, instant_resolve=true,
-	keywords = {polar=true},
-	level_range = {10, 50},
-	greater_ego = 1,
-	rarity = 15,
-	cost = 30,
-	wielder = {
-		combat_spellpower = resolvers.mbonus_material(12, 3),
-		inc_damage = {
-			[DamageType.COLD] = resolvers.mbonus_material(15, 5),
-		},
-		on_melee_hit = {
-			[DamageType.ICE] = resolvers.mbonus_material(10, 5),
-		},
-	},
-}
 
 newEntity{
 	power_source = {arcane=true},
-	name = "ethereal ", prefix=true, instant_resolve=true,
-	keywords = {ethereal=true},
+	name = " of displacement", suffix=true, instant_resolve=true,
+	keywords = {displacement=true},
 	level_range = {1, 50},
-	greater_ego = 1,
 	rarity = 10,
 	cost = 20,
-	wielder = {
-		inc_damage = {
-			[DamageType.ARCANE] = resolvers.mbonus_material(10, 5),
-		},
-		mana_regen = resolvers.mbonus_material(50, 10, function(e, v) v=v/100 return 0, v end),
-		combat_spellpower = resolvers.mbonus_material(12, 3),
-	},
+	max_power = 30, power_regen = 1,
+	use_talent = { id = Talents.T_DISPLACEMENT_SHIELD, level = resolvers.mbonus_material("learn_talent_5"), power = 20 },
 }
 
 newEntity{
 	power_source = {arcane=true},
-	name = "bloodlich's ", prefix=true, instant_resolve=true,
-	keywords = {bloodlich=true},
-	level_range = {40, 50},
-	greater_ego = 1,
-	rarity = 40,
-	cost = 90,
-	wielder = {
-		inc_stats = {
-			[Stats.STAT_MAG] = resolvers.mbonus_material(9, 1),
-		},
-		inc_damage = {
-			[DamageType.ACID] = resolvers.mbonus_material(10, 5),
-			[DamageType.LIGHTNING] = resolvers.mbonus_material(10, 5),
-			[DamageType.FIRE] = resolvers.mbonus_material(10, 5),
-			[DamageType.COLD] = resolvers.mbonus_material(10, 5),
-		},
-	},
-}
-
-newEntity{
-	power_source = {arcane=true},
-	name = " of conflagration", suffix=true, instant_resolve=true,
-	keywords = {conflagration=true},
+	name = " of renewal", suffix=true, instant_resolve=true,
+	keywords = {renewal=true},
 	level_range = {30, 50},
 	greater_ego = 1,
-	rarity = 30,
-	cost = 60,
-	wielder = {
-		mana_regen = resolvers.mbonus_material(50, 10, function(e, v) v=v/100 return 0, -v end),
-		combat_spellpower = resolvers.mbonus_material(12, 3),
-		inc_damage = {
-			[DamageType.FIRE] = resolvers.mbonus_material(20, 5),
-		},
-		resists_pen = {
-			[DamageType.FIRE] = resolvers.mbonus_material(20, 5),
-		},
-	},
+	rarity = 18,
+	cost = 45,
+	max_power = 50, power_regen = 1,
+	use_talent = { id = Talents.T_METAFLOW, level = resolvers.mbonus_material("learn_talent_5"), power = 50 },
 }
 
 newEntity{
-	power_source = {arcane=true},
-	name = " of the stars", suffix=true, instant_resolve=true,
-	keywords = {stars=true},
+	power_source = {nature=true},
+	name = "lifebinding ", prefix=true, instant_resolve=true,
+	keywords = {lifebinding=true},
 	level_range = {1, 50},
 	greater_ego = 1,
-	rarity = 15,
-	cost = 30,
-	max_power = 80, power_regen = 1,
-	use_talent = { id = Talents.T_STARFALL, level = 2, power = 50 },
+	rarity = 30,
+	cost = 80,
 	wielder = {
-		combat_spellpower = resolvers.mbonus_material(12, 3),
-		inc_damage = {
-			[DamageType.DARKNESS] = resolvers.mbonus_material(10, 5),
+		learn_talent = {
+			[Talents.T_LIFEBIND] = resolvers.mbonus_material("learn_talent_5"),
 		},
 	},
 }
 
 newEntity{
-	power_source = {arcane=true},
-	name = " of ruination", suffix=true, instant_resolve=true,
-	keywords = {ruination=true},
+	power_source = {nature=true},
+	name = "ghostly ", prefix=true, instant_resolve=true,
+	keywords = {ghostly=true},
 	level_range = {1, 50},
-	greater_ego = 1,
 	rarity = 15,
-	cost = 30,
-	max_power = 80, power_regen = 1,
-	use_talent = { id = Talents.T_CORRUPTED_NEGATION, level = 2, power = 80 },
-	wielder = {
-		combat_spellpower = resolvers.mbonus_material(12, 3),
-		inc_damage = {
-			[DamageType.BLIGHT] = resolvers.mbonus_material(10, 5),
-			[DamageType.NATURE] = resolvers.mbonus_material(10, 5),
-		},
-	},
+	cost = 15,
+	max_power = 50, power_regen = 1,
+	use_talent = { id = Talents.T_WRAITHFORM, level = resolvers.mbonus_material("learn_talent_5"), power = 50 },
 }
 
 newEntity{
 	power_source = {arcane=true},
-	name = " of lightning", suffix=true, instant_resolve=true,
-	keywords = {lightning=true},
-	level_range = {30, 50},
-	greater_ego = 1,
-	rarity = 30,
-	cost = 60,
-	max_power = 80, power_regen = 1,
-	use_talent = { id = Talents.T_CHAIN_LIGHTNING, level = 5, power = 60 },
-	wielder = {
-		combat_spellpower = resolvers.mbonus_material(12, 3),
-		resists_pen = {
-			[DamageType.LIGHTNING] = resolvers.mbonus_material(25, 5),
-		},
-	},
+	name = " of negation", suffix=true, instant_resolve=true,
+	keywords = {negation=true},
+	level_range = {1, 50},
+	rarity = 10,
+	cost = 20,
+	max_power = 40, power_regen = 1,
+	use_talent = { id = Talents.T_CORRUPTED_NEGATION, level = resolvers.mbonus_material("learn_talent_5"), power = 40 },
 }
diff --git a/game/modules/tome/data/general/objects/egos/weapon.lua b/game/modules/tome/data/general/objects/egos/weapon.lua
index c9bbff5918..3e5d610985 100644
--- a/game/modules/tome/data/general/objects/egos/weapon.lua
+++ b/game/modules/tome/data/general/objects/egos/weapon.lua
@@ -29,7 +29,7 @@ newEntity{
 	level_range = {1, 50},
 	rarity = 5,
 	combat = {
-		melee_project={[DamageType.FIRE] = resolvers.mbonus_material(25, 4)},
+		melee_project={[DamageType.FIRE] = resolvers.mbonus_material("melee_project", 1, true)},
 	},
 }
 newEntity{
@@ -39,7 +39,7 @@ newEntity{
 	level_range = {15, 50},
 	rarity = 5,
 	combat = {
-		melee_project={[DamageType.ICE] = resolvers.mbonus_material(15, 4)},
+		melee_project={[DamageType.ICE] = resolvers.mbonus_material("melee_project", 0.5, true)},
 	},
 }
 newEntity{
@@ -49,7 +49,7 @@ newEntity{
 	level_range = {1, 50},
 	rarity = 5,
 	combat = {
-		melee_project={[DamageType.ACID] = resolvers.mbonus_material(25, 4)},
+		melee_project={[DamageType.ACID] = resolvers.mbonus_material("melee_project", 1, true)},
 	},
 }
 newEntity{
@@ -59,18 +59,7 @@ newEntity{
 	level_range = {1, 50},
 	rarity = 5,
 	combat = {
-		melee_project={[DamageType.LIGHTNING] = resolvers.mbonus_material(25, 4)},
-	},
-}
-
-newEntity{
-	power_source = {nature=true},
-	name = "poisonous ", prefix=true, instant_resolve=true,
-	keywords = {poisonous=true},
-	level_range = {1, 50},
-	rarity = 5,
-	combat = {
-		melee_project={[DamageType.POISON] = resolvers.mbonus_material(45, 6)},
+		melee_project={[DamageType.LIGHTNING] = resolvers.mbonus_material("melee_project", 1, true)},
 	},
 }
 
@@ -81,7 +70,7 @@ newEntity{
 	level_range = {10, 50},
 	rarity = 5,
 	combat = {
-		melee_project={[DamageType.SLIME] = resolvers.mbonus_material(45, 6)},
+		melee_project={[DamageType.SLIME] = resolvers.mbonus_material("melee_project", 0.5, true)},
 	},
 }
 
@@ -92,7 +81,7 @@ newEntity{
 	level_range = {1, 50},
 	rarity = 3,
 	cost = 4,
-	wielder={combat_atk = resolvers.mbonus_material(20, 5)},
+	combat = {max_acc = resolvers.mbonus_material("max_acc")},
 }
 
 newEntity{
@@ -102,7 +91,7 @@ newEntity{
 	level_range = {1, 50},
 	rarity = 3,
 	cost = 6,
-	combat={apr = resolvers.mbonus_material(20, 5)},
+	combat = {apr = resolvers.mbonus_material("combat_apr", 4)},
 }
 
 newEntity{
@@ -115,10 +104,10 @@ newEntity{
 	cost = 35,
 	combat = {
 		melee_project={
-			[DamageType.FIRE] = resolvers.mbonus_material(25, 4),
-			[DamageType.ICE] = resolvers.mbonus_material(15, 4),
-			[DamageType.ACID] = resolvers.mbonus_material(25, 4),
-			[DamageType.LIGHTNING] = resolvers.mbonus_material(25, 4),
+			[DamageType.FIRE] = resolvers.mbonus_material("melee_project", 0.5, true),
+			[DamageType.ICE] = resolvers.mbonus_material("melee_project", 0.5, true),
+			[DamageType.ACID] = resolvers.mbonus_material("melee_project", 0.5, true),
+			[DamageType.LIGHTNING] = resolvers.mbonus_material("melee_project", 0.5, true),
 		},
 	},
 }
@@ -131,7 +120,7 @@ newEntity{
 	rarity = 3,
 	cost = 4,
 	combat = {
-		dam = resolvers.mbonus_material(15, 5),
+		dam = resolvers.mbonus_material("dam", 1, true),
 	},
 }
 
@@ -139,13 +128,13 @@ newEntity{
 	power_source = {arcane=true},
 	name = " of torment", suffix=true, instant_resolve=true,
 	keywords = {torment=true},
-	level_range = {15, 50},
+	level_range = {1, 50},
 	rarity = 18,
 	cost = 22,
 	combat = {
-		special_on_hit = {desc="10% chance to torment the target", fct=function(combat, who, target)
-			if not rng.percent(10) then return end
-			local eff = rng.table{"stun", "blind", "pin", "teleport", "stone", "confusion", "silence", "knockback"}
+		special_on_hit = {desc="30% chance to torment the target", fct=function(combat, who, target)
+			if not rng.percent(30) then return end
+			local eff = rng.table{"stun", "blind", "pin", "confusion", "silence"}
 			if not target:canBe(eff) then return end
 			if not target:checkHit(who:combatAttack(combat), target:combatPhysicalResist(), 15) then return end
 			if eff == "stun" then target:setEffect(target.EFF_STUNNED, 3, {})
@@ -153,8 +142,6 @@ newEntity{
 			elseif eff == "pin" then target:setEffect(target.EFF_PINNED, 3, {})
 			elseif eff == "confusion" then target:setEffect(target.EFF_CONFUSED, 3, {power=60})
 			elseif eff == "silence" then target:setEffect(target.EFF_SILENCED, 3, {})
-			elseif eff == "knockback" then target:knockback(who.x, who.y, 3)
-			elseif eff == "teleport" then target:teleportRandom(target.x, target.y, 10)
 			end
 		end},
 	},
@@ -169,18 +156,30 @@ newEntity{
 	rarity = 25,
 	cost = 35,
 	wielder = {
-		combat_atk = resolvers.mbonus_material(10, 2),
-		inc_damage = {
-			[DamageType.PHYSICAL] = resolvers.mbonus_material(15, 4),
-		},
-		inc_stats = {
-			[Stats.STAT_DEX] = resolvers.mbonus_material(4, 3),
-			[Stats.STAT_STR] = resolvers.mbonus_material(4, 3),
-		},
-		stamina_regen_on_hit = resolvers.mbonus_material(23, 7, function(e, v) v=v/10 return 0, v end),
+		stamina_regen_on_hit = resolvers.mbonus_material("stamina_regen_on_hit"),
+	},
+	combat = {
+		apr = resolvers.mbonus_material("combat_apr", 3),
+		dam = resolvers.mbonus_material("dam", 1, true),
+	},
+}
+
+newEntity{
+	power_source = {nature=true},
+	name = "insatiable ", prefix=true, instant_resolve=true,
+	keywords = {insatiable=true},
+	level_range = {1, 50},
+	greater_ego = 1,
+	rarity = 60,
+	cost = 40,
+	wielder = {
+		resource_leech_chance = resolvers.mbonus_material("resource_leech_chance"),
+		resource_leech_value = resolvers.mbonus_material("resource_leech_value", 2),
 	},
 	combat = {
-		apr = resolvers.mbonus_material(8, 1),
+		melee_project = {
+			[DamageType.NATURE] = resolvers.mbonus_material("melee_project", 1, true),
+		},
 	},
 }
 
@@ -194,14 +193,11 @@ newEntity{
 	cost = 35,
 	combat = {
 		melee_project={
-			[DamageType.BLIGHT] = resolvers.mbonus_material(25, 4),
-			[DamageType.DARKNESS] = resolvers.mbonus_material(25, 4),
+			[DamageType.BLIGHT] = resolvers.mbonus_material("melee_project", 1, true),
+			[DamageType.DARKNESS] = resolvers.mbonus_material("melee_project", 1, true),
 		},
 	},
-	wielder = {
-		see_invisible = resolvers.mbonus_material(20, 5),
-		combat_physcrit = resolvers.mbonus_material(10, 4),
-	},
+
 }
 
 newEntity{
@@ -211,8 +207,8 @@ newEntity{
 	level_range = {1, 50},
 	rarity = 3,
 	cost = 4,
-	wielder = {
-		combat_physcrit = resolvers.mbonus_material(7, 3),
+	combat = {
+		critical_power = resolvers.mbonus_material("critical_power"),
 	},
 }
 
@@ -224,10 +220,10 @@ newEntity{
 	rarity = 3,
 	cost = 4,
 	combat = {
-		melee_project={[DamageType.LIGHT] = resolvers.mbonus_material(45, 6)},
+		melee_project={[DamageType.LIGHT] = resolvers.mbonus_material("melee_project", 1, true)},
 	},
 }
-
+--[=[
 newEntity{
 	power_source = {technique=true},
 	name = " of defense", suffix=true, instant_resolve=true,
@@ -239,7 +235,7 @@ newEntity{
 		combat_def = resolvers.mbonus_material(7, 3),
 	},
 }
-
+]=]
 newEntity{
 	power_source = {technique=true},
 	name = " of ruin", suffix=true, instant_resolve=true,
@@ -248,15 +244,11 @@ newEntity{
 	greater_ego = 1,
 	rarity = 20,
 	cost = 25,
-	wielder = {
-		inc_stats = {
-			[Stats.STAT_STR] = resolvers.mbonus_material(4, 3),
-		},
-		combat_physcrit = resolvers.mbonus_material(7, 3),
-		combat_critical_power = resolvers.mbonus_material(10, 10),
-		combat_apr = resolvers.mbonus_material(7, 3),
+	combat = {
+		max_acc = resolvers.mbonus_material("max_acc"),
+		critical_power = resolvers.mbonus_material("critical_power"),
+		melee_project={[DamageType.TEMPORAL] = resolvers.mbonus_material("melee_project", 1, true)},
 	},
-
 }
 
 newEntity{
@@ -267,13 +259,9 @@ newEntity{
 	greater_ego = 1,
 	rarity = 25,
 	cost = 30,
-	combat = { physspeed = -0.1 },
-	wielder = {
-		combat_atk = resolvers.mbonus_material(20, 2),
-		inc_stats = {
-			[Stats.STAT_DEX] = resolvers.mbonus_material(4, 3),
-			[Stats.STAT_CUN] = resolvers.mbonus_material(4, 3),
-		},
+	combat = {
+		physspeed = resolvers.mbonus_material("physspeed"),
+		max_acc = resolvers.mbonus_material("max_acc"),
 	},
 }
 
@@ -285,12 +273,9 @@ newEntity{
 	greater_ego = 1,
 	rarity = 20,
 	cost = 30,
-	wielder = {
-		combat_spellcrit = resolvers.mbonus_material(7, 3),
-		inc_stats = {
-			[Stats.STAT_MAG] = resolvers.mbonus_material(4, 3),
-			[Stats.STAT_WIL] = resolvers.mbonus_material(4, 3),
-		},
+	combat = {
+		affects_spells = true,
+		melee_project={[DamageType.ARCANE] = resolvers.mbonus_material("melee_project", 1, true)},
 	},
 }
 
@@ -303,16 +288,13 @@ newEntity{
 	rarity = 35,
 	cost = 40,
 	wielder = {
-		on_melee_hit = {
-			[DamageType.FIRE] = resolvers.mbonus_material(20, 5),
-		},
 		resists_pen = {
-			[DamageType.FIRE] = resolvers.mbonus_material(20, 5),
+			[DamageType.FIRE] = resolvers.mbonus_material("resists_pen", 2),
 		},
 	},
 	combat = {
 		melee_project = {
-			[DamageType.FIRE] = resolvers.mbonus_material(46, 5),
+			[DamageType.FIRE] = resolvers.mbonus_material("melee_project", 2, true),
 		},
 	},
 }
@@ -326,16 +308,13 @@ newEntity{
 	rarity = 45,
 	cost = 40,
 	wielder = {
-		on_melee_hit = {
-			[DamageType.ICE] = resolvers.mbonus_material(20, 5),
-		},
 		resists_pen = {
-			[DamageType.COLD] = resolvers.mbonus_material(20, 5),
+			[DamageType.COLD] = resolvers.mbonus_material("resists_pen", 2),
 		},
 	},
 	combat = {
 		melee_project = {
-			[DamageType.COLD] = resolvers.mbonus_material(46, 5),
+			[DamageType.COLD] = resolvers.mbonus_material("melee_project", 2, true),
 		},
 	},
 }
@@ -349,16 +328,13 @@ newEntity{
 	rarity = 35,
 	cost = 40,
 	wielder = {
-		on_melee_hit = {
-			[DamageType.LIGHTNING] = resolvers.mbonus_material(20, 5),
-		},
 		resists_pen = {
-			[DamageType.LIGHTNING] = resolvers.mbonus_material(20, 5),
+			[DamageType.LIGHTNING] = resolvers.mbonus_material("resists_pen", 2),
 		},
 	},
 	combat = {
 		melee_project = {
-			[DamageType.LIGHTNING] = resolvers.mbonus_material(46, 5),
+			[DamageType.LIGHTNING] = resolvers.mbonus_material("melee_project", 2, true),
 		},
 	},
 }
@@ -372,16 +348,13 @@ newEntity{
 	rarity = 35,
 	cost = 40,
 	wielder = {
-		on_melee_hit = {
-			[DamageType.ACID] = resolvers.mbonus_material(20, 5),
-		},
 		resists_pen = {
-			[DamageType.ACID] = resolvers.mbonus_material(20, 5),
+			[DamageType.ACID] = resolvers.mbonus_material("resists_pen", 2),
 		},
 	},
 	combat = {
 		melee_project = {
-			[DamageType.ACID] = resolvers.mbonus_material(46, 5),
+			[DamageType.ACID] = resolvers.mbonus_material("melee_project", 2, true),
 		},
 	},
 }
@@ -395,16 +368,13 @@ newEntity{
 	rarity = 45,
 	cost = 40,
 	wielder = {
-		on_melee_hit = {
-			[DamageType.SLIME] = resolvers.mbonus_material(20, 5),
-		},
 		resists_pen = {
-			[DamageType.NATURE] = resolvers.mbonus_material(20, 5),
+			[DamageType.NATURE] = resolvers.mbonus_material("resists_pen", 2),
 		},
 	},
 	combat = {
 		melee_project = {
-			[DamageType.SLIME] = resolvers.mbonus_material(46, 5),
+			[DamageType.SLIME] = resolvers.mbonus_material("melee_project", 1, true),
 		},
 	},
 }
@@ -418,15 +388,14 @@ newEntity{
 	rarity = 30,
 	cost = 40,
 	wielder = {
-		inc_stats = {
-			[Stats.STAT_CON] = resolvers.mbonus_material(9, 1),
+		talents_types_mastery = {
+			["technique/combat-training"] = resolvers.mbonus_material("talents_types_mastery"),
 		},
-		disarm_immune = resolvers.mbonus_material(25, 10, function(e, v) v=v/100 return 0, v end),
-		combat_dam = resolvers.mbonus_material(15, 5),
-		resists_pen = {
-			[DamageType.PHYSICAL] = resolvers.mbonus_material(15, 5),
+		learn_talent = {
+			[Talents.T_GREATER_WEAPON_FOCUS] = resolvers.mbonus_material("learn_talent"),
 		},
 	},
+
 }
 
 newEntity{
@@ -437,13 +406,12 @@ newEntity{
 	greater_ego = 1,
 	rarity = 20,
 	cost = 40,
+	combat = {
+		apr = resolvers.mbonus_material("combat_apr", 5),
+	},
 	wielder = {
-		combat_apr = resolvers.mbonus_material(15, 5),
-		inc_damage = {
-			[DamageType.PHYSICAL] = resolvers.mbonus_material(10, 5),
-		},
 		resists_pen = {
-			[DamageType.PHYSICAL] = resolvers.mbonus_material(15, 5),
+			[DamageType.PHYSICAL] = resolvers.mbonus_material("resists_pen", 1, true),
 		},
 	},
 }
@@ -456,18 +424,11 @@ newEntity{
 	greater_ego = 1,
 	rarity = 30,
 	cost = 60,
-	max_power = 80, power_regen = 1,
-	use_talent = { id = Talents.T_EPIDEMIC, level = 4, power = 80 },
-	wielder = {
-		inc_stats = {
-			[Stats.STAT_CON] = resolvers.mbonus_material(10, 5, function(e, v) return 0, -v end),
-			[Stats.STAT_MAG] = resolvers.mbonus_material(5, 1),
-		},
-		disease_immune = resolvers.mbonus_material(55, 10, function(e, v) v=v/100 return 0, v end),
-	},
+	max_power = 20, power_regen = 1,
+	use_talent = { id = Talents.T_EPIDEMIC, level = 5, power = 10 },
 	combat = {
 		melee_project = {
-			[DamageType.BLIGHT] = resolvers.mbonus_material(46, 5),
+			[DamageType.BLIGHT] = resolvers.mbonus_material("melee_project", 2, true),
 		},
 	},
 }
@@ -481,7 +442,7 @@ newEntity{
 	rarity = 30,
 	cost = 60,
 	max_power = 20, power_regen = 1,
-	use_talent = { id = Talents.T_WAVE_OF_POWER, level = 4, power = 12 },
+	use_talent = { id = Talents.T_WAVE_OF_POWER, level = 4, power = 10 },
 }
 
 newEntity{
@@ -492,11 +453,10 @@ newEntity{
 	greater_ego = 1,
 	rarity = 20,
 	cost = 40,
-	max_power = 80, power_regen = 1,
-	use_talent = { id = Talents.T_LIFE_TAP, level = 3, power = 80 },
-	wielder = {
-		combat_physcrit = resolvers.mbonus_material(4, 3),
-		combat_dam = resolvers.mbonus_material(12, 3),
+	max_power = 30, power_regen = 1,
+	use_talent = { id = Talents.T_LIFE_TAP, level = 5, power = 30 },
+	combat = {
+		dam = resolvers.mbonus_material("dam", 2, true),
 	},
 }
 
@@ -508,37 +468,39 @@ newEntity{
 	greater_ego = 1,
 	rarity = 15,
 	cost = 30,
-	wielder = {
-		resists={
-			[DamageType.TEMPORAL] = resolvers.mbonus_material(15, 5),
-		},
-		on_melee_hit = {
-			[DamageType.TEMPORAL] = resolvers.mbonus_material(10, 5),
-		},
-	},
 	combat = {
 		melee_project = {
-			[DamageType.TEMPORAL] = resolvers.mbonus_material(46, 5),
+			[DamageType.TEMPORAL] = resolvers.mbonus_material("melee_project", 2, true),
+			[DamageType.RANDOM_CONFUSION] = resolvers.mbonus_material("melee_project", 0.5, true),
 		},
 	},
 }
 
 --[[ Todo: make it balanced
 newEntity{
-	power_source = {nature=true},
-	name = "insatiable ", prefix=true, instant_resolve=true,
-	keywords = {insatiable=true},
-	level_range = {1, 50},
+	power_source = {technique=true},
+	name = " of concussion", suffix=true, instant_resolve=true,
+	keywords = {concussion=true},
+	level_range = {10, 50},
 	greater_ego = 1,
-	rarity = 60,
+	rarity = 40,
+	cost = 40,
+	resolvers.generic(function(e)
+		e.combat.concussion = (e.combat.critical_power - 1) * 100
+	end),
+}
+
+newEntity{
+	power_source = {technique=true},
+	name = " of savagery", suffix=true, instant_resolve=true,
+	keywords = {savagery=true},
+	level_range = {30, 50},
+	greater_ego = 1,
+	rarity = 20,
 	cost = 40,
 	wielder = {
-		resource_leech_chance = resolvers.mbonus_material(4, 1, function(e, v) v=v*10 return 0, v end),
-		resource_leech_value = resolvers.mbonus_material(15, 5),
-	},
-	combat = {
-		melee_project = {
-			[DamageType.NATURE] = resolvers.mbonus_material(25, 5),
+		learn_talent = {
+			[Talents.T_SAVAGERY] = resolvers.mbonus_material("learn_talent_5"),
 		},
 	},
 }
diff --git a/game/modules/tome/data/general/objects/egos/wizard-hat.lua b/game/modules/tome/data/general/objects/egos/wizard-hat.lua
index 4bbfe27cb6..c3fcb53539 100644
--- a/game/modules/tome/data/general/objects/egos/wizard-hat.lua
+++ b/game/modules/tome/data/general/objects/egos/wizard-hat.lua
@@ -32,9 +32,9 @@ newEntity{
 	rarity = 10,
 	cost = 20,
 	wielder = {
-		stamina_regen_on_hit = resolvers.mbonus_material(23, 7, function(e, v) v=v/10 return 0, v end),
-		equilibrium_regen_on_hit = resolvers.mbonus_material(23, 7, function(e, v) v=v/10 return 0, v end),
-		mana_regen_on_hit = resolvers.mbonus_material(23, 7, function(e, v) v=v/10 return 0, v end),
+		stamina_regen_on_hit = resolvers.mbonus_material("stamina_regen_on_hit"),
+		equilibrium_regen_on_hit = resolvers.mbonus_material("equilibrium_regen_on_hit"),
+		mana_regen_on_hit = resolvers.mbonus_material("mana_regen_on_hit"),
 	},
 }
 
@@ -46,7 +46,7 @@ newEntity{
 	rarity = 6,
 	cost = 4,
 	wielder = {
-		inc_stats = { [Stats.STAT_MAG] = resolvers.mbonus_material(8, 2) },
+		inc_stats = { [Stats.STAT_MAG] = resolvers.mbonus_material("inc_stats") },
 	},
 }
 newEntity{
@@ -57,7 +57,7 @@ newEntity{
 	rarity = 6,
 	cost = 4,
 	wielder = {
-		inc_stats = { [Stats.STAT_WIL] = resolvers.mbonus_material(8, 2) },
+		inc_stats = { [Stats.STAT_WIL] = resolvers.mbonus_material("inc_stats") },
 	},
 }
 newEntity{
@@ -68,7 +68,7 @@ newEntity{
 	rarity = 6,
 	cost = 4,
 	wielder = {
-		inc_stats = { [Stats.STAT_CUN] = resolvers.mbonus_material(8, 2) },
+		inc_stats = { [Stats.STAT_CUN] = resolvers.mbonus_material("inc_stats") },
 	},
 }
 newEntity{
@@ -90,7 +90,7 @@ newEntity{
 	rarity = 10,
 	cost = 4,
 	wielder = {
-		max_mana = resolvers.mbonus_material(70, 40),
+		max_mana = resolvers.mbonus_material("max_mana"),
 	},
 }
 
@@ -102,7 +102,7 @@ newEntity{
 	rarity = 5,
 	cost = 6,
 	wielder = {
-		blind_immune = resolvers.mbonus_material(3, 3, function(e, v) v=v/10 return 0, v end),
+		blind_immune = resolvers.mbonus_material("immunity"),
 	},
 }
 
@@ -117,9 +117,9 @@ newEntity{
 	cost = 20,
 	wielder = {
 		resists={
-			[DamageType.ARCANE] = resolvers.mbonus_material(5, 5),
+			[DamageType.ARCANE] = resolvers.mbonus_material("rare_resists"),
 		},
-		combat_spellpower = resolvers.mbonus_material(5, 3),
+		combat_spellpower = resolvers.mbonus_material("combat_spellpower"),
 	},
 	max_power = 80, power_regen = 1,
 	use_talent = { id = Talents.T_MANAFLOW, level = 1, power = 80 },
@@ -134,8 +134,8 @@ newEntity{
 	cost = 5,
 	wielder = {
 		resists={
-			[DamageType.FIRE] = resolvers.mbonus_material(10, 5),
-			[DamageType.COLD] = resolvers.mbonus_material(10, 5),
+			[DamageType.FIRE] = resolvers.mbonus_material("resists"),
+			[DamageType.COLD] = resolvers.mbonus_material("resists"),
 		},
 	},
 }
@@ -149,9 +149,9 @@ newEntity{
 	cost = 5,
 	wielder = {
 		resists={
-			[DamageType.LIGHTNING] = resolvers.mbonus_material(10, 5),
+			[DamageType.LIGHTNING] = resolvers.mbonus_material("resists"),
 		},
-		stun_immune = resolvers.mbonus_material(20, 10, function(e, v) v=v/100 return 0, v end),
+		stun_immune = resolvers.mbonus_material("immunity"),
 	},
 }
 
@@ -164,9 +164,9 @@ newEntity{
 	cost = 5,
 	wielder = {
 		resists={
-			[DamageType.TEMPORAL] = resolvers.mbonus_material(10, 5),
+			[DamageType.TEMPORAL] = resolvers.mbonus_material("resists"),
 		},
-		teleport_immune = resolvers.mbonus_material(20, 10, function(e, v) v=v/100 return 0, v end),
+		teleport_immune = resolvers.mbonus_material("immunity"),
 	},
 }
 
@@ -178,8 +178,8 @@ newEntity{
 	rarity = 6,
 	cost = 5,
 	wielder = {
-		stun_immune = resolvers.mbonus_material(20, 10, function(e, v) v=v/100 return 0, v end),
-		knockback_immune = resolvers.mbonus_material(20, 10, function(e, v) v=v/100 return 0, v end),
+		stun_immune = resolvers.mbonus_material("immunity"),
+		knockback_immune = resolvers.mbonus_material("immunity"),
 	},
 }
 
@@ -192,10 +192,10 @@ newEntity{
 	cost = 9,
 	wielder = {
 		resists={
-			[DamageType.ACID] = resolvers.mbonus_material(10, 5),
+			[DamageType.ACID] = resolvers.mbonus_material("resists"),
 		},
-		poison_immune = resolvers.mbonus_material(10, 5, function(e, v) return 0, v/100 end),
-		disease_immune = resolvers.mbonus_material(10, 5, function(e, v) return 0, v/100 end),
+		poison_immune = resolvers.mbonus_material("immunity"),
+		disease_immune = resolvers.mbonus_material("immunity"),
 	},
 }
 
@@ -207,7 +207,7 @@ newEntity{
 	rarity = 10,
 	cost = 10,
 	wielder = {
-		mana_regen = resolvers.mbonus_material(30, 10, function(e, v) v=v/100 return 0, v end),
+		mana_regen = resolvers.mbonus_material("mana_regen"),
 	},
 }
 
@@ -220,10 +220,10 @@ newEntity{
 	rarity = 13,
 	cost = 20,
 	wielder = {
-		combat_spellcrit = resolvers.mbonus_material(3, 3),
+		combat_spellcrit = resolvers.mbonus_material("combat_spellcrit"),
 		inc_stats = {
-			[Stats.STAT_MAG] = resolvers.mbonus_material(3, 2),
-			[Stats.STAT_WIL] = resolvers.mbonus_material(3, 2),
+			[Stats.STAT_MAG] = resolvers.mbonus_material("inc_stats"),
+			[Stats.STAT_WIL] = resolvers.mbonus_material("inc_stats"),
 		},
 	},
 }
@@ -238,10 +238,10 @@ newEntity{
 	cost = 20,
 	wielder = {
 		inc_damage = {
-			[DamageType.FIRE] = resolvers.mbonus_material(7, 5),
-			[DamageType.COLD] = resolvers.mbonus_material(7, 5),
-			[DamageType.ACID] = resolvers.mbonus_material(7, 5),
-			[DamageType.LIGHTNING] = resolvers.mbonus_material(7, 5),
+			[DamageType.FIRE] = resolvers.mbonus_material("inc_damage"),
+			[DamageType.COLD] = resolvers.mbonus_material("inc_damage"),
+			[DamageType.ACID] = resolvers.mbonus_material("inc_damage"),
+			[DamageType.LIGHTNING] = resolvers.mbonus_material("inc_damage"),
 		},
 	},
 }
@@ -255,10 +255,10 @@ newEntity{
 	rarity = 11,
 	cost = 15,
 	wielder = {
-		max_life=resolvers.mbonus_material(30, 30),
-		life_regen = resolvers.mbonus_material(15, 5, function(e, v) v=v/10 return 0, v end),
+		max_life=resolvers.mbonus_material("max_life"),
+		life_regen = resolvers.mbonus_material("life_regen"),
 		talents_types_mastery = {
-			["spell/aegis"] = resolvers.mbonus_material(30, 10, function(e, v) v=v/100 return 0, v end),
+			["spell/aegis"] = resolvers.mbonus_material("talents_types_mastery"),
 		},
 	},
 }
@@ -272,9 +272,9 @@ newEntity{
 	rarity = 17,
 	cost = 20,
 	wielder = {
-		disease_immune = resolvers.mbonus_material(30, 20, function(e, v) v=v/100 return 0, v end),
-		confusion_immune = resolvers.mbonus_material(30, 20, function(e, v) v=v/100 return 0, v end),
-		poison_immune = resolvers.mbonus_material(30, 10, function(e, v) return 0, v/100 end),
+		disease_immune = resolvers.mbonus_material("immunity"),
+		confusion_immune = resolvers.mbonus_material("immunity"),
+		poison_immune = resolvers.mbonus_material("immunity"),
 	},
 }
 
@@ -288,16 +288,16 @@ newEntity{
 	cost = 40,
 	wielder = {
 		resists={
-			[DamageType.TEMPORAL] = resolvers.mbonus_material(10, 5),
+			[DamageType.TEMPORAL] = resolvers.mbonus_material("resists"),
 		},
 		inc_stats = {
-			[Stats.STAT_MAG] = resolvers.mbonus_material(7, 1),
-			[Stats.STAT_WIL] = resolvers.mbonus_material(5, 1, function(e, v) return 0, -v end),
-			[Stats.STAT_CUN] = resolvers.mbonus_material(7, 1),
+			[Stats.STAT_MAG] = resolvers.mbonus_material("inc_stats", 2),
+			[Stats.STAT_WIL] = resolvers.mbonus_material("inc_stats", -1),
+			[Stats.STAT_CUN] = resolvers.mbonus_material("inc_stats", 2),
 		},
-		confusion_immune = resolvers.mbonus_material(15, 10, function(e, v) v=v/100 return 0, -v end),
+		confusion_immune = resolvers.mbonus_material("immunity", -1),
 		talents_types_mastery = {
-			["spell/temporal"] = resolvers.mbonus_material(2, 2, function(e, v) v=v/10 return 0, v end),
+			["spell/temporal"] = resolvers.mbonus_material("talents_types_mastery"),
 		},
 	},
 }
@@ -312,10 +312,10 @@ newEntity{
 	cost = 40,
 	wielder = {
 		inc_stats = {
-			[Stats.STAT_CON] = resolvers.mbonus_material(5, 1),
+			[Stats.STAT_CON] = resolvers.mbonus_material("inc_stats"),
 		},
-		mana_regen = resolvers.mbonus_material(50, 10, function(e, v) v=v/100 return 0, v end),
-		combat_spellpower = resolvers.mbonus_material(7, 1),
+		mana_regen = resolvers.mbonus_material("mana_regen"),
+		combat_spellpower = resolvers.mbonus_material("combat_spellpower"),
 	},
 }
 
@@ -329,11 +329,11 @@ newEntity{
 	cost = 60,
 	wielder = {
 		inc_damage = {
-			[DamageType.ACID] = resolvers.mbonus_material(7, 3),
-			[DamageType.LIGHTNING] = resolvers.mbonus_material(7, 3),
-			[DamageType.FIRE] = resolvers.mbonus_material(7, 3),
-			[DamageType.COLD] = resolvers.mbonus_material(7, 3),
-			[DamageType.ARCANE] = resolvers.mbonus_material(7, 3),
+			[DamageType.ACID] = resolvers.mbonus_material("inc_damage"),
+			[DamageType.LIGHTNING] = resolvers.mbonus_material("inc_damage"),
+			[DamageType.FIRE] = resolvers.mbonus_material("inc_damage"),
+			[DamageType.COLD] = resolvers.mbonus_material("inc_damage"),
+			[DamageType.ARCANE] = resolvers.mbonus_material("inc_damage"),
 		},
 	},
 }
@@ -348,11 +348,11 @@ newEntity{
 	cost = 20,
 	wielder = {
 		resists={
-			[DamageType.BLIGHT] = resolvers.mbonus_material(10, 5),
+			[DamageType.BLIGHT] = resolvers.mbonus_material("resists"),
 		},
-		poison_immune = resolvers.mbonus_material(15, 10, function(e, v) v=v/100 return 0, v end),
-		disease_immune = resolvers.mbonus_material(15, 10, function(e, v) v=v/100 return 0, v end),
-		combat_physresist = resolvers.mbonus_material(7, 3),
+		poison_immune = resolvers.mbonus_material("immunity"),
+		disease_immune = resolvers.mbonus_material("immunity"),
+		combat_physresist = resolvers.mbonus_material("save"),
 	},
 }
 
@@ -365,10 +365,10 @@ newEntity{
 	rarity = 10,
 	cost = 20,
 	wielder = {
-		max_mana = resolvers.mbonus_material(40, 20),
+		max_mana = resolvers.mbonus_material("max_mana"),
 		talents_types_mastery = {
-			["spell/arcane"] = resolvers.mbonus_material(3, 1, function(e, v) v=v/10 return 0, v end),
-			["spell/arcane-shield"] = resolvers.mbonus_material(3, 1, function(e, v) v=v/10 return 0, v end),
+			["spell/arcane"] = resolvers.mbonus_material("talents_types_mastery"),
+			["spell/arcane-shield"] = resolvers.mbonus_material("talents_types_mastery"),
 		},
 	},
 }
@@ -385,13 +385,13 @@ newEntity{
 	use_talent = { id = Talents.T_HATEFUL_WHISPER, level = 4, power = 80 },
 	wielder = {
 		resists={
-			[DamageType.MIND] = resolvers.mbonus_material(10, 5, function(e, v) return 0, -v end),
+			[DamageType.MIND] = resolvers.mbonus_material("rare_resists", -1),
 		},
 		inc_stats = {
-			[Stats.STAT_MAG] = resolvers.mbonus_material(9, 1),
-			[Stats.STAT_WIL] = resolvers.mbonus_material(9, 1),
+			[Stats.STAT_MAG] = resolvers.mbonus_material("inc_stats", 2),
+			[Stats.STAT_WIL] = resolvers.mbonus_material("inc_stats", 2),
 		},
-		combat_mentalresist = resolvers.mbonus_material(10, 5, function(e, v) return 0, -v end),
+		combat_mentalresist = resolvers.mbonus_material("save", -1),
 	},
 }
 
@@ -407,9 +407,9 @@ newEntity{
 	use_talent = { id = Talents.T_STONE_WALL, level = 3, power = 80 },
 	wielder = {
 		inc_stats = {
-			[Stats.STAT_CON] = resolvers.mbonus_material(5, 1),
+			[Stats.STAT_CON] = resolvers.mbonus_material("inc_stats"),
 		},
-		combat_armor = resolvers.mbonus_material(5, 1),
+		combat_armor = resolvers.mbonus_material("combat_armor"),
 	},
 }
 
@@ -425,8 +425,8 @@ newEntity{
 	use_talent = { id = Talents.T_CORROSIVE_VAPOUR, level = 3, power = 80 },
 	wielder = {
 		resists={
-			[DamageType.ACID] = resolvers.mbonus_material(10, 5),
-			[DamageType.COLD] = resolvers.mbonus_material(10, 5),
+			[DamageType.ACID] = resolvers.mbonus_material("resists"),
+			[DamageType.COLD] = resolvers.mbonus_material("resists"),
 		},
 	},
 }
@@ -443,7 +443,7 @@ newEntity{
 	use_talent = { id = Talents.T_ARCANE_EYE, level = 5, power = 80 },
 	wielder = {
 		inc_stats = {
-			[Stats.STAT_MAG] = resolvers.mbonus_material(9, 1),
+			[Stats.STAT_MAG] = resolvers.mbonus_material("inc_stats", 2),
 		},
 	},
 }
diff --git a/game/modules/tome/data/general/objects/gauntlets.lua b/game/modules/tome/data/general/objects/gauntlets.lua
index 124ff654eb..7b29063330 100644
--- a/game/modules/tome/data/general/objects/gauntlets.lua
+++ b/game/modules/tome/data/general/objects/gauntlets.lua
@@ -23,7 +23,7 @@ newEntity{
 	define_as = "BASE_GAUNTLETS",
 	slot = "HANDS",
 	type = "armor", subtype="hands",
-	add_name = " (#ARMOR#)",
+	add_name = " (#GLOVES#)",
 	display = "[", color=colors.SLATE,
 	image = resolvers.image_material("hgloves", "metal"),
 	moddable_tile = resolvers.moddable_tile("gauntlets"),
@@ -31,6 +31,7 @@ newEntity{
 	encumber = 1.5,
 	rarity = 9,
 	metallic = true,
+	wielder = {combat = {physspeed = -0.2}},
 	desc = [[Metal gloves protecting the hands up to the middle of the lower arm.]],
 	randart_able = { attack=10, physical=10, spell=10, def=40, misc=30 },
 	egos = "/data/general/objects/egos/gloves.lua", egos_chance = { prefix=resolvers.mbonus(40, 5), suffix=resolvers.mbonus(40, 5) },
@@ -44,12 +45,10 @@ newEntity{ base = "BASE_GAUNTLETS",
 	wielder = {
 		combat_armor = 1,
 		combat = {
-			dam = resolvers.rngavg(7, 12),
-			apr = 4,
-			physcrit = 1,
-			physspeed = -0.2,
-			dammod = {dex=0.4, str=-0.6, cun=0.4 },
-			damrange = 0.3,
+			dam = resolvers.cbonus(4, 10, 1, 2),
+			max_acc = resolvers.cbonus(10, 25, 1, 3),
+			critical_power = resolvers.cbonus(4, 14, 0.1, 3),
+			dammod = {dex=0.1, str=0, cun=0.1 },
 		},
 	},
 }
@@ -57,17 +56,15 @@ newEntity{ base = "BASE_GAUNTLETS",
 newEntity{ base = "BASE_GAUNTLETS",
 	name = "dwarven-steel gauntlets", short_name = "d.steel",
 	level_range = {20, 40},
-	cost = 7,
+	cost = 25,
 	material_level = 3,
 	wielder = {
 		combat_armor = 2,
 		combat = {
-			dam = resolvers.rngavg(16, 22),
-			apr = 7,
-			physcrit = 1,
-			physspeed = -0.2,
-			dammod = {dex=0.4, str=-0.6, cun=0.4 },
-			damrange = 0.3,
+			dam = resolvers.cbonus(16),
+			max_acc = resolvers.cbonus(10, 25, 1, 4),
+			critical_power = resolvers.cbonus(4, 14, 0.1, 4),
+			dammod = {dex=0.2, str=0.1, cun=0.2 },
 		},
 	},
 }
@@ -75,17 +72,15 @@ newEntity{ base = "BASE_GAUNTLETS",
 newEntity{ base = "BASE_GAUNTLETS",
 	name = "voratun gauntlets", short_name = "voratun",
 	level_range = {40, 50},
-	cost = 10,
+	cost = 35,
 	material_level = 5,
 	wielder = {
 		combat_armor = 3,
 		combat = {
-			dam = resolvers.rngavg(25, 32),
-			apr = 10,
-			physcrit = 3,
-			physspeed = -0.2,
-			dammod = {dex=0.4, str=-0.6, cun=0.4 },
-			damrange = 0.3,
+			dam = resolvers.cbonus(40),
+			max_acc = resolvers.cbonus(10, 25, 1, 5),
+			critical_power = resolvers.cbonus(4, 14, 0.1, 5),
+			dammod = {dex=0.4, str=0.3, cun=0.4 },
 		},
 	},
 }
diff --git a/game/modules/tome/data/general/objects/gloves.lua b/game/modules/tome/data/general/objects/gloves.lua
index ffadd86d8c..d2b79c644b 100644
--- a/game/modules/tome/data/general/objects/gloves.lua
+++ b/game/modules/tome/data/general/objects/gloves.lua
@@ -23,12 +23,13 @@ newEntity{
 	define_as = "BASE_GLOVES",
 	slot = "HANDS",
 	type = "armor", subtype="hands",
-	add_name = " (#ARMOR#)",
+	add_name = " (#GLOVES#)",
 	display = "[", color=colors.UMBER,
 	image = resolvers.image_material("gloves", "leather"),
 	moddable_tile = resolvers.moddable_tile("gloves"),
 	encumber = 1,
 	rarity = 9,
+	wielder = {combat = {physspeed = -0.333}},
 	desc = [[Light gloves which do not seriously hinder finger movements, while still protecting the hands somewhat.]],
 	randart_able = { attack=10, physical=10, spell=10, def=30, misc=10 },
 	egos = "/data/general/objects/egos/gloves.lua", egos_chance = { prefix=resolvers.mbonus(40, 5), suffix=resolvers.mbonus(40, 5) },
@@ -42,11 +43,10 @@ newEntity{ base = "BASE_GLOVES",
 	wielder = {
 		combat_armor = 1,
 		combat = {
-			dam = resolvers.rngavg(5, 8),
-			apr = 1,
-			physcrit = 4,
-			physspeed = -0.4,
-			dammod = {dex=0.4, str=-0.6, cun=0.4 },
+			dam = resolvers.cbonus(3, 10, 1, 2),
+			max_acc = resolvers.cbonus(10, 25, 1, 3),
+			critical_power = resolvers.cbonus(2, 12, 0.1, 3),
+			dammod = {dex=0.1, str=0, cun=0.1 },
 		},
 	},
 }
@@ -54,16 +54,15 @@ newEntity{ base = "BASE_GLOVES",
 newEntity{ base = "BASE_GLOVES",
 	name = "hardened leather gloves", short_name = "hardened",
 	level_range = {20, 40},
-	cost = 7,
+	cost = 25,
 	material_level = 3,
 	wielder = {
 		combat_armor = 2,
 		combat = {
-			dam = resolvers.rngavg(14, 18),
-			apr = 1,
-			physcrit = 7,
-			physspeed = -0.4,
-			dammod = {dex=0.4, str=-0.6, cun=0.4 },
+			dam = resolvers.cbonus(12),
+			max_acc = resolvers.cbonus(10, 25, 1, 4),
+			critical_power = resolvers.cbonus(2, 12, 0.1, 4),
+			dammod = {dex=0.2, str=0.1, cun=0.2 },
 		},
 	},
 }
@@ -71,16 +70,15 @@ newEntity{ base = "BASE_GLOVES",
 newEntity{ base = "BASE_GLOVES",
 	name = "drakeskin leather gloves", short_name = "drakeskin",
 	level_range = {40, 50},
-	cost = 10,
+	cost = 35,
 	material_level = 5,
 	wielder = {
 		combat_armor = 3,
 		combat = {
-			dam = resolvers.rngavg(23, 28),
-			apr = 3,
-			physcrit = 10,
-			physspeed = -0.4,
-			dammod = {dex=0.4, str=-0.6, cun=0.4 },
+			dam = resolvers.cbonus(30),
+			max_acc = resolvers.cbonus(10, 25, 1, 5),
+			critical_power = resolvers.cbonus(2, 12, 0.1, 5),
+			dammod = {dex=0.4, str=0.3, cun=0.4 },
 		},
 	},
 }
diff --git a/game/modules/tome/data/general/objects/knifes.lua b/game/modules/tome/data/general/objects/knifes.lua
index da79b57621..b980e4c091 100644
--- a/game/modules/tome/data/general/objects/knifes.lua
+++ b/game/modules/tome/data/general/objects/knifes.lua
@@ -17,8 +17,11 @@
 -- Nicolas Casalini "DarkGod"
 -- darkgod@te4.org
 
+local Talents = require "engine.interface.ActorTalents"
+
 newEntity{
 	define_as = "BASE_KNIFE",
+	flavor_names = {"dagger", "dirk", "stiletto", "baselard"},
 	slot = "MAINHAND", offslot = "OFFHAND",
 	type = "weapon", subtype="dagger",
 	add_name = " (#COMBAT#)",
@@ -27,7 +30,7 @@ newEntity{
 	encumber = 1,
 	rarity = 5,
 	metallic = true,
-	combat = { talented = "knife", damrange = 1.3, physspeed = 1, sound = {"actions/melee", pitch=1.2, vol=1.2}, sound_miss = {"actions/melee", pitch=1.2, vol=1.2} },
+	combat = { talented = "knife", damrange = 1, physspeed = 0.666, sound = {"actions/melee", pitch=1.2, vol=1.2}, sound_miss = {"actions/melee", pitch=1.2, vol=1.2} },
 	desc = [[Sharp, short and deadly.]],
 	randart_able = { attack=40, physical=80, spell=20, def=10, misc=10 },
 	egos = "/data/general/objects/egos/weapon.lua", egos_chance = { prefix=resolvers.mbonus(40, 5), suffix=resolvers.mbonus(40, 5) },
@@ -40,10 +43,10 @@ newEntity{ base = "BASE_KNIFE",
 	cost = 5,
 	material_level = 1,
 	combat = {
-		dam = resolvers.rngavg(4,6),
-		apr = 5,
-		physcrit = 4,
-		dammod = {dex=0.45,str=0.45},
+		dam = resolvers.cbonus(3, 5, 1, 1.5),
+		max_acc = resolvers.cbonus(95, 100, 1, 1.5),
+		critical_power = resolvers.cbonus(16, 25, 0.1),
+		dammod = {dex=0.1, str=0.1},
 	},
 }
 
@@ -51,13 +54,13 @@ newEntity{ base = "BASE_KNIFE",
 	name = "steel dagger", short_name = "steel",
 	level_range = {10, 20},
 	require = { stat = { dex=16 }, },
-	cost = 10,
+	cost = 30,
 	material_level = 2,
 	combat = {
-		dam = resolvers.rngavg(8,12),
-		apr = 6,
-		physcrit = 5,
-		dammod = {dex=0.45,str=0.45},
+		dam = resolvers.cbonus(6, 10, 1, 2),
+		max_acc = resolvers.cbonus(95, 100, 1, 2),
+		critical_power = resolvers.cbonus(16, 25, 0.1, 2.5),
+		dammod = {dex=0.2, str=0.2},
 	},
 }
 
@@ -65,13 +68,13 @@ newEntity{ base = "BASE_KNIFE",
 	name = "dwarven-steel dagger", short_name = "d.steel",
 	level_range = {20, 30},
 	require = { stat = { dex=24 }, },
-	cost = 15,
+	cost = 80,
 	material_level = 3,
 	combat = {
-		dam = resolvers.rngavg(14,22),
-		apr = 7,
-		physcrit = 6,
-		dammod = {dex=0.45,str=0.45},
+		dam = resolvers.cbonus(12),
+		max_acc = resolvers.cbonus(95, 100, 1, 2.5),
+		critical_power = resolvers.cbonus(16, 25, 0.1, 3),
+		dammod = {dex=0.3, str=0.3},
 	},
 }
 
@@ -79,13 +82,13 @@ newEntity{ base = "BASE_KNIFE",
 	name = "stralite dagger", short_name = "stralite",
 	level_range = {30, 40},
 	require = { stat = { dex=35 }, },
-	cost = 25,
+	cost = 120,
 	material_level = 4,
 	combat = {
-		dam = resolvers.rngavg(25,32),
-		apr = 9,
-		physcrit = 8,
-		dammod = {dex=0.45,str=0.45},
+		dam = resolvers.cbonus(21),
+		max_acc = resolvers.cbonus(95, 100, 1, 3),
+		critical_power = resolvers.cbonus(16, 25, 0.1, 3.5),
+		dammod = {dex=0.4, str=0.4},
 	},
 }
 
@@ -93,12 +96,12 @@ newEntity{ base = "BASE_KNIFE",
 	name = "voratun dagger", short_name = "voratun",
 	level_range = {40, 50},
 	require = { stat = { dex=48 }, },
-	cost = 35,
+	cost = 170,
 	material_level = 5,
 	combat = {
-		dam = resolvers.rngavg(36,40),
-		apr = 9,
-		physcrit = 10,
-		dammod = {dex=0.45,str=0.45},
+		dam = resolvers.cbonus(30),
+		max_acc = resolvers.cbonus(95, 100, 1, 3.5),
+		critical_power = resolvers.cbonus(16, 25, 0.1, 4),
+		dammod = {dex=0.5, str=0.5},
 	},
 }
diff --git a/game/modules/tome/data/general/objects/maces.lua b/game/modules/tome/data/general/objects/maces.lua
index 3dae70e3c6..b7db1c6fd6 100644
--- a/game/modules/tome/data/general/objects/maces.lua
+++ b/game/modules/tome/data/general/objects/maces.lua
@@ -19,6 +19,7 @@
 
 newEntity{
 	define_as = "BASE_MACE",
+	flavor_names = {"cudgel", "mace", "flail", "dreadmace"},
 	slot = "MAINHAND", dual_wieldable = true,
 	type = "weapon", subtype="mace",
 	add_name = " (#COMBAT#)",
@@ -27,7 +28,7 @@ newEntity{
 	encumber = 3,
 	rarity = 5,
 	metallic = true,
-	combat = { talented = "mace", damrange = 1.4, physspeed = 1, sound = {"actions/melee", pitch=0.6, vol=1.2}, sound_miss = {"actions/melee", pitch=0.6, vol=1.2}},
+	combat = { talented = "mace", damrange = 1, physspeed = 1, sound = {"actions/melee", pitch=0.6, vol=1.2}, sound_miss = {"actions/melee", pitch=0.6, vol=1.2}},
 	desc = [[Blunt and deadly.]],
 	randart_able = { attack=40, physical=80, spell=20, def=10, misc=10 },
 	egos = "/data/general/objects/egos/weapon.lua", egos_chance = { prefix=resolvers.mbonus(40, 5), suffix=resolvers.mbonus(40, 5) },
@@ -40,10 +41,10 @@ newEntity{ base = "BASE_MACE",
 	cost = 5,
 	material_level = 1,
 	combat = {
-		dam = resolvers.rngavg(6,9),
-		apr = 2,
-		physcrit = 0.5,
-		dammod = {str=1},
+		dam = resolvers.cbonus(6),
+		max_acc = resolvers.cbonus(80, 100, 1, 3),
+		critical_power = resolvers.cbonus(15, 27, 0.1, 3),
+		dammod = {str=0.2},
 	},
 }
 
@@ -51,13 +52,13 @@ newEntity{ base = "BASE_MACE",
 	name = "steel mace", short_name = "steel",
 	level_range = {10, 20},
 	require = { stat = { str=16 }, },
-	cost = 10,
+	cost = 30,
 	material_level = 2,
 	combat = {
-		dam = resolvers.rngavg(11,17),
-		apr = 3,
-		physcrit = 1,
-		dammod = {str=1},
+		dam = resolvers.cbonus(12),
+		max_acc = resolvers.cbonus(80, 100, 1, 3.5),
+		critical_power = resolvers.cbonus(15, 27, 0.1, 3.5),
+		dammod = {str=0.4},
 	},
 }
 
@@ -65,13 +66,13 @@ newEntity{ base = "BASE_MACE",
 	name = "dwarven-steel mace", short_name = "d.steel",
 	level_range = {20, 30},
 	require = { stat = { str=24 }, },
-	cost = 15,
+	cost = 80,
 	material_level = 3,
 	combat = {
-		dam = resolvers.rngavg(22,28),
-		apr = 4,
-		physcrit = 1.5,
-		dammod = {str=1},
+		dam = resolvers.cbonus(24),
+		max_acc = resolvers.cbonus(80, 100, 1, 4),
+		critical_power = resolvers.cbonus(15, 27, 0.1, 4),
+		dammod = {str=0.6},
 	},
 }
 
@@ -79,13 +80,13 @@ newEntity{ base = "BASE_MACE",
 	name = "stralite mace", short_name = "stralite",
 	level_range = {30, 40},
 	require = { stat = { str=35 }, },
-	cost = 25,
+	cost = 120,
 	material_level = 4,
 	combat = {
-		dam = resolvers.rngavg(33,40),
-		apr = 5,
-		physcrit = 2.5,
-		dammod = {str=1},
+		dam = resolvers.cbonus(42),
+		max_acc = resolvers.cbonus(80, 100, 1, 4.5),
+		critical_power = resolvers.cbonus(15, 27, 0.1, 4.5),
+		dammod = {str=0.8},
 	},
 }
 
@@ -93,12 +94,12 @@ newEntity{ base = "BASE_MACE",
 	name = "voratun mace", short_name = "voratun",
 	level_range = {40, 50},
 	require = { stat = { str=48 }, },
-	cost = 35,
+	cost = 170,
 	material_level = 5,
 	combat = {
-		dam = resolvers.rngavg(43,48),
-		apr = 6,
-		physcrit = 3,
+		dam = resolvers.cbonus(60),
+		max_acc = resolvers.cbonus(80, 100, 1, 5),
+		critical_power = resolvers.cbonus(15, 27, 0.1, 5),
 		dammod = {str=1},
 	},
 }
diff --git a/game/modules/tome/data/general/objects/quest-artifacts.lua b/game/modules/tome/data/general/objects/quest-artifacts.lua
index f3477f9a6a..049d45ad92 100644
--- a/game/modules/tome/data/general/objects/quest-artifacts.lua
+++ b/game/modules/tome/data/general/objects/quest-artifacts.lua
@@ -18,6 +18,7 @@
 -- darkgod@te4.org
 
 local Stats = require "engine.interface.ActorStats"
+local Talents = require "engine.interface.ActorTalents"
 
 -- The staff of absorption, the reason the game exists!
 newEntity{ define_as = "STAFF_ABSORPTION",
@@ -26,8 +27,12 @@ newEntity{ define_as = "STAFF_ABSORPTION",
 	slot = "MAINHAND",
 	slot_forbid = "OFFHAND",
 	type = "weapon", subtype="staff",
+	twohanded = true,
 	unided_name = "dark runed staff",
 	name = "Staff of Absorption",
+	flavor_name = "magestaff",
+	no_command = true,
+	material_level = 5,
 	level_range = {30, 30},
 	display = "\\", color=colors.VIOLET, image = "object/artifact/staff_absorption.png",
 	encumber = 7,
@@ -35,17 +40,24 @@ newEntity{ define_as = "STAFF_ABSORPTION",
 Light around it seems to dim and you can feel its tremendous power simply by touching it.]],
 
 	require = { stat = { mag=60 }, },
+	modes = {"fire", "cold", "lightning", "arcane"},
 	combat = {
-		dam = 30,
-		apr = 4,
-		dammod = {mag=1},
+		dam = 40,
+		max_acc = 100,
+		critical_power = 2,
+		dammod = {mag=0.6},
 		damtype = DamageType.ARCANE,
+		affects_spells = true,
 		talented = "staff",
+		physspeed = 1,
+		damrange = 1,
+		sound = {"actions/melee", pitch=0.6, vol=1.2}, sound_miss = {"actions/melee", pitch=0.6, vol=1.2},
 	},
 	wielder = {
 		combat_atk = 20,
 		combat_spellpower = 20,
 		combat_spellcrit = 10,
+		learn_talent = {[Talents.T_COMMAND_STAFF] = 1},
 	},
 
 	max_power = 1000, power_regen = 1,
diff --git a/game/modules/tome/data/general/objects/shields.lua b/game/modules/tome/data/general/objects/shields.lua
index 36f370fca1..8a70b824e8 100644
--- a/game/modules/tome/data/general/objects/shields.lua
+++ b/game/modules/tome/data/general/objects/shields.lua
@@ -23,7 +23,7 @@ newEntity{
 	define_as = "BASE_SHIELD",
 	slot = "OFFHAND",
 	type = "armor", subtype="shield",
-	add_name = " (#ARMOR#)",
+	add_name = " (#SHIELD#)",
 	display = ")", color=colors.UMBER, image = resolvers.image_material("shield", "metal"),
 	moddable_tile = resolvers.moddable_tile("shield"),
 	rarity = 5,
@@ -32,7 +32,7 @@ newEntity{
 	desc = [[Handheld deflection devices]],
 	require = { talent = { {Talents.T_ARMOUR_TRAINING,3} }, },
 	randart_able = { attack=20, physical=10, spell=10, def=50, misc=10 },
-	special_combat = { damrange = 1.2 },
+	special_combat = { damrange = 1 },
 	egos = "/data/general/objects/egos/shield.lua", egos_chance = { prefix=resolvers.mbonus(40, 5), suffix=resolvers.mbonus(40, 5) },
 }
 
@@ -46,15 +46,17 @@ newEntity{ base = "BASE_SHIELD",
 	cost = 5,
 	material_level = 1,
 	special_combat = {
-		dam = resolvers.rngavg(7,11),
-		physcrit = 2.5,
-		dammod = {str=1},
+		dam = resolvers.cbonus(5),
+		block = resolvers.cbonus(20),
+		max_acc = 75,
+		critical_power = 1.1,
+		dammod = {str=0.2},
 	},
 	wielder = {
-		combat_armor = 2,
-		combat_def = 4,
-		combat_def_ranged = 4,
 		fatigue = 6,
+		learn_talent = {
+			[Talents.T_BLOCK] = 1,
+		},
 	},
 }
 
@@ -62,17 +64,19 @@ newEntity{ base = "BASE_SHIELD",
 	name = "steel shield", short_name = "steel",
 	level_range = {10, 20},
 	require = { stat = { str=16 }, },
-	cost = 10,
+	cost = 30,
 	material_level = 2,
 	special_combat = {
-		dam = resolvers.rngavg(10,20),
-		physcrit = 3,
-		dammod = {str=1},
+		dam = resolvers.cbonus(10),
+		block = resolvers.cbonus(40),
+		max_acc = 75,
+		critical_power = 1.1,
+		dammod = {str=0.4},
 	},
 	wielder = {
-		combat_armor = 2,
-		combat_def = 6,
-		combat_def_ranged = 6,
+		learn_talent = {
+			[Talents.T_BLOCK] = 2,
+		},
 		fatigue = 8,
 	},
 }
@@ -81,17 +85,19 @@ newEntity{ base = "BASE_SHIELD",
 	name = "dwarven-steel shield", short_name = "d.steel",
 	level_range = {20, 30},
 	require = { stat = { str=24 }, },
-	cost = 15,
+	cost = 80,
 	material_level = 3,
 	special_combat = {
-		dam = resolvers.rngavg(25,35),
-		physcrit = 3.5,
-		dammod = {str=1},
+		dam = resolvers.cbonus(20),
+		block = resolvers.cbonus(80),
+		max_acc = 75,
+		critical_power = 1.1,
+		dammod = {str=0.6},
 	},
 	wielder = {
-		combat_armor = 2,
-		combat_def = 8,
-		combat_def_ranged = 8,
+		learn_talent = {
+			[Talents.T_BLOCK] = 3,
+		},
 		fatigue = 12,
 	},
 }
@@ -100,17 +106,19 @@ newEntity{ base = "BASE_SHIELD",
 	name = "stralite shield", short_name = "stralite",
 	level_range = {30, 40},
 	require = { stat = { str=35 }, },
-	cost = 25,
+	cost = 120,
 	material_level = 4,
 	special_combat = {
-		dam = resolvers.rngavg(40,55),
-		physcrit = 4.5,
-		dammod = {str=1},
+		dam = resolvers.cbonus(35),
+		block = resolvers.cbonus(140),
+		max_acc = 75,
+		critical_power = 1.1,
+		dammod = {str=0.8},
 	},
 	wielder = {
-		combat_armor = 2,
-		combat_def = 10,
-		combat_def_ranged = 10,
+		learn_talent = {
+			[Talents.T_BLOCK] = 4,
+		},
 		fatigue = 14,
 	},
 }
@@ -119,17 +127,19 @@ newEntity{ base = "BASE_SHIELD",
 	name = "voratun shield", short_name = "voratun",
 	level_range = {40, 50},
 	require = { stat = { str=48 }, },
-	cost = 35,
+	cost = 170,
 	material_level = 5,
 	special_combat = {
-		dam = resolvers.rngavg(60,75),
-		physcrit = 5,
+		dam = resolvers.cbonus(50),
+		block = resolvers.cbonus(200),
+		max_acc = 75,
+		critical_power = 1.1,
 		dammod = {str=1},
 	},
 	wielder = {
-		combat_armor = 3,
-		combat_def = 12,
-		combat_def_ranged = 12,
+		learn_talent = {
+			[Talents.T_BLOCK] = 5,
+		},
 		fatigue = 14,
 	},
 }
diff --git a/game/modules/tome/data/general/objects/slings.lua b/game/modules/tome/data/general/objects/slings.lua
index 243f66d1c1..c66d3323c8 100644
--- a/game/modules/tome/data/general/objects/slings.lua
+++ b/game/modules/tome/data/general/objects/slings.lua
@@ -23,6 +23,7 @@ newEntity{
 	define_as = "BASE_SLING",
 	slot = "MAINHAND",
 	type = "weapon", subtype="sling",
+	add_name = " (#COMBAT_RANGED#)",
 	display = "}", color=colors.UMBER, image = resolvers.image_material("sling", "leather"),
 	moddable_tile = resolvers.moddable_tile("sling"),
 	encumber = 4,
@@ -31,7 +32,6 @@ newEntity{
 	archery = "sling",
 	require = { talent = { Talents.T_SHOOT }, },
 	proj_image = resolvers.image_material("shot_s", "metal"),
-	basic_ammo = { talented = "sling", damrange = 1.2},
 	desc = [[Slings are used to hurl stones or metal shots at your foes.]],
 	randart_able = { attack=40, physical=80, spell=20, def=10, misc=10 },
 	egos = "/data/general/objects/egos/sling.lua", egos_chance = { prefix=resolvers.mbonus(40, 5), suffix=resolvers.mbonus(40, 5) },
@@ -41,17 +41,13 @@ newEntity{ base = "BASE_SLING",
 	name = "rough leather sling", short_name = "rough",
 	level_range = {1, 10},
 	require = { stat = { dex=11 }, },
-	cost = 5,
+	cost = 1,
 	material_level = 1,
 	combat = {
+		dam = resolvers.cbonus(2, 4, 1, 1),
+		critical_power = resolvers.cbonus(15, 27, 0.1, 3),
 		range = 6,
-		physspeed = 0.8,
-	},
-	basic_ammo = {
-		dam = resolvers.rngavg(7,12),
-		apr = 1,
-		physcrit = 4,
-		dammod = {dex=0.7, cun=0.5},
+		dammod = {dex=0.1, cun=0.1},
 	},
 }
 
@@ -62,14 +58,10 @@ newEntity{ base = "BASE_SLING",
 	cost = 10,
 	material_level = 2,
 	combat = {
+		dam = resolvers.cbonus(4, 8, 1, 1),
+		critical_power = resolvers.cbonus(15, 27, 0.1, 3.5),
 		range = 7,
-		physspeed = 0.8,
-	},
-	basic_ammo = {
-		dam = resolvers.rngavg(15,22),
-		apr = 2,
-		physcrit = 4.5,
-		dammod = {dex=0.7, cun=0.5},
+		dammod = {dex=0.2, cun=0.2},
 	},
 }
 
@@ -80,14 +72,10 @@ newEntity{ base = "BASE_SLING",
 	cost = 15,
 	material_level = 3,
 	combat = {
+		dam = resolvers.cbonus(8),
+		critical_power = resolvers.cbonus(15, 27, 0.1, 4),
 		range = 8,
-		physspeed = 0.8,
-	},
-	basic_ammo = {
-		dam = resolvers.rngavg(28,37),
-		apr = 3,
-		physcrit = 5,
-		dammod = {dex=0.7, cun=0.5},
+		dammod = {dex=0.3, cun=0.3},
 	},
 }
 
@@ -98,14 +86,10 @@ newEntity{ base = "BASE_SLING",
 	cost = 25,
 	material_level = 4,
 	combat = {
+		dam = resolvers.cbonus(14),
+		critical_power = resolvers.cbonus(15, 27, 0.1, 4.5),
 		range = 9,
-		physspeed = 0.8,
-	},
-	basic_ammo = {
-		dam = resolvers.rngavg(40,47),
-		apr = 5,
-		physcrit = 5.5,
-		dammod = {dex=0.7, cun=0.5},
+		dammod = {dex=0.4, cun=0.4},
 	},
 }
 
@@ -116,102 +100,112 @@ newEntity{ base = "BASE_SLING",
 	cost = 35,
 	material_level = 5,
 	combat = {
+		dam = resolvers.cbonus(20),
+		critical_power = resolvers.cbonus(15, 27, 0.1, 5),
 		range = 10,
-		physspeed = 0.8,
-	},
-	basic_ammo = {
-		dam = resolvers.rngavg(50, 57),
-		apr = 6,
-		physcrit = 7,
-		dammod = {dex=0.7, cun=0.5},
+		dammod = {dex=0.5, cun=0.5},
 	},
 }
 
 ------------------ AMMO -------------------
 
 newEntity{
-	define_as = "BASE_SHOT",
+	define_as = "BASE_SHOT_POUCH",
 	slot = "QUIVER",
 	type = "ammo", subtype="shot",
-	add_name = " (#COMBAT#)",
+	add_name = " (#COMBAT_QUIVER#)",
 	display = "{", color=colors.UMBER, image = resolvers.image_material("shot", "metal"),
-	encumber = 0.03,
+	encumber = 3,
 	rarity = 11,
-	combat = { talented = "sling", damrange = 1.2},
+	combat = { talented = "sling", damrange = 1},
 	proj_image = resolvers.image_material("shot_s", "metal"),
 	archery_ammo = "sling",
-	desc = [[Shots are used with slings to pummel your foes to death.]],
-	generate_stack = resolvers.rngavg(100,200),
-	egos = "/data/general/objects/egos/ammo.lua", egos_chance = {100, resolvers.mbonus(30, 5)},
-	stacking = true,
+	desc = [[Shots are used with slings to pummel your foes.]],
+	egos = "/data/general/objects/egos/ammo.lua",
+	egos_chance = { prefix=resolvers.mbonus(40, 5), suffix=resolvers.mbonus(40, 5) },
 }
 
-newEntity{ base = "BASE_SHOT",
-	name = "iron shot", short_name = "iron",
+newEntity{ base = "BASE_SHOT_POUCH",
+	name = "pouch of iron shot", short_name = "iron",
 	level_range = {1, 10},
 	require = { stat = { dex=11 }, },
-	cost = 0.05,
+	cost = 1,
 	material_level = 1,
 	combat = {
-		dam = resolvers.rngavg(7,12),
-		apr = 1,
-		physcrit = 4,
-		dammod = {dex=0.7, cun=0.5},
+		capacity = resolvers.cbonus(40),
+		dam = resolvers.cbonus(2, 4, 1, 1),
+		max_acc = resolvers.cbonus(80, 100, 1, 3),
+		dammod = {dex=0.1},
+		shots_left = 40,
 	},
+	wielder = {},
+	--learn_talent = {[Talents.T_RELOAD] = 1},
 }
 
-newEntity{ base = "BASE_SHOT",
-	name = "steel shot", short_name = "steel",
+newEntity{ base = "BASE_SHOT_POUCH",
+	name = "pouch of steel shot", short_name = "steel",
 	level_range = {10, 20},
 	require = { stat = { dex=16 }, },
-	cost = 0.10,
+	cost = 10,
 	material_level = 2,
 	combat = {
-		dam = resolvers.rngavg(15,22),
-		apr = 2,
-		physcrit = 4.5,
-		dammod = {dex=0.7, cun=0.5},
+		capacity = resolvers.cbonus(40),
+		dam = resolvers.cbonus(4, 8, 1, 1),
+		max_acc = resolvers.cbonus(80, 100, 1, 3.5),
+		dammod = {dex=0.2},
+		shots_left = 40,
 	},
+	wielder = {},
+	learn_talent = {[Talents.T_RELOAD] = 1},
 }
 
-newEntity{ base = "BASE_SHOT",
-	name = "dwarven-steel shot", short_name = "d.steel",
+newEntity{ base = "BASE_SHOT_POUCH",
+	name = "pouch of dwarven-steel shot", short_name = "d.steel",
 	level_range = {20, 30},
 	require = { stat = { dex=24 }, },
-	cost = 0.15,
+	cost = 15,
 	material_level = 3,
 	combat = {
-		dam = resolvers.rngavg(28,37),
-		apr = 3,
-		physcrit = 5,
-		dammod = {dex=0.7, cun=0.5},
+		capacity = resolvers.cbonus(40),
+		dam = resolvers.cbonus(8),
+		max_acc = resolvers.cbonus(80, 100, 1, 4),
+		dammod = {dex=0.3},
+		shots_left = 40,
 	},
+	wielder = {},
+	learn_talent = {[Talents.T_RELOAD] = 1},
 }
 
-newEntity{ base = "BASE_SHOT",
-	name = "stralite shot", short_name = "stralite",
+newEntity{ base = "BASE_SHOT_POUCH",
+	name = "pouch of stralite shot", short_name = "stralite",
 	level_range = {30, 40},
 	require = { stat = { dex=35 }, },
-	cost = 0.25,
+	cost = 25,
 	material_level = 4,
 	combat = {
-		dam = resolvers.rngavg(40,47),
-		apr = 5,
-		physcrit = 5.5,
-		dammod = {dex=0.7, cun=0.5},
+		capacity = resolvers.cbonus(40),
+		dam = resolvers.cbonus(14),
+		max_acc = resolvers.cbonus(80, 100, 1, 4.5),
+		dammod = {dex=0.4},
+		shots_left = 40,
 	},
+	wielder = {},
+	learn_talent = {[Talents.T_RELOAD] = 2},
 }
 
-newEntity{ base = "BASE_SHOT",
-	name = "voratun shot", short_name = "voratun",
+newEntity{ base = "BASE_SHOT_POUCH",
+	name = "pouch of voratun shot", short_name = "voratun",
 	level_range = {40, 50},
 	require = { stat = { dex=48 }, },
-	cost = 0.35,
+	cost = 35,
 	material_level = 5,
 	combat = {
-		dam = resolvers.rngavg(50, 57),
-		apr = 6,
-		physcrit = 7,
-		dammod = {dex=0.7, cun=0.5},
+		capacity = resolvers.cbonus(40),
+		dam = resolvers.cbonus(20),
+		max_acc = resolvers.cbonus(80, 100, 1, 5),
+		dammod = {dex=0.5},
+		shots_left = 40,
 	},
+	wielder = {},
+	learn_talent = {[Talents.T_RELOAD] = 2},
 }
diff --git a/game/modules/tome/data/general/objects/staves.lua b/game/modules/tome/data/general/objects/staves.lua
index 5aca68510f..46996e9a98 100644
--- a/game/modules/tome/data/general/objects/staves.lua
+++ b/game/modules/tome/data/general/objects/staves.lua
@@ -17,27 +17,30 @@
 -- Nicolas Casalini "DarkGod"
 -- darkgod@te4.org
 
+local Talents = require "engine.interface.ActorTalents"
+
 newEntity{
 	define_as = "BASE_STAFF",
+	flavor_names = {"staff", "magestaff", "starstaff", "earthstaff"},
 	slot = "MAINHAND",
 	slot_forbid = "OFFHAND",
 	type = "weapon", subtype="staff",
 	twohanded = true,
-	add_name = " (#COMBAT_DAMTYPE#)",
+	add_name = " (#COMBAT_STAFF#)",
 	display = "\\", color=colors.LIGHT_RED, image = resolvers.image_material("staff", "wood"),
 	moddable_tile = resolvers.moddable_tile("staff"),
 	randart_able = { attack=10, physical=40, spell=80, def=10, misc=10 },
 	encumber = 5,
 	rarity = 4,
 	combat = {
+		affects_spells = true,
 		talented = "staff",
 		physspeed = 1,
-		damrange = 1.2,
+		damrange = 1,
 		sound = {"actions/melee", pitch=0.6, vol=1.2}, sound_miss = {"actions/melee", pitch=0.6, vol=1.2},
-		damtype = resolvers.rngtable{DamageType.FIRE, DamageType.COLD, DamageType.ACID, DamageType.LIGHTNING, DamageType.LIGHT, DamageType.DARKNESS, DamageType.NATURE, DamageType.BLIGHT},
 	},
 	desc = [[Staves designed for wielders of magic, by the greats of the art.]],
-	egos = "/data/general/objects/egos/staves.lua", egos_chance = { prefix=resolvers.mbonus(40, 5), suffix=resolvers.mbonus(40, 5) },
+	egos = "/data/general/objects/egos/weapon-test.lua", egos_chance = { prefix=resolvers.mbonus(40, 5), suffix=resolvers.mbonus(40, 5) },
 }
 
 newEntity{ base = "BASE_STAFF",
@@ -47,85 +50,70 @@ newEntity{ base = "BASE_STAFF",
 	cost = 5,
 	material_level = 1,
 	combat = {
-		dam = resolvers.rngavg(3,5),
-		apr = 2,
-		physcrit = 2.5,
-		dammod = {mag=1},
-	},
-	wielder = {
-		combat_spellpower = 1,
-		combat_spellcrit = 1,
+		dam = resolvers.cbonus(5, 10, 1, 2),
+		max_acc = resolvers.cbonus(90, 100, 1, 3),
+		critical_power = resolvers.cbonus(15, 25, 0.1),
+		dammod = {mag=0.1},
 	},
+	wielder = resolvers.staff_wielder(),
 }
 
 newEntity{ base = "BASE_STAFF",
 	name = "ash staff", short_name = "ash",
 	level_range = {10, 20},
 	require = { stat = { mag=16 }, },
-	cost = 10,
+	cost = 30,
 	material_level = 2,
 	combat = {
-		dam = resolvers.rngavg(7,11),
-		apr = 3,
-		physcrit = 3,
-		dammod = {mag=1},
-	},
-	wielder = {
-		combat_spellpower = 2,
-		combat_spellcrit = 2,
+		dam = resolvers.cbonus(10, 20, 1, 3),
+		max_acc = resolvers.cbonus(90, 100, 1, 3.5),
+		critical_power = resolvers.cbonus(15, 25, 0.1, 3),
+		dammod = {mag=0.2},
 	},
+	wielder = resolvers.staff_wielder(),
 }
 
 newEntity{ base = "BASE_STAFF",
 	name = "yew staff", short_name = "yew",
 	level_range = {20, 30},
 	require = { stat = { mag=24 }, },
-	cost = 15,
+	cost = 80,
 	material_level = 3,
 	combat = {
-		dam = resolvers.rngavg(14,22),
-		apr = 4,
-		physcrit = 3.5,
-		dammod = {mag=1},
-	},
-	wielder = {
-		combat_spellpower = 3,
-		combat_spellcrit = 3,
+		dam = resolvers.cbonus(20, 30, 1, 3),
+		max_acc = resolvers.cbonus(90, 100, 1, 4),
+		critical_power = resolvers.cbonus(15, 25, 0.1, 3.5),
+		dammod = {mag=0.3},
 	},
+	wielder = resolvers.staff_wielder(),
 }
 
 newEntity{ base = "BASE_STAFF",
 	name = "elven-wood staff", short_name = "e.wood",
 	level_range = {30, 40},
 	require = { stat = { mag=35 }, },
-	cost = 25,
+	cost = 120,
 	material_level = 4,
 	combat = {
-		dam = resolvers.rngavg(24,28),
-		apr = 5,
-		physcrit = 4.5,
-		dammod = {mag=1},
-	},
-	wielder = {
-		combat_spellpower = 4,
-		combat_spellcrit = 4,
+		dam = resolvers.cbonus(30, 40, 1, 3),
+		max_acc = resolvers.cbonus(90, 100, 1, 4.5),
+		critical_power = resolvers.cbonus(15, 25, 0.1, 4),
+		dammod = {mag=0.4},
 	},
+	wielder = resolvers.staff_wielder(),
 }
 
 newEntity{ base = "BASE_STAFF",
 	name = "dragonbone staff", short_name = "dragonbone",
 	level_range = {40, 50},
 	require = { stat = { mag=48 }, },
-	cost = 35,
+	cost = 170,
 	material_level = 5,
 	combat = {
-		dam = resolvers.rngavg(32,38),
-		apr = 6,
-		physcrit = 5,
-		dammod = {mag=1},
-	},
-	wielder = {
-		combat_spellpower = 7,
-		combat_spellcrit = 5,
+		dam = resolvers.cbonus(40, 50, 1, 4),
+		max_acc = resolvers.cbonus(90, 100, 1, 5),
+		critical_power = resolvers.cbonus(15, 25, 0.1, 4.5),
+		dammod = {mag=0.5},
 	},
+	wielder = resolvers.staff_wielder(),
 }
diff --git a/game/modules/tome/data/general/objects/swords.lua b/game/modules/tome/data/general/objects/swords.lua
index d39d1c15e8..103a97676d 100644
--- a/game/modules/tome/data/general/objects/swords.lua
+++ b/game/modules/tome/data/general/objects/swords.lua
@@ -19,6 +19,7 @@
 
 newEntity{
 	define_as = "BASE_LONGSWORD",
+	flavor_names = {"shortsword", "longsword", "scimitar", "warsword"},
 	slot = "MAINHAND", dual_wieldable = true,
 	type = "weapon", subtype="longsword",
 	add_name = " (#COMBAT#)",
@@ -27,7 +28,7 @@ newEntity{
 	encumber = 3,
 	rarity = 5,
 	metallic = true,
-	combat = { talented = "sword", damrange = 1.4, physspeed = 1, sound = {"actions/melee", pitch=0.6, vol=1.2}, sound_miss = {"actions/melee", pitch=0.6, vol=1.2}},
+	combat = { talented = "sword", damrange = 1, physspeed = 1, sound = {"actions/melee", pitch=0.6, vol=1.2}, sound_miss = {"actions/melee", pitch=0.6, vol=1.2}},
 	desc = [[Sharp, long, and deadly.]],
 	randart_able = { attack=40, physical=80, spell=20, def=10, misc=10 },
 	egos = "/data/general/objects/egos/weapon.lua", egos_chance = { prefix=resolvers.mbonus(40, 5), suffix=resolvers.mbonus(40, 5) },
@@ -40,10 +41,10 @@ newEntity{ base = "BASE_LONGSWORD",
 	cost = 5,
 	material_level = 1,
 	combat = {
-		dam = resolvers.rngavg(5,8),
-		apr = 2,
-		physcrit = 2.5,
-		dammod = {str=1},
+		dam = resolvers.cbonus(5),
+		max_acc = resolvers.cbonus(90, 100, 1, 3),
+		critical_power = resolvers.cbonus(13, 25, 0.1),
+		dammod = {str=0.2},
 	},
 }
 
@@ -51,13 +52,13 @@ newEntity{ base = "BASE_LONGSWORD",
 	name = "steel longsword", short_name = "steel",
 	level_range = {10, 20},
 	require = { stat = { str=16 }, },
-	cost = 10,
+	cost = 30,
 	material_level = 2,
 	combat = {
-		dam = resolvers.rngavg(10,16),
-		apr = 3,
-		physcrit = 3,
-		dammod = {str=1},
+		dam = resolvers.cbonus(10),
+		max_acc = resolvers.cbonus(90, 100, 1, 3.5),
+		critical_power = resolvers.cbonus(13, 25, 0.1, 3.5),
+		dammod = {str=0.4},
 	},
 }
 
@@ -65,13 +66,13 @@ newEntity{ base = "BASE_LONGSWORD",
 	name = "dwarven-steel longsword", short_name = "d.steel",
 	level_range = {20, 30},
 	require = { stat = { str=24 }, },
-	cost = 15,
+	cost = 80,
 	material_level = 3,
 	combat = {
-		dam = resolvers.rngavg(20,26),
-		apr = 4,
-		physcrit = 3.5,
-		dammod = {str=1},
+		dam = resolvers.cbonus(20),
+		max_acc = resolvers.cbonus(90, 100, 1, 4),
+		critical_power = resolvers.cbonus(13, 25, 0.1, 4),
+		dammod = {str=0.6},
 	},
 }
 
@@ -79,13 +80,13 @@ newEntity{ base = "BASE_LONGSWORD",
 	name = "stralite longsword", short_name = "stralite",
 	level_range = {30, 40},
 	require = { stat = { str=35 }, },
-	cost = 25,
+	cost = 120,
 	material_level = 4,
 	combat = {
-		dam = resolvers.rngavg(30,37),
-		apr = 5,
-		physcrit = 4.5,
-		dammod = {str=1},
+		dam = resolvers.cbonus(35),
+		max_acc = resolvers.cbonus(90, 100, 1, 4.5),
+		critical_power = resolvers.cbonus(13, 25, 0.1, 4.5),
+		dammod = {str=0.8},
 	},
 }
 
@@ -93,12 +94,12 @@ newEntity{ base = "BASE_LONGSWORD",
 	name = "voratun longsword", short_name = "voratun",
 	level_range = {40, 50},
 	require = { stat = { str=48 }, },
-	cost = 35,
+	cost = 170,
 	material_level = 5,
 	combat = {
-		dam = resolvers.rngavg(40,45),
-		apr = 6,
-		physcrit = 5,
+		dam = resolvers.cbonus(50),
+		max_acc = resolvers.cbonus(90, 100, 1, 5),
+		critical_power = resolvers.cbonus(13, 25, 0.1, 5),
 		dammod = {str=1},
 	},
 }
diff --git a/game/modules/tome/data/general/objects/whips.lua b/game/modules/tome/data/general/objects/whips.lua
index 9aa0a4bdc5..de5541427d 100644
--- a/game/modules/tome/data/general/objects/whips.lua
+++ b/game/modules/tome/data/general/objects/whips.lua
@@ -19,6 +19,7 @@
 
 newEntity{
 	define_as = "BASE_WHIP",
+	flavor_names = {"whip", "horsewhip", "bullwhip", "warlash"},
 	slot = "MAINHAND", offslot = "OFFHAND",
 	type = "weapon", subtype="whip",
 	add_name = " (#COMBAT#)",
@@ -27,7 +28,7 @@ newEntity{
 	encumber = 3,
 	rarity = 5,
 	metallic = true,
-	combat = { talented = "whip", damrange = 1.1, sound = "actions/melee", sound_miss = "actions/melee_miss",},
+	combat = { talented = "whip", damrange = 1, sound = "actions/melee", sound_miss = "actions/melee_miss",},
 	desc = [[Sharp, long and deadly.]],
 	randart_able = { attack=40, physical=80, spell=20, def=10, misc=10 },
 	egos = "/data/general/objects/egos/weapon.lua", egos_chance = { prefix=resolvers.mbonus(40, 5), suffix=resolvers.mbonus(40, 5) },
diff --git a/game/modules/tome/data/general/objects/world-artifacts-far-east.lua b/game/modules/tome/data/general/objects/world-artifacts-far-east.lua
index 2d770903f0..3660a164c2 100644
--- a/game/modules/tome/data/general/objects/world-artifacts-far-east.lua
+++ b/game/modules/tome/data/general/objects/world-artifacts-far-east.lua
@@ -89,8 +89,10 @@ newEntity{ base = "BASE_SHIELD",
 	cost = 400,
 	material_level = 5,
 	special_combat = {
-		dam = 50,
-		physcrit = 4.5,
+		dam = 60,
+		block = 280,
+		max_acc = 90,
+		critical_power = 1.1,
 		dammod = {str=1},
 		damtype = DamageType.LIGHT,
 	},
diff --git a/game/modules/tome/data/general/objects/world-artifacts.lua b/game/modules/tome/data/general/objects/world-artifacts.lua
index 5ff7ceec52..3237bf96ad 100644
--- a/game/modules/tome/data/general/objects/world-artifacts.lua
+++ b/game/modules/tome/data/general/objects/world-artifacts.lua
@@ -27,10 +27,11 @@ for def, e in pairs(game.state:getWorldArtifacts()) do
 end
 
 -- This file describes artifacts not bound to a special location, they can be found anywhere
-newEntity{ base = "BASE_STAFF",
+newEntity{ base = "BASE_STAFF", define_as = "STAFF_DESTRUCTION",
 	power_source = {arcane=true},
 	unique = true,
 	name = "Staff of Destruction",
+	flavor_name = "magestaff",
 	unided_name = "darkness infused staff", image = "object/artifact/staff_of_destruction.png",
 	level_range = {20, 25},
 	color=colors.VIOLET,
@@ -40,26 +41,32 @@ newEntity{ base = "BASE_STAFF",
 	material_level = 3,
 
 	require = { stat = { mag=24 }, },
+	modes = {"fire", "cold", "lightning", "arcane"},
 	combat = {
-		dam = 15,
-		apr = 4,
-		dammod = {mag=1.5},
+		dam = 25,
+		max_acc = 95,
+		critical_power = 2,
+		dammod = {mag=0.4},
 		damtype = DamageType.ARCANE,
+		is_greater = true,
 	},
 	wielder = {
 		combat_spellpower = 10,
-		combat_spellcrit = 15,
 		inc_damage={
-			[DamageType.FIRE] = resolvers.mbonus(25, 8),
-			[DamageType.LIGHTNING] = resolvers.mbonus(25, 8),
+			[DamageType.FIRE] = 25,
+			[DamageType.LIGHTNING] = 25,
+			[DamageType.COLD] = 25,
+			[DamageType.ARCANE] = 25,
 		},
+		learn_talent = {[Talents.T_COMMAND_STAFF] = 4},
 	},
 }
 
-newEntity{ base = "BASE_STAFF",
+newEntity{ base = "BASE_STAFF", define_as = "STAFF_PENITENCE",
 	power_source = {arcane=true},
 	unique = true,
 	name = "Penitence",
+	flavor_name = "earthstaff",
 	unided_name = "glowing staff", image = "object/artifact/staff_penitence.png",
 	level_range = {10, 18},
 	color=colors.VIOLET,
@@ -69,18 +76,22 @@ newEntity{ base = "BASE_STAFF",
 	material_level = 2,
 
 	require = { stat = { mag=24 }, },
+	modes = {"acid", "blight", "nature"},
 	combat = {
-		dam = 10,
-		apr = 4,
-		dammod = {mag=1.2},
-		damtype = DamageType.ARCANE,
+		sentient = "penitent",
+		dam = 15,
+		max_acc = 98,
+		critical_power = 1.5,
+		dammod = {mag=0.2},
+		damtype = DamageType.NATURE,
 	},
 	wielder = {
 		combat_spellpower = 15,
-		combat_spellcrit = 10,
 		resists = {
 			[DamageType.BLIGHT] = 30,
 		},
+		inc_damage = {[DamageType.NATURE] = 15},
+		learn_talent = {[Talents.T_COMMAND_STAFF] = 3},
 	},
 	max_power = 60, power_regen = 1,
 	use_power = { name = "cure diseases", power = 10,
@@ -113,9 +124,10 @@ newEntity{ base = "BASE_STAFF",
 }
 
 newEntity{ base = "BASE_STAFF",
-	power_source = {arcane=true},
+	power_source = {arcane=true}, define_as = "STAFF_TARELION",
 	unique = true,
 	name = "Lost Staff of Archmage Tarelion", image = "object/artifact/staff_lost_staff_archmage_tarelion.png",
+	flavor_name = "magestaff",
 	unided_name = "shining staff",
 	level_range = {37, 50},
 	color=colors.VIOLET,
@@ -125,18 +137,21 @@ newEntity{ base = "BASE_STAFF",
 	material_level = 5,
 
 	require = { stat = { mag=48 }, },
+	modes = {"fire", "cold", "lightning", "arcane"},
 	combat = {
-		dam = 38,
-		apr = 4,
-		dammod = {mag=1.5},
+		is_greater = true,
+		of_retribution = true,
+		dam = 40,
+		max_acc = 90,
+		critical_power = 1.8,
+		dammod = {mag=0.7},
 		damtype = DamageType.ARCANE,
 	},
 	wielder = {
 		inc_stats = { [Stats.STAT_WIL] = 7, [Stats.STAT_MAG] = 8 },
 		max_mana = 40,
-		combat_spellpower = 40,
-		combat_spellcrit = 25,
-		inc_damage = { [DamageType.ARCANE] = 24, [DamageType.FIRE] = 24, [DamageType.COLD] = 24, [DamageType.LIGHTNING] = 24,  },
+		combat_spellpower = 20,
+		inc_damage = { [DamageType.ARCANE] = 40, [DamageType.FIRE] = 40, [DamageType.COLD] = 40, [DamageType.LIGHTNING] = 40},
 		silence_immune = 0.4,
 		mana_on_crit = 12,
 		talent_cd_reduction={
@@ -144,10 +159,12 @@ newEntity{ base = "BASE_STAFF",
 			[Talents.T_FIREFLASH] = 2,
 			[Talents.T_CHAIN_LIGHTNING] = 2,
 		},
+		learn_talent = {[Talents.T_COMMAND_STAFF] = 5, [Talents.T_ELEMENTAL_RETRIBUTION] = 5},
+		elemental_retribution = {[DamageType.ARCANE] = 1, [DamageType.FIRE] = 1, [DamageType.COLD] = 1, [DamageType.LIGHTNING] = 1},
 	},
 }
 
-newEntity{ base = "BASE_STAFF",
+newEntity{ base = "BASE_STAFF", define_as = "STAFF_BOLBUM",
 	power_source = {arcane=true},
 	unique = true,
 	name = "Bolbum's Big Knocker", image = "object/artifact/staff_bolbums_big_knocker.png",
@@ -161,9 +178,11 @@ newEntity{ base = "BASE_STAFF",
 
 	require = { stat = { mag=38 }, },
 	combat = {
-		dam = 64,
-		apr = 10,
-		dammod = {mag=1.4},
+		of_retribution = true,
+		dam = 50,
+		max_acc = 90,
+		critical_power = 1.8,
+		dammod = {mag=0.7},
 		damtype = DamageType.PHYSICAL,
 	},
 	wielder = {
@@ -171,11 +190,13 @@ newEntity{ base = "BASE_STAFF",
 		combat_spellpower = 12,
 		combat_spellcrit = 18,
 		inc_damage={
-			[DamageType.PHYSICAL] = resolvers.mbonus(20, 8),
+			[DamageType.PHYSICAL] = 50,
 		},
 		talents_types_mastery = {
 			["spell/staff-combat"] = 0.2,
-		}
+		},
+		learn_talent = {[Talents.T_ELEMENTAL_RETRIBUTION] = 4},
+		elemental_retribution = {[DamageType.PHYSICAL] = 1},
 	},
 }
 
@@ -507,21 +528,18 @@ newEntity{ base = "BASE_LONGBOW",
 	cost = 800,
 	material_level = 5,
 	combat = {
+		dam = 35,
+		critical_power = 2,
 		range = 10,
+		dammod = {dex=0.5},
+		apr = 30,
 		physspeed = 0.7,
-		apr = 12,
-	},
-	basic_ammo = {
-		dam = 57,
-		apr = 18,
-		physcrit = 3,
-		dammod = {dex=0.7, str=0.5},
+		ranged_project={[DamageType.LIGHT] = 30},
 	},
 	wielder = {
 		inc_damage={ [DamageType.PHYSICAL] = 12, },
 		lite = 1,
-		inc_stats = { [Stats.STAT_DEX] = 5, [Stats.STAT_WIL] = 4,  },
-		ranged_project={[DamageType.LIGHT] = 30},
+		inc_stats = { [Stats.STAT_DEX] = 5, [Stats.STAT_WIL] = 4,  },	
 	},
 }
 
@@ -535,18 +553,15 @@ newEntity{ base = "BASE_LONGBOW",
 	cost = 50,
 	material_level = 2,
 	combat = {
+		dam = 10,
+		critical_power = 1.8,
 		range = 7,
-		physspeed = 0.8,
-	},
-	basic_ammo = {
-		dam = 20,
+		dammod = {dex=0.2},
 		apr = 7,
-		physcrit = 1.5,
-		dammod = {dex=0.7, str=0.5},
+		ranged_project = {[DamageType.CORRUPTED_BLOOD] = 15},
 	},
 	wielder = {
 		disease_immune = 0.5,
-		ranged_project = {[DamageType.CORRUPTED_BLOOD] = 15},
 	},
 }
 
@@ -562,14 +577,13 @@ newEntity{ base = "BASE_SLING",
 	cost = 350,
 	material_level = 3,
 	combat = {
+		dam = 10,
+		critical_power = 1.5,
 		range = 10,
+		dammod = {dex=0.2, cun=0.2},
 		physspeed = 0.7,
-	},
-	basic_ammo = {
-		dam = 36,
 		apr = 3,
 		physcrit = 5,
-		dammod = {dex=0.7, cun=0.5},
 	},
 	wielder = {
 		inc_stats = { [Stats.STAT_DEX] = 4, [Stats.STAT_CUN] = 3,  },
@@ -593,9 +607,10 @@ newEntity{ base = "BASE_LONGSWORD",
 	require = { stat = { mag=28, str=28, dex=28 }, },
 	material_level = 5,
 	combat = {
-		dam = 50,
-		apr = 2,
-		physcrit = 5,
+		affects_spells = true,
+		dam = 65,
+		max_acc = 90,
+		critical_power = 2,
 		dammod = {str=1},
 	},
 	wielder = {
@@ -603,7 +618,6 @@ newEntity{ base = "BASE_LONGSWORD",
 		combat_spellpower = 20,
 		combat_spellcrit = 9,
 		inc_damage={
-			[DamageType.PHYSICAL] = 18,
 			[DamageType.FIRE] = 18,
 			[DamageType.LIGHT] = 18,
 		},
@@ -624,10 +638,10 @@ newEntity{ base = "BASE_GREATSWORD",
 	require = { stat = { str=40, wil=20 }, },
 	material_level = 5,
 	combat = {
-		dam = 42,
-		apr = 4,
-		physcrit = 18,
-		dammod = {str=1.2},
+		dam = 100,
+		max_acc = 95,
+		critical_power = 2.5,
+		dammod = {str=1.25},
 	},
 	wielder = {
 		stamina_regen = 1,
@@ -650,9 +664,9 @@ newEntity{ base = "BASE_KNIFE",
 	material_level = 3,
 	combat = {
 		dam = 15,
-		apr = 10,
-		physcrit = 0,
-		dammod = {dex=0.55, str=0.45},
+		max_acc = 100,
+		critical_power = 2.8,
+		dammod = {dex=0.4, str=0.2},
 	},
 	wielder = {combat_atk=20},
 }
@@ -701,7 +715,9 @@ newEntity{ base = "BASE_SHIELD",
 	material_level = 5,
 	special_combat = {
 		dam = 58,
-		physcrit = 4.5,
+		block = 220,
+		max_acc = 80,
+		critical_power = 2,
 		dammod = {str=1},
 		damtype = DamageType.FIRE,
 	},
@@ -729,8 +745,10 @@ newEntity{ base = "BASE_SHIELD",
 	material_level = 4,
 	special_combat = {
 		dam = 48,
-		physcrit = 4.5,
-		dammod = {str=1},
+		block = 300,
+		max_acc = 75,
+		critical_power = 1.1,
+		dammod = {str=0.8,},
 	},
 	wielder = {
 		combat_armor = 18,
@@ -847,15 +865,14 @@ newEntity{ base = "BASE_KNIFE",
 	cost = 550,
 	material_level = 5,
 	combat = {
-		dam = 45,
-		apr = 11,
-		physcrit = 18,
-		dammod = {dex=0.55,str=0.35},
+		dam = 50,
+		max_acc = 98,
+		critical_power = 2.5,
+		dammod = {dex=0.6,str=0.4},
 	},
 	wielder = {
 		lite = 1,
 		inc_damage={
-			[DamageType.PHYSICAL] = 10,
 			[DamageType.LIGHT] = 8,
 		},
 		pin_immune = 0.5,
@@ -877,9 +894,9 @@ newEntity{ base = "BASE_KNIFE",
 	material_level = 3,
 	combat = {
 		dam = 25,
-		apr = 10,
-		physcrit = 8,
-		dammod = {dex=0.55,str=0.35},
+		max_acc = 99,
+		critical_power = 2.1,
+		dammod = {dex=0.4,str=0.2},
 		no_stealth_break = true,
 		melee_project={[DamageType.RANDOM_SILENCE] = 10},
 	},
@@ -899,9 +916,9 @@ newEntity{ base = "BASE_KNIFE", define_as = "ART_PAIR_MOON",
 	material_level = 3,
 	combat = {
 		dam = 30,
-		apr = 30,
-		physcrit = 10,
-		dammod = {dex=0.45,str=0.45},
+		max_acc = 96,
+		critical_power = 2,
+		dammod = {dex=0.3, str=0.3},
 		melee_project={[DamageType.DARKNESS] = 20},
 	},
 	wielder = {
@@ -935,9 +952,9 @@ newEntity{ base = "BASE_KNIFE", define_as = "ART_PAIR_STAR",
 	material_level = 3,
 	combat = {
 		dam = 25,
-		apr = 20,
-		physcrit = 20,
-		dammod = {dex=0.45,str=0.45},
+		max_acc = 96,
+		critical_power = 2.1,
+		dammod = {dex=0.3, str=0.3},
 		melee_project={[DamageType.LIGHT] = 20},
 	},
 	wielder = {
@@ -1001,10 +1018,10 @@ newEntity{ base = "BASE_GREATMAUL",
 	cost = 650,
 	material_level = 5,
 	combat = {
-		dam = 82,
-		apr = 7,
-		physcrit = 4,
-		dammod = {str=1.2},
+		dam = 160,
+		max_acc = 90,
+		critical_power = 2,
+		dammod = {str=1.25},
 		talent_on_hit = { [Talents.T_FLAMESHOCK] = {level=3, chance=10} },
 		melee_project={[DamageType.FIRE] = 30},
 	},
@@ -1027,10 +1044,10 @@ newEntity{ base = "BASE_GREATMAUL",
 	cost = 250,
 	material_level = 3,
 	combat = {
-		dam = 48,
-		apr = 15,
-		physcrit = 3,
-		dammod = {str=1.2},
+		dam = 70,
+		max_acc = 95,
+		critical_power = 1.5,
+		dammod = {str=0.75},
 		talent_on_hit = { [Talents.T_SUNDER_ARMOUR] = {level=3, chance=15} },
 	},
 	wielder = {
@@ -1040,7 +1057,7 @@ newEntity{ base = "BASE_GREATMAUL",
 	},
 }
 
-newEntity{ base = "BASE_MACE",
+newEntity{ base = "BASE_MACE", define_as = "CROOKED_CLUB",
 	power_source = {technique=true},
 	unique = true,
 	name = "Crooked Club", color = colors.GREEN, image = "object/artifact/weapon_crooked_club.png",
@@ -1053,9 +1070,9 @@ newEntity{ base = "BASE_MACE",
 	material_level = 2,
 	combat = {
 		dam = 25,
-		apr = 4,
-		physcrit = 10,
-		dammod = {str=1},
+		max_acc = 80,
+		critical_power = 1.8,
+		dammod = {str=0.4},
 		melee_project={[DamageType.RANDOM_CONFUSION] = 14},
 	},
 	wielder = {combat_atk=12,},
@@ -1073,9 +1090,9 @@ newEntity{ base = "BASE_MACE",
 	cost = 350,
 	material_level = 4,
 	combat = {
-		dam = 40,
-		apr = 4,
-		physcrit = 9,
+		dam = 50,
+		max_acc = 90,
+		critical_power = 1.5,
 		dammod = {str=1},
 		melee_project={[DamageType.RANDOM_SILENCE] = 10, [DamageType.NATURE] = 18},
 	},
@@ -1165,11 +1182,10 @@ newEntity{ base = "BASE_GLOVES",
 		disarm_immune=0.4,
 		knockback_immune=0.3,
 		combat = {
-			dam = 18,
-			apr = 1,
-			physcrit = 7,
-			physspeed = -0.4,
-			dammod = {dex=0.4, str=-0.6, cun=0.4 },
+			dam = 20,
+			max_acc = 2,
+			critical_power = 0.7,
+			dammod = {dex=0.2, str=0.1, cun=0.2 },
 		},
 	},
 }
@@ -1189,16 +1205,13 @@ newEntity{ base = "BASE_GAUNTLETS",
 		inc_damage = { [DamageType.PHYSICAL] = 10 },
 		combat_physcrit = 10,
 		combat_spellcrit = 10,
-		combat_critical_power = 50,
 		combat_armor = 6,
 		combat = {
 			dam = 35,
-			apr = 10,
-			physcrit = 10,
-			physspeed = -0.2,
-			dammod = {dex=0.4, str=-0.6, cun=0.4 },
+			max_acc = 15,
+			critical_power = .7,
+			dammod = {dex=0.2, str=0.1, cun=0.2 },
 			melee_project={[DamageType.ARCANE] = 20},
-			damrange = 0.3,
 		},
 	},
 }
@@ -1221,10 +1234,9 @@ newEntity{ base = "BASE_GLOVES",
 		max_life = 60,
 		combat = {
 			dam = 16,
-			apr = 1,
-			physcrit = 4,
-			physspeed = -0.4,
-			dammod = {dex=0.4, str=-0.6, cun=0.4 },
+			max_acc = 10,
+			critical_power = 0.4,
+			dammod = {dex=0.1, str=0, cun=0.1 },
 			melee_project={ [DamageType.COLD] = 10, [DamageType.LIGHTNING] = 10, },
 		},
 	},
@@ -1249,17 +1261,14 @@ newEntity{ base = "BASE_GAUNTLETS",
 		inc_damage = { [DamageType.LIGHTNING] = 10 },
 		resists_cap = { [DamageType.LIGHTNING] = 5 },
 		combat_spellcrit = 5,
-		combat_critical_power = 20,
 		combat_armor = 3,
 		combat = {
-			dam = 22,
-			apr = 10,
-			physcrit = 4,
-			physspeed = -0.2,
-			dammod = {dex=0.4, str=-0.6, cun=0.4 },
+			dam = 40,
+			max_acc = 15,
+			critical_power = 1,
+			dammod = {dex=0.4, str=0.3, cun=0.4 },
 			melee_project={ [DamageType.LIGHTNING] = 20, },
 			talent_on_hit = { [Talents.T_LIGHTNING] = {level=3, chance=10} },
-			damrange = 0.3,
 		},
 	},
 	max_power = 16, power_regen = 1,
@@ -1407,7 +1416,7 @@ newEntity{ base = "BASE_CLOTH_ARMOR",
 	use_talent = { id = Talents.T_DAMAGE_SMEARING, level = 3, power = 100 },
 }
 
-newEntity{ base = "BASE_GEM",
+newEntity{ base = "BASE_GEM", define_as = "GEM_TELOS",
 	power_source = {arcane=true},
 	unique = true,
 	unided_name = "scintillating white crystal",
@@ -1448,9 +1457,12 @@ newEntity{ base = "BASE_GEM",
 				who:sortInven(gem_inven)
 
 				-- Change the staff
+				voice.modes = o.modes
+				voice.flavor_name = o.flavor_name
 				voice.combat = o.combat
-				voice.combat.dam = voice.combat.dam * 1.4
-				voice.combat.damtype = engine.DamageType.ARCANE
+				voice.combat.dam = math.floor(voice.combat.dam * 1.4)
+				voice.combat.sentient = "telos"
+				voice.wielder.inc_damage[voice.combat.damtype] = voice.combat.dam
 				voice:identify(true)
 				o:replaceWith(voice)
 				who:sortInven()
@@ -1486,8 +1498,8 @@ newEntity{ base = "BASE_STAFF", define_as = "VOICE_TELOS",
 		max_mana = 100,
 		inc_stats = { [Stats.STAT_MAG] = 6, [Stats.STAT_WIL] = 5, [Stats.STAT_CUN] = 4 },
 		lite = 1,
-
-		inc_damage = { all=14 },
+		inc_damage = {},
+		learn_talent = {[Talents.T_COMMAND_STAFF] = 5},
 	},
 }
 
@@ -1527,15 +1539,14 @@ newEntity{ base = "BASE_BATTLEAXE",
 	rarity = 300,
 	material_level = 4,
 	combat = {
-		dam = 68,
-		apr = 7,
-		physcrit = 10,
-		dammod = {str=1.3},
+		dam = 120,
+		max_acc = 85,
+		critical_power = 2.1,
+		dammod = {str=1.1},
 	},
 	wielder = {
 		inc_stats = { [Stats.STAT_CON] = 2, [Stats.STAT_DEX] = 2, },
 		combat_def = 6, combat_armor = 6,
-		inc_damage = { [DamageType.PHYSICAL]=10 },
 		stun_immune = 0.3,
 		knockback_immune = 0.3,
 	},
@@ -1564,10 +1575,10 @@ newEntity{ base = "BASE_BATTLEAXE",
 	level_range = {20, 35},
 	material_level = 4,
 	combat = {
-		dam = 52,
-		apr = 21,
-		physcrit = 2,
-		dammod = {str=1.2},
+		dam = 75,
+		max_acc = 85,
+		critical_power = 3,
+		dammod = {str=1},
 		inc_damage_type = {dragon=25},
 	},
 	wielder = {
@@ -1590,10 +1601,10 @@ newEntity{ base = "BASE_WARAXE",
 	cost = 330,
 	material_level = 4,
 	combat = {
-		dam = 33,
-		apr = 4.5,
-		physcrit = 7,
-		dammod = {str=1},
+		dam = 40,
+		max_acc = 90,
+		critical_power = 2.5,
+		dammod = {str=0.8},
 		melee_project={[DamageType.COLD] = 25},
 	},
 	wielder = {
@@ -1611,9 +1622,9 @@ newEntity{ base = "BASE_WHIP",
 	material_level = 3,
 	combat = {
 		dam = 28,
-		apr = 8,
-		physcrit = 5,
-		dammod = {dex=1},
+		max_acc = 75,
+		critical_power = 2.5,
+		dammod = {dex=0.6},
 		melee_project={[DamageType.POISON] = 22},
 	},
 	wielder = {
@@ -1940,10 +1951,10 @@ newEntity{ base = "BASE_GREATSWORD",
 	moddable_tile = "special/golden_sword_right",
 	moddable_tile_big = true,
 	combat = {
-		dam = 40,
-		apr = 1,
-		physcrit = 7,
-		dammod = {str=1.2},
+		dam = 70,
+		max_acc = 95,
+		critical_power = 2,
+		dammod = {str=1},
 		special_on_hit = {desc="9% chance to stun or confuse the target", fct=function(combat, who, target)
 			if not rng.percent(9) then return end
 			local eff = rng.table{"stun", "confusion"}
@@ -1968,9 +1979,9 @@ newEntity{ base = "BASE_MACE",
 	cost = 300,
 	material_level = 5,
 	combat = {
-		dam = 52,
-		apr = 5,
-		physcrit = 2.5,
+		dam = 82,
+		max_acc = 80,
+		critical_power = 2,
 		dammod = {str=1},
 		special_on_hit = {desc="10% chance to shimer to a different hue and gain powers", fct=function(combat, who, target)
 			if not rng.percent(10) then return end
@@ -2036,17 +2047,15 @@ It is said the wielder will slowly grow mad. This, however, has never been prove
 	rarity = 250,
 	material_level = 5,
 	combat = {
-		dam = 58,
-		apr = 16,
-		physcrit = 7,
+		dam = 70,
+		max_acc = 95,
+		critical_power = 2,
 		dammod = {str=1},
-		damrange = 1.4,
 		damtype = DamageType.PHYSICALBLEED,
 	},
 	wielder = {
 		inc_stats = { [Stats.STAT_STR] = 4, [Stats.STAT_DEX] = 4, },
 		see_invisible = 5,
-		inc_damage = { [DamageType.PHYSICAL]=10 },
 	},
 }
 
@@ -2063,9 +2072,9 @@ newEntity{ base = "BASE_LONGSWORD", define_as = "ART_PAIR_TWSWORD",
 	material_level = 3,
 	combat = {
 		dam = 28,
-		apr = 10,
-		physcrit = 8,
-		dammod = {str=0.8,mag=0.2},
+		max_acc = 100,
+		critical_power = 1.3,
+		dammod = {str=0.5,mag=0.1},
 		melee_project={[DamageType.TEMPORAL] = 5},
 	},
 	wielder = {
@@ -2101,9 +2110,9 @@ newEntity{ base = "BASE_KNIFE", define_as = "ART_PAIR_TWDAG",
 	material_level = 3,
 	combat = {
 		dam = 25,
-		apr = 20,
-		physcrit = 20,
-		dammod = {dex=0.5,mag=0.5},
+		max_acc = 100,
+		critical_power = 2,
+		dammod = {dex=0.3,mag=0.3},
 		melee_project={[DamageType.TEMPORAL] = 5},
 	},
 	wielder = {
@@ -2137,9 +2146,10 @@ newEntity{ base = "BASE_LONGSWORD",
 	cost = 650,
 	material_level = 5,
 	combat = {
-		dam = 45,
-		apr = 4,
-		physcrit = 10,
+		affects_spells = true,
+		dam = 65,
+		max_acc = 95,
+		critical_power = 1.8,
 		dammod = {str=1},
 		talent_on_hit = { [Talents.T_MANA_CLASH] = {level=1, chance=25} },
 	},
@@ -2175,17 +2185,16 @@ newEntity{ base = "BASE_GAUNTLETS",
 		},
 		fatigue = 10,
 		combat_armor = 7,
-		inc_damage = { [DamageType.PHYSICAL]=5, [DamageType.ACID]=10, },
+		inc_damage = { [DamageType.ACID]=10, },
 		resists = {[DamageType.ACID] = 20, [DamageType.PHYSICAL] = 10, },
 		resists_cap = {[DamageType.ACID] = 10, [DamageType.PHYSICAL] = 5, },
 		resists_pen = {[DamageType.ACID] = 15, [DamageType.PHYSICAL] = 15, },
 		combat = {
-			dam = 26,
-			apr = 15,
-			physcrit = 5,
-			dammod = {dex=0.3, str=-0.4, cun=0.3 },
+			dam = 35,
+			max_acc = 10,
+			critical_power = 5,
+			dammod = {dex=0.2, str=0.1, cun=0.2 },
 			melee_project={[DamageType.ACID] = 10},
-			damrange = 0.3,
 		},
 	},
 }
diff --git a/game/modules/tome/data/gfx/effects/counterstrike.png b/game/modules/tome/data/gfx/effects/counterstrike.png
new file mode 100644
index 0000000000000000000000000000000000000000..a2f835d4fe30267ae3b576bb56f44adb739e5e21
GIT binary patch
literal 2275
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

literal 0
HcmV?d00001

diff --git a/game/modules/tome/data/gfx/particles/ward.lua b/game/modules/tome/data/gfx/particles/ward.lua
new file mode 100644
index 0000000000..570619f30f
--- /dev/null
+++ b/game/modules/tome/data/gfx/particles/ward.lua
@@ -0,0 +1,53 @@
+-- ToME - Tales of Maj'Eyal
+-- Copyright (C) 2009, 2010, 2011 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
+
+base_size = 32
+
+local color = color or {r=127, g=127, b=127}
+local ad = rng.range(0, 360)
+local a = math.rad(ad)
+local dir = math.rad(ad + 90)
+local r = 18
+local speed = rng.range(33, 99)
+local dirv = math.pi * 2 / speed
+local vel = math.pi * 2 * r / speed
+local first = true
+
+return { generator = function()
+	local dr = rng.range(0, 2)
+	local da = math.rad(rng.range(0, 360))
+	return {
+		life = core.particles.ETERNAL,
+		size = rng.range(3,8), sizev = 0, sizea = 0,
+
+		x = r * math.cos(a) + dr * math.cos(da), xv = 0, xa = 0,
+		y = r * math.sin(a) + dr * math.cos(da), yv = 0, ya = 0,
+		dir = dir, dirv = dirv, dira = 0,
+		vel = vel, velv = 0, vela = 0,
+
+		r = color.r/255,   rv = 0, ra = 0,
+		g = color.g/255,   gv = 0, ga = 0,
+		b = color.b/255,   gv = 0, ga = 0,
+		a = rng.range(230, 225)/255,   av = 0, aa = 0,
+	}
+end, },
+function(self)
+	if first then self.ps:emit(10) first = false end
+end,
+10
diff --git a/game/modules/tome/data/gfx/talents/block.png b/game/modules/tome/data/gfx/talents/block.png
new file mode 100644
index 0000000000000000000000000000000000000000..a94bc94e0d2557490f2cecfe26e19126a118b68a
GIT binary patch
literal 4274
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
U3ALL#VgLXD07*qoM6N<$g4*~`1ONa4

literal 0
HcmV?d00001

diff --git a/game/modules/tome/data/gfx/talents/bloodflow.png b/game/modules/tome/data/gfx/talents/bloodflow.png
new file mode 100644
index 0000000000000000000000000000000000000000..fbe8942ab1461dc2d5c05f1e4e16786e00494463
GIT binary patch
literal 3295
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

literal 0
HcmV?d00001

diff --git a/game/modules/tome/data/gfx/talents/command_staff.png b/game/modules/tome/data/gfx/talents/command_staff.png
new file mode 100644
index 0000000000000000000000000000000000000000..30c6ed37cb0e5ebbead103f9b37eee91faadac33
GIT binary patch
literal 3803
zcmV<14kYo3P)<h;3K|Lk000e1NJLTq002M$002M;1^@s6s%dfF00001b5ch_0Itp)
z=>Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2ipq^
z69gR%_C%-v01jJ8L_t(|+TELXcvN-P$3IgtB_VA>3S>eFAyh*&hLRvf0mCA^AUy^M
zO<0$uNKp}$R}ff5U{$~cc~_bgDbiNhRZ4)s0tuZoNF$B(Li!~0{&7h#OrIpK>v^7e
zp4_=N_uk*R=X}rieD4|2u_b5$sx%;z(!i!{g8aw)u1#F`$FqwE2o2_UZ&G7BU+n?*
zO1KaU=VP1Zf+CR!rBY5=S;cQF0t{J@FAVi>x(lk+THan*ft?-y9S#6^t_`?4G|dJ7
zFbw7`fZl!niyQzj<K@O*Or?U*H^A8$!l!~v_8V|OiJ7Sw<g5FgqpkTDa&m&H)8NHG
zVLN0fj2lm*Q$ZvGTU+b@UvlOy%WG<(i>GihWA-o)Qgfef+en1+Y3$~_yo9H|`Y#X~
z26DNuPpO2#LxfbQse!C4C@Zsk0bXA4$G0FV3aYEEa6ow#%WtNDUt4f<G=6a3PEb|}
zaT&t4vBd)@6e4ELhWFkF-%cQXrsl|G(7^}%dO%7F+`DV}0w#vS(q(Y@G9)Eh;Q(Mc
zKt(n5^Z|(pRIpb<ayI0dL69^Wh`I(BFACA1_IetwS}i0bz{aoO!)0*c0@T)8jwzq4
zdg|O0$AxIJ$^mKl;NQ-46u7j2fDXdnu^Hw$Atgn)xs+rW@~V&q2?;QMEPTHYa&s+T
zypt15n+|VG5*DvkL)t@l@W8TEsCNK>SPU<EgV+QX*vf>I@%4br0`ur{ZLJWZfq~%b
z3!68={=Jq1UQ=UA0|z8Nf}ihzw;Q;dhy<|+JXH|jErfGirs<1SR|_Bi=VAGWkdtkh
z0~885vu0~~?|rSAm?E;w0U&@}S{}UE0hDIcX<Iq;Xa_#-kWl~yrN)nclqDi187^9p
z^BPSJQP;#=yr^w5Oc8<54L)l&5*QT-!(ISY3-fL;rx*@hf#cC8qDO4`;&qxBDU2Qi
zUvB|>dx(!0Fy;0wD?v~vXSHxQP59W#1@Mzeji1a;4*qSy+Z{6U4M&4k+js`o6qsVv
z0d<!D7%s*MpGSqz+0(cq#A5Jrfq?d)sfC0r(>KxD)d@deFI=4+$jmJ?`{o;qDMnMk
zka@eoqT#|KP3CM3T)q$cA|W|P|1ndB_hsRvp?IrZsjAixdGkJt*6krSIn%8BQK>|{
zGDyo0hpl9SrXt{3D=38%*99`<)lx_gL*z*;hBhsQ(poD~5uaZElu+3zSoP;Id^Bq$
zYIhYf8!1Y;4BxgMNF-uToWE(-{gjtOY>dca0%VpTV$3cj2%ixFFu5PdZH!=p(gp{I
zmO#GHUUyWpX6`sbg8UHcAsybHt`_2f^`Ig(MLd*B<Ama96gb$z=w2Yz6A6!sZP<0m
ziL*E30T?+jfYo!y(z#tL!_}mq<X3Blji!LPoz|^Xuvb9m)(yW;El~1Jgo?<!j{uk#
zI)u*`PNa>8aR5n7&qkxE;rY&OY17JuYE2D=C1uUx0HYu{Yc{N01rx@>&p#PIQJ;?R
z?#QP!IxbVhw)4)!Bnx5x>HP7`nJ@^YTxM2CYtbSWiO|&4lAMvtx}7Ka`oQU5F9Iy>
zw9@hguHfSVu^A#Z|0E|NtpsNWJ2t*Mnb~6pBDb;8!wIw$6qjLRBS9<{*9)g&kqD7U
zghVXH#jyp!{vEk`FNvh|oaT3cwVl@02Y^_?k!S^pnPs@UIP%rIlL#9YghZ^rRGhgQ
z!&|F&;An44SMSya&#jcpc$k&XnX55P>Hz640Z*-lVXwg(VempgU8g0**;&KJ%|aKp
zV>|rxFQJ9iXM4^I8k?)LJzp#dW9;BSM0%vA+FC7#PG4i;=X*%a%A>NXn!f%Wad$D?
zg;iQn=uH86y#wTO2%7}+-v*Zk7}XPq#LiCW<-I$ARx4uvJ|TSd*MAY8&L3}Z@zt6d
zzBzo34>uhmx3C0nwJYyT9fqs3Vd=TJw48{jI4fj$m=X@_*FkBi5mmUN0yeCNv7?2j
zoR?RJk^e@k6`GBY{})D$fP)9L1{Yrkc#~cW*1P!9@=8|!-!YbK*hg+*3I3hhu>IpV
z896XOFDIziBeU`;DXTCVA=b$7daFQVI<2`A2eW40IK60}UsTFRUms%2!Lw9VYZw^V
zg)f$b(cMRF^1KyQ)#T)tP*zb%T6O_@e!R@KAI_PS%nl!c;J&cuJD5Hds;bNYL2Em$
zkf7&Sw<r`Rdt1FvaQ@oeY(I8^TCJARuLQDb>12G{dg!eTg(YR!NS{^)sYHTf3neX`
z?D6(=Wk^tWvT}>K9-GoA$;@CGG^f*Q@9D~nQT>U$c^`n)bH@?b&0FWVdx`1HUimG@
zB5oj+NSHZl0G}_MNNZPTy^H_(%01?+*@4Qzj?V4%R|cs>f)*`%PyM@5l9^E|eCD*E
zuEZO_o~6@=Gc?$b;}JKAP0r*-Tq<J*1vcy%Zrx|jnw><)Bx9$PvvAT-7Ec*U3tNR=
zaNKnwl4TnYkdaeJwWfx?&->ES$=*PZA#bp47|5R--vG#A|2~oNS7Z74aPWZs+COb%
zKf;Cu;pyhgpx)g8ICkzj899aZPx8e1n@nD|h3J@MRE~D6nLCd6XAIZ7_~O!XR&G7Y
zyw7%#kyD6oTMrgb`2)@lhF=|3R5rXZ{XqUyglP!m!abU7hxLKImxqckmrTOb&AFbW
zY(I8^NBPBcZr6$zI=5xV@r%s;%Pvy0@=&|0`0L^@!biM>R4UPBk&p6Ov~Dk(_MfJr
zvYLJ`bYjbg(-;`o1+kIWRVqh2$}6k5awpMh8Qx+&0KnDBo*AS1*FPP17f0^gPa`fR
zi=2WIQnK<`w0<uoWfgR3-<rQI3ui?C=k=Dw8*!=3{^VPZoQ*~-7BeBFHyf8urc3+Q
zrUhAroR@ocMI?fV=s2r@+$skY6qllQR}s{sqadJ4CD<wD>^*szwCn;RqT|qNp^u*r
zTR)mcUw>b{VE5z2TfDjA?_9f=^aLM5SoP<zxT|ytQDv2e+S*zq&!{g_iG(igTXQn<
zwoV&u4v<^r0Dz?Q90v93TF>6RJY0xN&Lk#DcwIE4Pj|L0pH8<9o_ZIv_3$|sto@FZ
z%sf0?9Qkzqc;<x;(E+x)YrXg7_oQbR5ZJA~P9%v%A`YF7A~iElj|`7d8D5N)cK_ic
zKKbSt#iiv>!coS8u#kGD=IQ2)m%B=D^nAGa5R2CBAv?dA?mlX^uXvN`Bl{t<k?Qmd
zry_4NcJWtybNC!<cl^km`{_F8j7iEMJ|)XyAa7Iz0NlQxMs2N@VE>NTNF}J<R03y@
zj^jpLDxKQ4!q3;M{`lmKT;_kan{9_9sMgdlxOaE9ESpMD4<DVUTJ*S_4ZBaVc>O*e
zq-EpmV8_hY2k>f8_XaF8ujnyLHtgfty(Ei(yh$7YaPdY0+4;qE>)?rtV+)@1@gh1V
znWXd_ZpA+&$iE}4U7fjdCy_T-{GF4Lw~<Q3gpYWMFWw2GgO{7mIqyD5Xa3sVeEt0y
z9+y|(*U^hF-U(yI>-`&~$m6mKmVWs?J5NM5k0fTUMaQOa>e3xDa|=-_WO%wcbK=5H
z@{3AINX??MO2gvyd$}2(ii4e!rPGJAeD+9O99!rRp@TnN<E>TOIe$GKsZ_%FS9`H(
z=@f!`_|(&4fbz;JR%|`OhTZ>cK1s}4b9S(!ptw{oe^@nVEE7U{A(b@b1KIh-tljY=
ze>-r7;?i<FTpU>vK8%^K_tzm#<&{;e+IEbUTaOA1P$s3))U?L0=>S7^=<~UZdO1Mn
z`zv=6dH<^eoW6RmzI=W%XAJ!VI_Y4;<FX1q-g1P`w*Nzr(ABOardcnOnIVgdC@X6k
zA00j&MV}r%cs!{T<&{<JIuXgrtw%}C%EMM6BYeb5yf^JN)OspNc78D*Y&yu6gJ<g_
zEi1RE`BK2k%eb0ijSUU<W8I=q>=bfVY(2u(Luczd%MWJ$51~W*AlLKqF(xU4B^&l}
zJmLlb3L6m>)mq#fC1e-XG>-!;k;N^suHK%=WzzayJ|yTlR?ZniK$muU-Y?d0JmLn+
zHXh{e1AzmK>IvP{u<?}Xc?7Fd;Mt+Z^AWmginVqx@hO>^`T79X%pHfy(N3?3vf;Z^
ztlN1K07p9!<9cfe=>axUNXmxY7k)#sxHYELYH_l+#mmD5TZOEiE$;ruB^IpxjvvlM
z0no7({BaQU>jF}V5V~p=lvF@swlK6=S>1>fFf5Bd5i?5#K5a@Cx7Paj`7j}*H&Th1
zJtr@7;d*@izQ7Lf)(~i^M;EEm2&r)TZX+>3p@0Q%8&*^5dw~1!(FcN>qBUdG!<-ka
zrp&)BEFEQdW+^cna*BkvQ{SGmG6kAzsIjr5tN>X>!YHq&O8<T*TTr_|S2c|9BTTT|
zOtAt3nq#Q3v7@Z@SON6%5r!`GMcLEVSf~(kDJ16#6R^fiZ#%5fz_Ftc@g$t~@3VaR
zN?#>u%y@ikhGoBB8r=(a{t3eS3)?ml3!9<F4j?skB`K{G#&P`GSW;nxv<MA`!G2Iw
zraP--v>P;~rs#&E$O2tnWHB(_c?b?l@NH!#!v7*Qlrre!3n4v(l39llMjapwAeldb
ztxzbKHM_P+M_He>s6@yrgifu^n`HeZhKQaxqHgrBS-L@`Qbb@+E#XrIPEl7<>nh3K
zJpz~}BnVhzt@(Jsv;o5JnXIwL6%do&jO}n!jj|ebwoD*M1G+Xb6>bV^s!>*Brm2BT
z@o@46)M&xO$+EO)RtGdiB{A13ss&K{;i|w2gM9V#h5v{mq*B2vgRpv()f)45gTIEG
zS0;ZINvtWx<1Mw&V3-*E6#ah_n&5xJTH3>^3DC;f0xJA_vfL8b{4c}%{~sHiCj35d
RoxT77002ovPDHLkV1nh9E>8de

literal 0
HcmV?d00001

diff --git a/game/modules/tome/data/gfx/talents/elemental_retribution.png b/game/modules/tome/data/gfx/talents/elemental_retribution.png
new file mode 100644
index 0000000000000000000000000000000000000000..9ea122dc9b1bfc9737599600e710adc8ad23d9f2
GIT binary patch
literal 4320
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
O0000<MNUMnLSTZ-4d9~y

literal 0
HcmV?d00001

diff --git a/game/modules/tome/data/gfx/talents/fearscape_fog.png b/game/modules/tome/data/gfx/talents/fearscape_fog.png
new file mode 100644
index 0000000000000000000000000000000000000000..a4aa55f437f1d24e7c47adc00568aa2ac1282a3c
GIT binary patch
literal 3100
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

literal 0
HcmV?d00001

diff --git a/game/modules/tome/data/gfx/talents/lifebind.png b/game/modules/tome/data/gfx/talents/lifebind.png
new file mode 100644
index 0000000000000000000000000000000000000000..874c66ebf004f2d4002c23602702e1d18a22e90f
GIT binary patch
literal 2214
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

literal 0
HcmV?d00001

diff --git a/game/modules/tome/data/gfx/talents/perception.png b/game/modules/tome/data/gfx/talents/perception.png
new file mode 100644
index 0000000000000000000000000000000000000000..8385a28547b27855c5e9409697d4757989530f71
GIT binary patch
literal 3049
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

literal 0
HcmV?d00001

diff --git a/game/modules/tome/data/gfx/talents/reload.png b/game/modules/tome/data/gfx/talents/reload.png
new file mode 100644
index 0000000000000000000000000000000000000000..e255d62a46ed2ac5bed74ef18b9a77778a3a63be
GIT binary patch
literal 4773
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

literal 0
HcmV?d00001

diff --git a/game/modules/tome/data/gfx/talents/savagery.png b/game/modules/tome/data/gfx/talents/savagery.png
new file mode 100644
index 0000000000000000000000000000000000000000..677101cd35a8fe505e355ffd5311313bec0b6d33
GIT binary patch
literal 3767
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

literal 0
HcmV?d00001

diff --git a/game/modules/tome/data/gfx/talents/soul_drain.png b/game/modules/tome/data/gfx/talents/soul_drain.png
new file mode 100644
index 0000000000000000000000000000000000000000..1501e559646edf37bc9fd460f4778d8735c75f3a
GIT binary patch
literal 4903
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
Z{{t*dm%BHN;Vu9G002ovPDHLkV1mE4jqm^f

literal 0
HcmV?d00001

diff --git a/game/modules/tome/data/gfx/talents/ward.png b/game/modules/tome/data/gfx/talents/ward.png
new file mode 100644
index 0000000000000000000000000000000000000000..5873554c26f252014d9406bc77514f9e12f55920
GIT binary patch
literal 3552
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
a{{H}=aK~Cg3?q>M0000<MNUMnLSTXpWT?mh

literal 0
HcmV?d00001

diff --git a/game/modules/tome/data/talents/celestial/light.lua b/game/modules/tome/data/talents/celestial/light.lua
index 7e97189cc0..4b2a07a49a 100644
--- a/game/modules/tome/data/talents/celestial/light.lua
+++ b/game/modules/tome/data/talents/celestial/light.lua
@@ -25,7 +25,7 @@ newTalent{
 	random_ego = "defensive",
 	cooldown = 10,
 	positive = -10,
-	tactical = { HEAL = 2 },
+	tactical = { HEAL = 2, },
 	getHeal = function(self, t) return self:combatTalentSpellDamage(t, 20, 440) end,
 	is_heal = true,
 	action = function(self, t)
diff --git a/game/modules/tome/data/talents/chronomancy/energy.lua b/game/modules/tome/data/talents/chronomancy/energy.lua
index ecacff1552..fd36177cb3 100644
--- a/game/modules/tome/data/talents/chronomancy/energy.lua
+++ b/game/modules/tome/data/talents/chronomancy/energy.lua
@@ -105,7 +105,7 @@ newTalent{
 		local target = game.level.map(tx, ty, Map.ACTOR)
 		if not target then return end
 
-		if not self:checkHit(self:combatSpellpower(), target:combatSpellResist()) then
+		if not self:checkHit(self:combatSpellpower(), target:combatSpellResist(), 0, self:getMaxAccuracy("spell")) then
 			game.logSeen(target, "%s resists!", target.name:capitalize())
 			return true
 		end
diff --git a/game/modules/tome/data/talents/chronomancy/matter.lua b/game/modules/tome/data/talents/chronomancy/matter.lua
index 0ba31c6bd1..b0f895fd7e 100644
--- a/game/modules/tome/data/talents/chronomancy/matter.lua
+++ b/game/modules/tome/data/talents/chronomancy/matter.lua
@@ -175,7 +175,7 @@ newTalent{
 		
 		-- Try to insta-kill
 		if target then
-			if target:checkHit(self:combatSpellpower(), target:combatPhysicalResist(), 0, 95, 15) and target:canBe("instakill") and target.life > 0 and target.life < target.max_life * 0.2 then
+			if target:checkHit(self:combatSpellpower(), target:combatPhysicalResist(), 0, self:getMaxAccuracy("spell"), 15) and target:canBe("instakill") and target.life > 0 and target.life < target.max_life * 0.2 then
 				-- KILL IT !
 				game.logSeen(target, "%s has been pulled apart at a molecular level!", target.name:capitalize())
 				target:die(self)
diff --git a/game/modules/tome/data/talents/chronomancy/paradox.lua b/game/modules/tome/data/talents/chronomancy/paradox.lua
index fe420b5acd..9fd8bd4ebe 100644
--- a/game/modules/tome/data/talents/chronomancy/paradox.lua
+++ b/game/modules/tome/data/talents/chronomancy/paradox.lua
@@ -86,7 +86,7 @@ newTalent{
 		if not target then return end
 		
 		-- does the spell hit?  if not nothing happens
-		if not self:checkHit(self:combatSpellpower(), target:combatSpellResist()) then
+		if not self:checkHit(self:combatSpellpower(), target:combatSpellResist(), 0, self:getMaxAccuracy("spell")) then
 			game.logSeen(target, "%s resists!", target.name:capitalize())
 			return true
 		end
diff --git a/game/modules/tome/data/talents/chronomancy/spacetime-folding.lua b/game/modules/tome/data/talents/chronomancy/spacetime-folding.lua
index 7a9adb750a..1b811e8070 100644
--- a/game/modules/tome/data/talents/chronomancy/spacetime-folding.lua
+++ b/game/modules/tome/data/talents/chronomancy/spacetime-folding.lua
@@ -76,7 +76,7 @@ newTalent{
 			power = self:combatSpellpower() * (1 + self:getTalentLevel(self.T_SPACETIME_MASTERY)/10)
 		end
 		
-		if target:canBe("teleport") and self:checkHit(power, target:combatSpellResist() + (target:attr("continuum_destabilization") or 0)) then
+		if target:canBe("teleport") and self:checkHit(power, target:combatSpellResist() + (target:attr("continuum_destabilization") or 0), 0, self:getMaxAccuracy("spell")) then
 			target:crossTierEffect(target.EFF_SPELLSHOCKED, self:combatSpellpower())
 			-- first remove the target so the destination tile is empty
 			game.level.map:remove(target.x, target.y, Map.ACTOR)
diff --git a/game/modules/tome/data/talents/chronomancy/spacetime-weaving.lua b/game/modules/tome/data/talents/chronomancy/spacetime-weaving.lua
index c82a74d56b..af1fb26c58 100644
--- a/game/modules/tome/data/talents/chronomancy/spacetime-weaving.lua
+++ b/game/modules/tome/data/talents/chronomancy/spacetime-weaving.lua
@@ -102,7 +102,7 @@ newTalent{
 		self:project(tg, self.x, self.y, function(px, py)
 			local target = game.level.map(px, py, Map.ACTOR)
 			if not target or target == self then return end
-			if self:checkHit(power, target:combatSpellResist() + (target:attr("continuum_destabilization") or 0)) and target:canBe("teleport") then
+			if self:checkHit(power, target:combatSpellResist() + (target:attr("continuum_destabilization") or 0), 0, self:getMaxAccuracy("spell")) and target:canBe("teleport") then
 				actors[#actors+1] = target
 			else
 				game.logSeen(target, "%s resists the banishment!", target.name:capitalize())
@@ -221,7 +221,7 @@ newTalent{
 			destabilization_power = self:combatSpellpower(0.3),
 			summoned_by = self, -- "summoner" is immune to it's own traps
 			triggered = function(self, x, y, who)
-				if who:checkHit(self.check_hit, who:combatSpellResist(), 0, 95, 15) and who:canBe("teleport") or who == self.summoned_by then
+				if who:checkHit(self.check_hit, who:combatSpellResist(), 0, self:getMaxAccuracy("spell"), 15) and who:canBe("teleport") or who == self.summoned_by then
 					-- since we're using a precise teleport we'll look for a free grid first
 					local tx, ty = util.findFreeGrid(self.dest.x, self.dest.y, 5, true, {[Map.ACTOR]=true})
 					if tx and ty then
diff --git a/game/modules/tome/data/talents/chronomancy/timetravel.lua b/game/modules/tome/data/talents/chronomancy/timetravel.lua
index c0aa022e62..9a68bb1fe1 100644
--- a/game/modules/tome/data/talents/chronomancy/timetravel.lua
+++ b/game/modules/tome/data/talents/chronomancy/timetravel.lua
@@ -25,13 +25,13 @@ newTalent{
 	message = "@Source@ rearranges history.",
 	cooldown = 24,
 	tactical = { PARADOX = 2 },
-	getDuration = function(self, t) 
+	getDuration = function(self, t)
 		local duration = 1 + math.floor(self:getTalentLevel(t)/2)
-		
+
 		if self:knowTalent(self.T_PARADOX_MASTERY) then
 			duration = 1 + math.floor((self:getTalentLevel(t)/2) + (self:getTalentLevel(self.T_PARADOX_MASTERY)/2))
 		end
-		
+
 		return duration
 	end,
 	getReduction = function(self, t) return self:combatTalentSpellDamage(t, 30, 300) end,
@@ -74,9 +74,9 @@ newTalent{
 		local target = x and game.level.map(x, y, engine.Map.ACTOR) or nil
 		if not target then return nil end
 
-		local hit = self:checkHit(self:combatSpellpower(), target:combatSpellResist() + (target:attr("continuum_destabilization") or 0))
+		local hit = self:checkHit(self:combatSpellpower(), target:combatSpellResist() + (target:attr("continuum_destabilization") or 0), 0, self:getMaxAccuracy("spell"))
 		if not hit then game.logSeen(target, "%s resists!", target.name:capitalize()) return true end
-		
+
 		target:setEffect(target.EFF_CONTINUUM_DESTABILIZATION, 100, {power=self:combatSpellpower(0.3)})
 		self:project(tg, x, y, DamageType.TEMPORAL, self:spellCrit(t.getDamage(self, t)))
 		game.level.map:particleEmitter(x, y, 1, "temporal_thrust")
@@ -84,7 +84,7 @@ newTalent{
 
 		-- End it here if we've killed the target or the target is a player
 		if target.dead or target.player then return true end
-		
+
 		-- set up instability
 		local summoner = self
 		-- Store the current terrain
@@ -115,7 +115,7 @@ newTalent{
 			summoner_gain_exp = true,
 			summoner = summoner,
 		}
-		
+
 		-- Mixin the old terrain
 		table.update(temporal_instability, terrain)
 		-- Now update the display overlay
@@ -129,12 +129,12 @@ newTalent{
 		else
 			table.append(temporal_instability.add_displays, overlay)
 		end
-		
+
 		game.logSeen(target, "%s has moved forward in time!", target.name:capitalize())
 		game.level:removeEntity(target)
 		game.level:addEntity(temporal_instability)
 		game.level.map(target.x, target.y, engine.Map.TERRAIN, temporal_instability)
-		
+
 		return true
 	end,
 	info = function(self, t)
@@ -197,7 +197,7 @@ newTalent{
 		for tid, cd in pairs(self.talents_cd) do
 			self.talents_cd[tid] = cd - t.getCooldownReduction(self, t)
 		end
-		
+
 		local target = self
 		local todel = {}
 		for eff_id, p in pairs(target.tmp) do
@@ -210,7 +210,7 @@ newTalent{
 		while #todel > 0 do
 			target:removeEffect(table.remove(todel))
 		end
-		
+
 		return true
 	end,
 	info = function(self, t)
diff --git a/game/modules/tome/data/talents/corruptions/blight.lua b/game/modules/tome/data/talents/corruptions/blight.lua
index a70a041d94..a99c8bc6c6 100644
--- a/game/modules/tome/data/talents/corruptions/blight.lua
+++ b/game/modules/tome/data/talents/corruptions/blight.lua
@@ -91,7 +91,7 @@ newTalent{
 				if #effs == 0 then break end
 				local eff = rng.tableRemove(effs)
 
-				if self:checkHit(self:combatSpellpower(), target:combatSpellResist(), 0, 95, 5) then
+				if self:checkHit(self:combatSpellpower(), target:combatSpellResist(), 0, self:getMaxAccuracy("spell"), 5) then
 					target:crossTierEffect(target.EFF_SPELLSHOCKED, self:combatSpellpower())
 					if eff[1] == "effect" then
 						target:removeEffect(eff[2])
diff --git a/game/modules/tome/data/talents/cunning/stealth.lua b/game/modules/tome/data/talents/cunning/stealth.lua
index 90a728e76f..862945fdda 100644
--- a/game/modules/tome/data/talents/cunning/stealth.lua
+++ b/game/modules/tome/data/talents/cunning/stealth.lua
@@ -83,12 +83,12 @@ newTalent{
 	require = cuns_req2,
 	mode = "passive",
 	points = 5,
-	getMultiplier = function(self, t) return 1.5 + self:getTalentLevel(t) / 7 end,
+	getMultiplier = function(self, t) return self:getTalentLevel(t) / 7 end,
 	info = function(self, t)
 		local multiplier = t.getMultiplier(self, t)
 		return ([[When striking from stealth, hits are automatically criticals if the target does not notice you.
-		Shadowstrikes do %.02f%% damage versus a normal hit.]]):
-		format(multiplier * 100)
+		Shadowstrike criticals have their multiplier increased by %.02f.]]):
+		format(multiplier)
 	end,
 }
 
diff --git a/game/modules/tome/data/talents/gifts/earthen-vines.lua b/game/modules/tome/data/talents/gifts/earthen-vines.lua
index e4acaf4925..cefd04ab2e 100644
--- a/game/modules/tome/data/talents/gifts/earthen-vines.lua
+++ b/game/modules/tome/data/talents/gifts/earthen-vines.lua
@@ -45,7 +45,7 @@ newTalent{
 		-- Randomly take targets
 		local tg = {type="hit", range=self:getTalentRange(t), talent=t}
 		local a, id = rng.table(tgts)
-		local hit, chance = a:checkHit(self:combatTalentStatDamage(t, "wil", 5, 110), a:combatPhysicalResist(), 0, 95, 5)
+		local hit, chance = a:checkHit(self:combatTalentStatDamage(t, "wil", 5, 110), a:combatPhysicalResist(), 0, self:getMaxAccuracy("spell"), 5)
 		if a:canBe("pin") and hit then
 			local turns, dam = t.getValues(self, t)
 			a:setEffect(a.EFF_STONE_VINE, turns, {dam=dam, src=self, free=rad*2, free_chance=100-chance})
diff --git a/game/modules/tome/data/talents/gifts/summon-distance.lua b/game/modules/tome/data/talents/gifts/summon-distance.lua
index 8030af8c5e..b3db88cda7 100644
--- a/game/modules/tome/data/talents/gifts/summon-distance.lua
+++ b/game/modules/tome/data/talents/gifts/summon-distance.lua
@@ -463,7 +463,7 @@ newTalent{
 			infravision = 10,
 
 			combat_armor = 15, combat_def = 0,
-			combat = { dam=resolvers.levelup(resolvers.rngavg(15,25), 1, 1.3), atk=resolvers.levelup(resolvers.rngavg(15,25), 1, 1.3), dammod={cun=1.1} },
+			combat = { dam=resolvers.levelup(resolvers.rngavg(15,25), 1, 1.3), atk=resolvers.levelup(resolvers.rngavg(15,25), 1, 1.3), dammod={cun=resolvers.levelup(0.2, 5, 0.2, 1.1)} },
 
 			wild_gift_detonate = t.id,
 
@@ -547,7 +547,7 @@ newTalent{
 				infravision = 10,
 
 				combat_armor = 0, combat_def = 0,
-				combat = { dam=resolvers.levelup(resolvers.rngavg(25,40), 1, 0.6), atk=resolvers.rngavg(25,60), apr=25, dammod={str=1.1} },
+				combat = { dam=resolvers.levelup(resolvers.rngavg(25,40), 1, 0.6), atk=resolvers.rngavg(25,60), apr=25, dammod={str=resolvers.levelup(0.2, 5, 0.2, 1.1)} },
 				on_melee_hit = {[DamageType.FIRE]=resolvers.mbonus(7, 2)},
 
 				resists = { [DamageType.FIRE] = 100, },
diff --git a/game/modules/tome/data/talents/gifts/summon-melee.lua b/game/modules/tome/data/talents/gifts/summon-melee.lua
index 2bccf865da..5db790b091 100644
--- a/game/modules/tome/data/talents/gifts/summon-melee.lua
+++ b/game/modules/tome/data/talents/gifts/summon-melee.lua
@@ -75,7 +75,7 @@ newTalent{
 			infravision = 10,
 
 			combat_armor = 2, combat_def = 4,
-			combat = { dam=self:getTalentLevel(t) * 10 + rng.avg(12,25), atk=10, apr=10, dammod={str=0.8} },
+			combat = { dam=self:getTalentLevel(t) * 10 + rng.avg(12,25), atk=10, apr=10, dammod={str=resolvers.levelup(0.2, 5, 0.1, 0.8)} },
 
 			wild_gift_detonate = t.id,
 
@@ -165,7 +165,7 @@ newTalent{
 			combat_armor = 1, combat_def = 1,
 			never_move = 1,
 
-			combat = { dam=8, atk=15, apr=5, damtype=DamageType.ACID, dammod={str=0.7} },
+			combat = { dam=8, atk=15, apr=5, damtype=DamageType.ACID, dammod={str=resolvers.levelup(0.2, 5, 0.1, 0.7)} },
 
 			wild_gift_detonate = t.id,
 
@@ -360,7 +360,7 @@ newTalent{
 			level_range = {self.level, self.level}, exp_worth = 0,
 
 			combat_armor = 25, combat_def = -20,
-			combat = { dam=25 + self:getWil(), atk=20, apr=5, dammod={str=0.9} },
+			combat = { dam=25 + self:getWil(), atk=20, apr=5, dammod={str=resolvers.levelup(0.2, 5, 0.2, 0.9)} },
 			resolvers.talents{ [Talents.T_UNSTOPPABLE]=3, [Talents.T_STUN]=3, },
 
 			poison_immune=1, cut_immune=1, fear_immune=1, blind_immune=1,
diff --git a/game/modules/tome/data/talents/gifts/summon-utility.lua b/game/modules/tome/data/talents/gifts/summon-utility.lua
index 13bc856171..6ab854fe1d 100644
--- a/game/modules/tome/data/talents/gifts/summon-utility.lua
+++ b/game/modules/tome/data/talents/gifts/summon-utility.lua
@@ -249,7 +249,7 @@ newTalent{
 			infravision = 10,
 
 			combat_armor = 0, combat_def = 0,
-			combat = { dam=resolvers.rngavg(20,25), atk=16, apr=9, damtype=DamageType.NATURE, dammod={dex=1.2} },
+			combat = { dam=resolvers.rngavg(20,25), atk=16, apr=9, damtype=DamageType.NATURE, dammod={dex=resolvers.levelup(0.2, 5, 0.2, 1.2)} },
 
 			wild_gift_detonate = t.id,
 
diff --git a/game/modules/tome/data/talents/misc/horrors.lua b/game/modules/tome/data/talents/misc/horrors.lua
index 7593ce1331..49ba4f248a 100644
--- a/game/modules/tome/data/talents/misc/horrors.lua
+++ b/game/modules/tome/data/talents/misc/horrors.lua
@@ -457,7 +457,7 @@ newTalent{
 				autolevel = "summoner",
 				ai = "summoned", ai_real = "dumb_talented_simple", ai_state = { talent_in=2, ai_move="move_snake" },
 				combat_armor = 1, combat_def = 1,
-				combat = { dam=resolvers.levelup(resolvers.mbonus(40, 15), 1, 1.2), atk=15, apr=15, dammod={wil=0.8}, damtype=DamageType.TEMPORAL },
+				combat = { dam=resolvers.levelup(resolvers.mbonus(40, 15), 1, 1.2), atk=15, apr=15, dammod={wil=resolvers.levelup(0.2, 5, 0.2, 0.8)}, damtype=DamageType.TEMPORAL },
 				on_melee_hit = { [DamageType.TEMPORAL] = resolvers.mbonus(20, 10), },
 
 				infravision = 10,
diff --git a/game/modules/tome/data/talents/misc/inscriptions.lua b/game/modules/tome/data/talents/misc/inscriptions.lua
index 3ec8d32290..63ff771ffa 100644
--- a/game/modules/tome/data/talents/misc/inscriptions.lua
+++ b/game/modules/tome/data/talents/misc/inscriptions.lua
@@ -729,7 +729,7 @@ newInscription{
 
 		local hit = self:checkHit(self:combatSpellpower(), target:combatSpellResist() + (target:attr("continuum_destabilization") or 0))
 		if not hit then game.logSeen(target, "%s resists!", target.name:capitalize()) return true end
-		
+
 		target:setEffect(target.EFF_CONTINUUM_DESTABILIZATION, 100, {power=self:combatSpellpower(0.3)})
 		self:project(tg, x, y, DamageType.TEMPORAL, self:spellCrit(t.getDamage(self, t)))
 		game.level.map:particleEmitter(x, y, 1, "temporal_thrust")
@@ -737,7 +737,7 @@ newInscription{
 
 		-- End it here if we've killed the target or the target is a player
 		if target.dead or target.player then return true end
-		
+
 		-- set up instability
 		local summoner = self
 		-- Store the current terrain
@@ -768,7 +768,7 @@ newInscription{
 			summoner_gain_exp = true,
 			summoner = summoner,
 		}
-		
+
 		-- Mixin the old terrain
 		table.update(temporal_instability, terrain)
 		-- Now update the display overlay
@@ -782,7 +782,7 @@ newInscription{
 		else
 			table.append(temporal_instability.add_displays, overlay)
 		end
-		
+
 		game.logSeen(target, "%s has moved forward in time!", target.name:capitalize())
 		game.level:removeEntity(target)
 		game.level:addEntity(temporal_instability)
diff --git a/game/modules/tome/data/talents/misc/item.lua b/game/modules/tome/data/talents/misc/item.lua
new file mode 100644
index 0000000000..713f48dae3
--- /dev/null
+++ b/game/modules/tome/data/talents/misc/item.lua
@@ -0,0 +1,491 @@
+-- ToME - Tales of Maj'Eyal
+-- Copyright (C) 2009, 2010, 2011 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
+
+newTalent{
+	name = "Command Staff",
+	type = {"misc/item", 1},
+	cooldown = function(self, t)
+		--return math.max(30 - 5 * self:getTalentLevel(t), 5)
+		return 5
+	end,
+	points = 5,
+	--hard_cap = 5,
+	no_npc_use = true,
+	--[=[
+	en_fct = function(self, t)
+		if self:getTalentLevel(t) > 5 then 
+			print("instant?")
+			return "instant"
+		else
+			print("not instant?")
+			return "1 turn"
+		end
+	end,
+]=]
+	action = function(self, t)
+		local staff = self:hasStaffWeapon()
+		if not staff then
+			game.logPlayer(self, "You must be holding a staff.")
+			return
+		end
+		local state = {}
+		local Chat = require("engine.Chat")
+		local chat = Chat.new("command-staff", {name="Command Staff"}, self, {version=staff, state=state, co=coroutine.running()})
+		local d = chat:invoke()
+		if not coroutine.yield() then return nil end
+		return true		
+	end,
+	info = function(self, t)
+		--return ([[Alter the flow of energies through a staff. The effect is instantaneous at extremely high talent levels.]])
+		return ([[Alter the flow of energies through a staff.]])
+	end,
+}
+
+newTalent{
+	name = "Reload",
+	type = {"misc/item", 1},
+	cooldown = 0,
+	points = 5,
+	hard_cap = 5,
+	tactical = { AMMO = 2 },
+	on_pre_use = function(self, t, silent) if not self:hasAmmo() then if not silent then game.logPlayer(self, "You must have a quiver or pouch equipped.") end return false end return true end,
+	shots_per_turn = function(self, t)
+		local s =  self:getTalentFromId(self.T_BOW_MASTERY)
+		local add = s.getReloadBoost(self, s)
+		return self:getTalentLevelRaw(t) + add
+	end,
+	action = function(self, t)
+		local q, err = self:hasAmmo()
+		if not q then 
+			game.logPlayer(self, "%s", err) 
+			return
+		end
+		if q.combat.shots_left == q.combat.capacity then
+			game.logPlayer(self, "Your %s is full.", q.name)
+			return
+		end
+		self:setEffect(self.EFF_RELOADING, q.combat.capacity, {ammo = q, shots_per_turn = t.shots_per_turn(self, t)})
+		return true
+	end,
+	info = function(self, t)
+		local spt = t.shots_per_turn(self, t)
+		return ([[Reload your quiver or shot pouch at the rate of %d shot%s per turn.]]):format(spt, (spt > 1 and "s") or "")
+	end,
+}
+
+newTalent{
+	name = "Savagery",
+	type = {"misc/item", 1},
+	points = 5,
+	hard_cap = 5,
+	mode = "passive",
+	getDuration = function(self, t)
+		return 2 * self:getTalentLevel(t) + 3
+	end,
+	getPower = function(self, t)
+		return 0.5
+	end,
+	do_savagery = function(self, t)
+		self:setEffect(self.EFF_SAVAGERY, t.getDuration(self, t), {power = t.getPower(self, t)})
+	end,
+	info = function(self, t)
+		return ([[Whenever you land a critical strike, you gain a stacking bonus of %d to your critical power multiplier, up to a maximum bonus of 1.5. The buff lasts for %d turns.]]):format(t.getPower(self, t), t.getDuration(self, t))
+	end,
+}
+
+newTalent{
+	name = "Ward",
+	type = {"misc/item", 1},
+	cooldown = function(self, t)
+		return 45 - 5 * self:getTalentLevel(t)
+	end,
+	points = 5,
+	hard_cap = 5,
+	no_npc_use = true,
+	action = function(self, t)
+		local state = {}
+		local Chat = require("engine.Chat")
+		local chat = Chat.new("ward", {name="Ward"}, self, {version=self, state=state})
+		local d = chat:invoke()
+		local co = coroutine.running()
+		--print("before d.unload, state.set_ward is ", state.set_ward)
+		d.unload = function() coroutine.resume(co, state.set_ward) end
+		--print("state.set_ward is ", state.set_ward)
+		if not coroutine.yield() then return nil end
+		return true
+	end,
+	info = function(self, t)
+		return ([[Bring a damage-type-specific ward into being. The ward will fully negate as many attacks of its element as it has charges.]])
+	end,
+}
+
+
+newTalent{
+	name = "Bloodflow",
+	type = {"misc/item", 1},
+	cooldown = function(self, t)
+		return 45 - 5 * self:getTalentLevel(t)
+	end,
+	points = 5,
+	hard_cap = 5,
+	no_npc_use = true,
+	tactical = { BUFF = 2 },
+	getTalentCount = function(self, t) return math.ceil(self:getTalentLevel(t) + 1) end,
+	getMaxLevel = function(self, t) return self:getTalentLevelRaw(t) end,
+	action = function(self, t)
+		local amount = self.life * 0.5
+		if self.life <= amount + 1 then
+			game.logPlayer(self, "Doing this would kill you.")
+			return
+		end
+		local tids = {}
+		for tid, _ in pairs(self.talents_cd) do
+			local tt = self:getTalentFromId(tid)
+			if tt.type[2] <= t.getMaxLevel(self, t) then
+				tids[#tids+1] = tid
+			end
+		end
+		for i = 1, t.getTalentCount(self, t) do
+			if #tids == 0 then break end
+			local tid = rng.tableRemove(tids)
+			self.talents_cd[tid] = nil
+		end
+		self.changed = true
+		game:playSoundNear(self, "talents/spell_generic")
+		self:takeHit(amount, self)
+		return true
+	end,
+	info = function(self, t)
+		local talentcount = t.getTalentCount(self, t)
+		local maxlevel = t.getMaxLevel(self, t)
+		return ([[Sacrifice half of your current health to reset the cooldown of %d talents of tier %d or less.]]):
+		format(talentcount, maxlevel)
+	end,
+}
+
+newTalent{
+	name = "Elemental Retribution",
+	type = {"misc/item", 1},
+	points = 5,
+	hard_cap = 5,
+	mode = "passive",
+	tactical = { BUFF = 1 },
+	getDuration = function(self, t)
+		return 2 * self:getTalentLevel(t) + 3
+	end,
+	getPower = function(self, t)
+		return self:getTalentLevel(t)*3
+	end,
+	getElementsString = function(self, t)
+		if not self.elemental_retribution then return "(error 1)" end
+		local ret_list = {}
+		local count = 1
+		for k, v in pairs(self.elemental_retribution) do
+			if v > 0 then 
+				ret_list[count] = k 
+				count = count + 1
+			end
+		end
+		local n = #ret_list
+		--print("just defined n as: ", n)
+		if n < 1 then return "(error 2)" end
+		local e_string = ""
+		if n == 1 then 
+			e_string = DamageType.dam_def[ret_list[1]].name
+			--print("1: e_string is ", e_string)
+		elseif n == 2 then
+			e_string = DamageType.dam_def[ret_list[1]].name.." or "..DamageType.dam_def[ret_list[2]].name
+			--print("2: e_string is ", e_string)
+		else
+			for i = 1, #ret_list-1 do 
+				e_string = e_string..DamageType.dam_def[ret_list[i]].name..", "
+				--print("3+: e_string is ", e_string)
+			end
+			e_string = e_string.."or "..DamageType.dam_def[ret_list[n]].name
+		end
+		return e_string
+	end,
+	do_retribution = function(self, t)
+		self:setEffect(self.EFF_ELEMENTAL_RETRIBUTION, t.getDuration(self, t), {power = t.getPower(self, t), e_string = t.getElementsString(self, t), maximum = t.getPower(self, t)*3})
+	end,
+	info = function(self, t)
+		return ([[Whenever you suffer %s damage, you gain a stacking bonus of %d to spellpower up to a maximum of %d. The buff lasts for %d turns.]]):format(t.getElementsString(self, t), t.getPower(self, t), t.getPower(self, t)*3, t.getDuration(self, t))
+	end,
+}
+
+newTalent{
+	name = "Soul Drain",
+	type = {"misc/item", 1},
+	points = 5,
+	hard_cap = 5,
+	cooldown = function(self, t)
+		return math.max(6, math.ceil(25 - self:getTalentLevelRaw(t)*3))
+	end,
+	tactical = { DEFEND = 2, ATTACKAREA = 2, DISABLE = 1 },
+	direct_hit = true,
+	range = 0,
+	radius = function(self, t)
+		return 2 + math.ceil(self:getTalentLevel(t)/2)
+	end,
+	target = function(self, t)
+		return {type="ball", range=self:getTalentRange(t), radius=self:getTalentRadius(t), selffire=false, talent=t}
+	end,
+	getLeech = function(self, t)
+		--return self:combatStatTalentIntervalDamage(t, "combatMindpower", 6, 30)
+		return 3
+	end,
+	getDam = function(self, t)
+		return self:spellCrit(self:combatTalentSpellDamage(t, 28, 270))
+	end,
+	action = function(self, t)
+		local leech = t.getLeech(self, t)
+		local dam = t.getDam(self, t)
+		local tg = self:getTalentTarget(t)
+		self:project(tg, self.x, self.y, function(tx, ty)
+			local act = game.level.map(tx, ty, engine.Map.ACTOR)
+			if act then
+				self:incMana(leech)
+				self:incVim(leech * 0.5)
+				self:incPositive(leech * 0.25)
+				self:incNegative(leech * 0.25)
+				self:incEquilibrium(-leech * 0.35)
+				self:incStamina(leech * 0.65)
+				self:incHate(leech * 0.05)
+				self:incPsi(leech * 0.2)
+			end
+			DamageType:get(DamageType.SOUL_DRAIN).projector(self, tx, ty, DamageType.SOUL_DRAIN, dam)
+		end)
+		-- Lightning ball gets a special treatment to make it look neat
+		local sradius = (tg.radius + 0.5) * (engine.Map.tile_w + engine.Map.tile_h) / 2
+		local nb_forks = 16
+		local angle_diff = 360 / nb_forks
+		for i = 0, nb_forks - 1 do
+			local a = math.rad(rng.range(0+i*angle_diff,angle_diff+i*angle_diff))
+			local tx = self.x + math.floor(math.cos(a) * tg.radius)
+			local ty = self.y + math.floor(math.sin(a) * tg.radius)
+			game.level.map:particleEmitter(x, y, tg.radius, "lightning", {radius=tg.radius, grids=grids, tx=tx-self.x, ty=ty-self.y, nb_particles=25, life=8})
+		end
+
+		game:playSoundNear(self, "talents/lightning")
+		return true
+	end,
+	info = function(self, t)
+		local range = self:getTalentRadius(t)
+		local en = t.getLeech(self, t)
+		local dam = damDesc(self, DamageType.BLIGHT, t.getDam(self, t))
+		return ([[You tear at the very soul of every target around you in a radius of %d. Deals %d blight damage. Reduces the mana, vim, positive enerty, negative energy, stamina, hate, and psi of each target by 50%%. Increases their equilibrium by 50%%. Provides a small boost to all of your resources.]]):format(range, dam)
+	end,
+}
+
+newTalent{
+	name = "Fearscape Fog",
+	type = {"misc/item", 1},
+	points = 5,
+	cooldown = 20,
+	tactical = {
+		ATTACK = 10,
+	},
+	range = 0,
+	radius = function(self, t)
+		return 2 + self:getTalentLevelRaw(t)
+	end,
+	direct_hit = true,
+	tactical = { DISABLE = 3 },
+	--requires_target = true,
+	target = function(self, t)
+		return {type="ball", range=self:getTalentRange(t), radius=self:getTalentRadius(t), talent=t}
+	end,
+	action = function(self, t)
+		local tg = self:getTalentTarget(t)
+		--local x, y = self:getTarget(tg)
+		--if not x or not y then return nil end
+		self:project(tg, self.x, self.y, function(px, py)
+			local g = engine.Entity.new{name="darkness", show_tooltip=true, block_sight=true, always_remember=false, unlit=self:getTalentLevel(t) * 10}
+			game.level.map(px, py, Map.TERRAIN+1, g)
+			game.level.map.remembers(px, py, false)
+			game.level.map.lites(px, py, false)
+		end, nil, {type="dark"})
+		game:playSoundNear(self, "talents/breath")
+		return true
+	end,
+	info = function(self, t)
+		return ([[Call forth the dread mists of the Fearscape, blocking all but the most powerful light in a radius of %d.]]):format(self:getTalentRadius(t))
+	end,
+}
+
+newTalent{
+	name = "Perception",
+	type = {"misc/item", 1},
+	points = 5,
+	tactical = { BUFF = 2 },
+	cooldown = 30,
+	getSeeInvisible = function(self, t) return self:combatTalentSpellDamage(t, 10, 45) end,
+	getSeeStealth = function(self, t) return self:combatTalentSpellDamage(t, 10, 20) end,
+	getCriticalPower = function(self, t) return 0.3 + self:getTalentLevel(t) * 0.1 end,
+	action = function(self, t)
+		self:setEffect(self.EFF_PERCEPTION, 5, {si=t.getSeeInvisible(self, t), ss=t.getSeeStealth(self, t), crit=t.getCriticalPower(self, t)})
+		game:playSoundNear(self, "talents/spell_generic")
+		return true
+	end,
+	info = function(self, t)
+		local seeinvisible = t.getSeeInvisible(self, t)
+		local seestealth = t.getSeeStealth(self, t)
+		local criticalpower = t.getCriticalPower(self, t)
+		return ([[You sharpen your senses to supernatural acuity.
+		See invisible: +%d
+		See through stealth: +%d
+		Critical power: +%.1f
+		The effects will improve with your Spellpower.]]):
+		format(seeinvisible, seestealth, criticalpower)
+	end,
+}
+
+newTalent{
+	name = "Lifebind",
+	type = {"misc/item", 1},
+	points = 5,
+	cooldown = 50,
+	tactical = { ATTACK = 2 },
+	range = function(self, t)
+		return self:getTalentLevel(t)
+	end,
+	direct_hit = true,
+	requires_target = true,
+	target = function(self, t)
+		return {type="hit", range=self:getTalentRange(t), talent=t}
+	end,
+	getDamage = function(self, t) return  end,
+	action = function(self, t)
+		local tg = self:getTalentTarget(t)
+		local x, y, target = self:getTarget(tg)
+		if not x or not y then return nil end
+		game:playSoundNear(self, "talents/arcane")
+		
+		-- Try to insta-kill
+		if target then
+			if target:checkHit(self:combatSpellpower(), target:combatPhysicalResist(), 0, self:getMaxAccuracy("spell"), 15) and target:canBe("instakill") and target.life > 0 then
+				local t_percent = target.life / target.max_life
+				local s_percent = self.life / self.max_life
+				target.life = target.max_life * s_percent
+				self.life = self.max_life * t_percent
+				game.level.map:particleEmitter(x, y, 1, "entropythrust")
+				game.level.map:particleEmitter(self.x, self.y, 1, "entropythrust")
+			else
+				game.logSeen(target, "%s resists the lifebind!", target.name:capitalize())
+			end
+		end
+		
+		return true
+	end,
+	info = function(self, t)
+		local damage = t.getDamage(self, t)
+		return ([[Attempts to swap your life force for that of the target. If the swap is successful, your health percentage will be set at the target's health percentage, and vice versa. Enemies that are immune to instakill effects will resist this. The range increases with talent level.]])
+	end,
+}
+
+newTalent{
+	name = "Block",
+	type = {"misc/item", 1},
+	cooldown = function(self, t)
+		return 8 - self:getTalentLevelRaw(t)
+	end,
+	points = 5,
+	hard_cap = 5,
+	on_pre_use = function(self, t, silent) if not self:hasShield() then if not silent then game.logPlayer(self, "You require a weapon and a shield to use this talent.") end return false end return true end,
+	getProperties = function(self, t)
+		local shield = self:hasShield()
+		--if not shield then return nil end
+		local p = {
+			sp = (shield and shield.special_combat and shield.special_combat.spellplated or false),
+			ref = (shield and shield.special_combat and shield.special_combat.reflective or false),
+			br = (shield and shield.special_combat and shield.special_combat.bloodruned or false),
+		}
+		return p
+	end,
+	getBlockValue = function(self, t)
+		local shield = self:hasShield()
+		if not shield then return 0 end
+		return (shield.special_combat and shield.special_combat.block) or 0
+	end,
+	getBlockedTypes = function(self, t)
+		local shield = self:hasShield()
+		local bt = {DamageType.PHYSICAL}
+		if not shield then return bt, "error!" end
+		local count = 2
+		if shield.wielder.resists then 
+			for res, v in pairs(shield.wielder.resists) do
+				if v > 0 then 
+					bt[count] = res
+					count = count + 1
+				end
+			end
+		end
+		if shield.wielder.on_melee_hit then 
+			for res, v in pairs(shield.wielder.on_melee_hit) do
+				if v > 0 then
+					local add = true
+					for i = 1, #bt do
+						if bt[i] == res then add = false end 
+					end
+					if add then 
+						bt[count] = res
+						count = count + 1
+					end
+				end
+			end
+		end
+		local n = #bt
+		if n < 1 then return "(error 2)" end
+		local e_string = ""
+		if n == 1 then 
+			e_string = DamageType.dam_def[bt[1]].name
+		elseif n == 2 then
+			e_string = DamageType.dam_def[bt[1]].name.." and "..DamageType.dam_def[bt[2]].name
+		else
+			for i = 1, #bt-1 do 
+				e_string = e_string..DamageType.dam_def[bt[i]].name..", "
+			end
+			e_string = e_string.."and "..DamageType.dam_def[bt[n]].name
+		end
+		return bt, e_string
+	end,
+	action = function(self, t)
+		local properties = t.getProperties(self, t)
+		local bt, bt_string = t.getBlockedTypes(self, t)
+		self:setEffect(self.EFF_BLOCKING, 1, {power = t.getBlockValue(self, t), d_types=bt, properties=properties})
+		return true
+	end,
+	info = function(self, t)
+		local properties = t.getProperties(self, t)
+		local sp_text = ""
+		local ref_text = ""
+		local br_text = ""
+		if properties.sp then
+			sp_text = (" Increases your spell save by %d for that turn."):format(t.getBlockValue(self, t))
+		end
+		if properties.ref then
+			ref_text = " Reflects all blocked damage back to the source."
+		end
+		if properties.br then
+			br_text = " All blocked damage heals the wielder."
+		end
+		local bt, bt_string = t.getBlockedTypes(self, t)
+		return ([[Raise your shield into blocking position for one turn, reducing the damage of all %s attacks by %d. If you block all of an attack's damage, the attacker will be vulnerable to a deadly counterstrike for one turn.%s%s%s]]):format(bt_string, t.getBlockValue(self, t), sp_text, ref_text, br_text)
+	end,
+}
diff --git a/game/modules/tome/data/talents/misc/misc.lua b/game/modules/tome/data/talents/misc/misc.lua
index e7ea5e0d6e..dfe1f32aea 100644
--- a/game/modules/tome/data/talents/misc/misc.lua
+++ b/game/modules/tome/data/talents/misc/misc.lua
@@ -23,6 +23,7 @@ newTalentType{ type="base/race", name = "race", hide = true, description = "The
 newTalentType{ type="inscriptions/infusions", name = "infusions", hide = true, description = "Infusions are not class abilities, you must find them or learn them from other people." }
 newTalentType{ is_spell=true, no_silence=true, type="inscriptions/runes", name = "runes", hide = true, description = "Runes are not class abilities, you must find them or learn them from other people." }
 newTalentType{ is_spell=true, no_silence=true, type="inscriptions/taints", name = "taints", hide = true, description = "Taints are not class abilities, you must find them or learn them from other people." }
+newTalentType{ type="misc/item", name = "item", hide = true, description = "Talents granted only by special items." }
 
 -- Load other misc things
 load("/data/talents/misc/inscriptions.lua")
@@ -30,6 +31,7 @@ load("/data/talents/misc/npcs.lua")
 load("/data/talents/misc/horrors.lua")
 load("/data/talents/misc/races.lua")
 load("/data/talents/misc/tutorial.lua")
+load("/data/talents/misc/item.lua")
 
 -- Default melee attack
 newTalent{
@@ -312,3 +314,4 @@ newTalent{
 		format(physical_reduction, spell_reduction, mental_reduction)
 	end,
 }
+
diff --git a/game/modules/tome/data/talents/misc/races.lua b/game/modules/tome/data/talents/misc/races.lua
index b7c1fc0a58..6f7d60d509 100644
--- a/game/modules/tome/data/talents/misc/races.lua
+++ b/game/modules/tome/data/talents/misc/races.lua
@@ -368,7 +368,7 @@ newTalent{
 				autolevel = "none",
 				ai = "summoned", ai_real = "tactical", ai_state = { talent_in=2, },
 				stats = {str=0, dex=0, con=0, cun=0, wil=0, mag=0},
-				combat = { dam=resolvers.levelup(resolvers.rngavg(15,25), 1, 1.3), atk=resolvers.levelup(resolvers.rngavg(15,25), 1, 1.3), dammod={str=1.1} },
+				combat = { dam=resolvers.levelup(resolvers.rngavg(15,25), 1, 1.3), atk=resolvers.levelup(resolvers.rngavg(15,25), 1, 1.3), dammod={str=resolvers.levelup(0.2, 5, 0.2, 1.1)} },
 				inc_stats = { str=25 + self:getWil() * self:getTalentLevel(t) / 5, dex=18, con=10 + self:getTalentLevel(t) * 2, },
 
 				level_range = {1, nil}, exp_worth = 0,
diff --git a/game/modules/tome/data/talents/psionic/other.lua b/game/modules/tome/data/talents/psionic/other.lua
index faadffdc9e..2def4b53d9 100644
--- a/game/modules/tome/data/talents/psionic/other.lua
+++ b/game/modules/tome/data/talents/psionic/other.lua
@@ -169,21 +169,22 @@ newTalent{
 		end
 		if o.type == "weapon" then
 			self.use_psi_combat = true
-			atk = self:combatAttack(o.combat)
 			dam = self:combatDamage(o.combat)
+			critical_power = o.combat.critical_power
+			max_acc = o.combat.max_acc
 			apr = self:combatAPR(o.combat)
 			crit = self:combatCrit(o.combat)
-			speed = self:combatSpeed(o.combat)
 			self.use_psi_combat = false
 		end
 		return ([[Allows you to wield a weapon telekinetically, directing it with your willpower and cunning rather than crude flesh. When activated, the telekinetically-wielded weapon will attack a random melee-range target each turn.
 		The telekinetically-wielded weapon uses Willpower in place of Strength and Cunning in place of Dexterity to determine attack and damage.
-		Combat stats:
-		Accuracy: %d
-		Damage: %d
-		APR: %d
-		Crit: %0.2f
-		Speed: %0.2f]]):
-		format(atk, dam, apr, crit, speed)
+		Combat attributes:
+		
+		#LIGHT_GREEN#Damage:#WHITE#          %d
+		#LIGHT_GREEN#Crit multiplier:#WHITE# %.1fx
+		#LIGHT_GREEN#Max accuracy:#WHITE#    %d%%
+		#LIGHT_GREEN#APR:#WHITE#             %d
+		#LIGHT_GREEN#Crit chance:#WHITE#     %0.2f]]):
+		format(dam, critical_power, max_acc, apr, crit)
 	end,
 }
diff --git a/game/modules/tome/data/talents/spells/advanced-necrotic-minions.lua b/game/modules/tome/data/talents/spells/advanced-necrotic-minions.lua
index 071434fd8e..bc71e032f9 100644
--- a/game/modules/tome/data/talents/spells/advanced-necrotic-minions.lua
+++ b/game/modules/tome/data/talents/spells/advanced-necrotic-minions.lua
@@ -22,7 +22,7 @@ local minions_list = {
 		type = "undead", subtype = "giant",
 		blood_color = colors.GREY,
 		display = "K",
-		combat = { dam=resolvers.levelup(resolvers.mbonus(45, 20), 1, 1), atk=15, apr=10, dammod={str=0.8} },
+		combat = { dam=resolvers.levelup(resolvers.mbonus(45, 20), 1, 1), atk=15, apr=10, dammod={str=resolvers.levelup(0.2, 5, 0.2, 0.8)} },
 		body = { INVEN = 10, MAINHAND=1, OFFHAND=1, BODY=1 },
 		infravision = 10,
 		life_rating = 12,
@@ -56,7 +56,7 @@ local minions_list = {
 		type = "undead", subtype = "giant",
 		blood_color = colors.GREY,
 		display = "K",
-		combat = { dam=resolvers.levelup(resolvers.mbonus(45, 20), 1, 1), atk=15, apr=10, dammod={str=0.8} },
+		combat = { dam=resolvers.levelup(resolvers.mbonus(45, 20), 1, 1), atk=15, apr=10, dammod={str=resolvers.levelup(0.2, 5, 0.2, 0.8)} },
 		body = { INVEN = 10, MAINHAND=1, OFFHAND=1, BODY=1 },
 		infravision = 10,
 		life_rating = 12,
@@ -90,7 +90,7 @@ local minions_list = {
 		type = "undead", subtype = "giant",
 		blood_color = colors.GREY,
 		display = "K",
-		combat = { dam=resolvers.levelup(resolvers.mbonus(45, 20), 1, 1), atk=15, apr=10, dammod={str=0.8} },
+		combat = { dam=resolvers.levelup(resolvers.mbonus(45, 20), 1, 1), atk=15, apr=10, dammod={str=resolvers.levelup(0.2, 5, 0.2, 0.8)} },
 		body = { INVEN = 10, MAINHAND=1, OFFHAND=1, BODY=1 },
 		infravision = 10,
 		life_rating = 12,
@@ -126,7 +126,7 @@ local minions_list = {
 		type = "undead", subtype = "giant",
 		blood_color = colors.GREY,
 		display = "K",
-		combat = { dam=resolvers.levelup(resolvers.mbonus(45, 20), 1, 1), atk=15, apr=10, dammod={str=0.8} },
+		combat = { dam=resolvers.levelup(resolvers.mbonus(45, 20), 1, 1), atk=15, apr=10, dammod={str=resolvers.levelup(0.2, 5, 0.2, 0.8)} },
 		body = { INVEN = 10, MAINHAND=1, OFFHAND=1, BODY=1 },
 		infravision = 10,
 		life_rating = 12,
diff --git a/game/modules/tome/data/talents/spells/conveyance.lua b/game/modules/tome/data/talents/spells/conveyance.lua
index 0033308cf9..f62502d420 100644
--- a/game/modules/tome/data/talents/spells/conveyance.lua
+++ b/game/modules/tome/data/talents/spells/conveyance.lua
@@ -44,7 +44,7 @@ newTalent{
 			end
 		end
 		if target ~= self and target:canBe("teleport") then
-			local hit = self:checkHit(self:combatSpellpower(), target:combatSpellResist() + (target:attr("continuum_destabilization") or 0))
+			local hit = self:checkHit(self:combatSpellpower(), target:combatSpellResist() + (target:attr("continuum_destabilization") or 0), 0, self:getMaxAccuracy("spell"))
 			if not hit then
 				game.logSeen(target, "The spell fizzles!")
 				return true
@@ -125,7 +125,7 @@ newTalent{
 		end
 
 		if target ~= self and target:canBe("teleport") then
-			local hit = self:checkHit(self:combatSpellpower(), target:combatSpellResist() + (target:attr("continuum_destabilization") or 0))
+			local hit = self:checkHit(self:combatSpellpower(), target:combatSpellResist() + (target:attr("continuum_destabilization") or 0), 0, self:getMaxAccuracy("spell"))
 			if not hit then
 				game.logSeen(target, "The spell fizzles!")
 				return true
diff --git a/game/modules/tome/data/talents/spells/golemancy.lua b/game/modules/tome/data/talents/spells/golemancy.lua
index cede45bc1d..81e79d00ff 100644
--- a/game/modules/tome/data/talents/spells/golemancy.lua
+++ b/game/modules/tome/data/talents/spells/golemancy.lua
@@ -38,7 +38,7 @@ local function makeGolem()
 		never_anger = true,
 		save_hotkeys = true,
 
-		combat = { dam=10, atk=10, apr=0, dammod={str=1} },
+		combat = { dam=10, atk=10, apr=0, dammod={str=resolvers.levelup(0.1, 5, 0.2, 1)} },
 
 		body = { INVEN = 1000, QS_MAINHAND = 1, QS_OFFHAND = 1, MAINHAND = 1, OFFHAND = 1, BODY=1, GEM=2 },
 		equipdoll = "alchemist_golem",
diff --git a/game/modules/tome/data/talents/spells/necrotic-minions.lua b/game/modules/tome/data/talents/spells/necrotic-minions.lua
index 1811bf67a4..ce9f1bef22 100644
--- a/game/modules/tome/data/talents/spells/necrotic-minions.lua
+++ b/game/modules/tome/data/talents/spells/necrotic-minions.lua
@@ -316,7 +316,7 @@ local minions_list = {
 			T_ROTTING_DISEASE={base=1, every=10, max=5},
 		},
 		ai_state = { talent_in=4, },
-		combat = { dam=resolvers.levelup(10, 1, 1), atk=resolvers.levelup(5, 1, 1), apr=3, dammod={str=0.6} },
+		combat = { dam=resolvers.levelup(10, 1, 1), atk=resolvers.levelup(5, 1, 1), apr=3, dammod={str=resolvers.levelup(0.1, 5, 0.1, 0.6)} },
 	},
 	ghast = {
 		type = "undead", subtype = "ghoul",
@@ -344,7 +344,7 @@ local minions_list = {
 			T_ROTTING_DISEASE={base=1, every=10, max=5},
 		},
 		ai_state = { talent_in=4, },
-		combat = { dam=resolvers.levelup(10, 1, 1), atk=resolvers.levelup(5, 1, 1), apr=3, dammod={str=0.6} },
+		combat = { dam=resolvers.levelup(10, 1, 1), atk=resolvers.levelup(5, 1, 1), apr=3, dammod={str=resolvers.levelup(0.1, 5, 0.1, 0.6)} },
 	},
 	ghoulking = {
 		type = "undead", subtype = "ghoul",
@@ -368,7 +368,7 @@ local minions_list = {
 		combat_armor = 3, combat_def = 10,
 		ai_state = { talent_in=2, ai_pause=20 },
 		rank = 3,
-		combat = { dam=resolvers.levelup(30, 1, 1.2), atk=resolvers.levelup(8, 1, 1), apr=4, dammod={str=0.6} },
+		combat = { dam=resolvers.levelup(30, 1, 1.2), atk=resolvers.levelup(8, 1, 1), apr=4, dammod={str=resolvers.levelup(0.1, 5, 0.1, 0.6)} },
 		resolvers.talents{
 			T_STUN={base=3, every=9, max=7},
 			T_BITE_POISON={base=3, every=9, max=7},
@@ -382,7 +382,7 @@ local minions_list = {
 	vampire = {
 		type = "undead", subtype = "vampire",
 		display = "V",
-		combat = { dam=resolvers.levelup(resolvers.mbonus(30, 10), 1, 0.8), atk=10, apr=9, damtype=DamageType.DRAINLIFE, dammod={str=1.9} },
+		combat = { dam=resolvers.levelup(resolvers.mbonus(30, 10), 1, 0.8), atk=10, apr=9, damtype=DamageType.DRAINLIFE, dammod={str=resolvers.levelup(0.3, 5, 0.2, 1.9)} },
 		level_range = {1, nil}, exp_worth = 0,
 		body = { INVEN = 10, MAINHAND=1, OFFHAND=1, BODY=1 },
 		autolevel = "warriormage",
@@ -409,7 +409,7 @@ local minions_list = {
 	m_vampire = {
 		type = "undead", subtype = "vampire",
 		display = "V",
-		combat = { dam=resolvers.levelup(resolvers.mbonus(30, 10), 1, 0.8), atk=10, apr=9, damtype=DamageType.DRAINLIFE, dammod={str=1.9} },
+		combat = { dam=resolvers.levelup(resolvers.mbonus(30, 10), 1, 0.8), atk=10, apr=9, damtype=DamageType.DRAINLIFE, dammod={str=resolvers.levelup(0.3, 5, 0.2, 1.9)} },
 		level_range = {1, nil}, exp_worth = 0,
 		body = { INVEN = 10, MAINHAND=1, OFFHAND=1, BODY=1 },
 		autolevel = "warriormage",
@@ -522,7 +522,7 @@ local minions_list = {
 		combat_armor = 0, combat_def = resolvers.mbonus(10, 50),
 		invisibility = resolvers.mbonus(5, 10),
 		ai_state = { talent_in=4, },
-		combat = { dam=resolvers.mbonus(45, 45), atk=resolvers.mbonus(25, 45), apr=100, dammod={str=0.5, mag=0.5} },
+		combat = { dam=resolvers.mbonus(45, 45), atk=resolvers.mbonus(25, 45), apr=100, dammod={str=resolvers.levelup(0.1, 5, 0.1, 0.5), mag=resolvers.levelup(0.1, 5, 0.1, 0.5)} },
 		resolvers.talents{
 			T_BURNING_HEX={base=3, every=5, max=7},
 			T_BLUR_SIGHT={base=4, every=6, max=8},
@@ -532,7 +532,7 @@ local minions_list = {
 		type = "undead", subtype = "lich",
 		display = "L",
 		rank = 3, size = 3,
-		combat = { dam=resolvers.rngavg(16,27), atk=16, apr=9, damtype=DamageType.DARKSTUN, dammod={mag=0.9} },
+		combat = { dam=resolvers.rngavg(16,27), atk=16, apr=9, damtype=DamageType.DARKSTUN, dammod={mag=resolvers.levelup(0.2, 5, 0.2, 0.9)} },
 		body = { INVEN = 10, MAINHAND = 1, OFFHAND = 1, FINGER = 2, NECK = 1, LITE = 1, BODY = 1, HEAD = 1, CLOAK = 1, HANDS = 1, BELT = 1, FEET = 1},
 		equipment = resolvers.equip{
 			{type="armor", subtype="cloth", ego_chance=75, autoreq=true},
diff --git a/game/modules/tome/data/talents/spells/staff-combat.lua b/game/modules/tome/data/talents/spells/staff-combat.lua
index 29e0b42e6d..5b64858ebd 100644
--- a/game/modules/tome/data/talents/spells/staff-combat.lua
+++ b/game/modules/tome/data/talents/spells/staff-combat.lua
@@ -72,6 +72,7 @@ newTalent{
 		elseif damtype == DamageType.NATURE then    explosion = "slime"               particle = "bolt_slime"     trail = "slimetrail"
 		elseif damtype == DamageType.BLIGHT then    explosion = "slime"               particle = "bolt_slime"     trail = "slimetrail"
 		elseif damtype == DamageType.PHYSICAL then  explosion = "dark"                particle = "stone_shards"   trail = "earthtrail"
+		elseif damtype == DamageType.TEMPORAL then  explosion = "manathrust"          particle = "bolt_arcane"    trail = "arcanetrail"
 		else                                        explosion = "manathrust"          particle = "bolt_arcane"    trail = "arcanetrail" damtype = DamageType.ARCANE
 		end
 
@@ -106,13 +107,13 @@ newTalent{
 	mode = "passive",
 	require = spells_req2,
 	points = 5,
-	getDamage = function(self, t) return self:getTalentLevel(t) * 5 end,
-	getPercentInc = function(self, t) return math.sqrt(self:getTalentLevel(t) / 10) / 2 end,
+	getDamage = function(self, t) return math.floor(t.getPercentInc(self, t) * self:combatSpellpower()) end,
+	getPercentInc = function(self, t) return self:getTalentLevel(t) / 10 end,
 	info = function(self, t)
 		local damage = t.getDamage(self, t)
 		local inc = t.getPercentInc(self, t)
-		return ([[Increases Physical Power by %d. Also increases damage done with staves by %d%%.]]):
-		format(damage, 100 * inc)
+		return ([[Increases damage done with staves by %d%% of your spellpower (%d).]]):
+		format(100*inc, damage)
 	end,
 }
 
diff --git a/game/modules/tome/data/talents/techniques/2hweapon.lua b/game/modules/tome/data/talents/techniques/2hweapon.lua
index 0d7468aa18..04a3075db0 100644
--- a/game/modules/tome/data/talents/techniques/2hweapon.lua
+++ b/game/modules/tome/data/talents/techniques/2hweapon.lua
@@ -185,7 +185,7 @@ newTalent{
 
 		-- Try to insta-kill
 		if hit then
-			if target:checkHit(self:combatPhysicalpower(), target:combatPhysicalResist(), 0, 95, 5 - self:getTalentLevel(t) / 2) and target:canBe("instakill") and target.life > 0 and target.life < target.max_life * 0.2 then
+			if target:checkHit(self:combatPhysicalpower(), target:combatPhysicalResist(), 0, self:getMaxAccuracy("physical", weapon.combat), 5 - self:getTalentLevel(t) / 2) and target:canBe("instakill") and target.life > 0 and target.life < target.max_life * 0.2 then
 				-- KILL IT !
 				game.logSeen(target, "%s feels the pain of the death blow!", target.name:capitalize())
 				target:die(self)
diff --git a/game/modules/tome/data/talents/techniques/archery.lua b/game/modules/tome/data/talents/techniques/archery.lua
index 51d21fc41a..ce2b02c1f7 100644
--- a/game/modules/tome/data/talents/techniques/archery.lua
+++ b/game/modules/tome/data/talents/techniques/archery.lua
@@ -31,6 +31,9 @@ newTalent{
 	tactical = { ATTACK = { weapon = 1 } },
 	on_pre_use = function(self, t, silent) if not self:hasArcheryWeapon() then if not silent then game.logPlayer(self, "You require a bow or sling for this talent.") end return false end return true end,
 	no_unlearn_last = true,
+	on_learn = function(self, t)
+		self:learnTalent(self.T_RELOAD, true, 1, {no_unlearn=true})
+	end,
 	use_psi_archery = function(self, t)
 		local inven = self:getInven("PSIONIC_FOCUS")
 		if not inven then return false end
diff --git a/game/modules/tome/data/talents/techniques/bow.lua b/game/modules/tome/data/talents/techniques/bow.lua
index 0ff857f388..7467c0af1d 100644
--- a/game/modules/tome/data/talents/techniques/bow.lua
+++ b/game/modules/tome/data/talents/techniques/bow.lua
@@ -23,13 +23,15 @@ newTalent{
 	points = 10,
 	require = { stat = { dex=function(level) return 12 + level * 3 end }, },
 	mode = "passive",
-	getDamage = function(self, t) return self:getTalentLevel(t) * 5 end,
-	getPercentInc = function(self, t) return math.sqrt(self:getTalentLevel(t) / 10) / 2 end,
+	getDamage = function(self, t) return math.floor(t.getPercentInc(self, t) * self:combatPhysicalpower()) end,
+	getPercentInc = function(self, t) return self:getTalentLevel(t) / 10 end,
+	getReloadBoost = function(self, t) return math.floor(self:getTalentLevel(t) / 5) end,
 	info = function(self, t)
-		local damage = t.getDamage(self, t)
 		local inc = t.getPercentInc(self, t)
-		return ([[Increases Physical Power by %d. Also increases damage done with bows by %d%%.]]):
-		format(damage, inc * 100)
+		local damage = t.getDamage(self, t)
+		local shots = t.getReloadBoost(self, t)
+		return ([[Increases damage done with bows by %d%% of your physical power (%d). Also increases the number of arrows you can reload per turn by %d.]]):
+		format(inc * 100, damage, shots)
 	end,
 }
 
diff --git a/game/modules/tome/data/talents/techniques/combat-training.lua b/game/modules/tome/data/talents/techniques/combat-training.lua
index c16b5985b2..73d6f082e9 100644
--- a/game/modules/tome/data/talents/techniques/combat-training.lua
+++ b/game/modules/tome/data/talents/techniques/combat-training.lua
@@ -100,15 +100,15 @@ newTalent{
 	name = "Weapons Mastery",
 	type = {"technique/combat-training", 1},
 	points = 10,
-	require = { stat = { str=function(level) return 12 + level * 3 end }, },
+	require = { stat = { str=function(level) return math.ceil(12 + level * 4.5) end }, },
 	mode = "passive",
-	getDamage = function(self, t) return self:getTalentLevel(t) * 5 end,
-	getPercentInc = function(self, t) return math.sqrt(self:getTalentLevel(t) / 10) / 2 end,
+	getDamage = function(self, t) return math.floor(t.getPercentInc(self, t) * self:combatPhysicalpower()) end,
+	getPercentInc = function(self, t) return self:getTalentLevel(t) / 10 end,
 	info = function(self, t)
 		local damage = t.getDamage(self, t)
 		local inc = t.getPercentInc(self, t)
-		return ([[Increases Physical Power by %d. Also increases damage done with swords, axes, maces by %d%%]]):
-		format(damage, 100*inc)
+		return ([[Increases damage done with swords, axes and maces by %d%% of your physical power (%d).]]):
+		format(100*inc, damage)
 	end,
 }
 
@@ -119,13 +119,13 @@ newTalent{
 	points = 10,
 	require = { stat = { dex=function(level) return 10 + level * 3 end }, },
 	mode = "passive",
-	getDamage = function(self, t) return self:getTalentLevel(t) * 5 end,
-	getPercentInc = function(self, t) return math.sqrt(self:getTalentLevel(t) / 10) / 2 end,
+	getDamage = function(self, t) return math.floor(t.getPercentInc(self, t) * self:combatPhysicalpower()) end,
+	getPercentInc = function(self, t) return self:getTalentLevel(t) / 20 end,
 	info = function(self, t)
 		local damage = t.getDamage(self, t)
 		local inc = t.getPercentInc(self, t)
-		return ([[Increases Physical Power by %d. Also increases damage done with knives by %d%%]]):
-		format(damage, 100*inc)
+		return ([[Increases damage done with knives by %d%% of your physical power (%d).]]):
+		format(100*inc, damage)
 	end,
 }
 
@@ -136,12 +136,12 @@ newTalent{
 	points = 10,
 	require = { stat = { str=function(level) return 10 + level * 3 end, dex=function(level) return 10 + level * 3 end }, },
 	mode = "passive",
-	getDamage = function(self, t) return self:getTalentLevel(t) * 5 end,
-	getPercentInc = function(self, t) return math.sqrt(self:getTalentLevel(t) / 10) / 2 end,
+	getDamage = function(self, t) return math.floor(t.getPercentInc(self, t) * self:combatPhysicalpower()) end,
+	getPercentInc = function(self, t) return self:getTalentLevel(t) / 10 end,
 	info = function(self, t)
 		local damage = t.getDamage(self, t)
 		local inc = t.getPercentInc(self, t)
-		return ([[Increases Physical Power by %d. Also increases damage done with exotic weapons by %d%%]]):
-		format(damage, 100*inc)
+		return ([[Increases damage done with exotic weapons by %d%% of your physical power (%d).]]):
+		format(100*inc, damage)
 	end,
 }
diff --git a/game/modules/tome/data/talents/techniques/finishing-moves.lua b/game/modules/tome/data/talents/techniques/finishing-moves.lua
index 8fa504d7b2..81d60a8fba 100644
--- a/game/modules/tome/data/talents/techniques/finishing-moves.lua
+++ b/game/modules/tome/data/talents/techniques/finishing-moves.lua
@@ -218,7 +218,7 @@ newTalent{
 
 		-- Try to insta-kill
 		if hit then
-			if target:checkHit(self:combatPhysicalpower(), target:combatPhysicalResist(), 0, 95, 5 - self:getTalentLevel(t) / 2) and target:canBe("instakill") and target.life > 0 and target.life < target.max_life * 0.2 then
+			if target:checkHit(self:combatPhysicalpower(), target:combatPhysicalResist(), 0, self:getMaxAccuracy("physical", self.combat), 5 - self:getTalentLevel(t) / 2) and target:canBe("instakill") and target.life > 0 and target.life < target.max_life * 0.2 then
 				-- KILL IT !
 				game.logSeen(target, "%s feels the pain of the death blow!", target.name:capitalize())
 				target:die(self)
diff --git a/game/modules/tome/data/talents/techniques/sling.lua b/game/modules/tome/data/talents/techniques/sling.lua
index 1063fe4c49..b1cf3b67da 100644
--- a/game/modules/tome/data/talents/techniques/sling.lua
+++ b/game/modules/tome/data/talents/techniques/sling.lua
@@ -23,13 +23,15 @@ newTalent{
 	points = 10,
 	require = { stat = { dex=function(level) return 12 + level * 3 end }, },
 	mode = "passive",
-	getDamage = function(self, t) return self:getTalentLevel(t) * 5 end,
-	getPercentInc = function(self, t) return math.sqrt(self:getTalentLevel(t) / 10) / 2 end,
+	getDamage = function(self, t) return math.floor(t.getPercentInc(self, t) * self:combatPhysicalpower()) end,
+	getPercentInc = function(self, t) return self:getTalentLevel(t) / 10 end,
+	getReloadBoost = function(self, t) return math.floor(self:getTalentLevel(t) / 5) end,
 	info = function(self, t)
 		local damage = t.getDamage(self, t)
 		local inc = t.getPercentInc(self, t)
-		return ([[Increases Physical Power by %d. Also increases damage done with slings by %d%%.]]):
-		format(damage, inc * 100)
+		local shots = t.getReloadBoost(self, t)
+		return ([[Increases damage done with slings by %d%% of your physical power (%d). Also increases the number of shots you can reload per turn by %d.]]):
+		format(inc * 100, damage, shots)
 	end,
 }
 
@@ -81,7 +83,8 @@ newTalent{
 	tactical = { ATTACK = { weapon = 2 }, DISABLE = { knockback = 2 }, ESCAPE = { knockback = 1 } },
 	on_pre_use = function(self, t, silent) if not self:hasArcheryWeapon("sling") then if not silent then game.logPlayer(self, "You require a sling for this talent.") end return false end return true end,
 	archery_onhit = function(self, t, target, x, y)
-		if target:checkHit(self:combatAttack(), target:combatPhysicalResist(), 0, 95, 15) and target:canBe("knockback") then
+		local w, a = self:hasArcheryWeapon("sling")
+		if target:checkHit(self:combatAttack(), target:combatPhysicalResist(), 0, self:getMaxAccuracy("physical", a.combat), 15) and target:canBe("knockback") then
 			target:knockback(self.x, self.y, 4)
 			target:crossTierEffect(target.EFF_OFFBALANCE, self:combatAttack())
 			game.logSeen(target, "%s is knocked back!", target.name:capitalize())
diff --git a/game/modules/tome/data/talents/techniques/unarmed-discipline.lua b/game/modules/tome/data/talents/techniques/unarmed-discipline.lua
index 599d97354f..24e557f59d 100644
--- a/game/modules/tome/data/talents/techniques/unarmed-discipline.lua
+++ b/game/modules/tome/data/talents/techniques/unarmed-discipline.lua
@@ -82,7 +82,7 @@ newTalent{
 	getDamage = function(self, t) return self:combatTalentPhysicalDamage(t, 5, 50) * getUnarmedTrainingBonus(self) end,
 	getDamageTwo = function(self, t) return self:combatTalentPhysicalDamage(t, 10, 75) * getUnarmedTrainingBonus(self) end,
 	do_throw = function(self, target, t)
-		local hit = self:checkHit(self:combatAttack(), target:combatDefense(), 0, 95, 5 - self:getTalentLevel(t) / 2)
+		local hit = self:checkHit(self:combatAttack(), target:combatDefense(), 0, self:getMaxAccuracy("physical", self.combat), 5 - self:getTalentLevel(t) / 2)
 		if hit then
 			self:project(target, target.x, target.y, DamageType.PHYSICAL, self:physicalCrit(t.getDamageTwo(self, t), nil, target, self:combatAttack(), target:combatDefense()))
 			-- if grappled stun
diff --git a/game/modules/tome/data/talents/techniques/weaponshield.lua b/game/modules/tome/data/talents/techniques/weaponshield.lua
index a84e1fe581..c676c5e350 100644
--- a/game/modules/tome/data/talents/techniques/weaponshield.lua
+++ b/game/modules/tome/data/talents/techniques/weaponshield.lua
@@ -72,8 +72,19 @@ newTalent{
 	require = techs_req2,
 	mode = "passive",
 	points = 5,
+	getDurInc = function(self, t)
+		return math.ceil(self:getTalentLevel(t)/4)
+	end,
+	getCritInc = function(self, t)
+		return self:combatTalentIntervalDamage(t, "dex", 10, 50)
+	end,
 	info = function(self, t)
-		return ([[When you block/avoid a melee blow you have a %d%% chance to get a free, automatic melee attack against your foe. Your chances increase with dexterity.]]):format(self:getTalentLevel(t) * (5 + self:getDex(5, true)))
+		local inc = t.getDurInc(self, t)
+		return ([[Improves your ability to perform counterstrikes after blocks in the following ways:
+		Allows counterstrikes after incomplete blocks. 
+		Increases the duration of the counterstrike debuff on attackers by %d turn%s.
+		Increases the number of counterstrikes you can perform on a target while they're vulnerable by %d.
+		Increases the crit chance of counterstrikes by %d%%. This increase scales with Dexterity.]]):format(inc, (inc > 1 and "s" or ""), inc, t.getCritInc(self, t))
 	end,
 }
 
@@ -109,7 +120,7 @@ newTalent{
 
 		-- Try to stun !
 		if hit then
-			if target:checkHit(self:combatAttack(shield.special_combat), target:combatPhysicalResist(), 0, 95, 5 - self:getTalentLevel(t) / 2) and target:canBe("knockback") then
+			if target:checkHit(self:combatAttack(shield.special_combat), target:combatPhysicalResist(), 0, self:getMaxAccuracy("physical", shield.special_combat), 5 - self:getTalentLevel(t) / 2) and target:canBe("knockback") then
 				target:knockback(self.x, self.y, 4)
 			else
 				game.logSeen(target, "%s resists the knockback!", target.name:capitalize())
diff --git a/game/modules/tome/data/timed_effects/magical.lua b/game/modules/tome/data/timed_effects/magical.lua
index 91385ab028..61fe7f805b 100644
--- a/game/modules/tome/data/timed_effects/magical.lua
+++ b/game/modules/tome/data/timed_effects/magical.lua
@@ -1601,3 +1601,85 @@ newEffect{
 		self:removeTemporaryValue("bloodcasting", eff.tmpid)
 	end,
 }
+
+
+newEffect{
+	name = "WARD", image = "talents/ward.png",
+	desc = "Ward",
+	long_desc = function(self, eff) return ("Fully absorbs %d %s attack%s."):format(#eff.particles, DamageType.dam_def[eff.d_type].name, #eff.particles > 1 and "s" or "") end,
+	type = "magical",
+	subtype = { acrane=true },
+	status = "beneficial",
+	parameters = { nb=3 },
+	on_gain = function(self, eff) return ("#Target# warded against %s!"):format(DamageType.dam_def[eff.d_type].name), "+Ward" end,
+	on_lose = function(self, eff) return ("#Target#'s %s ward fades"):format(DamageType.dam_def[eff.d_type].name), "-Ward" end,
+	absorb = function(type, dam, eff, self, src)
+		if eff.d_type ~= type then return dam end
+		game.logPlayer(self, "Your %s ward absorbs the damage!", DamageType.dam_def[eff.d_type].name)
+		local pid = table.remove(eff.particles)
+		if pid then self:removeParticles(pid) end
+		if #eff.particles <= 0 then
+			--eff.dur = 0
+			self:removeEffect(self.EFF_WARD)
+		end
+		return 0
+	end,
+	activate = function(self, eff)
+		local nb = eff.nb
+		local ps = {}
+		for i = 1, nb do ps[#ps+1] = self:addParticles(Particles.new("ward", 1, {color=DamageType.dam_def[eff.d_type].color})) end
+		eff.particles = ps
+	end,
+	deactivate = function(self, eff)
+		for i, particle in ipairs(eff.particles) do self:removeParticles(particle) end
+	end,
+}
+
+newEffect{
+	name = "ELEMENTAL_RETRIBUTION", image = "talents/elemental_retribution.png",
+	desc = "Retribution",
+	long_desc = function(self, eff) return ("Seeking retribution for having suffered %s damage. Spellpower increased by %d."):format(eff.e_string, eff.power) end,
+	type = "magical",
+	subtype = { arcane=true },
+	status = "beneficial",
+	parameters = { power=1 },
+	on_gain = function(self, err) return nil, "+Retribution" end,
+	on_lose = function(self, err) return nil, "-Retribution" end,
+	on_merge = function(self, old_eff, new_eff)
+		-- stack the critical power boost up to a maximum
+		self:removeTemporaryValue("combat_spellpower", old_eff.tmpid)
+		old_eff.power = math.min(old_eff.power + new_eff.power, old_eff.maximum)
+		old_eff.tmpid = self:addTemporaryValue("combat_spellpower", old_eff.power)
+		old_eff.dur = new_eff.dur
+		return old_eff
+	end,
+	activate = function(self, eff)
+		eff.tmpid = self:addTemporaryValue("combat_spellpower", eff.power)
+	end,
+	deactivate = function(self, eff)
+		self:removeTemporaryValue("combat_spellpower", eff.tmpid)
+	end,
+
+}
+
+newEffect{
+	name = "PERCEPTION", image = "talents/perception.png",
+	desc = "Perception",
+	long_desc = function(self, eff) return ("Increased capacity for spotting invisible and stealthy foes, as well as taking advantage of enemy weak points. (%+d see invisible, %+d see through stealth, and %+.1f critical power)"):format(eff.si, eff.ss, eff.crit) end,
+	type = "magical",
+	subtype = { sense=true },
+	status = "beneficial",
+	parameters = { power=10, crit=10, apr=10 },
+	on_gain = function(self, err) return nil, "+Perception" end,
+	on_lose = function(self, err) return nil, "-Perception" end,
+	activate = function(self, eff)
+		eff.siid = self:addTemporaryValue("see_invisible", eff.si)
+		eff.ssid = self:addTemporaryValue("see_stealth", eff.ss)
+		eff.critid = self:addTemporaryValue("combat_critical_power", eff.crit)
+	end,
+	deactivate = function(self, eff)
+		self:removeTemporaryValue("see_invisible", eff.siid)
+		self:removeTemporaryValue("see_stealth", eff.ssid)
+		self:removeTemporaryValue("combat_critical_power", eff.critid)
+	end,
+}
diff --git a/game/modules/tome/data/timed_effects/mental.lua b/game/modules/tome/data/timed_effects/mental.lua
index b588c8c486..895888e6b6 100644
--- a/game/modules/tome/data/timed_effects/mental.lua
+++ b/game/modules/tome/data/timed_effects/mental.lua
@@ -1148,14 +1148,14 @@ newEffect{
 			-- in range
 			if not self:attr("never_move") and rng.percent(eff.chance) then
 				local sourceX, sourceY = eff.source.x, eff.source.y
-				
+
 				local bestX, bestY
 				local bestDistance = 0
 				local start = rng.range(0, 8)
 				for i = start, start + 8 do
 					local x = self.x + (i % 3) - 1
 					local y = self.y + math.floor((i % 9) / 3) - 1
-					
+
 					if x ~= self.x or y ~= self.y then
 						local distance = core.fov.distance(x, y, sourceX, sourceY)
 						if distance > bestDistance
@@ -1168,7 +1168,7 @@ newEffect{
 						end
 					end
 				end
-				
+
 				if bestX then
 					self:move(bestX, bestY, false)
 					game.logPlayer(self, "#F53CBE#You panic and flee from %s.", eff.source.name)
@@ -1400,7 +1400,7 @@ newEffect{
 	on_timeout = function(self, eff)
 		if eff.src.dead or not game.level:hasEntity(eff.src) then eff.dur = 0 return true end
 		if rng.percent(eff.chance or 0) then
-			if self:checkHit(eff.src:combatSpellpower(), self:combatMentalResist(), 0, 95, 5) then
+			if self:checkHit(eff.src:combatSpellpower(), self:combatSpellResist(), 0, eff.src:getMaxAccuracy("spell"), 5) then
 				local t = eff.src:getTalentFromId(eff.src.T_INNER_DEMONS)
 				t.summon_inner_demons(eff.src, self, t)
 			else
@@ -1863,7 +1863,7 @@ newEffect{
 	addEffect = function(self, eff)
 		if eff.physicalResistId then self:removeTemporaryValue("resists", eff.physicalResistId) end
 		eff.physicalResistId = self:addTemporaryValue("resists", { [DamageType.PHYSICAL]=eff.physicalResistChange })
-	
+
 		local maxId
 		local maxValue = 0
 		for id, def in ipairs(self.stats_def) do
@@ -1992,9 +1992,9 @@ newEffect{
 		if old_eff.incStatsId then self:removeTemporaryValue("inc_stats", old_eff.incStatsId) end
 		old_eff.incStats = nil
 		old_eff.incStatsId = nil
-		
+
 		self.tempeffect_def[self.EFF_MIMIC].activate(self, new_eff)
-		
+
 		return new_eff
 	end
 }
@@ -2123,6 +2123,33 @@ newEffect{
 	end,
 }
 
+newEffect{
+	name = "SAVAGERY", image = "talents/savagery.png",
+	desc = "Savage",
+	long_desc = function(self, eff) return ("Savagely seeking the lives of foes. Critical power increased by %.1f."):format(eff.power) end,
+	type = "physical",
+	subtype = { frenzy=true },
+	status = "beneficial",
+	parameters = { power=1 },
+	on_gain = function(self, err) return nil, "+Savagery" end,
+	on_lose = function(self, err) return nil, "-Savagery" end,
+	on_merge = function(self, old_eff, new_eff)
+		-- stack the critical power boost up to a maximum
+		self:removeTemporaryValue("combat_critical_power", old_eff.tmpid)
+		old_eff.power = math.min(old_eff.power + new_eff.power, 1.5)
+		old_eff.tmpid = self:addTemporaryValue("combat_critical_power", old_eff.power)
+		old_eff.dur = new_eff.dur
+		return old_eff
+	end,
+	activate = function(self, eff)
+		eff.tmpid = self:addTemporaryValue("combat_critical_power", eff.power)
+	end,
+	deactivate = function(self, eff)
+		self:removeTemporaryValue("combat_critical_power", eff.tmpid)
+	end,
+
+}
+
 newEffect{
 	name = "LOBOTOMIZED", image = "talents/psychic_lobotomy.png",
 	desc = "Lobotomized",
diff --git a/game/modules/tome/data/timed_effects/other.lua b/game/modules/tome/data/timed_effects/other.lua
index a38ffb5c15..72c9bb79ca 100644
--- a/game/modules/tome/data/timed_effects/other.lua
+++ b/game/modules/tome/data/timed_effects/other.lua
@@ -730,7 +730,7 @@ newEffect{
 			T_BITE_POISON={base=1, every=10, max=5},
 			T_ROTTING_DISEASE={base=1, every=10, max=5},
 		},
-		combat = { dam=resolvers.levelup(10, 1, 1), atk=resolvers.levelup(5, 1, 1), apr=3, dammod={str=0.6} },
+		combat = { dam=resolvers.levelup(10, 1, 1), atk=resolvers.levelup(5, 1, 1), apr=3, dammod={str=resolvers.levelup(0.2, 5, 0.1, 0.6)} },
 	},
 	doReprieveFromDeath = function(self, eff, target)
 		local def = self.tempeffect_def[self.EFF_CURSE_OF_CORPSES]
@@ -1131,7 +1131,7 @@ newEffect{
 		see_invisible = 80,
 		max_life = resolvers.rngavg(50, 80),
 		combat_armor = 1, combat_def = 10,
-		combat = { dam=resolvers.levelup(resolvers.rngavg(15,20), 1, 1.1), atk=resolvers.rngavg(5,15), apr=5, dammod={str=1} },
+		combat = { dam=resolvers.levelup(resolvers.rngavg(15,20), 1, 1.1), atk=resolvers.rngavg(5,15), apr=5, dammod={str=resolvers.levelup(0.2, 5, 0.2, 1)} },
 		resolvers.talents{
 		},
 	},
@@ -1299,3 +1299,30 @@ newEffect{
 		return dam
 	end,
 }
+
+
+newEffect{
+	name = "RELOADING", image = "talents/reload.png",
+	desc = "Reloading",
+	long_desc = function(self, eff) return ("Reloading.") end,
+	decrease = 0,
+	type = "other",
+	subtype = { miscellaneous=true },
+	status = "beneficial",
+	parameters = {},
+	activate = function(self, eff)
+		game.logPlayer(self, "#LIGHT_BLUE#You begin reloading.")
+	end,
+	deactivate = function(self, eff)
+	end,
+	on_timeout = function(self, eff)
+		for i = 1, eff.shots_per_turn do
+			eff.ammo.combat.shots_left = eff.ammo.combat.shots_left + 1
+			if eff.ammo.combat.shots_left == eff.ammo.combat.capacity then
+				game.logPlayer(self, "Your %s is full.", eff.ammo.name)
+				self:breakReloading()
+				break
+			end	
+		end
+	end,
+}
diff --git a/game/modules/tome/data/timed_effects/physical.lua b/game/modules/tome/data/timed_effects/physical.lua
index d46bbc3b10..b1829c1183 100644
--- a/game/modules/tome/data/timed_effects/physical.lua
+++ b/game/modules/tome/data/timed_effects/physical.lua
@@ -1566,6 +1566,73 @@ newEffect{
 	end,
 }
 
+newEffect{
+	name = "BLOCKING", image = "talents/block.png",
+	desc = "Blocking",
+	long_desc = function(self, eff) return ("Absorbs %d damage from the next blockable attack."):format(eff.power) end,
+	type = "physical",
+	subtype = { tactic=true },
+	status = "beneficial",
+	parameters = { nb=1 },
+	on_gain = function(self, eff) return nil, nil end,
+	on_lose = function(self, eff) return nil, nil end,
+	do_block = function(type, dam, eff, self, src)
+		local dur_inc = 0
+		local crit_inc = 0
+		local nb = 1
+		if self:knowTalent(self.T_RIPOSTE) then
+			local t = self:getTalentFromId(self.T_RIPOSTE)
+			dur_inc = t.getDurInc(self, t)
+			crit_inc = t.getCritInc(self, t)
+			nb = nb + dur_inc
+		end
+		local b = false
+		for i = 1, #eff.d_types do
+			if type == eff.d_types[i] then b = true break end
+		end
+		if not b then return dam end
+		eff.dur = 0
+		local amt = util.bound(dam - eff.power, 0, dam)
+		local blocked = dam - amt
+		if eff.properties.br then self:heal(blocked) end
+		if eff.properties.ref and src.life then DamageType.defaultProjector(src, src.x, src.y, type, blocked, tmp, true) end
+		if (self:knowTalent(self.T_RIPOSTE) or amt == 0) and src.life then src:setEffect(src.EFF_COUNTERSTRIKE, 1 + dur_inc, {power=eff.power, no_ct_effect=true, src=self, crit_inc=crit_inc, nb=nb}) end
+		return amt
+	end,
+	activate = function(self, eff)
+		eff.tmpid = self:addTemporaryValue("block", eff.power)
+		eff.def = self:addTemporaryValue("combat_def", -eff.power)
+		if eff.properties.sp then eff.spell = self:addTemporaryValue("combat_spellresist", eff.power) end
+	end,
+	deactivate = function(self, eff)
+		self:removeTemporaryValue("block", eff.tmpid)
+		self:removeTemporaryValue("combat_def", eff.def)
+		if eff.properties.sp then self:removeTemporaryValue("combat_spellresist", eff.spell) end
+	end,
+}
+
+newEffect{
+	name = "COUNTERSTRIKE", image = "effects/counterstrike.png",
+	desc = "Counterstrike",
+	long_desc = function(self, eff) return "Vulnerable to deadly counterstrikes. Next melee attack will inflict double damage." end,
+	type = "physical",
+	subtype = { tactic=true },
+	status = "detrimental",
+	parameters = { nb=1 },
+	on_gain = function(self, eff) return nil, "+Counter" end,
+	on_lose = function(self, eff) return nil, "-Counter" end,
+	activate = function(self, eff)
+		eff.tmpid = self:addTemporaryValue("counterstrike", 1)
+		eff.def = self:addTemporaryValue("combat_def", -eff.power)
+		eff.dur = eff.dur * (self.global_speed or 1)
+	end,
+	deactivate = function(self, eff)
+		self:removeTemporaryValue("counterstrike", eff.tmpid)
+		self:removeTemporaryValue("combat_def", eff.def)
+		print("counterstrike gone!")
+	end,
+}
+
 newEffect{
 	name = "CURSED_WOUND", image = "talents/slash.png",
 	desc = "Cursed Wound",
@@ -1586,11 +1653,11 @@ newEffect{
 		-- add the remaining healing reduction spread out over the new duration
 		old_eff.healFactorChange = math.max(-0.75, (old_eff.healFactorChange / old_eff.totalDuration) * old_eff.dur + new_eff.healFactorChange)
 		old_eff.dur = math.max(old_eff.dur, new_eff.dur)
-		
+
 		self:removeTemporaryValue("healing_factor", old_eff.healFactorId)
 		old_eff.healFactorId = self:addTemporaryValue("healing_factor", old_eff.healFactorChange)
 		game.logSeen(self, "%s has re-opened a cursed wound!", self.name:capitalize())
-		
+
 		return old_eff
 	end,
 }
@@ -1612,4 +1679,3 @@ newEffect{
 		self:removeTemporaryValue("inc_stealth", eff.stealthid)
 	end,
 }
-
diff --git a/game/modules/tome/data/zones/arena/objects.lua b/game/modules/tome/data/zones/arena/objects.lua
index 908003736a..14ef866eac 100644
--- a/game/modules/tome/data/zones/arena/objects.lua
+++ b/game/modules/tome/data/zones/arena/objects.lua
@@ -107,11 +107,12 @@ newEntity{ define_as = "ARENA_BOOTS_RUSH", name = "a pair of leather boots of ru
 
 newEntity{ define_as = "ARENA_BOW", name = "elm longbow of piercing arrows",
 	base = "BASE_LONGBOW",
+	short_name = "elm",
 	level_range = {1, 10},
 	power_source = {technique=true},
 	require = { stat = { dex=11 }, },
 	rarity = 30,
-	add_name = " #CHARGES#",
+	--add_name = " #CHARGES#",
 	egoed = true,
 	greater_ego = 1,
 	identified = true,
@@ -120,23 +121,21 @@ newEntity{ define_as = "ARENA_BOW", name = "elm longbow of piercing arrows",
 	use_talent = { id = Talents.T_PIERCING_ARROW, level = 2, power = 10 },
 	max_power = 10, power_regen = 1,
 	combat = {
+		dam = 5,
+		critical_power = 1.8,
 		range = 8,
 		physspeed = 0.8,
-	},
-	basic_ammo = {
-		dam = 20,
-		apr = 5,
-		physcrit = 1,
-		dammod = {dex=0.7, str=0.5},
+		dammod = {dex=0.2},
 	},
 }
 
 newEntity{ define_as = "ARENA_SLING", name = "rough leather sling of flare",
 	base = "BASE_SLING",
+	short_name = "rough",
 	level_range = {1, 10},
 	power_source = {technique=true},
 	require = { stat = { dex=11 }, },
-	add_name = " #CHARGES#",
+	--add_name = " #CHARGES#",
 	rarity = 30,
 	egoed = true,
 	greater_ego = 1,
@@ -146,13 +145,10 @@ newEntity{ define_as = "ARENA_SLING", name = "rough leather sling of flare",
 	use_talent = { id = Talents.T_FLARE, level = 3, power = 25 },
 	max_power = 25, power_regen = 1,
 	combat = {
+		dam = 5,
+		critical_power = 1.8,
 		range = 8,
 		physspeed = 0.8,
-	},
-	basic_ammo = {
-		dam = 20,
-		apr = 1,
-		physcrit = 4,
-		dammod = {dex=0.7, cun=0.5},
+		dammod = {dex=0.2},
 	},
 }
diff --git a/game/modules/tome/data/zones/deep-bellow/npcs.lua b/game/modules/tome/data/zones/deep-bellow/npcs.lua
index e9a72f8b9e..bb6a87d108 100644
--- a/game/modules/tome/data/zones/deep-bellow/npcs.lua
+++ b/game/modules/tome/data/zones/deep-bellow/npcs.lua
@@ -92,7 +92,7 @@ It seems to come from the digestive system of the mouth.]],
 	movement_speed = 3,
 	size_category = 1,
 
-	combat = { dam=resolvers.mbonus(25, 15), damtype=DamageType.SLIME, dammod={str=1} },
+	combat = { dam=resolvers.mbonus(25, 15), damtype=DamageType.SLIME, dammod={str=resolvers.levelup(0.1, 5, 0.2, 1)} },
 
 	autolevel = "warrior",
 	ai = "dumb_talented_simple", ai_state = { talent_in=4, ai_move="move_astar" },
diff --git a/game/modules/tome/data/zones/high-peak/objects.lua b/game/modules/tome/data/zones/high-peak/objects.lua
index 9dbf1a98e2..6292e3d7f5 100644
--- a/game/modules/tome/data/zones/high-peak/objects.lua
+++ b/game/modules/tome/data/zones/high-peak/objects.lua
@@ -21,12 +21,14 @@ load("/data/general/objects/objects-far-east.lua")
 load("/data/general/objects/lore/sunwall.lua")
 
 local Stats = require "engine.interface.ActorStats"
+local Talents = require "engine.interface.ActorTalents"
 
 -- The staff of absorption, the reason the game exists!
 newEntity{ define_as = "STAFF_ABSORPTION_AWAKENED", base="BASE_STAFF",
 	power_source = {unknown=true},
 	unique = true, godslayer=true,
 	name = "Awakened Staff of Absorption", identified=true, force_lore_artifact=true,
+	flavor_name = "magestaff",
 	display = "\\", color=colors.VIOLET, image = "object/artifact/staff_absorption.png",
 	encumber = 7,
 	desc = [[Carved with runes of power, this staff seems to have been made long ago. Yet it bears no signs of tarnishment.
@@ -35,20 +37,42 @@ The Sorcerers seem to have awakened its power.
 #{italic}#"And lo they came to Amakthel himself, and thousands were killed in the assault on his throne, and three of the Godslayers were broken beneath his feet. But Falion with his dying breath pierced the great god on his knee with the icy sword Arkil, and seeing his opportunity Caldizar, leader of the Godslayers, advanced with the Staff of Absorption and struck a terrifying blow against Amakthel. So fell the greatest of the gods by the hands of his own children, and his face was forced into the dust."#{normal}#]],
 
 	require = { stat = { mag=60 }, },
+	modes = {"fire", "cold", "lightning", "arcane"},
 	combat = {
-		dam = 80,
-		apr = 60,
-		atk = 30,
-		dammod = {mag=1.3},
+		is_greater = true,
+		of_breaching = true,
+		of_retribution = true,
+		dam = 60,
+		max_acc = 100,
+		critical_power = 2.5,
+		dammod = {mag=0.8},
 		damtype = DamageType.ARCANE,
 	},
 	wielder = {
 		combat_spellpower = 48,
-		combat_spellcrit = 15,
 		max_mana = 100,
 		max_positive = 50,
 		max_negative = 50,
 		inc_stats = { [Stats.STAT_MAG] = 10, [Stats.STAT_WIL] = 10 },
+		inc_damage={
+			[DamageType.FIRE] = 60,
+			[DamageType.LIGHTNING] = 60,
+			[DamageType.COLD] = 60,
+			[DamageType.ARCANE] = 60,
+		},
+		resists_pen={
+			[DamageType.FIRE] = 30,
+			[DamageType.LIGHTNING] = 30,
+			[DamageType.COLD] = 30,
+			[DamageType.ARCANE] = 30,
+		},
+		elemental_retribution = {
+			[DamageType.FIRE] = 1,
+			[DamageType.LIGHTNING] = 1,
+			[DamageType.COLD] = 1,
+			[DamageType.ARCANE] = 1,
+		},
+		learn_talent = {[Talents.T_COMMAND_STAFF] = 5, [Talents.T_ELEMENTAL_RETRIBUTION] = 5,},
 		speaks_shertul = 1,
 	},
 
diff --git a/game/modules/tome/data/zones/norgos-lair/npcs.lua b/game/modules/tome/data/zones/norgos-lair/npcs.lua
index 8e6ae846d5..4da6d3cf36 100644
--- a/game/modules/tome/data/zones/norgos-lair/npcs.lua
+++ b/game/modules/tome/data/zones/norgos-lair/npcs.lua
@@ -46,7 +46,7 @@ newEntity{ base="BASE_NPC_BEAR", define_as = "NORGOS",
 	instakill_immune = 1,
 	move_others=true,
 
-	combat = { dam=resolvers.levelup(17, 1, 0.8), atk=10, apr=9, dammod={str=1.2} },
+	combat = { dam=resolvers.levelup(17, 1, 0.8), atk=10, apr=9, dammod={str=resolvers.levelup(0.3, 5, 0.2, 1.2)} },
 
 	resists = { [DamageType.COLD] = 20 },
 
diff --git a/game/modules/tome/data/zones/old-forest/npcs.lua b/game/modules/tome/data/zones/old-forest/npcs.lua
index 7290ca07d7..fb712a3e59 100644
--- a/game/modules/tome/data/zones/old-forest/npcs.lua
+++ b/game/modules/tome/data/zones/old-forest/npcs.lua
@@ -51,7 +51,7 @@ newEntity{ define_as = "WRATHROOT",
 	instakill_immune = 1,
 	move_others=true,
 
-	combat = { dam=resolvers.levelup(27, 1, 0.8), atk=10, apr=0, dammod={str=1.2}, sound="actions/melee_thud" },
+	combat = { dam=resolvers.levelup(27, 1, 0.8), atk=10, apr=0, dammod={str=resolvers.levelup(0.3, 5, 0.2, 1.2)}, sound="actions/melee_thud" },
 
 	resists = { [DamageType.FIRE] = -50 },
 
diff --git a/game/modules/tome/data/zones/paradox-plane/objects.lua b/game/modules/tome/data/zones/paradox-plane/objects.lua
index c3eecb7dae..1856e65524 100644
--- a/game/modules/tome/data/zones/paradox-plane/objects.lua
+++ b/game/modules/tome/data/zones/paradox-plane/objects.lua
@@ -36,20 +36,17 @@ According to legend it was made from the first ash sapling to sprout after the S
 	cost = 200,
 	material_level = 5,
 	combat = {
+		dam = 15,
+		critical_power = 1.8,
 		range = 9,
+		dammod = {dex=0.3},
 		physspeed = 0.6,
-	},
-	basic_ammo = {
-		dam = 30,
-		apr = 10,
-		physcrit = 2,
-		dammod = {dex=0.7, str=0.5},
+		ranged_project={[DamageType.TEMPORAL] = 15},
 	},
 	wielder = {
 		life_regen = 2.0,
 		stamina_regen = 1.0,
 		inc_damage={ [DamageType.TEMPORAL] = 10, },
 		inc_stats = { [Stats.STAT_DEX] = 5, [Stats.STAT_WIL] = 4,  },
-		ranged_project={[DamageType.TEMPORAL] = 15},
 	},
 }
diff --git a/game/modules/tome/data/zones/ritch-tunnels/npcs.lua b/game/modules/tome/data/zones/ritch-tunnels/npcs.lua
index 78be453ab8..a8a9e2f067 100644
--- a/game/modules/tome/data/zones/ritch-tunnels/npcs.lua
+++ b/game/modules/tome/data/zones/ritch-tunnels/npcs.lua
@@ -32,7 +32,7 @@ newEntity{
 Vicious predators, they inject corrupting diseases into their foes, and their sharp claws cut through most armours.]],
 	killer_message = ", who incubated her eggs in the corpse,",
 
-	combat = { dam=resolvers.rngavg(10,32), atk=0, apr=4, damtype=DamageType.BLIGHT, dammod={dex=1.2} },
+	combat = { dam=resolvers.rngavg(10,32), atk=0, apr=4, damtype=DamageType.BLIGHT, dammod={dex=resolvers.levelup(0.1, 5, 0.1, 1.2)} },
 
 	body = { INVEN = 10, MAINHAND=1, OFFHAND=1, BODY=1 },
 
@@ -110,7 +110,7 @@ newEntity{ base = "BASE_NPC_RITCH_REL", define_as = "HIVE_MOTHER",
 	rank = 4,
 	size_category = 4,
 
-	combat = { dam=30, atk=22, apr=7, dammod={str=1.1} },
+	combat = { dam=30, atk=22, apr=7, dammod={str=resolvers.levelup(0.3, 5, 0.2, 1.1)} },
 
 	resists = { [DamageType.BLIGHT] = 40 },
 
diff --git a/game/modules/tome/data/zones/telmur/objects.lua b/game/modules/tome/data/zones/telmur/objects.lua
index c95c07ee43..a8e30991bb 100644
--- a/game/modules/tome/data/zones/telmur/objects.lua
+++ b/game/modules/tome/data/zones/telmur/objects.lua
@@ -20,6 +20,7 @@
 load("/data/general/objects/objects-maj-eyal.lua")
 
 local Stats = require "engine.interface.ActorStats"
+local Talents = require "engine.interface.ActorTalents"
 
 newEntity{ base = "BASE_STAFF",
 	power_source = {arcane=true},
@@ -32,13 +33,17 @@ newEntity{ base = "BASE_STAFF",
 	require = { stat = { mag=35 }, },
 	encumberance = 2.5,
 	cost = 500,
+	combat = {
+		dam = 10,
+		max_acc = 80,
+		critical_power = 1.1,
+		dammod = {mag=0.2},
+		damtype = DamageType.PHYSICAL,
+	},
 	wielder = {
 		inc_stats = { [Stats.STAT_MAG] = 4, },
 		max_mana = 50,
 		combat_mentalresist = 8,
-		inc_damage={
-			[DamageType.COLD] = 20,
-			[DamageType.ACID] = 20,
-		},
+		learn_talent = {[Talents.T_SAVAGERY] = 5},
 	},
 }
diff --git a/game/modules/tome/data/zones/tutorial-combat-stats/npcs.lua b/game/modules/tome/data/zones/tutorial-combat-stats/npcs.lua
index ca7c2850bc..67e3696bc1 100644
--- a/game/modules/tome/data/zones/tutorial-combat-stats/npcs.lua
+++ b/game/modules/tome/data/zones/tutorial-combat-stats/npcs.lua
@@ -135,7 +135,7 @@ newEntity{ base = "BASE_NPC_ORC",
 	image="npc/humanoid_orc_orc_child.png",
 	level_range = {1, nil}, exp_worth = 1,
 	max_life = 100,
-	combat_atk = 6,
+	combat_atk = 7,
 	combat_def = 86,
 	never_move = 1,
 	combat = false,
@@ -146,7 +146,7 @@ newEntity{ base = "BASE_NPC_ORC",
 	name = "Orc", color=colors.LIGHT_UMBER,
 	image="npc/humanoid_orc_orc_child.png",
 	level_range = {1, nil}, exp_worth = 1,
-	combat_atk = 6,
+	combat_atk = 7,
 	max_life = 100,
 	combat_def = 83,
 	never_move = 1,
diff --git a/game/modules/tome/dialogs/CharacterSheet.lua b/game/modules/tome/dialogs/CharacterSheet.lua
index 6de75747d2..3c034358e3 100644
--- a/game/modules/tome/dialogs/CharacterSheet.lua
+++ b/game/modules/tome/dialogs/CharacterSheet.lua
@@ -51,7 +51,7 @@ function _M:init(actor)
 	self.vs = Separator.new{dir="vertical", size=self.iw}
 
 	self.c_tut = Textzone.new{width=self.iw * 0.6, auto_height=true, no_color_bleed=true, font = self.font, text=[[
-Values #00FF00#in bracets ( )#LAST# shows changes made from last character sheet checking.
+Values #00FF00#in brackets ( )#LAST# shows changes made from last character sheet checking.
 Keyboard: #00FF00#'d'#LAST# to save character dump. #00FF00#TAB key#LAST# to switch between tabs.
 Mouse: Hover over stat for info
 ]]}
@@ -188,6 +188,8 @@ function _M:drawDialog(kind, actor_to_compare)
 	local w = 0
 
 	local text = ""
+	local dur_text = ""
+	local sp_text = ""
 
 	if player.__te4_uuid and profile.auth and profile.auth.drupid then
 		local path = "http://te4.org/characters/"..profile.auth.drupid.."/tome/"..player.__te4_uuid
@@ -500,6 +502,32 @@ function _M:drawDialog(kind, actor_to_compare)
 		print_stat(self.actor.STAT_CON, ("%-12s"):format(Stats.stats_def[self.actor.STAT_CON].name:capitalize()), self.TOOLTIP_CON)
 		h = h + self.font_h
 
+		s:drawColorStringBlended(self.font, "#LIGHT_BLUE#Combat stats:", w, h, 255, 255, 255, true) h = h + self.font_h
+
+		text = compare_fields(player, actor_to_compare, function(actor, ...) return actor:combatPhysicalpower() end, "%3d", "%+.0f")
+		dur_text = ("%d"):format(math.floor(player:combatPhysicalpower()/5))
+		self:mouseTooltip(self.TOOLTIP_SPELL_POWER, s:drawColorStringBlended(self.font, ("Physical power: #00ff00#%s  [+%s effect duration]"):format(text, dur_text), w, h, 255, 255, 255, true)) h = h + self.font_h	
+
+		text = compare_fields(player, actor_to_compare, function(actor, ...) return actor:combatSpellpower() end, "%3d", "%+.0f")
+		dur_text = ("%d"):format(math.floor(player:combatSpellpower()/5))
+		self:mouseTooltip(self.TOOLTIP_SPELL_POWER, s:drawColorStringBlended(self.font, ("Spellpower    : #00ff00#%s  [+%s effect duration]"):format(text, dur_text), w, h, 255, 255, 255, true)) h = h + self.font_h	
+
+		text = compare_fields(player, actor_to_compare, function(actor, ...) return actor:combatMindpower() end, "%3d", "%+.0f")
+		dur_text = ("%d"):format(math.floor(player:combatMindpower()/5))
+		self:mouseTooltip(self.TOOLTIP_SPELL_POWER, s:drawColorStringBlended(self.font, ("Mindpower     : #00ff00#%s  [+%s effect duration]"):format(text, dur_text), w, h, 255, 255, 255, true)) h = h + self.font_h	
+
+		text = compare_fields(player, actor_to_compare, function(actor, ...) return math.floor(actor:combatPhysicalResist(true)) end, "%3d", "%+.0f")
+		dur_text = ("%d"):format(math.floor(player:combatPhysicalResist(true)/5))
+		self:mouseTooltip(self.TOOLTIP_PHYS_SAVE,   s:drawColorStringBlended(self.font, ("Physical save : #00ff00#%s  [-%s effect duration]"):format(text, dur_text), w, h, 255, 255, 255, true)) h = h + self.font_h
+		text = compare_fields(player, actor_to_compare, function(actor, ...) return math.floor(actor:combatSpellResist(true)) end, "%3d", "%+.0f")
+		dur_text = ("%d"):format(math.floor(player:combatSpellResist(true)/5))
+		self:mouseTooltip(self.TOOLTIP_SPELL_SAVE,  s:drawColorStringBlended(self.font, ("Spell save    : #00ff00#%s  [-%s effect duration]"):format(text, dur_text), w, h, 255, 255, 255, true)) h = h + self.font_h
+		text = compare_fields(player, actor_to_compare, function(actor, ...) return math.floor(actor:combatMentalResist(true)) end, "%3d", "%+.0f")
+		dur_text = ("%d"):format(math.floor(player:combatMentalResist(true)/5))
+		self:mouseTooltip(self.TOOLTIP_MENTAL_SAVE, s:drawColorStringBlended(self.font, ("Mental save   : #00ff00#%s  [-%s effect duration]"):format(text, dur_text), w, h, 255, 255, 255, true)) h = h + self.font_h
+
+		h = h + self.font_h
+		
 		local nb_inscriptions = 0
 		for i = 1, player.max_inscriptions do if player.inscriptions[i] then nb_inscriptions = nb_inscriptions + 1 end end
 		self:mouseTooltip(self.TOOLTIP_INSCRIPTIONS, s:drawColorStringBlended(self.font, ("#AQUAMARINE#Inscriptions (%d/%d)"):format(nb_inscriptions, player.max_inscriptions), w, h, 255, 255, 255, true)) h = h + self.font_h
@@ -554,22 +582,26 @@ function _M:drawDialog(kind, actor_to_compare)
 
 			for i, o in ipairs(player:getInven(player.INVEN_MAINHAND)) do
 				local mean, dam = o.combat, o.combat
-				if o.archery and mean then
-					dam = (player:getInven("QUIVER")[1] and player:getInven("QUIVER")[1].combat) or o.basic_ammo
-				end
 				if mean and dam then
+					local max_acc = o.combat.max_acc
+					if o.archery and player:hasAmmo(o.archery) then max_acc = player:hasAmmo(o.archery).combat.max_acc end
+					sp_text = (o.combat.affects_spells and " (affects spells)") or ""
+					local attack_speed_bonus = (1 / player:combatSpeed(o.combat))*100 - 100
 					s:drawColorStringBlended(self.font, WeaponTxt, w, h, 255, 255, 255, true) h = h + self.font_h
-					text = compare_fields(player, actor_to_compare, function(actor, ...) return math.floor(actor:combatAttack(...)) end, "%3d", "%+.0f", 1, false, false, mean)
-					dur_text = ("%d"):format(math.floor(player:combatAttack(o.combat)/5))
-					self:mouseTooltip(self.TOOLTIP_COMBAT_ATTACK, s:drawColorStringBlended(self.font, ("Accuracy    : #00ff00#%s"):format(text), w, h, 255, 255, 255, true)) h = h + self.font_h
-					text = compare_fields(player, actor_to_compare, function(actor, ...) return actor:combatDamage(...) end, "%3d", "%+.0f", 1, false, false, dam)
+					
+					text = compare_fields(player, actor_to_compare, function(actor, ...) return actor:getCombinedDamage(o) end, "%d", "%+d", 1, false, false, dam)
 					self:mouseTooltip(self.TOOLTIP_COMBAT_DAMAGE, s:drawColorStringBlended(self.font, ("Damage      : #00ff00#%s"):format(text), w, h, 255, 255, 255, true)) h = h + self.font_h
-					text = compare_fields(player, actor_to_compare, function(actor, ...) return actor:combatAPR(...) end, "%3d", "%+.0f", 1, false, false, dam)
-					self:mouseTooltip(self.TOOLTIP_COMBAT_APR,    s:drawColorStringBlended(self.font, ("APR         : #00ff00#%s"):format(text), w, h, 255, 255, 255, true)) h = h + self.font_h
-					text = compare_fields(player, actor_to_compare, function(actor, ...) return actor:combatCrit(...) end, "%3d%%", "%+.0f%%", 1, false, false, dam)
+					text = compare_fields(player, actor_to_compare, function(actor, ...) return (o.combat.critical_power or 1.1) + (actor.combat_critical_power or 0)/100 end, "%.2fx", "%+.2f")
+					self:mouseTooltip(self.TOOLTIP_INC_CRIT_POWER  , s:drawColorStringBlended(self.font,   ("Crit mult.  : #00ff00#%s%s"):format(text, sp_text), w, h, 255, 255, 255, true)) h = h + self.font_h
+					text = compare_fields(player, actor_to_compare, function(actor, ...) return (max_acc or 75) end, "%d%%", "%+d%%", 1, false, false, mean)
+					self:mouseTooltip(self.TOOLTIP_COMBAT_ATTACK, s:drawColorStringBlended(self.font, ("Max accuracy: #00ff00#%s%s"):format(text, sp_text), w, h, 255, 255, 255, true)) h = h + self.font_h
+					text = compare_fields(player, actor_to_compare, function(actor, ...) return attack_speed_bonus end, "%d%%", "%+d%%", 1, false, false, mean)
+					self:mouseTooltip(self.TOOLTIP_COMBAT_SPEED,  s:drawColorStringBlended(self.font, ("Speed bonus : #00ff00#%s"):format(text), w, h, 255, 255, 255, true)) h = h + self.font_h
+					text = compare_fields(player, actor_to_compare, function(actor, ...) return actor:combatAPR(...) end, "%d", "%+d", 1, false, false, dam)
+					self:mouseTooltip(self.TOOLTIP_COMBAT_APR,    s:drawColorStringBlended(self.font, ("Armor pen.  : #00ff00#%s"):format(text), w, h, 255, 255, 255, true)) h = h + self.font_h
+					text = compare_fields(player, actor_to_compare, function(actor, ...) return actor:combatCrit(...) end, "%d%%", "%+d%%", 1, false, false, dam)
 					self:mouseTooltip(self.TOOLTIP_COMBAT_CRIT,   s:drawColorStringBlended(self.font, ("Crit. chance: #00ff00#%s"):format(text), w, h, 255, 255, 255, true)) h = h + self.font_h
-					text = compare_fields(player, actor_to_compare, function(actor, ...) return actor:combatSpeed(...) end, "%.2f%%", "%+.2f%%", 100, false, false, mean)
-					self:mouseTooltip(self.TOOLTIP_COMBAT_SPEED,  s:drawColorStringBlended(self.font, ("Speed       : #00ff00#%s"):format(text), w, h, 255, 255, 255, true)) h = h + self.font_h
+
 				end
 				if mean and mean.range then
 					self:mouseTooltip(self.TOOLTIP_COMBAT_RANGE, s:drawColorStringBlended(self.font, ("Range (Main Hand): #00ff00#%3d"):format(mean.range), w, h, 255, 255, 255, true)) h = h + self.font_h
@@ -580,17 +612,23 @@ function _M:drawDialog(kind, actor_to_compare)
 			s:drawColorStringBlended(self.font, "#LIGHT_BLUE#Unarmed:", w, h, 255, 255, 255, true) h = h + self.font_h
 			local mean, dam = player.combat, player.combat
 			if mean and dam then
-				text = compare_fields(player, actor_to_compare, function(actor, ...) return math.floor(actor:combatAttack(...)) end, "%3d", "%+.0f", 1, false, false, mean)
-				dur_text = ("%d"):format(math.floor(player:combatAttack(player.combat)/5))
-				self:mouseTooltip(self.TOOLTIP_COMBAT_ATTACK, s:drawColorStringBlended(self.font, ("Accuracy    : #00ff00#%s"):format(text), w, h, 255, 255, 255, true)) h = h + self.font_h
-				text = compare_fields(player, actor_to_compare, function(actor, ...) return actor:combatDamage(...) end, "%3d", "%+.0f", 1, false, false, dam)
+				sp_text = (player.combat.affects_spells and " (affects spells)") or ""
+				local attack_speed_bonus = (1 / player:combatSpeed(player.combat))*100 - 100
+				local gloves = player:hasGloves()
+				local total_dam = player:combatDamage(player.combat) + (gloves and gloves:getMeleeProjectDam() or 0)
+				text = compare_fields(player, actor_to_compare, function(actor, ...) return total_dam end, "%d", "%+d", 1, false, false, dam)
 				self:mouseTooltip(self.TOOLTIP_COMBAT_DAMAGE, s:drawColorStringBlended(self.font, ("Damage      : #00ff00#%s"):format(text), w, h, 255, 255, 255, true)) h = h + self.font_h
-				text = compare_fields(player, actor_to_compare, function(actor, ...) return actor:combatAPR(...) end, "%3d", "%+.0f", 1, false, false, dam)
-				self:mouseTooltip(self.TOOLTIP_COMBAT_APR,    s:drawColorStringBlended(self.font, ("APR         : #00ff00#%s"):format(text), w, h, 255, 255, 255, true)) h = h + self.font_h
-				text = compare_fields(player, actor_to_compare, function(actor, ...) return actor:combatCrit(...) end, "%3d%%", "%+.0f%%", 1, false, false, dam)
+				text = compare_fields(player, actor_to_compare, function(actor, ...) return (actor.combat.critical_power or 1.1) + (actor.combat_critical_power or 0)/100 end, "%.2fx", "%+.2f")
+				self:mouseTooltip(self.TOOLTIP_INC_CRIT_POWER  , s:drawColorStringBlended(self.font,   ("Crit mult.  : #00ff00#%s%s"):format(text, sp_text), w, h, 255, 255, 255, true)) h = h + self.font_h
+				text = compare_fields(player, actor_to_compare, function(actor, ...) return actor.combat.max_acc end, "%d%%", "%+d%%", 1, false, false, mean)
+				self:mouseTooltip(self.TOOLTIP_COMBAT_ATTACK, s:drawColorStringBlended(self.font, ("Max accuracy: #00ff00#%s%s"):format(text, sp_text), w, h, 255, 255, 255, true)) h = h + self.font_h
+				text = compare_fields(player, actor_to_compare, function(actor, ...) return attack_speed_bonus end, "%d%%", "%+d%%", 1, false, false, mean)
+				self:mouseTooltip(self.TOOLTIP_COMBAT_SPEED,  s:drawColorStringBlended(self.font, ("Speed bonus : #00ff00#%s"):format(text), w, h, 255, 255, 255, true)) h = h + self.font_h
+				text = compare_fields(player, actor_to_compare, function(actor, ...) return actor:combatAPR(...) end, "%d", "%+d", 1, false, false, dam)
+				self:mouseTooltip(self.TOOLTIP_COMBAT_APR,    s:drawColorStringBlended(self.font, ("Armor pen.  : #00ff00#%s"):format(text), w, h, 255, 255, 255, true)) h = h + self.font_h
+				text = compare_fields(player, actor_to_compare, function(actor, ...) return actor:combatCrit(...) end, "%d%%", "%+d%%", 1, false, false, dam)
 				self:mouseTooltip(self.TOOLTIP_COMBAT_CRIT,   s:drawColorStringBlended(self.font, ("Crit. chance: #00ff00#%s"):format(text), w, h, 255, 255, 255, true)) h = h + self.font_h
-				text = compare_fields(player, actor_to_compare, function(actor, ...) return actor:combatSpeed(...) end, "%.2f%%", "%+.2f%%", 100, false, false, mean)
-				self:mouseTooltip(self.TOOLTIP_COMBAT_SPEED,  s:drawColorStringBlended(self.font, ("Speed       : #00ff00#%s"):format(text), w, h, 255, 255, 255, true)) h = h + self.font_h
+
 			end
 			if mean and mean.range then
 				self:mouseTooltip(self.TOOLTIP_COMBAT_RANGE, s:drawColorStringBlended(self.font, ("Range (Main Hand): #00ff00#%3d"):format(mean.range), w, h, 255, 255, 255, true)) h = h + self.font_h
@@ -604,22 +642,25 @@ function _M:drawDialog(kind, actor_to_compare)
 			local offmult = player:getOffHandMult()
 			for i, o in ipairs(player:getInven(player.INVEN_OFFHAND)) do
 				local mean, dam = o.combat, o.combat
-				if o.archery and mean then
-					dam = (player:getInven("QUIVER")[1] and player:getInven("QUIVER")[1].combat) or o.basic_ammo
-				end
 				if mean and dam then
+					local max_acc = o.combat.max_acc
+					if o.archery and player:hasAmmo(o.archery) then max_acc = player:hasAmmo(o.archery).combat.max_acc end
+					sp_text = (o.combat.affects_spells and " (affects spells)") or ""
+					local attack_speed_bonus = (1 / player:combatSpeed(o.combat))*100 - 100
 					s:drawColorStringBlended(self.font, "#LIGHT_BLUE#Off Hand:", w, h, 255, 255, 255, true) h = h + self.font_h
-					text = compare_fields(player, actor_to_compare, function(actor, ...) return math.floor(actor:combatAttack(...)) end, "%3d", "%+.0f", 1, false, false, mean)
-					dur_text = ("%d"):format(math.floor(player:combatAttack(o.combat)/5))
-					self:mouseTooltip(self.TOOLTIP_COMBAT_ATTACK, s:drawColorStringBlended(self.font, ("Accuracy    : #00ff00#%s"):format(text), w, h, 255, 255, 255, true)) h = h + self.font_h
-					text = compare_fields(player, actor_to_compare, function(actor, ...) return actor:combatDamage(...) end, "%3d", "%+.0f", offmult, false, false, dam)
+					
+					text = compare_fields(player, actor_to_compare, function(actor, ...) return actor:getCombinedDamage(o, offmult) end, "%d", "%+d", 1, false, false, dam)
 					self:mouseTooltip(self.TOOLTIP_COMBAT_DAMAGE, s:drawColorStringBlended(self.font, ("Damage      : #00ff00#%s"):format(text), w, h, 255, 255, 255, true)) h = h + self.font_h
-					text = compare_fields(player, actor_to_compare, function(actor, ...) return actor:combatAPR(...) end, "%3d", "%+.0f", 1, false, false, dam)
-					self:mouseTooltip(self.TOOLTIP_COMBAT_APR,    s:drawColorStringBlended(self.font, ("APR         : #00ff00#%s"):format(text), w, h, 255, 255, 255, true)) h = h + self.font_h
-					text = compare_fields(player, actor_to_compare, function(actor, ...) return actor:combatCrit(...) end, "%3d%%", "%+.0f%%", 1, false, false, dam)
+					text = compare_fields(player, actor_to_compare, function(actor, ...) return (o.combat.critical_power or 1.1) + (actor.combat_critical_power or 0)/100 end, "%.2fx", "%+.2f")
+					self:mouseTooltip(self.TOOLTIP_INC_CRIT_POWER  , s:drawColorStringBlended(self.font,   ("Crit mult.  : #00ff00#%s%s"):format(text, sp_text), w, h, 255, 255, 255, true)) h = h + self.font_h
+					text = compare_fields(player, actor_to_compare, function(actor, ...) return (max_acc or 75) end, "%d%%", "%+d%%", 1, false, false, mean)
+					self:mouseTooltip(self.TOOLTIP_COMBAT_ATTACK, s:drawColorStringBlended(self.font, ("Max accuracy: #00ff00#%s%s"):format(text, sp_text), w, h, 255, 255, 255, true)) h = h + self.font_h
+					text = compare_fields(player, actor_to_compare, function(actor, ...) return attack_speed_bonus end, "%d%%", "%+d%%", 1, false, false, mean)
+					self:mouseTooltip(self.TOOLTIP_COMBAT_SPEED,  s:drawColorStringBlended(self.font, ("Speed bonus : #00ff00#%s"):format(text), w, h, 255, 255, 255, true)) h = h + self.font_h
+					text = compare_fields(player, actor_to_compare, function(actor, ...) return actor:combatAPR(...) end, "%d", "%+d", 1, false, false, dam)
+					self:mouseTooltip(self.TOOLTIP_COMBAT_APR,    s:drawColorStringBlended(self.font, ("Armor pen.  : #00ff00#%s"):format(text), w, h, 255, 255, 255, true)) h = h + self.font_h
+					text = compare_fields(player, actor_to_compare, function(actor, ...) return actor:combatCrit(...) end, "%d%%", "%+d%%", 1, false, false, dam)
 					self:mouseTooltip(self.TOOLTIP_COMBAT_CRIT,   s:drawColorStringBlended(self.font, ("Crit. chance: #00ff00#%s"):format(text), w, h, 255, 255, 255, true)) h = h + self.font_h
-					text = compare_fields(player, actor_to_compare, function(actor, ...) return actor:combatSpeed(...) end, "%.2f%%", "%+.2f%%", 100, false, false, mean)
-					self:mouseTooltip(self.TOOLTIP_COMBAT_SPEED,  s:drawColorStringBlended(self.font, ("Speed       : #00ff00#%s"):format(text), w, h, 255, 255, 255, true)) h = h + self.font_h
 				end
 				if mean and mean.range then self:mouseTooltip(self.TOOLTIP_COMBAT_RANGE, s:drawColorStringBlended(self.font, ("Range (Off Hand): #00ff00#%3d"):format(mean.range), w, h, 255, 255, 255, true)) h = h + self.font_h end
 			end
@@ -647,10 +688,8 @@ function _M:drawDialog(kind, actor_to_compare)
 		h = 0
 		w = self.w * 0.5
 
-		s:drawColorStringBlended(self.font, "#LIGHT_BLUE#Damage mods.:", w, h, 255, 255, 255, true) h = h + self.font_h
-		text = compare_fields(player, actor_to_compare, function(actor, ...) return 150 + (actor.combat_critical_power or 0) end, "%3d%%", "%+.0f%%")
-		self:mouseTooltip(self.TOOLTIP_INC_CRIT_POWER  , s:drawColorStringBlended(self.font,   ("Critical mult.: #00ff00#%s"):format(text), w, h, 255, 255, 255, true)) h = h + self.font_h
-
+		s:drawColorStringBlended(self.font, "#LIGHT_BLUE#Damage mods:", w, h, 255, 255, 255, true) h = h + self.font_h
+		
 		if player.inc_damage.all then
 			text = compare_fields(player, actor_to_compare, function(actor, ...) return actor.inc_damage and actor.inc_damage.all or 0 end, "%3d%%", "%+.0f%%")
 			self:mouseTooltip(self.TOOLTIP_INC_DAMAGE_ALL, s:drawColorStringBlended(self.font, ("All damage    : #00ff00#%s"):format(text), w, h, 255, 255, 255, true)) h = h + self.font_h
@@ -716,7 +755,7 @@ function _M:drawDialog(kind, actor_to_compare)
 		h = 0
 		w = self.w * 0.75
 
-		s:drawColorStringBlended(self.font, "#LIGHT_BLUE#Damage penetration.:", w, h, 255, 255, 255, true) h = h + self.font_h
+		s:drawColorStringBlended(self.font, "#LIGHT_BLUE#Damage penetration:", w, h, 255, 255, 255, true) h = h + self.font_h
 
 		if player.resists_pen.all then
 			text = compare_fields(player, actor_to_compare, function(actor, ...) return actor.resists_pen and actor.resists_pen.all or 0 end, "%3d%%", "%+.0f%%")
@@ -931,30 +970,31 @@ function _M:dump()
 	if player:getInven(player.INVEN_MAINHAND) then
 		for i, o in ipairs(player:getInven(player.INVEN_MAINHAND)) do
 			local mean, dam = o.combat, o.combat
-			if o.archery and mean then
-				dam = (player:getInven("QUIVER")[1] and player:getInven("QUIVER")[1].combat) or o.basic_ammo
-			end
 			if mean and dam then
-				strings[1] = ("Accuracy(Main Hand): %3d"):format(player:combatAttack(mean))
-				strings[2] = ("Damage  (Main Hand): %3d"):format(player:combatDamage(dam))
-				strings[3] = ("APR     (Main Hand): %3d"):format(player:combatAPR(dam))
-				strings[4] = ("Crit    (Main Hand): %3d%%"):format(player:combatCrit(dam))
-				strings[5] = ("Speed   (Main Hand): %0.2f"):format(player:combatSpeed(mean))
+				strings[1] = ("Damage    (Main Hand): %d"):format(player:getCombinedDamage(o))
+				strings[2] = ("crit mult (Main Hand): %.1fx"):format(o.combat.critical_power)
+				strings[3] = ("Max acc   (Main Hand): %d"):format(o.combat.max_acc)
+				strings[4] = ("Sp. bonus (Main Hand): %d%%"):format((1 / player:combatSpeed(o.combat))*100 - 100)
+				strings[5] = ("APR       (Main Hand): %d"):format(player:combatAPR(dam))
+				strings[6] = ("Crit      (Main Hand): %d%%"):format(player:combatCrit(dam))
 			end
-			if mean and mean.range then strings[6] = ("Range (Main Hand): %3d"):format(mean.range) end
+			if mean and mean.range then strings[7] = ("Range (Main Hand): %3d"):format(mean.range) end
 		end
 	end
 	--Unarmed??
 	if player:isUnarmed() then
+		local gloves = player:hasGloves()
+		local total_dam = player:combatDamage(player.combat) + (gloves and gloves:getMeleeProjectDam() or 0)
 		local mean, dam = player.combat, player.combat
 		if mean and dam then
-			strings[1] = ("Accuracy(Unarmed): %3d"):format(player:combatAttack(mean))
-			strings[2] = ("Damage  (Unarmed): %3d"):format(player:combatDamage(dam))
-			strings[3] = ("APR     (Unarmed): %3d"):format(player:combatAPR(dam))
-			strings[4] = ("Crit    (Unarmed): %3d%%"):format(player:combatCrit(dam))
-			strings[5] = ("Speed   (Unarmed): %0.2f"):format(player:combatSpeed(mean))
-		end
-		if mean and mean.range then strings[6] = ("Range (Unarmed): %3d"):format(mean.range) end
+				strings[1] = ("Damage    (Main Hand): %d"):format(total_dam)
+				strings[2] = ("crit mult (Main Hand): %.1fx"):format(player.combat.critical_power)
+				strings[3] = ("Max acc   (Main Hand): %d"):format(player.combat.max_acc)
+				strings[4] = ("Sp. bonus (Main Hand): %d%%"):format((1 / player:combatSpeed(player.combat))*100 - 100)
+				strings[5] = ("APR       (Main Hand): %d"):format(player:combatAPR(dam))
+				strings[6] = ("Crit      (Main Hand): %d%%"):format(player:combatCrit(dam))
+		end
+		if mean and mean.range then strings[7] = ("Range (Unarmed): %d"):format(mean.range) end
 	end
 
 	local enc, max = player:getEncumbrance(), player:getMaxEncumbrance()
@@ -1016,18 +1056,16 @@ function _M:dump()
 		local offmult = player:getOffHandMult()
 		for i, o in ipairs(player:getInven(player.INVEN_OFFHAND)) do
 			local mean, dam = o.combat, o.combat
-			if o.archery and mean then
-				dam = (player:getInven("QUIVER")[1] and player:getInven("QUIVER")[1].combat) or o.basic_ammo
-			end
 			if mean and dam then
 				nl()
-				nl(("Accuracy(Off Hand): %3d"):format(player:combatAttack(mean)))
-				nl(("Damage  (Off Hand): %3d"):format(player:combatDamage(dam) * offmult))
-				nl(("APR     (Off Hand): %3d"):format(player:combatAPR(dam)))
-				nl(("Crit    (Off Hand): %3d%%"):format(player:combatCrit(dam)))
-				nl(("Speed   (Off Hand): %0.2f"):format(player:combatSpeed(mean)))
+				nl(("Damage    (Main Hand): %d"):format(player:getCombinedDamage(o, offmult)))
+				nl(("crit mult (Main Hand): %.1fx"):format(o.combat.critical_power))
+				nl(("Max acc   (Main Hand): %d"):format(o.combat.max_acc))
+				nl(("Sp. bonus (Main Hand): %d%%"):format((1 / player:combatSpeed(o.combat))*100 - 100))
+				nl(("APR       (Main Hand): %d"):format(player:combatAPR(dam)))
+				nl(("Crit      (Main Hand): %d%%"):format(player:combatCrit(dam)))
 			end
-			if mean and mean.range then strings[6] = ("Range (Off Hand): %3d"):format(mean.range) end
+			if mean and mean.range then strings[7] = ("Range (Off Hand): %d"):format(mean.range) end
 		end
 	end
 
diff --git a/game/modules/tome/dialogs/LevelupDialog.lua b/game/modules/tome/dialogs/LevelupDialog.lua
index 075a4d4277..bcad72a241 100644
--- a/game/modules/tome/dialogs/LevelupDialog.lua
+++ b/game/modules/tome/dialogs/LevelupDialog.lua
@@ -1186,9 +1186,6 @@ function _M:drawDialog(kind)
 
 			for i, o in ipairs(self.actor:getInven(self.actor.INVEN_MAINHAND)) do
 				local mean, dam = o.combat, o.combat
-				if o.archery and mean then
-					dam = (self.actor:getInven("QUIVER")[1] and self.actor:getInven("QUIVER")[1].combat) or o.basic_ammo
-				end
 				if mean and dam then
 					s:drawColorStringBlended(self.font, WeaponTxt, w, h, 255, 255, 255, true) h = h + self.font_h
 					if self.actor.use_psi_combat then
@@ -1196,7 +1193,7 @@ function _M:drawDialog(kind)
 					else
 						self:mouseTooltip(self.TOOLTIP_COMBAT_ATTACK, s:drawColorStringBlended(self.font, ("Accuracy    : #00ff00#%.1f"):format(self.actor:combatAttack(mean) - self.actor_dup:combatAttack(mean)), w, h, 255, 255, 255, true)) h = h + self.font_h
 					end
-					self:mouseTooltip(self.TOOLTIP_COMBAT_DAMAGE, s:drawColorStringBlended(self.font, ("Damage      : #00ff00#%.1f"):format(self.actor:combatDamage(dam) - self.actor_dup:combatDamage(dam)), w, h, 255, 255, 255, true)) h = h + self.font_h
+					self:mouseTooltip(self.TOOLTIP_COMBAT_DAMAGE, s:drawColorStringBlended(self.font, ("Damage      : #00ff00#%.1f"):format(self.actor:getCombinedDamage(o) - self.actor_dup:getCombinedDamage(o)), w, h, 255, 255, 255, true)) h = h + self.font_h
 					self:mouseTooltip(self.TOOLTIP_COMBAT_APR, s:drawColorStringBlended(self.font,    ("APR         : #00ff00#%.1f"):format(self.actor:combatAPR(dam) - self.actor_dup:combatAPR(dam)), w, h, 255, 255, 255, true)) h = h + self.font_h
 					self:mouseTooltip(self.TOOLTIP_COMBAT_CRIT, s:drawColorStringBlended(self.font,   ("Crit. chance: #00ff00#%.1f%%"):format(self.actor:combatCrit(dam) - self.actor_dup:combatCrit(dam)), w, h, 255, 255, 255, true)) h = h + self.font_h
 					self:mouseTooltip(self.TOOLTIP_COMBAT_SPEED, s:drawColorStringBlended(self.font,  ("Speed       : #00ff00#%.2f%%"):format((self.actor:combatSpeed(mean) - self.actor_dup:combatSpeed(mean))*100), w, h, 255, 255, 255, true)) h = h + self.font_h
@@ -1224,9 +1221,6 @@ function _M:drawDialog(kind)
 			local act_dup_offmult = self.actor_dup:getOffHandMult()
 			for i, o in ipairs(self.actor:getInven(self.actor.INVEN_OFFHAND)) do
 				local mean, dam = o.combat, o.combat
-				if o.archery and mean then
-					dam = (self.actor:getInven("QUIVER")[1] and self.actor:getInven("QUIVER")[1].combat) or o.basic_ammo
-				end
 				if mean and dam then
 					s:drawColorStringBlended(self.font, "#LIGHT_BLUE#Off Hand:", w, h, 255, 255, 255, true) h = h + self.font_h
 					if self.actor.use_psi_combat then
@@ -1234,7 +1228,7 @@ function _M:drawDialog(kind)
 					else
 						self:mouseTooltip(self.TOOLTIP_COMBAT_ATTACK, s:drawColorStringBlended(self.font, ("Accuracy    : #00ff00#%.1f"):format(self.actor:combatAttack(mean) - self.actor_dup:combatAttack(mean)), w, h, 255, 255, 255, true)) h = h + self.font_h
 					end
-					self:mouseTooltip(self.TOOLTIP_COMBAT_DAMAGE, s:drawColorStringBlended(self.font, ("Damage      : #00ff00#%.1f"):format(self.actor:combatDamage(dam) * act_offmult - self.actor_dup:combatDamage(dam) * act_dup_offmult), w, h, 255, 255, 255, true)) h = h + self.font_h
+					self:mouseTooltip(self.TOOLTIP_COMBAT_DAMAGE, s:drawColorStringBlended(self.font, ("Damage      : #00ff00#%.1f"):format(self.actor:getCombinedDamage(o) * act_offmult - self.actor_dup:getCombinedDamage(o) * act_dup_offmult), w, h, 255, 255, 255, true)) h = h + self.font_h
 					self:mouseTooltip(self.TOOLTIP_COMBAT_APR   , s:drawColorStringBlended(self.font, ("APR         : #00ff00#%.1f"):format(self.actor:combatAPR(dam) - self.actor_dup:combatAPR(dam)), w, h, 255, 255, 255, true)) h = h + self.font_h
 					self:mouseTooltip(self.TOOLTIP_COMBAT_CRIT  , s:drawColorStringBlended(self.font, ("Crit. chance: #00ff00#%.1f%%"):format(self.actor:combatCrit(dam) - self.actor_dup:combatCrit(dam)), w, h, 255, 255, 255, true)) h = h + self.font_h
 					self:mouseTooltip(self.TOOLTIP_COMBAT_SPEED , s:drawColorStringBlended(self.font, ("Speed       : #00ff00#%.2f%%"):format((self.actor:combatSpeed(mean) - self.actor_dup:combatSpeed(mean))*100), w, h, 255, 255, 255, true)) h = h + self.font_h
diff --git a/game/modules/tome/dialogs/SentientWeapon.lua b/game/modules/tome/dialogs/SentientWeapon.lua
new file mode 100644
index 0000000000..4b76c1a5f8
--- /dev/null
+++ b/game/modules/tome/dialogs/SentientWeapon.lua
@@ -0,0 +1,205 @@
+-- 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 th+e 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
+
+require "engine.class"
+
+local Dialog = require "engine.ui.Dialog"
+local ListColumns = require "engine.ui.ListColumns"
+local Textzone = require "engine.ui.Textzone"
+local TextzoneList = require "engine.ui.TextzoneList"
+local Separator = require "engine.ui.Separator"
+
+--local LevelupTalentsDialog = require "mod.dialogs.LevelupTalentsDialog"
+
+module(..., package.seeall, class.inherit(Dialog))
+
+local _points_text = "Points left: #00FF00#%d#WHITE#"
+
+function _M:init(actor, on_finish)
+	self.actor = actor.actor
+
+	self.o = actor.o
+	print("Incoming factory settings:", self.o.factory_settings.dam, self.o.factory_settings.critical_power, self.o.factory_settings.max_acc)
+	print("Incoming factory setting mins:", self.o.factory_settings.mins.dam, self.o.factory_settings.mins.critical_power, self.o.factory_settings.mins.max_acc)
+	print("Incoming factory setting maxes:", self.o.factory_settings.maxes.dam, self.o.factory_settings.maxes.critical_power, self.o.factory_settings.maxes.max_acc)
+	self.actor_dup = actor.actor:clone()
+	self.unused_stats = self.o.unused_stats
+	--Dialog.init(self, self.o.name, 500, 300)
+	Dialog.init(self, self.o.name, 300, 200)
+
+	self.sel = 1
+
+	self.c_tut = Textzone.new{width=math.floor(self.iw / 2 - 10), auto_height=true, no_color_bleed=true, text=[[
+Keyboard: #00FF00#up key/down key#FFFFFF# to select a stat; #00FF00#right key#FFFFFF# to increase stat; #00FF00#left key#FFFFFF# to decrease a stat.
+Mouse: #00FF00#Left click#FFFFFF# to increase a stat; #00FF00#right click#FFFFFF# to decrease a stat.
+]]}
+	self.c_desc = TextzoneList.new{width=math.floor(self.iw - 10), height=self.ih - self.c_tut.h - 20, no_color_bleed=true}
+	self.c_points = Textzone.new{width=math.floor(self.iw - 10), auto_height=true, no_color_bleed=true, text=_points_text:format(self.unused_stats)}
+
+	self.c_list = ListColumns.new{width=math.floor(self.iw - 10), height=self.ih - 10, all_clicks=true, columns={
+		{name="Stat", width=70, display_prop="name"},
+		{name="Value", width=30, display_prop="val"},
+	}, list={
+		{name="Damage", val=self.o.combat.dam, stat_id = "dam", delta = self.o.material_level},
+		{name="Critical power", val=self.o.combat.critical_power, stat_id = "critical_power", delta = 0.1},
+		{name="Maximum hit chance", val=self.o.combat.max_acc, stat_id = "max_acc", delta = 5},
+		--{name="Strength", val=self.actor:getStr(), stat_id=self.actor.STAT_STR},
+		--{name="Dexterity", val=self.actor:getDex(), stat_id=self.actor.STAT_DEX},
+		--{name="Magic", val=self.actor:getMag(), stat_id=self.actor.STAT_MAG},
+		--{name="Willpower", val=self.actor:getWil(), stat_id=self.actor.STAT_WIL},
+		--{name="Cunning", val=self.actor:getCun(), stat_id=self.actor.STAT_CUN},
+		--{name="Constitution", val=self.actor:getCon(), stat_id=self.actor.STAT_CON},
+	}, fct=function(item, _, v)
+		self:incStat(v == "left" and 1 or -1, item.stat_id)
+	--end, select=function(item, sel) self.sel = sel self.c_desc:switchItem(item, self.actor.stats_def[item.stat_id].description) end}
+	--end, select=function(item, sel) self.sel = sel game.logPlayer(game.player, "just selected %s", sel)  end}
+	--end, select=function(item, sel) self.sel = sel game.logPlayer(game.player, "just selected %s", item.stat_id)  end}
+	end, select=function(item, sel) self.sel = sel self.id = item.stat_id self.delta = item.delta end}
+	self:loadUI{
+		{left=0, top=0, ui=self.c_points},
+		--{left=5, top=self.c_points.h+5, ui=Separator.new{dir="vertical", size=math.floor(self.iw / 2) - 10}},
+		{left=0, top=self.c_points.h+15, ui=self.c_list},
+
+		--{hcenter=0, top=5, ui=Separator.new{dir="horizontal", size=self.ih - 10}},
+
+		--{right=0, top=self.c_tut.h + 20, ui=self.c_desc},
+		--{right=0, top=0, ui=self.c_tut},
+	}
+	self:setFocus(self.c_list)
+	self:setupUI()
+
+	self:update()
+
+	self.key:addBinds{
+		EXIT = function()
+			game:unregisterDialog(self)
+			self:finish()
+		end,
+	}
+end
+
+function _M:finish()
+	--if self.actor.unused_stats == self.unused_stats then return end
+--[=[	local reset = {}
+	for tid, act in pairs(self.actor.sustain_talents) do
+		if act then
+			local t = self.actor:getTalentFromId(tid)
+			if t.no_sustain_autoreset then
+				game.logPlayer(self.actor, "#LIGHT_BLUE#Warning: You have increased some of your statistics. Talent %s is actually sustained; if it is dependent on one of the stats you changed, you need to re-use it for the changes to take effect.", t.name)
+			else
+				reset[#reset+1] = tid
+			end
+		end
+	end
+	for i, tid in ipairs(reset) do
+		self.actor:forceUseTalent(tid, {ignore_energy=true, ignore_cd=true})
+		self.actor:forceUseTalent(tid, {ignore_energy=true, ignore_cd=true})
+	end
+	]=]
+end
+
+function _M:incStat(v, id)
+	print("inside incStat. self.sel is", self.sel)
+	print("inside incStat. id is", self.id)
+	local id = self.id
+	local delta = self.delta * v
+	if v == 1 then
+		if self.o.unused_stats <= 0 then
+			self:simplePopup("Not enough stat points", "You have no stat points left!")
+			return
+		end
+		if self.o.combat[id] >= self.o.factory_settings.maxes[id] then
+			self:simplePopup("Stat is at the maximum", "You can not increase this stat further!")
+			return
+		end
+	else
+		if self.o.combat[id] <= self.o.factory_settings.mins[id] then
+			self:simplePopup("Impossible", "You cannot take out more points!")
+			return
+		end
+		if self.o.combat[id] + delta <= 0 then
+			self:simplePopup("Impossible", "You cannot take out more points!")
+			return
+		end
+	end
+
+	local sel = self.sel
+	self.o.combat[id] = self.o.combat[id] + delta
+	if id == "dam" then 
+		for k, v in pairs(self.o.wielder["inc_damage"]) do
+			self.o.wielder["inc_damage"][k] = v + delta
+		end
+		if self.o.combat.of_breaching then
+			for k, v in pairs(self.o.wielder["resists_pen"]) do
+				self.o.wielder["resists_pen"][k] = v + (delta/2)
+			end
+		end
+		--update_secondary(self.o, delta/2, "resists_pen") 
+	end
+	--self.actor:incStat(sel, v)
+	self.o.unused_stats = self.o.unused_stats - v
+	self.c_list.list[sel].val = self.o.combat[id]
+	self.c_list:generate()
+	self.c_list.sel = sel
+	self.c_list:onSelect()
+	self.c_points.text = _points_text:format(self.o.unused_stats)
+	self.c_points:generate()
+	self:update()
+end
+
+--local function update_secondary(o, d, tab)
+--	for k, v in pairs(o.wielder[tab]) do
+--		o.wielder[tab][k] = v + d
+--	end
+--end
+
+function _M:update()
+	self.c_list.key:addBinds{
+		ACCEPT = function() self.key:triggerVirtual("EXIT") end,
+		MOVE_LEFT = function() self:incStat(-1) end,
+		MOVE_RIGHT = function() self:incStat(1) end,
+	}
+end
+
+function _M:drawDialog(s)
+	-- Description part
+	self:drawHBorder(s, self.iw / 2, 2, self.ih - 4)
+	local statshelp = ([[Keyboard: #00FF00#up key/down key#FFFFFF# to select a stat; #00FF00#right key#FFFFFF# to increase stat; #00FF00#left key#FFFFFF# to decrease a stat.
+Mouse: #00FF00#Left click#FFFFFF# to increase a stat; #00FF00#right click#FFFFFF# to decrease a stat.
+]]):splitLines(self.iw / 2 - 10, self.font)
+	local lines = self.actor.stats_def[self.sel].description:splitLines(self.iw / 2 - 10, self.font)
+	for i = 1, #statshelp do
+		s:drawColorStringBlended(self.font, statshelp[i], self.iw / 2 + 5, 2 + (i-1) * self.font:lineSkip())
+	end
+	for i = 1, #lines do
+		s:drawColorStringBlended(self.font, lines[i], self.iw / 2 + 5, 2 + (i + #statshelp + 1) * self.font:lineSkip())
+	end
+
+	-- Stats
+	s:drawColorStringBlended(self.font, "Stats points left: #00FF00#"..self.actor.unused_stats, 2, 2)
+	self:drawWBorder(s, 2, 20, 200)
+
+	self:drawSelectionList(s, 2, 25, self.font_h, {
+		"Strength", "Dexterity", "Magic", "Willpower", "Cunning", "Constitution"
+	}, self.sel)
+	self:drawSelectionList(s, 100, 25, self.font_h, {
+		self.actor:getStr(), self.actor:getDex(), self.actor:getMag(), self.actor:getWil(), self.actor:getCun(), self.actor:getCon(),
+	}, self.sel)
+	self.changed = false
+end
diff --git a/game/modules/tome/dialogs/UseTalents.lua b/game/modules/tome/dialogs/UseTalents.lua
index d6fda8102a..6b127f8b4b 100644
--- a/game/modules/tome/dialogs/UseTalents.lua
+++ b/game/modules/tome/dialogs/UseTalents.lua
@@ -33,7 +33,7 @@ function _M:init(actor)
 	Dialog.init(self, "Use Talents: "..actor.name, game.w * 0.8, game.h * 0.8)
 
 	self.c_tut = Textzone.new{width=math.floor(self.iw / 2 - 10), height=1, auto_height=true, no_color_bleed=true, text=[[
-You can bind a talent to a hotkey by pressing the corresponding hotkey while selecting a talent or by right-clicking on the talent.
+You can bind a non-passive talent to a hotkey by pressing the corresponding hotkey while selecting a talent or by right-clicking on the talent.
 Check out the keybinding screen in the game menu to bind hotkeys to a key (default is 1-0 plus control or shift).
 Right click or press '*' to configure.
 ]]}
@@ -119,7 +119,8 @@ end
 
 function _M:use(item, button)
 	if not item or not item.talent then return end
-
+	local t = self.actor:getTalentFromId(item.talent)
+	if t.mode == "passive" then return end
 	if button == "right" then
 		local list = {
 			{name="Unbind", what="unbind"},
@@ -127,7 +128,7 @@ function _M:use(item, button)
 			{name="Bind to middle mouse click (on a target)", what="middle"},
 		}
 
-		local t = self.actor:getTalentFromId(item.talent)
+		--local t = self.actor:getTalentFromId(item.talent)
 		if self.actor:isTalentAuto(t) then table.insert(list, 1, {name="Disable automatic use", what="auto-dis"})
 		else table.insert(list, 1, {name="Enable automatic use", what="auto-en"})
 		end
@@ -248,6 +249,9 @@ function _M:generateList()
 			elseif t.mode == "sustained" then
 				if self.actor:isTalentActive(t.id) then nodes = sustained end
 				status = self.actor:isTalentActive(t.id) and tstring{{"color", "YELLOW"}, "Sustaining"} or tstring{{"color", "LIGHT_GREEN"}, "Sustain"}
+			elseif t.mode == "passive" then
+				nodes = passives
+				status = tstring{{"color", "BLUE"}, "Passive"}
 			end
 
 			-- Pregenenerate icon with the Tiles instance that allows images
@@ -262,6 +266,7 @@ function _M:generateList()
 				desc=self.actor:getTalentFullDescription(t),
 				color=function() return {0xFF, 0xFF, 0xFF} end,
 				hotkey=function(item)
+					if t.mode == "passive" then return "" end
 					for i = 1, 12 * self.actor.nb_hotkey_pages do if self.actor.hotkey[i] and self.actor.hotkey[i][1] == "talent" and self.actor.hotkey[i][2] == item.talent then
 						return "H.Key "..i..""
 					end end
diff --git a/game/modules/tome/resolvers.lua b/game/modules/tome/resolvers.lua
index 5667020471..3e1be833e7 100644
--- a/game/modules/tome/resolvers.lua
+++ b/game/modules/tome/resolvers.lua
@@ -17,6 +17,8 @@
 -- Nicolas Casalini "DarkGod"
 -- darkgod@te4.org
 
+local Talents = require "engine.interface.ActorTalents"
+
 --- Resolves equipment creation for an actor
 function resolvers.equip(t)
 	return {__resolver="equip", __resolve_last=true, t}
@@ -243,25 +245,152 @@ function resolvers.calc.chatfeature(t, e)
 	return nil
 end
 
---- Random bonus based on level (sets the mbonus max level, we use 60 instead of 50 to get some forced randomness at high level)
+
 resolvers.mbonus_max_level = 90
 
---- Random bonus based on level and material quality
+--- Random bonus based on level and material quality. Contains standard inputs for rng.mbonus for each attribute found in egos.
+-- The reason for centralizing ego bonuses here is ease of balancing. If we decide that, for example, combat_physcrit is too abundant on egos in general, we can change the value in the atts table below and alter all egos simultaneously.
 resolvers.current_level = 1
-function resolvers.mbonus_material(max, add, pricefct)
-	return {__resolver="mbonus_material", max, add, pricefct}
+function resolvers.mbonus_material(att_name, mult, subtype_adjust, max, add, pricefct)
+	return {__resolver="mbonus_material", att_name, mult, subtype_adjust, max, add, pricefct}
 end
 function resolvers.calc.mbonus_material(t, e)
+	local att_name = t[1] or nil
 	local ml = e.material_level or 1
-	local v = math.ceil(rng.mbonus(t[1], resolvers.current_level, resolvers.mbonus_max_level) * ml / 5) + (t[2] or 0)
-
-	if e.cost and t[3] then
-		local ap, nv = t[3](e, v)
-		e.cost = e.cost + ap
-		v = nv or v
+	local v = 0
+	local atts = {
+		-- format is {max, add, factor1, factor2}
+		-- It's not necessary to have two factors, since they both get applied the same way. But they have two different purposes, and separating them makes things clearer.
+		
+	---COMBAT STATS
+		combat_atk = {8, 2},
+		combat_dam = {8, 2},
+		combat_spellpower = {8, 2},
+		combat_mindpower = {8, 2},
+		combat_def = {8, 2},
+		combat_def_ranged = {8, 2},
+		combat_physresist = {13, 2},
+		combat_spellresist = {13, 2},
+		combat_mentalresist = {13, 2},
+		save = {13, 2},
+	---OTHER
+		dam = {15, 5},
+		critical_power = {8, 2, 1, 0.1},
+		block = {95, 5},
+		physspeed = {3, 1, 5, 0.01},
+		learn_talent = {1, 1},
+		learn_talent_5 = {4, 1},
+		concussion = {5, 5, 10},
+		combat_apr = {2, 1, 5},
+		combat_physcrit = {4, 1},
+		combat_spellcrit = {4, 1},
+		combat_mindcrit = {4, 1},
+		combat_armor = {2, 1, 5},
+		combat_armor_hardiness = {2, 1, 5},
+		fatigue = {3, 1, 5, -1},
+		melee_project = {2, 1, 5},
+		inc_stats = {3, 1},
+		ranged_project = {5, 1, 5},
+		on_melee_hit = {2, 1, 5},
+		--resists = {1, 1, 25},
+		resists = {1, 1, 10},
+		rare_resists = {5, 5},
+		resists_cap = {2, 1, 5},
+		resists_pen = {2, 1, 5},
+		inc_damage = {5, 5},
+		damage_affinity = {3, 1, 10},
+		esp_range = {9, 1},
+		talents_types_mastery = {2, 2, 1, 0.1},
+		talent_on_hit_level = {4, 1},
+		talent_on_hit_chance = {3, 2, 10},
+		combat_critical_power = {1, 1, 1, 0.1},
+		disarm_bonus = {5, 1, 5},
+		trap_detect_power = {5, 1, 5},
+		inc_stealth = {2, 1, 5},
+		max_encumber = {3, 2, 10},
+		immunity = {1, 1, 10, 0.01},
+		life_regen = {3, 1, 5, 0.1},
+		stamina_regen = {4, 1, 1, 0.1},
+		mana_regen = {4, 1, 1, 0.1},
+		hate_regen = {3, 3, 1, 0.001},
+		stamina_regen_on_hit = {5, 2, 5, 0.1},
+		mana_regen_on_hit = {5, 2, 5, 0.1},
+		equilibrium_regen_on_hit = {5, 2, 5, 0.1},
+		mana_on_crit = {7, 1},
+		die_at = {7, 3, 10, -1},
+		max_life = {7, 3, 10},
+		max_mana = {5, 2, 10},
+		max_stamina = {3, 1, 10},
+		max_hate = {5, 5, 1, 0.1},
+		max_vim = {3, 1, 10},
+		max_air = {3, 1, 10},
+		lite = {1, 1},
+		infravision = {2, 1},
+		heightened_senses = {1, 1},
+		see_invisible = {3, 1, 5},
+		invisible = {9, 1},
+		movement_speed = {1, 1, 1, .1},
+		combat_physspeed = {3, 1, 5, 0.01},
+		combat_spellspeed = {3, 1, 5, 0.01},
+		healing_factor = {2, 1, 1, 0.1},
+		life_leech_chance = {9, 1},
+		life_leech_value = {2, 2, 5},
+		resource_leech_chance = {4, 1, 10},
+		resource_leech_value = {15, 5},
+		inc_damage_type = {1, 1, 25},
+		max_acc = {14, 1},
+		capacity = {7, 3},
+		ammo_regen = {3, 1},
+		cross_tier_bonus = {5, 5},
+		wards = {1, 1},
+
+--[=[	--Unused, but here in case we want individual immunities to have different numbers. Right now, all egos using immunities just use the "immunity" key above
+		blind_immune = {1.5, 1, 25, 0.01},
+		poison_immune = {1.5, 1, 25, 0.01},
+		disease_immune = {1.5, 1, 25, 0.01},
+		cut_immune = {1.5, 1, 25, 0.01},
+		silence_immune = {1.5, 1, 25, 0.01},
+		disarm_immune = {1.5, 1, 25, 0.01},
+		confusion_immune = {1.5, 1, 25, 0.01},
+		pin_immune = {1.5, 1, 25, 0.01},
+		stun_immune = {1.5, 1, 25, 0.01},
+		fear_immune = {1.5, 1, 25, 0.01},
+		knockback_immune = {1.5, 1, 25, 0.01},
+		instakill_immune = {1.5, 1, 25, 0.01},
+		teleport_immune = {1.5, 1, 25, 0.01},
+		]=]
+		
+	
+	}
+	if not atts[att_name] then return 0 end
+	local parity_fix = 1
+	if t[2] and t[2] < 0 then 
+		parity_fix = -1 
+	end
+	local subtype_adjust = 1
+	if t[3] then
+		if e.twohanded then subtype_adjust = 3
+		elseif e.subtype == "dagger" then subtype_adjust = 1
+		else subtype_adjust = 2
+		end
+	end
+	local max = (atts[att_name][1] or 0) * (t[2] or 1) * parity_fix * subtype_adjust
+	local add = (atts[att_name][2] or 0) * (t[2] or 1) * parity_fix
+	if t[4] and t[5] then 
+		v = math.ceil(rng.mbonus(t[4], resolvers.current_level, resolvers.mbonus_max_level) * ml / 5) + (t[5] or 0) 
+		if e.cost and t[6] then
+			local ap, nv = t[6](e, v)
+			e.cost = e.cost + ap
+			v = nv or v
+		end
+	else
+		local min = add * (atts[att_name][3] or 1) * (atts[att_name][4] or 1)
+		v = math.ceil(rng.mbonus(max, resolvers.current_level, resolvers.mbonus_max_level) * ml / 5) + (add or 0)
+		v = v * (atts[att_name][3] or 1) * (atts[att_name][4] or 1)
+		if v < min then v = min end
 	end
 
-	return v
+	return v * parity_fix
 end
 
 --- Random bonus based on level, more strict
@@ -306,6 +435,74 @@ function resolvers.calc.mbonus(t, e)
 	return v
 end
 
+--- Random, normally-distributed positive bonus used for combat attributes on weapons
+
+function resolvers.cbonus(base, max, factor, stand)
+	return {__resolver="cbonus", base, max, factor, stand}
+end
+function resolvers.calc.cbonus(t, e)
+	local base = t[1]
+	local max = t[2] or 2 * base
+	local factor = t[3] or 1
+	local stand = t[4] or (max - base) / 4
+	local val = util.bound(math.floor(rng.normal(base, stand)), base, max)
+	
+	--update name with flavors that reflect the object's power:
+	if not e.flavor_names then e.flavor_names = {e.subtype, e.subtype, e.subtype, e.subtype} end
+	if not e.flavor_name and e.subtype ~= "staff" then 
+		e.flavor_name = e.flavor_names[1] 
+		e.name = e.name:gsub(e.subtype, e.flavor_name) 
+	end
+	if val > base and e.subtype ~= "staff" then 
+		e.pow = (e.pow or 1) + 1
+		e.name = e.name:gsub(e.flavor_name or e.subtype, e.flavor_names[e.pow]) 
+		e.flavor_name = e.flavor_names[e.pow]
+	end
+	--fill quivers to capacity
+	if e.combat and e.combat.capacity then e.combat.shots_left = e.combat.capacity end
+	return val * factor
+end
+
+--Unused for now:
+function resolvers.w_name()
+	return {__resolver="w_name"}
+end
+function resolvers.calc.w_name(t, e)
+	--update name with flavors that reflect the object's power:
+	if e.subtype ~= "staff" then 
+		print("pow is", e.pow or 11)
+		if not e.flavor_names then e.flavor_names = {e.subtype, e.subtype, e.subtype, e.subtype} end
+		e.name = e.name:gsub(e.flavor_name or e.subtype, e.flavor_names[e.pow] or "error") 
+		e.flavor_name = e.flavor_names[e.pow]
+	end
+end
+
+--- give staves a flavor and appropriate damage type, as well as the command staff talent
+function resolvers.staff_wielder(name)
+	return {__resolver="staff_wielder", name}
+end
+function resolvers.calc.staff_wielder(t, e)
+	local staff_type = rng.table{2, 2, 2, 2, 3, 3, 3, 4, 4, 4}
+	e.flavor_name = e["flavor_names"][staff_type]
+	if staff_type == 2 then
+		e.combat.damtype = rng.table{engine.DamageType.FIRE, engine.DamageType.COLD, engine.DamageType.LIGHTNING, engine.DamageType.ARCANE}
+		e.modes = {"fire", "cold", "lightning", "arcane"}
+		e.name = e.name:gsub(" staff", " magestaff")
+	elseif staff_type == 3 then
+		e.combat.damtype = rng.table{engine.DamageType.LIGHT, engine.DamageType.DARKNESS, engine.DamageType.TEMPORAL}
+		e.modes = {"light", "darkness", "temporal"}
+		e.name = e.name:gsub(" staff", " starstaff")
+	elseif staff_type == 4 then
+		e.combat.damtype = rng.table{engine.DamageType.NATURE, engine.DamageType.BLIGHT, engine.DamageType.ACID}
+		e.modes = {"nature", "blight", "acid"}
+		e.name = e.name:gsub(" staff", " earthstaff")
+	end
+	return {
+		inc_damage = {[e.combat.damtype] = e.combat.dam},
+		learn_talent = {[Talents.T_COMMAND_STAFF] = e.material_level},
+	}
+end
+
 --- Generic resolver, takes a function, executes at the end
 function resolvers.genericlast(fct)
 	return {__resolver="genericlast", __resolve_last=true, fct}
-- 
GitLab