Page 1 of 1

Geomancers

Posted: Fri Oct 22, 2010 7:51 pm
by edge2054
Alright going to break this down into a few separate posts for ease of editing.

Class

Code: Select all

newBirthDescriptor{
	type = "subclass",
	name = "Geomancer",
	desc = {
		"A Geomancer is an archmage specialized in earth and stone magic.",
		"They gain access to the special Stone talents whose main purpose is to crush and destroy.",
		"They can even learn to pierce through physical resistance and immunity.",
		"Most archmagi lack basic skills that others take for granted (like general fighting sense), but they make up for it by their raw magical power.",
		"Archmagi know all schools of magic but the more intricate (Temporal and Meta) from the start. They however usually refuse to have anything to do with Necromancy.",
		"All archmagi have been trained in the secret town of Angolwen and posses a unique spell to teleport to it directly.",
		"Their most important stats are: Magic and Willpower",
		"#GOLD#Stats modifiers:",
		"#LIGHT_BLUE# * +0 Strength, +0 Dexterity, +0 Constitution",
		"#LIGHT_BLUE# * +5 Magic, +3 Willpower, +1 Cunning",
	},
	stats = { mag=5, wil=3, cun=1, },
	talents_types = {
		["spell/arcane"]={true, 0.2},
		["spell/earth"]={true, 0.3},
		["spell/stone"]={true, 0.4},
		["spell/water"]={true, 0.2},
		["spell/phantasm"]={true, 0.3},
		["spell/temporal"]={false, 0.3},
		["spell/meta"]={false, 0.3},
		["spell/divination"]={true, 0.3},
		["spell/conveyance"]={true, 0.3},
		["cunning/survival"]={false, -0.1},
	},
	talents = {
		[ActorTalents.T_ARCANE_POWER] = 1,
		[ActorTalents.T_STONE_SKIN] = 1,
		[ActorTalents.T_STALACTITIC_MISSILES] = 1,
		[ActorTalents.T_PHASE_DOOR] = 1,
		[ActorTalents.T_TELEPORT_ANGOLWEN]=1,
	},
	copy = {
		-- All mages are of angolwen faction
		faction = "angolwen",
		max_life = 90,
		life_rating = -4,
		resolvers.equip{ id=true,
			{type="weapon", subtype="staff", name="elm staff", autoreq=true},
			{type="armor", subtype="cloth", name="linen robe", autoreq=true},
		},
		resolvers.inventory{ id=true,
			{type="potion", subtype="potion", name="potion of lesser mana", ego_chance=-1000},
			{type="potion", subtype="potion", name="potion of lesser mana", ego_chance=-1000},
		},
	},
}

Re: Geomancers

Posted: Fri Oct 22, 2010 11:23 pm
by edge2054
Talents

talents\spells\stone

Code: Select all

newTalent{
	name = "Stalactitic Missiles",
	type = {"spell/stone",1},
	require = spells_req1,
	points = 5,
	random_ego = "attack",
	mana = 10,
	cooldown = 3,
	tactical = {
		ATTACK = 10,
	},
	range = 20,
	direct_hit = true,
	reflectable = true,
	proj_speed = 20,
	requires_target = true,
	action = function(self, t)
		local tg = {type="bolt", range=self:getTalentRange(t), talent=t, display={particle="stone_shards", trail="earthtrail"}}
		local x, y = self:getTarget(tg)
		if not x or not y then return nil end
		self:projectile(tg, x, y, DamageType.SPLIT_BLEED, self:spellCrit(self:combatTalentSpellDamage(t, 15, 120)), nil)
		game:playSoundNear(self, "talents/earth")
		--missile #2
		local tg2 = {type="bolt", range=self:getTalentRange(t), talent=t, display={particle="stone_shards", trail="earthtrail"}}
		local x, y = self:getTarget(tg2)
		if not x or not y then return nil end
		self:projectile(tg2, x, y, DamageType.SPLIT_BLEED, self:spellCrit(self:combatTalentSpellDamage(t, 15, 120)), nil)
		game:playSoundNear(self, "talents/earth")
		--missile #3 (Talent Level 4 Bonus Missile)
		if self:getTalentLevel(t) >= 5 then 
			local tg3 = {type="bolt", range=self:getTalentRange(t), talent=t, display={particle="stone_shards", trail="earthtrail"}}
			local x, y = self:getTarget(tg3)
			if not x or not y then return nil end
			self:projectile(tg3, x, y, DamageType.SPLIT_BLEED, self:spellCrit(self:combatTalentSpellDamage(t, 15, 120)), nil)
			game:playSoundNear(self, "talents/earth")
		else end
		return true
	end,
	info = function(self, t)
		return ([[Conjures stalactite shaped rocks that you target individually at any target or targets in range.  Each missile deals %0.2f physical damage and an additional %0.2f bleeding damage over six turns.
		At talent level 1 you conjure two missile with an additional missile at talent level 5.
		The damage will increase with the Magic stat]]):format(damDesc(self, DamageType.PHYSICAL, self:combatTalentSpellDamage(t, 20, 120)/2), damDesc(self, DamageType.PHYSICAL, self:combatTalentSpellDamage(t, 20, 120)/2))
	end,
}

