diff --git a/game/modules/tome/data/birth/classes/afflicted.lua b/game/modules/tome/data/birth/classes/afflicted.lua
index 2ee563e649a7c6665d37394698ea0ca01f49c9f7..01f9d06df0934d2b4a0020267f4c3ddf38be1552 100644
--- a/game/modules/tome/data/birth/classes/afflicted.lua
+++ b/game/modules/tome/data/birth/classes/afflicted.lua
@@ -107,7 +107,7 @@ newBirthDescriptor{
 	},
 	talents = {
 		[ActorTalents.T_UNNATURAL_BODY] = 1,
-		[ActorTalents.T_FEED_HATE] = 1,
+		[ActorTalents.T_FEED] = 1,
 		[ActorTalents.T_WILLFUL_STRIKE] = 1,
 	},
 	copy = {
diff --git a/game/modules/tome/data/damage_types.lua b/game/modules/tome/data/damage_types.lua
index 90ef988a7b6413e4cab1c16f7d869a433588c61d..7d2579e50059555aaefc2768e794bda6bd3995a5 100644
--- a/game/modules/tome/data/damage_types.lua
+++ b/game/modules/tome/data/damage_types.lua
@@ -111,6 +111,11 @@ setDefaultProjector(function(src, x, y, type, dam, tmp, no_martyr)
 
 		if target.knowTalent and target:knowTalent(target.T_RESOLVE) then local t = target:getTalentFromId(target.T_RESOLVE) t.on_absorb(target, t, type, dam) end
 
+		if not target.dead and dam > 0 and type == DamageType.MIND and src and src.knowTalent and src:knowTalent(src.T_MADNESS) then
+			local t = src:getTalentFromId(src.T_MADNESS)
+			t.doMadness(target, t, src)
+		end
+
 		return dam
 	end
 	return 0
diff --git a/game/modules/tome/data/gfx/particles/feed_hate.lua b/game/modules/tome/data/gfx/particles/feed_hate.lua
index 2d10b95609aadf2c82490c47c01d29602265a826..da4b3b74622d7fc67a0f1c5e8d884a7290018d48 100644
--- a/game/modules/tome/data/gfx/particles/feed_hate.lua
+++ b/game/modules/tome/data/gfx/particles/feed_hate.lua
@@ -45,7 +45,7 @@ return { generator = function()
 		r = 32 / 255, rv = 0, ra = 0,
 		g = 32 / 255, gv = 0, ga = 0,
 		b = 32 / 255, bv = 0, ba = 0,
-		a = rng.range(60, 120) / 255, av = 0, aa = 0,
+		a = rng.range(80, 150) / 255, av = 0, aa = 0,
 	}
 end, },
 function(self)
diff --git a/game/modules/tome/data/talents/cursed/dark-sustenance.lua b/game/modules/tome/data/talents/cursed/dark-sustenance.lua
index 96f14d6185343382959c52c527653963c18bd89b..de1f9a270a66a9e38f66613916b44835473ee3eb 100644
--- a/game/modules/tome/data/talents/cursed/dark-sustenance.lua
+++ b/game/modules/tome/data/talents/cursed/dark-sustenance.lua
@@ -18,19 +18,16 @@
 -- darkgod@te4.org
 
 newTalent{
-	name = "Feed Hate",
+	name = "Feed",
 	type = {"cursed/dark-sustenance", 1},
 	require = cursed_wil_req1,
 	points = 5,
 	random_ego = "attack",
-	cooldown = 8,
+	cooldown = 6,
 	range = 15,
 	requires_target = true,
 	getHateGain = function(self, t)
-		return self:getWil(0.3) + self:getTalentLevel(t) * 0.1
-	end,
-	getExtension = function(self, t)
-		return math.floor(self:getTalentLevel(t) - 1)
+		return math.sqrt(self:getTalentLevel(t)) * 0.2 + self:getWil(0.15)
 	end,
 	action = function(self, t)
 		local tg = {type="hit", range=self:getTalentRange(t)}
@@ -46,38 +43,48 @@ newTalent{
 		if self:hasEffect(self.EFF_FEED_HATE) then
 			self:removeEffect(self.EFF_FEED_HATE)
 		end
-
+		
 		local hateGain = t.getHateGain(self, t)
-		local extension = t.getExtension(self, t)
-		self:setEffect(self.EFF_FEED_HATE, 99999, { target=target, hateGain=hateGain, extension=extension })
+		local constitutionGain = 0
+		local lifeRegenGain = 0
+		local damageGain = 0
+		local resistGain = 0
+		
+		local tFeedHealth = self:getTalentFromId(self.T_FEED_HEALTH)
+		if tFeedHealth and self:getTalentLevelRaw(tFeedHealth) > 0 then
+			constitutionGain = tFeedHealth.getConstitutionGain(self, tFeedHealth, target)
+			lifeRegenGain = tFeedHealth.getLifeRegenGain(self, tFeedHealth)
+		end
+		
+		local tFeedPower = self:getTalentFromId(self.T_FEED_POWER)
+		if tFeedPower and self:getTalentLevelRaw(tFeedPower) > 0 then
+			damageGain = tFeedPower.getDamageGain(self, tFeedPower, target)
+		end
+		
+		local tFeedStrengths = self:getTalentFromId(self.T_FEED_STRENGTHS)
+		if tFeedStrengths and self:getTalentLevelRaw(tFeedStrengths) > 0 then
+			resistGain = tFeedStrengths.getResistGain(self, tFeedStrengths, target)
+		end
+
+		self:setEffect(self.EFF_FEED, 99999, { target=target, hateGain=hateGain, constitutionGain=constitutionGain, lifeRegenGain=lifeRegenGain, damageGain=damageGain, resistGain=resistGain, extension=0 })
 
 		return true
 	end,
 	info = function(self, t)
 		local hateGain = t.getHateGain(self, t)
-		local extension = t.getExtension(self, t)
-		local extensionText = ""
-		if extension > 0 then
-			return ([[Draws %0.2f hate per turn from a targeted foe as long as the foe remains in your line of sight. You will continue to gain hate for %d turns after the link is severed.
-			Improves with the Willpower stat.]]):format(hateGain, extension)
-		else
-			return ([[Draws %0.2f hate per turn from a targeted foe as long as the foe remains in your line of sight.
-			Improves with the Willpower stat.]]):format(hateGain)
-		end
+		return ([[Feed from the essence of your enemy. Draws %0.2f hate per turn from a targeted foe as long as the foe remains in your line of sight.
+		Improves with the Willpower stat.]]):format(hateGain)
 	end,
 }
 
 newTalent{
 	name = "Feed Health",
 	type = {"cursed/dark-sustenance", 2},
+	mode = "passive",
 	require = cursed_wil_req2,
 	points = 5,
-	random_ego = "attack",
-	cooldown = 8,
-	range = 15,
-	requires_target = true,
 	getConstitutionGain = function(self, t, target)
-		local gain = 2 + math.floor(self:getWil(18) * (0.3 + self:getTalentLevel(t) * 0.2))
+		local gain = math.floor((6 + self:getWil(6)) * math.sqrt(self:getTalentLevel(t)) * 0.392)
 		if target then
 			-- return capped gain
 			return math.min(gain, math.floor(target:getCon() * 0.75))
@@ -87,141 +94,47 @@ newTalent{
 		end
 	end,
 	getLifeRegenGain = function(self, t, target)
-		return self.max_life * (0.003 + self:getWil(0.005) + self:getTalentLevel(t) * 0.005)
-	end,
-	getExtension = function(self, t)
-		return math.floor(self:getTalentLevel(t) - 1)
-	end,
-	action = function(self, t)
-		local tg = { type="hit", range=self:getTalentRange(t) }
-		local x, y, target = self:getTarget(tg)
-		if not x or not y or not target then return nil end
-
-		if self:reactionToward(target) >= 0 or target.summoner == self then
-			game.logPlayer(self, "You can only gain sustenance from your foes!");
-			return nil
-		end
-
-		-- remove old effect
-		if self:hasEffect(self.EFF_FEED_HEALTH) then
-			self:removeEffect(self.EFF_FEED_HEALTH)
-		end
-
-		local constitutionGain = t.getConstitutionGain(self, t, target)
-		local lifeRegenGain = t.getLifeRegenGain(self, t)
-		local extension = t.getExtension(self, t)
-		self:setEffect(self.EFF_FEED_HEALTH, 99999, { target=target, constitutionGain=constitutionGain, lifeRegenGain=lifeRegenGain, extension=extension })
-
-		return true
+		return self.max_life * (math.sqrt(self:getTalentLevel(t)) * 0.012 + self:getWil(0.01))
 	end,
 	info = function(self, t)
 		local constitutionGain = t.getConstitutionGain(self, t)
 		local lifeRegenGain = t.getLifeRegenGain(self, t)
-		local extension = t.getExtension(self, t)
-		if extension > 0 then
-			return ([[Transfers %d constitution and %0.1f life per turn from a targeted foe to you as long as the foe remains in your line of sight. You will continue to gain life for %d turns after the link is severed.
-			Improves with the Willpower stat.]]):format(constitutionGain, lifeRegenGain, extension)
-		else
-			return ([[Transfers %d constitution and %0.1f life per turn from a targeted foe to you as long as the foe remains in your line of sight.
-			Improves with the Willpower stat.]]):format(constitutionGain, lifeRegenGain)
-		end
+		return ([[Enhances your feeding by transfering %d constitution and %0.1f life per turn from a targeted foe to you.
+		Improves with the Willpower stat.]]):format(constitutionGain, lifeRegenGain)
 	end,
 }
 
 newTalent{
 	name = "Feed Power",
 	type = {"cursed/dark-sustenance", 3},
+	mode = "passive",
 	require = cursed_wil_req3,
 	points = 5,
-	random_ego = "attack",
-	cooldown = 8,
-	range = 15,
-	requires_target = true,
 	getDamageGain = function(self, t)
-		return self:getWil(10) + self:getTalentLevel(t) * 5
-	end,
-	getExtension = function(self, t)
-		return math.floor(self:getTalentLevel(t) - 1)
-	end,
-	action = function(self, t)
-		local tg = { type="hit", range=self:getTalentRange(t) }
-		local x, y, target = self:getTarget(tg)
-		if not x or not y or not target then return nil end
-
-		if self:reactionToward(target) >= 0 or target.summoner == self then
-			game.logPlayer(self, "You can only gain sustenance from your foes!");
-			return nil
-		end
-
-		-- remove old effect
-		if self:hasEffect(self.EFF_FEED_POWER) then
-			self:removeEffect(self.EFF_FEED_POWER)
-		end
-
-		local damageGain = t.getDamageGain(self, t)
-		local extension = t.getExtension(self, t)
-		self:setEffect(self.EFF_FEED_POWER, 99999, { target=target, damageGain=damageGain, extension=extension })
-
-		return true
+		return math.sqrt(self:getTalentLevel(t)) * 5 + self:getWil(5)
 	end,
 	info = function(self, t)
 		local damageGain = t.getDamageGain(self, t)
-		local extension = t.getExtension(self, t)
-		if extension > 0 then
-			return ([[Reduces your targeted foe's damage by %d%% and increases yours by the same amount as long as the foe remains in your line of sight. You will continue to gain power for %d turns after the link is severed.
-			Improves with the Willpower stat.]]):format(damageGain, extension)
-		else
-			return ([[Reduces your targeted foe's damage by %d%% and increases yours by the same amount as long as the foe remains in your line of sight.
-			Improves with the Willpower stat.]]):format(damageGain)
-		end
+		return ([[Enhances your feeding by reducing your targeted foe's damage by %d%% and increasing yours by the same amount.
+		Improves with the Willpower stat.]]):format(damageGain)
 	end,
 }
 
 newTalent{
 	name = "Feed Strengths",
 	type = {"cursed/dark-sustenance", 4},
+	mode = "passive",
 	require = cursed_wil_req4,
 	points = 5,
-	random_ego = "attack",
-	cooldown = 8,
-	range = 15,
-	requires_target = true,
 	getResistGain = function(self, t)
-		return 20 + self:getWil(10) + self:getTalentLevel(t) * 7
+		return math.sqrt(self:getTalentLevel(t)) * 22 + self:getWil(15)
 	end,
 	getExtension = function(self, t)
 		return math.floor(self:getTalentLevel(t) - 1)
 	end,
-	action = function(self, t)
-		local tg = { type="hit", range=self:getTalentRange(t) }
-		local x, y, target = self:getTarget(tg)
-		if not x or not y or not target then return nil end
-
-		if self:reactionToward(target) >= 0 or target.summoner == self then
-			game.logPlayer(self, "You can only gain sustenance from your foes!");
-			return nil
-		end
-
-		-- remove old effect
-		if self:hasEffect(self.EFF_FEED_STRENGTHS) then
-			self:removeEffect(self.EFF_FEED_STRENGTHS)
-		end
-
-		local resistGain = t.getResistGain(self, t)
-		local extension = t.getExtension(self, t)
-		self:setEffect(self.EFF_FEED_STRENGTHS, 99999, { target=target, resistGain=resistGain, extension=extension })
-
-		return true
-	end,
 	info = function(self, t)
 		local resistGain = t.getResistGain(self, t)
-		local extension = t.getExtension(self, t)
-		if extension > 0 then
-			return ([[Reduces your targeted foe's positive resistances by %d%% and increases yours by the same amount as long as the foe remains in your line of sight. You will continue to gain power for %d turns after the link is severed.
-			Improves with the Willpower stat.]]):format(resistGain, extension)
-		else
-			return ([[Reduces your targeted foes positive resistances by %d%% and increases yours by the same amount as long as the foe remains in your line of sight.
-			Improves with the Willpower stat.]]):format(resistGain)
-		end
+		return ([[Enhances your feeding by reducing your targeted foe's positive resistances by %d%% and increasing yours by the same amount.
+		Improves with the Willpower stat.]]):format(resistGain)
 	end,
 }
diff --git a/game/modules/tome/data/talents/cursed/darkness.lua b/game/modules/tome/data/talents/cursed/darkness.lua
index 8442675cea2ded118cb9933e98a66d550b3388c8..acb4ac363a310ad96ef828260cfc302ab9f6171b 100644
--- a/game/modules/tome/data/talents/cursed/darkness.lua
+++ b/game/modules/tome/data/talents/cursed/darkness.lua
@@ -19,130 +19,13 @@
 
 local Object = require "engine.Object"
 local Map = require "engine.Map"
-local canCreep, doCreep, createDark
 
 local function combatTalentDamage(self, t, min, max)
 	return self:combatTalentSpellDamage(t, min, max, self.level + self:getMag())
 end
 
-function canCreep(x, y, ignoreCreepingDark)
-	-- not on map
-	if not game.level.map:isBound(x, y) then return false end
-	 -- already dark
-	 if not ignoreCreepingDark then
-		if game.level.map:checkAllEntities(x, y, "creepingDark") then return false end
-	end
-	 -- allow objects and terrain to block, but not actors
-	if game.level.map:checkAllEntities(x, y, "block_move") and not game.level.map(x, y, Map.ACTOR) then return false end
-
-	return true
-end
-
-function doCreep(self, useCreep)
-	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 not (x == self.x and y == self.y) and canCreep(x, y) then
-			-- add new dark
-			local newCreep
-			if useCreep then
-				 -- transfer some of our creep to the new dark
-				newCreep = math.ceil(self.creep / 2)
-				self.creep = self.creep - newCreep
-			else
-				-- just clone our creep
-				newCreep = self.creep
-			end
-			createDark(self.summoner, x, y, self.damage, self.originalDuration, newCreep, self.creepChance, 0)
-			return true
-		end
-
-		-- nowhere to creep
-		return false
-	end
-end
-
-function createDark(summoner, x, y, damage, duration, creep, creepChance, initialCreep)
-	local e = Object.new{
-		name = "creeping dark",
-		block_sight=true,
-		canAct = false,
-		canCreep = true,
-		x = x, y = y,
-		damage = damage,
-		originalDuration = duration,
-		duration = duration,
-		creep = creep,
-		creepChance = creepChance,
-		summoner = summoner,
-		summoner_gain_exp = true,
-		act = function(self)
-			local Map = require "engine.Map"
-
-			self:useEnergy()
-
-			-- apply damage to anything inside the darkness
-			local actor = game.level.map(self.x, self.y, Map.ACTOR)
-			if actor and actor ~= self.summoner and (not actor.summoner or actor.summoner ~= self.summoner) then
-				self.summoner:project(actor, actor.x, actor.y, engine.DamageType.DARKNESS, self.damage)
-				--DamageType:get(DamageType.DARKNESS).projector(self.summoner, actor.x, actor.y, DamageType.DARKNESS, damage)
-			end
-
-			if self.duration <= 0 then
-				-- remove
-				if self.particles then game.level.map:removeParticleEmitter(self.particles) end
-				game.level.map:remove(self.x, self.y, Map.TERRAIN+3)
-				game.level:removeEntity(self)
-				--game.level.map:redisplay()
-			else
-				self.duration = self.duration - 1
-
-				if self.canCreep and self.creep > 0 and rng.percent(self.creepChance) then
-					if not doCreep(self, true) then
-						-- doCreep failed..pass creep on to a neighbor and stop creeping
-						self.canCreep = false
-						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 not (x == self.x and y == self.y) and canCreep(x, y) then
-								local dark = game.level.map:checkAllEntities(x, y, "creepingDark")
-								if dark and dark.canCreep then
-									-- transfer creep
-									dark.creep = dark.creep + self.creep
-									self.creep = 0
-									return
-								end
-							end
-						end
-					end
-				end
-			end
-		end,
-	}
-	e.creepingDark = e -- used for checkAllEntities to return the dark Object itself
-	game.level:addEntity(e)
-	game.level.map(x, y, Map.TERRAIN+3, e)
-
-	-- add particles
-	e.particles = Particles.new("creeping_dark", 1, { })
-	e.particles.x = x
-	e.particles.y = y
-	game.level.map:addParticleEmitter(e.particles)
-
-	-- do some initial creeping
-	while initialCreep > 0 do
-		if not doCreep(e, false) then
-			e.canCreep = false
-			e.initialCreep = 0
-			break
-		end
-		initialCreep = initialCreep - 1
-	end
-end
-
 local function createDarkTendrils(summoner, x, y, target, damage, duration, pinDuration)
+	if not summoner:getTalentFromId(summoner.T_CREEPING_DARKNESS) then return end
 
 	local e = Object.new{
 		name = "dark tendril",
@@ -163,6 +46,8 @@ local function createDarkTendrils(summoner, x, y, target, damage, duration, pinD
 			local done = false
 			local hitTarget = false
 
+			local tCreepingDarkness = self.summoner:getTalentFromId(summoner.T_CREEPING_DARKNESS)
+			
 			if self.finalizing then
 				if self.duration <= 0 or self.target.dead or self.x ~= self.target.x or self.y ~= self.target.y then
 					game.logSeen(self, "The dark tendrils dissipate.")
@@ -181,7 +66,7 @@ local function createDarkTendrils(summoner, x, y, target, damage, duration, pinD
 				for i = start, start + 8 do
 					local nextX = self.x + (i % 3) - 1
 					local nextY = self.y + math.floor((i % 9) / 3) - 1
-					if not (nextX == self.x and nextY == self.y) and canCreep(nextX, nextY, true) then
+					if not (nextX == self.x and nextY == self.y) and tCreepingDarkness.canCreep(nextX, nextY, true) then
 						local distance = core.fov.distance(nextX, nextY, target.x, target.y)
 						if distance < bestDistance then
 							bestDistance, bestX, bestY = distance, nextX, nextY
@@ -193,7 +78,7 @@ local function createDarkTendrils(summoner, x, y, target, damage, duration, pinD
 				if bestX and bestY then
 					self.x, self.y = bestX, bestY
 					if not game.level.map:checkAllEntities(self.x, self.y, "creepingDark") then
-						createDark(self.summoner, self.x, self.y, damage, 3, 2, 33, 0)
+						tCreepingDarkness.createDark(self.summoner, self.x, self.y, damage, 3, 2, 33, 0)
 					end
 
 					if self.x == target.x and self.y == target.y then
@@ -218,7 +103,7 @@ local function createDarkTendrils(summoner, x, y, target, damage, duration, pinD
 				if dark then
 					dark.duration = math.max(dark.duration, self.pinDuration + 1)
 					for i = 1, 4 do
-						if rng.chance(50) then doCreep(dark, false) end
+						if rng.chance(50) then tCreepingDarkness.doCreep(tCreepingDarkness, dark, false) end
 					end
 				end
 
@@ -263,6 +148,128 @@ newTalent{
 	hate = 1.5,
 	range = 5,
 	requires_target = true,
+	
+	-- implementation of creeping darkness..used in various locations, but stored here
+	canCreep = function(x, y, ignoreCreepingDark)
+		-- not on map
+		if not game.level.map:isBound(x, y) then return false end
+		 -- already dark
+		 if not ignoreCreepingDark then
+			if game.level.map:checkAllEntities(x, y, "creepingDark") then return false end
+		end
+		 -- allow objects and terrain to block, but not actors
+		if game.level.map:checkAllEntities(x, y, "block_move") and not game.level.map(x, y, Map.ACTOR) then return false end
+
+		return true
+	end,
+	doCreep = function(tCreepingDarkness, self, useCreep)
+		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 not (x == self.x and y == self.y) and tCreepingDarkness.canCreep(x, y) then
+				-- add new dark
+				local newCreep
+				if useCreep then
+					 -- transfer some of our creep to the new dark
+					newCreep = math.ceil(self.creep / 2)
+					self.creep = self.creep - newCreep
+				else
+					-- just clone our creep
+					newCreep = self.creep
+				end
+				tCreepingDarkness.createDark(self.summoner, x, y, self.damage, self.originalDuration, newCreep, self.creepChance, 0)
+				return true
+			end
+
+			-- nowhere to creep
+			return false
+		end
+	end,
+	createDark = function(summoner, x, y, damage, duration, creep, creepChance, initialCreep)
+		local e = Object.new{
+			name = "creeping dark",
+			block_sight=true,
+			canAct = false,
+			canCreep = true,
+			x = x, y = y,
+			damage = damage,
+			originalDuration = duration,
+			duration = duration,
+			creep = creep,
+			creepChance = creepChance,
+			summoner = summoner,
+			summoner_gain_exp = true,
+			act = function(self)
+				local Map = require "engine.Map"
+
+				self:useEnergy()
+
+				-- apply damage to anything inside the darkness
+				local actor = game.level.map(self.x, self.y, Map.ACTOR)
+				if actor and actor ~= self.summoner and (not actor.summoner or actor.summoner ~= self.summoner) then
+					self.summoner:project(actor, actor.x, actor.y, engine.DamageType.DARKNESS, self.damage)
+					--DamageType:get(DamageType.DARKNESS).projector(self.summoner, actor.x, actor.y, DamageType.DARKNESS, damage)
+				end
+
+				if self.duration <= 0 then
+					-- remove
+					if self.particles then game.level.map:removeParticleEmitter(self.particles) end
+					game.level.map:remove(self.x, self.y, Map.TERRAIN+3)
+					game.level:removeEntity(self)
+					--game.level.map:redisplay()
+				else
+					self.duration = self.duration - 1
+					
+					local tCreepingDarkness = self.summoner:getTalentFromId(self.summoner.T_CREEPING_DARKNESS)
+					
+					if self.canCreep and self.creep > 0 and rng.percent(self.creepChance) then
+						if not tCreepingDarkness.doCreep(tCreepingDarkness, self, true) then
+							-- doCreep failed..pass creep on to a neighbor and stop creeping
+							self.canCreep = false
+							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 not (x == self.x and y == self.y) and tCreepingDarkness.canCreep(x, y) then
+									local dark = game.level.map:checkAllEntities(x, y, "creepingDark")
+									if dark and dark.canCreep then
+										-- transfer creep
+										dark.creep = dark.creep + self.creep
+										self.creep = 0
+										return
+									end
+								end
+							end
+						end
+					end
+				end
+			end,
+		}
+		e.creepingDark = e -- used for checkAllEntities to return the dark Object itself
+		game.level:addEntity(e)
+		game.level.map(x, y, Map.TERRAIN+3, e)
+
+		-- add particles
+		e.particles = Particles.new("creeping_dark", 1, { })
+		e.particles.x = x
+		e.particles.y = y
+		game.level.map:addParticleEmitter(e.particles)
+
+		-- do some initial creeping
+		if initialCreep > 0 then
+			local tCreepingDarkness = self.summoner:getTalentFromId(summoner.T_CREEPING_DARKNESS)
+			while initialCreep > 0 do
+				if not tCreepingDarkness.doCreep(tCreepingDarkness, e, false) then
+					e.canCreep = false
+					e.initialCreep = 0
+					break
+				end
+				initialCreep = initialCreep - 1
+			end
+		end
+	end,
+	
 	getRadius = function(self, t)
 		return 3
 	end,
@@ -287,7 +294,7 @@ newTalent{
 		local locations = {}
 		for darkX = x - dist, x + dist do
 			for darkY = y - dist, y + dist do
-				if canCreep(darkX, darkY) then
+				if t.canCreep(darkX, darkY) then
 					locations[#locations+1] = {darkX, darkY}
 				end
 			end
@@ -300,7 +307,7 @@ newTalent{
 			local selection = rng.range(i, #locations)
 			locations[i], locations[selection] = locations[selection], locations[i]
 
-			createDark(self, locations[i][1], locations[i][2], damage, 8, 4, 70, 0)
+			t.createDark(self, locations[i][1], locations[i][2], damage, 8, 4, 70, 0)
 		end
 
 		game:playSoundNear(self, "talents/breath")
@@ -348,7 +355,7 @@ newTalent{
 	points = 5,
 	random_ego = "attack",
 	hate = 0.8,
-	cooldown = 3,
+	cooldown = 6,
 	tactical = {
 		ATTACK = 10,
 	},
diff --git a/game/modules/tome/data/talents/cursed/punishments.lua b/game/modules/tome/data/talents/cursed/punishments.lua
index 8546a93a5f5f32af6c708fdc34c4fea16ee4a12a..59f65b248c2a54b67e200be6630bfc4078858081 100644
--- a/game/modules/tome/data/talents/cursed/punishments.lua
+++ b/game/modules/tome/data/talents/cursed/punishments.lua
@@ -195,7 +195,7 @@ newTalent{
 	require = cursed_wil_req3,
 	points = 5,
 	random_ego = "attack",
-	cooldown = 3,
+	cooldown = 6,
 	hate =  0.5,
 	range = 12,
 	getDuration = function(self, t)
@@ -234,6 +234,54 @@ newTalent{
 	end,
 }
 
+newTalent{
+	name = "Madness",
+	type = {"cursed/punishments", 4},
+	mode = "passive",
+	require = cursed_wil_req4,
+	points = 5,
+	getMindpower = function(self, t)
+		return math.sqrt(self:getTalentLevel(t)) * 0.4 * combatPower(self, t)
+	end,
+	getChance = function(self, t)
+		return 25
+	end,
+	doMadness = function(self, t, src)
+		local mindpower = t.getMindpower(src, t)
+		local chance = t.getChance(src, t)
+		
+		if self and src and self:reactionToward(src) < 0 and self:checkHit(mindpower, self:combatMentalResist(), 0, chance, 5) then
+			local effect = rng.range(1, 3)
+			if effect == 1 then
+				-- confusion
+				if self:canBe("confusion") and not self:hasEffect(self.EFF_MADNESS_CONFUSED) then
+					self:setEffect(self.EFF_MADNESS_CONFUSED, 2, {power=70})
+					hit = true
+				end
+			elseif effect == 2 then
+				-- stun
+				if self:canBe("stun") and not self:hasEffect(self.EFF_MADNESS_STUNNED) then
+					self:setEffect(self.EFF_MADNESS_STUNNED, 2, {})
+					hit = true
+				end
+			elseif effect == 3 then
+				-- slow
+				if self:canBe("slow") and not self:hasEffect(self.EFF_MADNESS_SLOW) then
+					self:setEffect(self.EFF_MADNESS_SLOW, 2, {power=0.3})
+					hit = true
+				end
+			end
+		end
+	end,
+	info = function(self, t)
+		local mindpower = t.getMindpower(self, t)
+		local chance = t.getChance(self, t)
+		return ([[Every time you inflict mental damage there is a %d%% chance that your foe must save against your mindpower or go mad. Madness can briefly cause them to become confused, slowed or stunned. (%d mindpower vs mental resistance).
+		The mindpower will increase with the Willpower stat.]]):format(chance, mindpower)
+	end,
+}
+
+--[[
 newTalent{
 	name = "Tortured Sanity",
 	type = {"cursed/punishments", 4},
@@ -265,7 +313,7 @@ newTalent{
 				local target = game.level.map(x, y, Map.ACTOR)
 				if target and self:reactionToward(target) < 0 then
 					if target:canBe("stun") and rng.percent(chance) then
-						if target:checkHit(self:combatMindpower(), target:combatMentalResist(), 0, 95, 5) then
+						if target:checkHit(mindpower, target:combatMentalResist(), 0, 95, 5) then
 							target:setEffect(target.EFF_DAZED, duration, {src=self})
 							game.level.map:particleEmitter(x, y, 1, "cursed_ground", {})
 						else
@@ -282,8 +330,8 @@ newTalent{
 		local mindpower = t.getMindpower(self, t)
 		local duration = t.getDuration(self, t)
 		local chance = t.getChance(self, t)
-		return ([[Your will reaches into the minds of all nearby enemies and tortures their sanity. Anyone within range who fails a mental save has a %d%% chance of being dazed for %d turns (%d mindpower vs mental resistance).
-		The mindpower will increase with the Willpower stat.]]):format(chance, duration, mindpower)
+		return ([Your will reaches into the minds of all nearby enemies and tortures their sanity. Anyone within range who fails a mental save has a %d%% chance of being dazed for %d turns (%d mindpower vs mental resistance).
+		The mindpower will increase with the Willpower stat.]):format(chance, duration, mindpower)
 	end,
 }
-
+]]
diff --git a/game/modules/tome/data/timed_effects.lua b/game/modules/tome/data/timed_effects.lua
index 018d59dee2805526728fcbe0c46ed06297fc07b2..5a132ce26b803f98f512276b88ee67e1ccd20eb9 100644
--- a/game/modules/tome/data/timed_effects.lua
+++ b/game/modules/tome/data/timed_effects.lua
@@ -368,7 +368,7 @@ newEffect{
 newEffect{
 	name = "DAZED",
 	desc = "Dazed",
-	long_desc = function(self, eff) return "The target is dazed, redering it unable to act. Any damage will remove the daze." end,
+	long_desc = function(self, eff) return "The target is dazed, rendering it unable to act. Any damage will remove the daze." end,
 	type = "physical",
 	status = "detrimental",
 	parameters = {},
@@ -1564,7 +1564,7 @@ newEffect{
 newEffect{
 	name = "GLOOM_STUNNED",
 	desc = "Stunned by the gloom",
-	long_desc = function(self, eff) return "The gloom has stunned the target, redering it unable to act." end,
+	long_desc = function(self, eff) return "The gloom has stunned the target, rendering it unable to act." end,
 	type = "mental",
 	status = "detrimental",
 	parameters = {},
@@ -2354,245 +2354,74 @@ newEffect{
 }
 
 newEffect{
-	name = "FEED_HATE",
-	desc = "Feeding Hate",
-	long_desc = function(self, eff) return ("%s is feeding %0.2f hate from %s."):format(self.name:capitalize(), eff.hateGain, eff.target.name) end,
+	name = "FEED",
+	desc = "Feeding",
+	long_desc = function(self, eff) return ("%s is feeding from %s."):format(self.name:capitalize(), eff.target.name) end,
 	type = "mental",
 	status = "beneficial",
 	parameters = { },
 	activate = function(self, eff)
-		eff.hateGainId = self:addTemporaryValue("hate_regen", eff.hateGain)
-
-		eff.extension = eff.extension or 0
-		eff.isSevered = false
-	end,
-	deactivate = function(self, eff)
-		if eff.hateGainId then self:removeTemporaryValue("hate_regen", eff.hateGainId) end
-
-		if eff.particles then
-			-- remove old particle emitter
-			eff.particles.x = nil
-			eff.particles.y = nil
-			game.level.map:removeParticleEmitter(eff.particles)
-			eff.particles = nil
+		-- hate
+		if eff.hateGain and eff.hateGain > 0 then
+			eff.hateGainId = self:addTemporaryValue("hate_regen", eff.hateGain)
 		end
-	end,
-	on_timeout = function(self, eff)
-		if eff.isSevered then
-			eff.extension = eff.extension - 1
-			if eff.extension <= 0 then
-				self:removeEffect(self.EFF_FEED_HATE)
-			end
-		elseif eff.target.dead or not self:hasLOS(eff.target.x, eff.target.y) then
-			eff.isSevered = true
-
-			if eff.particles then
-				-- remove old particle emitter
-				eff.particles.x = nil
-				eff.particles.y = nil
-				game.level.map:removeParticleEmitter(eff.particles)
-				eff.particles = nil
-			end
-
-			if eff.extension <= 0 then
-				self:removeEffect(self.EFF_FEED_HATE)
-			end
-		else
-			if eff.particles then
-				-- remove old particle emitter
-				eff.particles.x = nil
-				eff.particles.y = nil
-				game.level.map:removeParticleEmitter(eff.particles)
-			end
-			-- add updated particle emitter
-			local dx, dy = eff.target.x - self.x, eff.target.y - self.y
-			eff.particles = Particles.new("feed_hate", math.max(math.abs(dx), math.abs(dy)), { tx=dx, ty=dy })
-			eff.particles.x = self.x
-			eff.particles.y = self.y
-			game.level.map:addParticleEmitter(eff.particles)
-		end
-	end,
-}
-
-newEffect{
-	name = "FEED_HEALTH",
-	desc = "Feeding Health",
-	long_desc = function(self, eff)
-		if eff.lifeRegenGain and eff.lifeRegenGain > 0 then
-			return ("#Target# is feeding %d constitution and %0.1f life per turn from %s."):format(eff.constitutionGain, eff.lifeRegenGain, eff.target.name)
-		else
-			return ("#Target# is feeding %d constitution from %s."):format(eff.constitutionGain, eff.target.name)
+		
+		-- health
+		if eff.constitutionGain and eff.constitutionGain > 0 then
+			eff.constitutionGainId = self:addTemporaryValue("inc_stats",
+			{
+				[Stats.STAT_CON] = eff.constitutionGain,
+			})
+			eff.constitutionLossId = eff.target:addTemporaryValue("inc_stats",
+			{
+				[Stats.STAT_CON] = -eff.constitutionGain,
+			})
 		end
-	end,
-	type = "mental",
-	status = "beneficial",
-	parameters = { },
-	activate = function(self, eff)
-		eff.constitutionGainId = self:addTemporaryValue("inc_stats",
-		{
-			[Stats.STAT_CON] = eff.constitutionGain,
-		})
-		eff.constitutionLossId = eff.target:addTemporaryValue("inc_stats",
-		{
-			[Stats.STAT_CON] = -eff.constitutionGain,
-		})
-
 		if eff.lifeRegenGain and eff.lifeRegenGain > 0 then
 			eff.lifeRegenGainId = self:addTemporaryValue("life_regen", eff.lifeRegenGain)
 			eff.lifeRegenLossId = eff.target:addTemporaryValue("life_regen", -eff.lifeRegenGain)
 		end
-
-		eff.extension = eff.extension or 0
-		eff.isSevered = false
-	end,
-	deactivate = function(self, eff)
-		if eff.constitutionGainId then self:removeTemporaryValue("inc_stats", eff.constitutionGainId) end
-		if eff.constitutionLossId then eff.target:removeTemporaryValue("inc_stats", eff.constitutionLossId) end
-		if eff.lifeRegenGainId then self:removeTemporaryValue("life_regen", eff.lifeRegenGainId) end
-		if eff.lifeRegenLossId then eff.target:removeTemporaryValue("life_regen", eff.lifeRegenLossId) end
-
-		if eff.particles then
-			-- remove old particle emitter
-			eff.particles.x = nil
-			eff.particles.y = nil
-			game.level.map:removeParticleEmitter(eff.particles)
-			eff.particles = nil
+		
+		-- power
+		if eff.damageGain and eff.damageGain > 0 then
+			eff.damageGainId = self:addTemporaryValue("inc_damage", {all=eff.damageGain})
+			eff.damageLossId = eff.target:addTemporaryValue("inc_damage", {all=eff.damageLoss})
 		end
-	end,
-	on_timeout = function(self, eff)
-		if eff.isSevered then
-			eff.extension = eff.extension - 1
-			if eff.extension <= 0 then
-				self:removeEffect(self.EFF_FEED_HEALTH)
-			end
-		elseif eff.target.dead or not self:hasLOS(eff.target.x, eff.target.y) then
-			eff.isSevered = true
-
-			if eff.particles then
-				-- remove old particle emitter
-				eff.particles.x = nil
-				eff.particles.y = nil
-				game.level.map:removeParticleEmitter(eff.particles)
-				eff.particles = nil
+		
+		-- strengths
+		if eff.resistGain and eff.resistGain > 0 then
+			local gainList = {}
+			local lossList = {}
+			for id, resist in pairs(eff.target.resists) do
+				if resist > 0 then
+					local amount = eff.resistGain * 0.01 * resist
+					gainList[id] = amount
+					lossList[id] = -amount
+				end
 			end
 
-			eff.target:removeTemporaryValue("inc_stats", eff.constitutionLossId)
-			eff.constitutionLossId = nil
-			eff.target:removeTemporaryValue("life_regen", eff.lifeRegenLossId)
-			eff.lifeRegenLossId = nil
-
-			if eff.extension <= 0 then
-				self:removeEffect(self.EFF_FEED_HEALTH)
-			end
-		else
-			if eff.particles then
-				-- remove old particle emitter
-				eff.particles.x = nil
-				eff.particles.y = nil
-				game.level.map:removeParticleEmitter(eff.particles)
-			end
-			-- add updated particle emitter
-			local dx, dy = eff.target.x - self.x, eff.target.y - self.y
-			eff.particles = Particles.new("feed_health", math.max(math.abs(dx), math.abs(dy)), { tx=dx, ty=dy })
-			eff.particles.x = self.x
-			eff.particles.y = self.y
-			game.level.map:addParticleEmitter(eff.particles)
+			eff.resistGainId = self:addTemporaryValue("resists", gainList)
+			eff.resistLossId = eff.target:addTemporaryValue("resists", lossList)
 		end
-	end,
-}
 
-newEffect{
-	name = "FEED_POWER",
-	desc = "Feeding Power",
-	long_desc = function(self, eff)
-		return ("%s is feeding %d%% increased damage from %s."):format(self.name:capitalize(), eff.damageGain, eff.target.name)
-	end,
-	type = "mental",
-	status = "beneficial",
-	parameters = { },
-	activate = function(self, eff)
-		eff.damageGainId = self:addTemporaryValue("inc_damage", {all=eff.damageGain})
-		eff.damageLossId = eff.target:addTemporaryValue("inc_damage", {all=eff.damageLoss})
 		eff.extension = eff.extension or 0
 		eff.isSevered = false
 	end,
 	deactivate = function(self, eff)
+		-- hate
+		if eff.hateGainId then self:removeTemporaryValue("hate_regen", eff.hateGainId) end
+		
+		-- health
+		if eff.constitutionGainId then self:removeTemporaryValue("inc_stats", eff.constitutionGainId) end
+		if eff.constitutionLossId then eff.target:removeTemporaryValue("inc_stats", eff.constitutionLossId) end
+		if eff.lifeRegenGainId then self:removeTemporaryValue("life_regen", eff.lifeRegenGainId) end
+		if eff.lifeRegenLossId then eff.target:removeTemporaryValue("life_regen", eff.lifeRegenLossId) end
+		
+		-- power
 		if eff.damageGainId then self:removeTemporaryValue("inc_damage", eff.damageGainId) end
 		if eff.damageLossId then eff.target:removeTemporaryValue("inc_damage", eff.damageLossId) end
-
-		if eff.particles then
-			-- remove old particle emitter
-			eff.particles.x = nil
-			eff.particles.y = nil
-			game.level.map:removeParticleEmitter(eff.particles)
-			eff.particles = nil
-		end
-	end,
-	on_timeout = function(self, eff)
-		if eff.isSevered then
-			eff.extension = eff.extension - 1
-			if eff.extension <= 0 then
-				self:removeEffect(self.EFF_FEED_POWER)
-			end
-		elseif eff.target.dead or not self:hasLOS(eff.target.x, eff.target.y) then
-			eff.isSevered = true
-
-			if eff.particles then
-				-- remove old particle emitter
-				eff.particles.x = nil
-				eff.particles.y = nil
-				game.level.map:removeParticleEmitter(eff.particles)
-				eff.particles = nil
-			end
-
-			eff.target:removeTemporaryValue("inc_damage", eff.damageLossId)
-			eff.damageLossId = nil
-
-			if eff.extension <= 0 then
-				self:removeEffect(self.EFF_FEED_POWER)
-			end
-		else
-			if eff.particles then
-				-- remove old particle emitter
-				eff.particles.x = nil
-				eff.particles.y = nil
-				game.level.map:removeParticleEmitter(eff.particles)
-			end
-			-- add updated particle emitter
-			local dx, dy = eff.target.x - self.x, eff.target.y - self.y
-			eff.particles = Particles.new("feed_power", math.max(math.abs(dx), math.abs(dy)), { tx=dx, ty=dy })
-			eff.particles.x = self.x
-			eff.particles.y = self.y
-			game.level.map:addParticleEmitter(eff.particles)
-		end
-	end,
-}
-
-newEffect{
-	name = "FEED_STRENGTHS",
-	desc = "Feeding Strengths",
-	long_desc = function(self, eff) return ("%s is feeding %d%% or resistances %s."):format(self.name:capitalize(), eff.resistGain, eff.target.name) end,
-	type = "mental",
-	status = "beneficial",
-	parameters = { },
-	activate = function(self, eff)
-		local gainList = {}
-		local lossList = {}
-		for id, resist in pairs(eff.target.resists) do
-			if resist > 0 then
-				local amount = eff.resistGain * 0.01 * resist
-				gainList[id] = amount
-				lossList[id] = -amount
-			end
-		end
-
-		eff.resistGainId = self:addTemporaryValue("resists", gainList)
-		eff.resistLossId = eff.target:addTemporaryValue("resists", lossList)
-
-		eff.extension = eff.extension or 0
-		eff.isSevered = false
-	end,
-	deactivate = function(self, eff)
+		
+		-- strengths
 		if eff.resistGainId then self:removeTemporaryValue("resists", eff.resistGainId) end
 		if eff.resistLossId then eff.target:removeTemporaryValue("resists", eff.resistLossId) end
 
@@ -2608,7 +2437,7 @@ newEffect{
 		if eff.isSevered then
 			eff.extension = eff.extension - 1
 			if eff.extension <= 0 then
-				self:removeEffect(self.EFF_FEED_STRENGTHS)
+				self:removeEffect(self.EFF_FEED)
 			end
 		elseif eff.target.dead or not self:hasLOS(eff.target.x, eff.target.y) then
 			eff.isSevered = true
@@ -2621,11 +2450,8 @@ newEffect{
 				eff.particles = nil
 			end
 
-			if eff.resistLossId then eff.target:removeTemporaryValue("resists", eff.resistLossId) end
-			eff.resistLossId = nil
-
 			if eff.extension <= 0 then
-				self:removeEffect(self.EFF_FEED_STRENGTHS)
+				self:removeEffect(self.EFF_FEED)
 			end
 		else
 			if eff.particles then
@@ -2636,7 +2462,7 @@ newEffect{
 			end
 			-- add updated particle emitter
 			local dx, dy = eff.target.x - self.x, eff.target.y - self.y
-			eff.particles = Particles.new("feed_strengths", math.max(math.abs(dx), math.abs(dy)), { tx=dx, ty=dy })
+			eff.particles = Particles.new("feed_hate", math.max(math.abs(dx), math.abs(dy)), { tx=dx, ty=dy })
 			eff.particles.x = self.x
 			eff.particles.y = self.y
 			game.level.map:addParticleEmitter(eff.particles)
@@ -2688,6 +2514,68 @@ newEffect{
 	end,
 }
 
+newEffect{
+	name = "MADNESS_SLOW",
+	desc = "Slowed by madness",
+	long_desc = function(self, eff) return ("Madness reduces the target's global speed by %d%%."):format((1 / (1 - eff.power) - 1) * 100) end,
+	type = "mental",
+	status = "detrimental",
+	parameters = { power=0.1 },
+	on_gain = function(self, err) return "#F53CBE##Target# slows in the grip of madness!", "+Slow" end,
+	on_lose = function(self, err) return "#Target# overcomes the madness.", "-Slow" end,
+	activate = function(self, eff)
+		eff.particle = self:addParticles(Particles.new("gloom_slow", 1))
+		eff.tmpid = self:addTemporaryValue("energy", {mod=-eff.power})
+		eff.dur = self:updateEffectDuration(eff.dur, "slow")
+	end,
+	deactivate = function(self, eff)
+		self:removeTemporaryValue("energy", eff.tmpid)
+		self:removeParticles(eff.particle)
+	end,
+}
+
+newEffect{
+	name = "MADNESS_STUNNED",
+	desc = "Stunned by madness",
+	long_desc = function(self, eff) return "Madness has stunned the target, rendering it unable to act." end,
+	type = "mental",
+	status = "detrimental",
+	parameters = {},
+	on_gain = function(self, err) return "#F53CBE##Target# is paralyzed by madness!", "+Stunned" end,
+	on_lose = function(self, err) return "#Target# overcomes the madness", "-Stunned" end,
+	activate = function(self, eff)
+		eff.particle = self:addParticles(Particles.new("gloom_stunned", 1))
+		eff.tmpid = self:addTemporaryValue("stunned", 1)
+		-- Start the stun counter only if this is the first stun
+		if self.stunned == 1 then self.stunned_counter = (self:attr("stun_immune") or 0) * 100 end
+		eff.dur = self:updateEffectDuration(eff.dur, "stun")
+	end,
+	deactivate = function(self, eff)
+		self:removeParticles(eff.particle)
+		self:removeTemporaryValue("stunned", eff.tmpid)
+		if not self:attr("stunned") then self.stunned_counter = nil end
+	end,
+}
+
+newEffect{
+	name = "MADNESS_CONFUSED",
+	desc = "Confused by madness",
+	long_desc = function(self, eff) return ("Madness has confused the target, making it act randomly (%d%% chance) and unable to perform complex actions."):format(eff.power) end,
+	type = "mental",
+	status = "detrimental",
+	parameters = {},
+	on_gain = function(self, err) return "#F53CBE##Target# is lost in madness!", "+Confused" end,
+	on_lose = function(self, err) return "#Target# overcomes the madness", "-Confused" end,
+	activate = function(self, eff)
+		eff.particle = self:addParticles(Particles.new("gloom_confused", 1))
+		eff.tmpid = self:addTemporaryValue("confused", eff.power)
+		eff.dur = self:updateEffectDuration(eff.dur, "confusion")
+	end,
+	deactivate = function(self, eff)
+		self:removeParticles(eff.particle)
+		self:removeTemporaryValue("confused", eff.tmpid)
+	end,
+}
 
 newEffect{
 	name = "TOTALITY",
diff --git a/game/modules/tome/data/zones/vor-pride/npcs.lua b/game/modules/tome/data/zones/vor-pride/npcs.lua
index 82b629477f928002007436765abfe9a456a8d5d0..8ec80fec15b52e3f8cad9d4411b087e0491acfff 100644
--- a/game/modules/tome/data/zones/vor-pride/npcs.lua
+++ b/game/modules/tome/data/zones/vor-pride/npcs.lua
@@ -52,7 +52,7 @@ newEntity{ base="BASE_NPC_ORC_VOR", define_as = "VOR",
 	},
 	resolvers.drops{chance=100, nb=1, {defined="ORB_ELEMENTS"} },
 	resolvers.drops{chance=20, nb=1, {defined="JEWELER_TOME"} },
-	resolvers.drops{chance=1020, nb=1, {defined="NOTE_LORE"} },
+	resolvers.drops{chance=100, nb=1, {defined="NOTE_LORE"} },
 	resolvers.drops{chance=100, nb=5, {ego_chance=100} },
 
 	resolvers.talents{
diff --git a/game/xmpp/init.lua b/game/xmpp/init.lua
index 3d544f5f24283144065ca6cd2f425e81eb54c71d..98076226639784149252aa42e7f628743e58599d 100644
--- a/game/xmpp/init.lua
+++ b/game/xmpp/init.lua
@@ -1,56 +1,6 @@
-print("XMPP thread starting...")
+print("TE4Online starting...")
 
-local jid, password = "test@online.te4.org", "test"
+require "socket"
 
-require "verse" -- Verse main library
-require "verse.client" -- XMPP client library
-
--- We always connect at least to the general channel
-local channels = { general = true }
-
-c = verse.new()
-c:add_plugin("version")
-c:add_plugin("disco")
-c:add_plugin("pep")
-
--- Add some hooks for debugging
-c:hook("opened", function()
-	print("Stream opened!")
-end)
-c:hook("closed", function()
-	print("Stream closed!")
-end)
-c:hook("stanza", function(stanza)
---	print("Stanza:", stanza)
-end)
-
--- This one prints all received data
---c:hook("incoming-raw", print, 1000)
-
--- Print a message after authentication
-c:hook("authentication-success", function() print("Logged in!") end)
-c:hook("authentication-failure", function(err) print("Failed to log in! Error: "..tostring(err.condition)) end)
-
--- Print a message and exit when disconnected
-c:hook("disconnected", function()
-	print("Disconnected!")
-end)
-
--- Now, actually start the connection:
-c:connect_client(jid, password)
-
--- Catch the "ready" event to know when the stream is ready to use
-c:hook("ready", function()
-	print("Stream ready!")
-	c.version:set{name = "T-Engine4 XMPP Client"}
-
-	c:hook_pep("http://jabber.org/protocol/te4chat", function(event)
-		if channels[event.item.tags[1][1]] then
-			print(event.from, "says", event.item.tags[2][1])
-		end
---		core.xmpp.
-	end)
-	c:send(verse.presence():add_child(c:caps()))
-end)
-
-verse.loop()
+local sock = socket.connect("te4.org", 5122)
+if not sock then return end