diff --git a/game/engines/default/engine/PlayerProfile.lua b/game/engines/default/engine/PlayerProfile.lua
index a248e749aa30851bbe45d85eae15eb786a5bc2aa..26b53d3a8603f448c49c5ebb9222ea10424ec397 100644
--- a/game/engines/default/engine/PlayerProfile.lua
+++ b/game/engines/default/engine/PlayerProfile.lua
@@ -203,7 +203,51 @@ end
 -- Events
 -----------------------------------------------------------------------
 
+function _M:waitEvent(name, cb)
+	-- Wait anwser, this blocks thegame but cant really be avoided :/
+	local stop = false
+	local first = true
+	while not stop do
+		if not first then core.game.sleep(50) end
+		local evt = core.profile.popEvent()
+		while evt do
+			if type(game) == "table" then evt = game:handleProfileEvent(evt)
+			else evt = self:handleEvent(evt) end
+--			print("==== waiting event", name, evt.e)
+			if evt.e == name then
+				stop = true
+				cb(evt)
+				break
+			end
+			evt = core.profile.popEvent()
+		end
+		first = false
+	end
+end
+
+function _M:waitFirstAuth(timeout)
+	if self.auth_tried and self.auth_tried >= 1 then return end
+	if not self.waiting_auth then return end
+	print("[PROFILE] waiting for first auth")
+	local first = true
+	timeout = timeout or 20
+	while self.waiting_auth and timeout > 0 do
+		if not first then core.game.sleep(50) end
+		local evt = core.profile.popEvent()
+		while evt do
+			if type(game) == "table" then game:handleProfileEvent(evt)
+			else self:handleEvent(evt) end
+			if not self.waiting_auth then break end
+			evt = core.profile.popEvent()
+		end
+		first = false
+		timeout = timeout - 1
+	end
+end
+
 function _M:eventAuth(e)
+	self.waiting_auth = false
+	self.auth_tried = (self.auth_tried or 0) + 1
 	if e.ok then
 		self.auth = e.ok:unserialize()
 		print("[PROFILE] Main thread got authed", self.auth.name, self.auth.email, self.auth.drupid)
@@ -263,11 +307,10 @@ function _M:getNews(callback)
 	core.profile.pushOrder("o='GetNews'")
 end
 
-function _M:tryAuth(sync)
+function _M:tryAuth()
 	print("[ONLINE PROFILE] auth")
 	core.profile.pushOrder(table.serialize{o="Login", l=self.login, p=self.pass})
---	if sync then
---	end
+	self.waiting_auth = true
 end
 
 function _M:logOut()
@@ -282,12 +325,14 @@ function _M:logOut()
 end
 
 function _M:getConfigs(module, cb)
+	self:waitFirstAuth()
 	if not self.auth then return end
 	self.evt_cbs.GetConfigs = cb
 	core.profile.pushOrder(table.serialize{o="GetConfigs", module=module})
 end
 
 function _M:setConfigs(module, name, val)
+	self:waitFirstAuth()
 	if not self.auth then return end
 	if name == "online" then return end
 	if type(val) ~= "string" then val = serialize(val) end
@@ -295,6 +340,7 @@ function _M:setConfigs(module, name, val)
 end
 
 function _M:syncOnline(module)
+	self:waitFirstAuth()
 	if not self.auth then return end
 	local sync = self.generic
 	if module ~= "generic" then sync = self.modules[module] end
@@ -307,27 +353,14 @@ function _M:syncOnline(module)
 end
 
 function _M:checkModuleHash(module, md5)
+do self.hash_valid = true return true end
 	self.hash_valid = false
 --	if not self.auth then return nil, "no online profile active" end
 	if config.settings.cheat then return nil, "cheat mode active" end
 	if game and game:isTainted() then return nil, "savefile tainted" end
 	core.profile.pushOrder(table.serialize{o="CheckModuleHash", module=module, md5=md5})
 
-	-- Wait anwser, this blocks thegame but cant really be avoided :/
-	local stop = false
-	local ok = false
-	while not stop do
-		local evt = core.profile.popEvent()
-		while evt do
-			evt = self:handleEvent(evt) -- Bypass game handling, there is none around at this point
-			if evt.e == "CheckModuleHash" then
-				ok = evt.ok
-				stop = true
-				break
-			end
-			evt = core.profile.popEvent()
-		end
-	end
+	self:waitEvent("CheckModuleHash", function(e) ok = e.ok end)
 
 	if not ok then return nil, "bad game version" end
 	print("[ONLINE PROFILE] module hash is valid")