newTalent{
	name = "Body of Stone",
	type = {"spell/stone",2},
	require = spells_req2,
	points = 5,
	mode = "sustained",
	sustain_mana = 50,
	cooldown = 12,
	activate = function(self, t)
		local fire = self:combatTalentSpellDamage(t, 5, 80)
		local light = self:combatTalentSpellDamage(t, 5, 50)
		local phys = self:combatTalentSpellDamage(t, 5, 20)
		local kb = self:getTalentLevel(t)/10
		local cdr = self:getTalentLevel(t)/2
		local rad = 5 + self:combatSpellpower(0.1) * self:getTalentLevel(t)
		game:playSoundNear(self, "talents/earth")
		return {
			particle = self:addParticles(Particles.new("stone_skin", 1)),
			move = self:addTemporaryValue("never_move", 1),
			knock = self:addTemporaryValue("knockback_immune", kb),
			detect = self:addTemporaryValue("detect_range", rad),
			tremor = self:addTemporaryValue("detect_actor", 1),			
			cdred = self:addTemporaryValue("talent_cd_reduction", {
				[self.T_STALACTITIC_MISSILES] = cdr,
				[self.T_STRIKE] = cdr,
				[self.T_EARTHQUAKE] = cdr,
			}),
			res = self:addTemporaryValue("resists", {
				[DamageType.FIRE] = fire,
				[DamageType.LIGHTNING] = light,
				[DamageType.PHYSICAL] = phys,
			}),
		}
	end,
	deactivate = function(self, t, p)
		self:removeParticles(p.particle)
		self:removeTemporaryValue("never_move", p.move)
		self:removeTemporaryValue("knockback_immune", p.knock)
		self:removeTemporaryValue("detect_actor", p.tremor)
		self:removeTemporaryValue("detect_range", p.detect)
		self:removeTemporaryValue("talent_cd_reduction", p.cdred)
		self:removeTemporaryValue("resists", p.res)
		return true
	end,
	info = function(self, t)
		return ([[You root yourself into the earth and transform your flesh into stone.  While this spell is sustained you may not move and any forced movement will end the effect.
		Your stoned form and your affinity with the earth while the spell is active has the following effects:
		* Reduces the cooldown of Stalactitic Missiles, Earthquake, and Strike by %d
		* Grants %d%% Fire Resistance, %d%% Lightning Resistance, %d%% Physical Resistance, and %d%% Knockback Resistance
		* Sense foes around you in a radius of %d.
		Resistances and Sense radius scale with the Magic Stat.]])
		:format((self:getTalentLevel(t)/2), self:combatTalentSpellDamage(t, 5, 80), self:combatTalentSpellDamage(t, 5, 50), self:combatTalentSpellDamage(t, 5, 20), (self:getTalentLevel(t)*10), (5 + self:combatSpellpower(0.1) * self:getTalentLevel(t)))
	end,
}

newTalent{
	name = "Earthquake",
	type = {"spell/stone",3},
	require = spells_req3,
	points = 5,
	random_ego = "attack",
	mana = 50,
	cooldown = 30,
	tactical = {
		ATTACKAREA = 40,
	},
	range = 20,
	direct_hit = true,
	requires_target = true,
	action = function(self, t)
		local duration = 3 + self:getTalentLevel(t)
		local radius = 2 + (self:getTalentLevel(t)/2)
		local dam = self:combatTalentSpellDamage(t, 15, 70)
		local tg = {type="ball", range=self:getTalentRange(t), radius=radius}
		local x, y = self:getTarget(tg)
		if not x or not y then return nil end
		local _ _, x, y = self:canProject(tg, x, y)
		-- Add a lasting map effect
		game.level.map:addEffect(self,
			x, y, duration,
			DamageType.PHYSICAL_STUN, dam,
			radius,
			5, nil,
			{type="quake"},
			nil, self:spellFriendlyFire()
		)

		game:playSoundNear(self, "talents/earth")
		return true
	end,
	info = function(self, t)
		return ([[Causes a violent earthquake that deals %0.2f physical damage in a radius of %d each turn for %d turns and potentially stuns all creatures it affects.
		The damage and duration will increase with the Magic stat]]):format(damDesc(self, DamageType.PHYSICAL, self:combatTalentSpellDamage(t, 15, 70)), 2 + (self:getTalentLevel(t)/2), 3 + self:getTalentLevel(t))
	end,
}

newTalent{
	name = "Crystalline Focus",
	type = {"spell/stone",4},
	require = spells_req4,
	points = 5,
	mode = "sustained",
	sustain_mana = 80,
	cooldown = 30,
	activate = function(self, t)
		game:playSoundNear(self, "talents/earth")
		return {
			dam = self:addTemporaryValue("inc_damage", {[DamageType.PHYSICAL] = self:getTalentLevelRaw(t) * 2}),
			resist = self:addTemporaryValue("resists_pen", {[DamageType.PHYSICAL] = self:getTalentLevelRaw(t) * 10}),
			particle = self:addParticles(Particles.new("crystalline_focus", 1)),
		}
	end,
	deactivate = function(self, t, p)
		self:removeParticles(p.particle)
		self:removeTemporaryValue("inc_damage", p.dam)
		self:removeTemporaryValue("resists_pen", p.resist)
		return true
	end,
	info = function(self, t)
		return ([[Concentrate on maintaining a Crystalline Focus, increasing all your physical damage by %d%% and ignoring %d%% physical resistance of your targets.]])
		:format(self:getTalentLevelRaw(t) * 2, self:getTalentLevelRaw(t) * 10)
	end,
}

Re: Geomancers

Posted: Fri Oct 22, 2010 11:24 pm
by edge2054
Damage Types

Code: Select all

-- Physical + Stun Chance
newDamageType{
	name = "physical stun", type = "PHYSICAL_STUN",
	projector = function(src, x, y, type, dam)
		DamageType:get(DamageType.PHYSICAL).projector(src, x, y, DamageType.PHYSICAL, dam)
		local target = game.level.map(x, y, Map.ACTOR)
		if target and rng.percent(25) then
			if target:checkHit(src:combatSpellpower(), target:combatSpellResist(), 0, 95, 15) and target:canBe("stun") then
				target:setEffect(target.EFF_STUNNED, 2, {src=src})
			else
				game.logSeen(target, "%s resists!", target.name:capitalize())
			end
		end
	end,
}

-- Physical Damage/Cut Split
newDamageType{
	name = "split bleed", type = "SPLIT_BLEED",
	projector = function(src, x, y, type, dam)
		DamageType:get(DamageType.PHYSICAL).projector(src, x, y, DamageType.PHYSICAL, dam / 2)
		DamageType:get(DamageType.PHYSICAL).projector(src, x, y, DamageType.PHYSICAL, dam / 12)
		dam = dam - dam / 12
		local target = game.level.map(x, y, Map.ACTOR)
		if target and target:canBe("cut") then
			-- Set on fire!
			target:setEffect(target.EFF_CUT, 5, {src=src, power=dam / 11})
		end
	end,
}