@@ -335,16 +368,35 @@ function _M:checkModuleHash(module, md5)
 	return true
 end
 
---[[
 function _M:sendError(what, err)
 	print("[ONLINE PROFILE] sending error")
-	local popup = Dialog:simplePopup("Sending...", "Sending the error report. Thank you.", nil, true)
-	popup.__showup = nil
-	core.display.forceRedraw()
-	self:rpc{action="SendError", login=self.login, what=what, err=err, module=game.__mod_info.short_name, version=game.__mod_info.version_name}
-	game:unregisterDialog(popup)
+	core.profile.pushOrder(table.serialize{o="SendError", login=self.login, what=what, err=err, module=game.__mod_info.short_name, version=game.__mod_info.version_name})
 end
 
+function _M:registerNewCharacter(module)
+	if not self.auth or not self.hash_valid then return end
+	local dialog = Dialog:simplePopup("Registering character", "Character is being registered on http://te4.org/") dialog.__showup = nil core.display.forceRedraw()
+
+	core.profile.pushOrder(table.serialize{o="RegisterNewCharacter", module=module})
+	local uuid = nil
+	self:waitEvent("RegisterNewCharacter", function(e) uuid = e.uuid end)
+
+	game:unregisterDialog(dialog)
+	if not uuid then return end
+	print("[ONLINE PROFILE] new character UUID ", uuid)
+	return uuid
+end
+
+function _M:registerSaveChardump(module, uuid, title, tags, data)
+	if not self.auth or not self.hash_valid then return end
+	local dialog = Dialog:simplePopup("Uploading character data", "Character sheet is being uploaded to http://te4.org/") dialog.__showup = nil core.display.forceRedraw()
+	local data = self:rpc{action="SaveChardump", login=self.login, hash=self.auth.hash, module=module, uuid=uuid, title=title, tags=tags, data=data}
+	game:unregisterDialog(dialog)
+	if not data or not data.ok then return end
+	print("[ONLINE PROFILE] saved character ", uuid)
+end
+
+--[[
 function _M:newProfile(Login, Name, Password, Email)
 	print("[ONLINE PROFILE] profile options ", Login, Email, Name)
 	local data = self:rpc{action="NewProfile2", login=Login, email=Email, name=Name, pass=Password}
diff --git a/game/modules/tome/class/Game.lua b/game/modules/tome/class/Game.lua
index 801070f5e7c9583101367443df2fd4af93c3337f..7da4f75e1f2ff0da6e7ee127fdf26783f03230a2 100644
--- a/game/modules/tome/class/Game.lua
+++ b/game/modules/tome/class/Game.lua
@@ -802,6 +802,7 @@ function _M:setupCommands()
 --			self.nicer_tiles:postProcessLevelTiles(self.level)
 --			local m = game.zone:makeEntityByName(game.level, "actor", "NPC_COLD_DRAKE")
 --			game.zone:addEntity(game.level, m, "actor", game.player.x + 1, game.player.y + 1)
+			error("plop")
 		end end,
 	}
 
diff --git a/game/modules/tome/data/talents/cursed/cursed-form.lua b/game/modules/tome/data/talents/cursed/cursed-form.lua
index 0044dec6a2f2610d138cae2a025417bb3e059d1f..176d3bcaefda58efc1d9201dbc9bb62e495e30fa 100644
--- a/game/modules/tome/data/talents/cursed/cursed-form.lua
+++ b/game/modules/tome/data/talents/cursed/cursed-form.lua
@@ -21,6 +21,10 @@ local function getHateMultiplier(self, min, max)
 	return (min + ((max - min) * math.min(self.hate, 10) / 10))
 end
 
+local function combatTalentDamage(self, t, min, max)
+	return self:combatTalentSpellDamage(t, min, max, self.level + self:getWil())
+end
+
 newTalent{
 	name = "Unnatural Body",
 	type = {"cursed/cursed-form", 1},
@@ -34,20 +38,29 @@ newTalent{
 		return true
 	end,
 	getHealPerKill = function(self, t)
-		return math.sqrt(self:getTalentLevel(t)) * 15
+		return combatTalentDamage(self, t, 25, 100)
 	end,
 	getRegenRate = function(self, t)
-		return math.sqrt(self:getTalentLevel(t) * 2) * self.max_life * 0.008
+		return 3 + math.sqrt(self:getTalentLevel(t) * 2) * math.min(1000, self.max_life) * 0.006
 	end,
 	getResist = function(self, t)
 		return -18 + (self:getTalentLevel(t) * 3) + (18 * getHateMultiplier(self, 0, 1))
 	end,
 	do_regenLife  = function(self, t)
+		-- initialize
+		if (self.unnatural_body_healing_factor or 0) == 0 then
+			self.unnatural_body_healing_factor = -0.5
+			self.healing_factor = (self.healing_factor or 1) + self.unnatural_body_healing_factor
+		end
+	
 		-- heal
 		local maxHeal = self.unnatural_body_heal or 0
 		if maxHeal > 0 then
 			local heal = math.min(t.getRegenRate(self, t), maxHeal)
+			local temp = self.healing_factor
+			self.healing_factor = 1
 			self:heal(heal)
+			self.healing_factor = temp
 
 			self.unnatural_body_heal = math.max(0, (self.unnatural_body_heal or 0) - heal)
 		end
@@ -60,7 +73,7 @@ newTalent{
 	end,
 	on_kill = function(self, t, target)
 		if target and target.max_life then
-			heal = t.getHealPerKill(self, t) * 0.01 * target.max_life
+			heal = math.min(t.getHealPerKill(self, t), target.max_life)
 			if heal > 0 then
 				self.unnatural_body_heal = math.min(self.life, (self.unnatural_body_heal or 0) + heal)
 			end
@@ -74,7 +87,8 @@ newTalent{
 		local modifier1, modifier2 = "more", "more"
 		if resist > 0 then modifier1 = "less" end
 		if resist + 18 > 0 then modifier2 = "less" end
-		return ([[Your body's strength is fed by your hatred. With each kill you regenerate %d%% of your victim's life at a rate of %0.1f life per turn. You also take %d%% %s damage (at 0 Hate) to %d%% %s damage (at 10+ Hate).]]):format(healPerKill, regenRate, math.abs(resist), modifier1, math.abs(resist + 18), modifier2)
+		return ([[Your body's strength is fed by your hatred. With each kill you regenerate %d life at a rate of %0.1f life per turn. This healing cannot be reduced but most other forms of healing are reduced by 50%%. You also take %d%% %s damage (at 0 Hate) to %d%% %s damage (at 10+ Hate).
+		Healing from kills improves with the Willpower stat.]]):format(healPerKill, regenRate, math.abs(resist), modifier1, math.abs(resist + 18), modifier2)
 	end,
 }
 
@@ -125,10 +139,10 @@ newTalent{
 	random_ego = "utility",
 	require = cursed_wil_req2,
 	points = 5,
-	cooldown = 500,
+	cooldown = 400,
 	tactical = { BUFF = 1 },
 	getHateGain = function(self, t)
-		return (math.sqrt(self:getTalentLevel(t)) - 0.5) * 2.3
+		return (math.sqrt(self:getTalentLevel(t)) - 0.5) * 3
 	end,
 	action = function(self, t)
 		self:incHate(t.getHateGain(self, t))
diff --git a/game/modules/tome/data/talents/cursed/darkness.lua b/game/modules/tome/data/talents/cursed/darkness.lua
index 51dd4a84449db48e3bf82f1497bcc28a09938219..0168ef86d90a50ca79896307f64ba16aa5798acc 100644
--- a/game/modules/tome/data/talents/cursed/darkness.lua
+++ b/game/modules/tome/data/talents/cursed/darkness.lua
@@ -278,7 +278,7 @@ newTalent{
 		return 2 + math.floor(self:getTalentLevel(t))
 	end,
 	getDamage = function(self, t)
-		return combatTalentDamage(self, t, 18, 45)
+		return combatTalentDamage(self, t, 15, 70)
 	end,
 	action = function(self, t)
 		local range = self:getTalentRange(t)
@@ -342,10 +342,7 @@ newTalent{
 		return math.floor(2 + self:getTalentLevel(t) * 2)
 	end,
 	getDamageIncrease = function(self, t)
-		local level = self:getTalentLevel(t)
-		if level < 3 then return 0 end
-
-		return 5 + (level - 3) * 3
+		return combatTalentDamage(self, t, 5, 40)
 	end,
 	hasLOS = function(x1, y1, x2, y2)
 		local l = line.new(x1, y1, x2, y2)
@@ -360,11 +357,7 @@ newTalent{
 	end,
 	info = function(self, t)
 		local damageIncrease = t.getDamageIncrease(self, t)
-		if damageIncrease <= 0 then
-			return ([[Your eyes penetrate the darkness to find anyone that may be hiding there. You can also see through the creeping dark but not well enough to directly target someone. At level 3 you begin to do extra damage to anyone in the dark.]])
-		else
-			return ([[Your eyes penetrate the darkness to find anyone that may be hiding there. You can also see through the creeping dark but not well enough to directly target someone. You do %d%% more damage to anyone in the dark.]]):format(damageIncrease)
-		end
+		return ([[Your eyes penetrate the darkness to find anyone that may be hiding there. You can also see through the creeping dark but not well enough to directly target someone. You do %d%% more damage to anyone in the dark (or in creeping dark).]]):format(damageIncrease)
 	end,
 }
 
@@ -381,7 +374,7 @@ newTalent{
 	reflectable = true,
 	requires_target = true,
 	getDamage = function(self, t)
-		return combatTalentDamage(self, t, 20, 200)
+		return combatTalentDamage(self, t, 15, 250)
 	end,
 	action = function(self, t)
 		local tg = {type="beam", range=self:getTalentRange(t), talent=t}
@@ -433,10 +426,10 @@ newTalent{
 	direct_hit = true,
 	requires_target = true,
 	getPinDuration = function(self, t)
-		return 1 + math.floor(self:getTalentLevel(t) / 2)
+		return 2 + math.floor(self:getTalentLevel(t) / 2)
 	end,
 	getDamage = function(self, t)
-		return combatTalentDamage(self, t, 40, 80)
+		return combatTalentDamage(self, t, 30, 95)
 	end,
 	action = function(self, t)
 		if self.dark_tendrils then return false end
diff --git a/game/modules/tome/data/talents/cursed/endless-hunt.lua b/game/modules/tome/data/talents/cursed/endless-hunt.lua
index 3be15f62afa3ff27716f0dd7a114fb8505e2a8cb..8a36d106c5debd0de429f435a722484458a46ad7 100644
--- a/game/modules/tome/data/talents/cursed/endless-hunt.lua
+++ b/game/modules/tome/data/talents/cursed/endless-hunt.lua
@@ -56,7 +56,7 @@ newTalent{
 		if math.floor(core.fov.distance(self.x, self.y, x, y)) > 1 then return nil end
 
 		-- attempt domination
-		if checkWillFailure(self, target, 15, 85, 1) then
+		if checkWillFailure(self, target, 50, 90, 1) then
 			local damMult = 1 + self:combatTalentWeaponDamage(t, 0.1, 0.5)
 			target:setEffect(target.EFF_DOMINATED, 4, { dominatedSource = self, dominatedDamMult = damMult })
 		else
@@ -70,7 +70,7 @@ newTalent{
 	end,
 	info = function(self, t)
 		local damMult = 1 + self:combatTalentWeaponDamage(t, 0.1, 0.5)
-		return ([[Combine strength and will to overpower your opponent with a vicious attack. If your opponent fails to save versus willpower then all of your melee hits will do %d%% damage against them for for 4 turns.]]):format(damMult * 100)
+		return ([[Combine strength and will to overpower your opponent with a vicious attack. If your opponent fails to save versus willpower then all of your melee hits will do %d%% damage against them for for 4 turns. There is a 50%% chance of guaranteed success.]]):format(damMult * 100)
 	end,
 }
 
diff --git a/game/modules/tome/data/talents/cursed/force-of-will.lua b/game/modules/tome/data/talents/cursed/force-of-will.lua
index 79ba231536302f6c381cdb081b0751c5ee76ea98..33137624de47b5bf7a48cea587e788f0bd78dfd1 100644
--- a/game/modules/tome/data/talents/cursed/force-of-will.lua
+++ b/game/modules/tome/data/talents/cursed/force-of-will.lua
@@ -109,7 +109,7 @@ newTalent{
 		return 4
 	end,
 	getDamage = function(self, t)
-		return combatTalentDamage(self, t, 20, 200)
+		return combatTalentDamage(self, t, 15, 240)
 	end,
 	getKnockback = function(self, t)
 		return math.floor(self:getTalentLevel(t))
@@ -147,7 +147,7 @@ newTalent{
 	tactical = { DEFEND = 2 },
 	no_sustain_autoreset = true,
 	getMaxDamage = function(self, t)
-		return combatTalentDamage(self, t, 20, 200)
+		return combatTalentDamage(self, t, 15, 200)
 	end,
 	getDisplayName = function(self, t, p)
 		return ("Deflection (%d)"):format(p.value)
@@ -168,7 +168,7 @@ newTalent{
 		if p.value < maxDamage and self.hate >= 0.02 then
 			self:incHate(-0.02)
 
-			p.value = math.min(p.value + maxDamage / 50, maxDamage)
+			p.value = math.min(p.value + maxDamage / 35, maxDamage)
 
 			t.updateParticles(self, t, p)
 		end
@@ -208,7 +208,7 @@ newTalent{
 	require = cursed_wil_req3,
 	points = 5,
 	random_ego = "attack",
-	cooldown = 10,
+	cooldown = 14,
 	tactical = { ATTACK = 2 },
 	requires_target = true,
 	hate = 1.5,
@@ -219,11 +219,14 @@ newTalent{
 		return math.floor(2 + self:getTalentLevel(t) / 3)
 	end,
 	getDamage = function(self, t)
-		return combatTalentDamage(self, t, 20, 200)
+		return combatTalentDamage(self, t, 10, 300)
 	end,
 	getKnockback = function(self, t)
 		return 2 + math.floor(self:getTalentLevel(t))
 	end,
+	getDazeDuration = function(self, t)
+		return 3
+	end,
 	action = function(self, t)
 		local range = self:getTalentRange(t)
 		local radius = t.getRadius(self, t)
@@ -242,7 +245,12 @@ newTalent{
 					local distance = math.floor(core.fov.distance(blastX, blastY, x, y))
 					local power = (1 - (distance / radius))
 					local localDamage = damage * power
+					local dazeDuration = t.getDazeDuration(self, t)
+					
 					forceHit(self, target, blastX, blastY, damage, math.max(0, knockback - distance), 15, power)
+					if target:canBe("stun") then
+						target:setEffect(target.EFF_DAZED, dazeDuration, {src=self})
+					end
 				end
 			end,
 			nil, nil)
@@ -257,7 +265,8 @@ newTalent{
 		local radius = t.getRadius(self, t)
 		local damage = t.getDamage(self, t)
 		local knockback = t.getKnockback(self, t)
-		return ([[You rage coalesces at a single point and then explodes outward blasting enemies within a radius of %d in all directions. The blast causes %d damage and %d knockback at the center that decreases with distance.
+		local dazeDuration = t.getDazeDuration(self, t)
+		return ([[You rage coalesces at a single point and then explodes outward blasting enemies within a radius of %d in all directions. The blast causes %d damage and %d knockback at the center that decreases with distance. Anyone caught in the explosion will also be dazed for 3 turns.
 		Damage increases with the Willpower stat.]]):format(radius, damDesc(self, DamageType.PHYSICAL, damage), knockback)
 	end,
 }
@@ -277,7 +286,7 @@ newTalent{
 		return 5 + math.floor(self:getTalentLevel(t))
 	end,
 	getDamage = function(self, t)
-		return combatTalentDamage(self, t, 20, 160)
+		return combatTalentDamage(self, t, 10, 200)
 	end,
 	getKnockback = function(self, t)
 		return math.floor(self:getTalentLevel(t))
diff --git a/game/modules/tome/data/talents/cursed/gloom.lua b/game/modules/tome/data/talents/cursed/gloom.lua
index f053037a2c7c871e30cc9a9ff8f5d1ae1a885d66..91259b3a0cd63f6f7dc6322b7d71c7296c97a4a5 100644
--- a/game/modules/tome/data/talents/cursed/gloom.lua
+++ b/game/modules/tome/data/talents/cursed/gloom.lua
@@ -21,11 +21,8 @@ local function getHateMultiplier(self, min, max)
 	return (min + ((max - min) * math.min(self.hate, 10) / 10))
 end
 
-local function getWillDamage(self, t, base, max)
-	-- Compute at "max"
-	local mod = max / ((base + 100) * ((math.sqrt(5) - 1) * 0.8 + 1))
-	-- Compute real
-	return ((base + self:getWil()) * ((math.sqrt(self:getTalentLevel(t)) - 1) * 0.8 + 1) * mod) * 0.75
+local function combatTalentDamage(self, t, min, max)
+	return self:combatTalentSpellDamage(t, min, max, self.level + self:getWil())
 end
 
 local function checkWillFailure(self, target, minChance, maxChance, attackStrength)
@@ -162,14 +159,13 @@ newTalent{
 							--game:playSoundNear(self, "talents/spell_generic")
 							doTorment = false
 						else
-							game.logSeen(target, "#F53CBE#%s resists your torment.", target.name:capitalize())
+							game.logSeen(target, "#F53CBE#%s resists the torment.", target.name:capitalize())
 						end
 					end
 
 					-- Life Leech
 					if tLifeLeech and self:getTalentLevelRaw(tLifeLeech) > 0 then
-						local fraction = self:getTalentLevel(tLifeLeech) * 0.002
-						local damage = math.min(target.max_life * fraction, self.max_life * fraction * 2)
+						local damage = tLifeLeech.getDamage(self, tLifeLeech)
 						local actualDamage = DamageType:get(DamageType.LIFE_LEECH).projector(self, target.x, target.y, DamageType.LIFE_LEECH, damage)
 						lifeLeeched = lifeLeeched + actualDamage
 					end
@@ -183,7 +179,11 @@ newTalent{
 
 		-- life leech
 		if lifeLeeched > 0 then
+			lifeLeeched = math.min(lifeLeeched, tLifeLeech.getMaxHeal(self, tLifeLeech))
+			local temp = self.healing_factor
+			self.healing_factor = 1
 			self:heal(lifeLeeched)
+			self.healing_factor = temp
 			game.logPlayer(self, "#F53CBE#You leech %0.1f life from your foes.", lifeLeeched)
 		end
 	end,
@@ -222,7 +222,8 @@ newTalent{
 		local baseDamage = 30 + self:getWil() * 0.4 * self:getTalentLevel(t)
 		local attackStrength = 0.3 + self:getTalentLevel(t) * 0.12
 		local effectiveness = getWillFailureEffectiveness(self, 30, 95, attackStrength)
-		return ([[Your rage builds within you for 20 turns, then unleashes itself for %d (at 0 Hate) to %d (at 10+ Hate) darkness damage on the first one to enter your gloom. (%d effectiveness)]]):format(baseDamage * .5, baseDamage * 1.5, effectiveness)
+		return ([[Your rage builds within you for 20 turns, then unleashes itself for %d (at 0 Hate) to %d (at 10+ Hate) darkness damage on the first one to enter your gloom. (%d effectiveness)
+		Improves with the Willpower stat.]]):format(baseDamage * .5, baseDamage * 1.5, effectiveness)
 	end,
 }
 
@@ -232,7 +233,16 @@ newTalent{
 	mode = "passive",
 	require = cursed_wil_req4,
 	points = 5,
+	getDamage = function(self, t)
+		return combatTalentDamage(self, t, 3, 15)
+	end,
+	getMaxHeal = function(self, t)
+		return combatTalentDamage(self, t, 5, 30)
+	end,
 	info = function(self, t)
-		return ([[Each turn your gloom leeches up to %0.1f%% of the life of foes.]]):format(self:getTalentLevel(t) * 0.2)
+		local damage = t.getDamage(self, t)
+		local maxHeal = t.getMaxHeal(self, t)
+		return ([[Every turn you leech %0.1f life from each foe in your gloom restoring up to a total of %0.1f of your own life. This form of healing cannot be reduced.
+		Improves with the Willpower stat.]]):format(damage, maxHeal)
 	end,
 }
diff --git a/game/modules/tome/data/talents/cursed/punishments.lua b/game/modules/tome/data/talents/cursed/punishments.lua
index 7eed24bbca6a58af678377675abf291cb96b3406..1644d5d37db191d54b3a56386310b08bc32e5c8c 100644
--- a/game/modules/tome/data/talents/cursed/punishments.lua
+++ b/game/modules/tome/data/talents/cursed/punishments.lua
@@ -36,7 +36,7 @@ newTalent{
 	range = 2,
 	tactical = { ATTACKAREA = 2 },
 	getDamage = function(self, t)
-		return combatTalentDamage(self, t, 25, 240)
+		return combatTalentDamage(self, t, 10, 290)
 	end,
 	getMindpower = function(self, t)
 		return combatPower(self, t)
@@ -90,7 +90,7 @@ newTalent{
 		return 10
 	end,
 	getDamage = function(self, t)
-		return combatTalentDamage(self, t, 20, 100)
+		return combatTalentDamage(self, t, 15, 180)
 	end,
 	getMindpower = function(self, t)
 		return combatPower(self, t)
@@ -268,7 +268,7 @@ newTalent{
 		return 5
 	end,
 	getDamage = function(self, t)
-		return combatTalentDamage(self, t, 20, 110)
+		return combatTalentDamage(self, t, 15, 160)
 	end,
 	getMindpower = function(self, t)
 		return combatPower(self, t, 1.2)
diff --git a/game/modules/tome/data/talents/cursed/rampage.lua b/game/modules/tome/data/talents/cursed/rampage.lua
index 7c4fdb01df864d662aeca94f606e3f8404d1744f..23038e17eaec7061e9d327995c5e15d92f8dec79 100644
--- a/game/modules/tome/data/talents/cursed/rampage.lua
+++ b/game/modules/tome/data/talents/cursed/rampage.lua
@@ -106,7 +106,7 @@ newTalent{
 	end,
 	on_unlearn = function(self, t)
 	end,
-	getDuration = function(self, t) return 5 + math.floor(2 * self:getTalentLevel(t)) end,
+	getDuration = function(self, t) return 4 + math.floor(1 * self:getTalentLevel(t)) end,
 	getDamage = function(self, t) return 10 * self:getTalentLevel(t) end,
 	info = function(self, t)
 		local duration = t.getDuration(self, t)
diff --git a/game/profile-thread/Client.lua b/game/profile-thread/Client.lua
index 34d4f3c9d159333fcac7f1bf264dfca167cd35ad..503539c87f43004452ae9f96fd5495329c4815a7 100644
--- a/game/profile-thread/Client.lua
+++ b/game/profile-thread/Client.lua
@@ -145,6 +145,14 @@ function _M:orderSetConfigs(o)
 	end
 end
 
+function _M:orderSendError(o)
+	o = table.serialize(o)
+	self:command("ERR_", o:len())
+	if self:read("200") then
+		self.sock:send(o)
+	end
+end
+
 function _M:orderCheckModuleHash(o)
 	self:command("CMD5", o.md5, o.module)
 	if self:read("200") then
@@ -154,8 +162,17 @@ function _M:orderCheckModuleHash(o)
 	end
 end
 
+function _M:orderRegisterNewCharacter(o)
+	self:command("CHAR", "NEW", o.module)
+	if self:read("200") then
+		cprofile.pushEvent(string.format("e='RegisterNewCharacter' uuid=%q", self.last_line))
+	else
+		cprofile.pushEvent("e='RegisterNewCharacter' uuid=nil")
+	end
+end
+
 function _M:handleOrder(o)
-	if not self.sock then return end
 	o = o:unserialize()
+	if not self.sock and o.o ~= "Login" then return end -- Dont do stuff without a connection, unless we try to auth
 	if self["order"..o.o] then self["order"..o.o](self, o) end
 end
diff --git a/game/profile-thread/init.lua b/game/profile-thread/init.lua
index a138c998712b057c3e69c6ba32dc1727694337ff..50b44f33415ecdd1f1517e48e38328dd3cb330b5 100644
--- a/game/profile-thread/init.lua
+++ b/game/profile-thread/init.lua
@@ -23,7 +23,7 @@ local Client = require "profile-thread.Client"
 local c = Client.new()
 
 function step_profile()
-	local ok, res = pcall(function() return c:run() end, function(...) server:logError("[profile-thread-error:stacktrace] %s", debug.traceback(...)) end)
+	local ok, res = xpcall(function() return c:run() end, function(...) server:logError("[profile-thread-error:stacktrace] %s", debug.traceback(...)) end)
 	if not ok and res then
 		return false
 	end
diff --git a/ideas/DLCs.ods b/ideas/DLCs.ods
index ea4e54edd314e4e1feb2cff486d2f0a662656cb8..290b65c45112f19332fcf9cba5ae5bd464a4a30f 100644
Binary files a/ideas/DLCs.ods and b/ideas/DLCs.ods differ
diff --git a/ideas/setting.ods b/ideas/setting.ods
index f9382e977325382cdfbed1538815c003e679813b..6621723fed6c6b4644988db4446b51d401a4c397 100644
Binary files a/ideas/setting.ods and b/ideas/setting.ods differ