Re: Geomancers

Posted: Fri Oct 22, 2010 11:27 pm
by edge2054
Body of Stone Modifications

Breaks on Move - Added to class\player.lua _M:move

Code: Select all

	if moved and self:isTalentActive(self.T_BODY_OF_STONE) then
		local old = self.energy.value
		self.energy.value = 100000
		self:useTalent(T_BODY_OF_STONE)
		self.energy.value = old
	end

Re: Geomancers

Posted: Fri Oct 22, 2010 11:27 pm
by edge2054
Particles

stone_shards

Code: Select all

local starts = {}
for i = 1, 4 do
	starts[#starts+1] = { a = math.rad(rng.range(0, 360)), r = rng.range(6, 20) }
end

-- Populate the beam based on the forks
return { generator = function()
	local rad = rng.range(-3,3)
	local s = rng.table(starts)
	local ra = s.a
	local r = s.r

	return {
		life = 4,
		size = rng.range(4, 6), sizev = -0.1, sizea = 0,

		x = 2 * math.cos(ra), xv = 0, xa = 0,
		y = 2 * math.sin(ra), yv = 0, ya = 0,
		dir = 0, dirv = 0, dira = 0,
		vel = 0, velv = 0, vela = 0,

		r = 0xD7/255, rv = 0, ra = 0,
		g = 0x8E/255, gv = 0, ga = 0,
		b = 0x45/255, bv = 0, ba = 0,
		a = rng.range(100, 220)/255,   av = 0.05, aa = 0,
	}
end, },
function(self)
	self.ps:emit(30 * 4)
end,
4*30*4
quake

Code: Select all

return { generator = function()
	local ad = rng.range(0, 360)
	local a = math.rad(ad)
	local dir = math.rad(ad + 90)
	local r = rng.range(1, 20)
	local dirv = math.rad(1)

	return {
		trail = 1,
		life = 10,
		size = 1, sizev = 0.5, sizea = 0,

		x = r * math.cos(a), xv = -0.1, xa = 0,
		y = r * math.sin(a), yv = -0.1, ya = 0,
		dir = math.rad(rng.range(0, 360)), dirv = 0, dira = 0,
		vel = 0.1, velv = 0, vela = 0,

		r = rng.range(200, 230)/255,  rv = 0, ra = 0,
		g = rng.range(130, 160)/255,  gv = 0, ga = 0,
		b = rng.range(50, 70)/255,    bv = 0, ba = 0,
		a = rng.range(25, 220)/255,   av = 0, aa = 0,
	}
end, },
function(self)
	self.ps:emit(4)
end,
40
crystalline_focus

Code: Select all

return { generator = function()
	local ad = rng.range(0, 360)
	local a = math.rad(ad)
	local dir = math.rad(ad)
	local r = rng.range(18, 22)
	local dirchance = rng.chance(2)

	return {
		life = 20,
		size = 4, sizev = -0.05, sizea = 0,

		x = r * math.cos(a), xv = 0, xa = 0,
		y = r * math.sin(a), yv = 0, ya = 0,
		dir = dir, dirv = 0.1, dira = 0,
		vel = dirchance and 0.2 or -0.2, velv = 0, vela = dirchance and -0.02 or 0.02,

		r = rng.range(0, 0)/255, rv = rng.range(0, 10)/100, ra = 0,
		g = rng.range(80, 200)/255,  gv = 0.005, ga = 0.0005,
		b = 0,   bv = 0, ba = 0,
		a = rng.range(70, 255)/255,   av = 0, aa = 0,
	}
end, },
function(self)
	self.ps:emit(4)
end,
80

Re: Geomancers

Posted: Sat Oct 23, 2010 3:41 pm
by edge2054
Finished.

Re: Geomancers

Posted: Sat Oct 23, 2010 4:55 pm
by edge2054
Tweaked the talents a bit to make Stalactitic Missiles scaling a bit more even at lower levels and to make the targeting more understandable in the description.

Dropped the cooldown on Body of Stone down to 12.

Still thinking of a quest idea but I have something in mind.

I'll post it or discuss it in IRC later on today.