Class trait mystery

Ask for help about creating mods and scripts for Grimrock 2 or share your tips, scripts, tools and assets with other modders here. Warning: forum contains spoilers!
Post Reply
Minandreas
Posts: 4
Joined: Thu Sep 17, 2015 7:09 pm

Class trait mystery

Post by Minandreas »

So I apologize in advance if this is already addressed somewhere, but I hit the search bar with the most probable cues I could think of and came up empty handed, aside from one person asking about it and not getting any answers.

There are some aspects of classes that I have no clue where they come from. I can only assume they are hardcoded somehow, but wanted to check and see. For example, alchemists spawning of additional herbs, or fighters having reduced weapon skill charge times. I'm not seeing any such traits defined anywhere in the asset pack. I was hoping to play around with those mechanics some for a custom class.

Please forgive my noobness. I am indeed a noob. :oops: Reading all I can though!
User avatar
Drakkan
Posts: 1318
Joined: Mon Dec 31, 2012 12:25 am

Re: Class trait mystery

Post by Drakkan »

all traits / classes are to be found inside the downloadable asset pack (traits.lua etc...)
viewtopic.php?f=22&t=9505

Some of them are scripted, some of them are hard-coded and cannot be changed. In case you are skilled scripter you can create your own ones and even to re-create some of the hard-coded.
Breath from the unpromising waters.
Eye of the Atlantis
Minandreas
Posts: 4
Joined: Thu Sep 17, 2015 7:09 pm

Re: Class trait mystery

Post by Minandreas »

Ya I looked through those. I'm saying I didn't see any traits in the asset pack that governed those particular mechanics. Alchemists creating herbs and fighters having weapon skill charge up reduction. I just wanted to verify that I'm not looking in the wrong places or something, and that those are just out of our ability to work with.
User avatar
akroma222
Posts: 1029
Joined: Thu Oct 04, 2012 10:08 am

Re: Class trait mystery

Post by akroma222 »

Hey Minandreas,
Those traits you mentioned.. including
SpoilerShow
shield_expert,
melee_expert,
armor_expert,
rogue_dual_wield,
hand_caster,
firearms_expert,
hand_caster = true,
are hard coded and also are "hidden" traits... not listed in the traits.lua of the asset pack

To add these to a Class definition just do it like this...
SpoilerShow

Code: Select all

defineCharClass{
	name = "fighter",
	uiName = "Pit Fighter",
	traits = {"melee_specialist"},      -- add them to this table
	optionalTraits = 2,
	skillPoints = 2,
}
Having said that, it seems to work fine for those hidden traits... but I have had mixed success adding custom traits this way.
So I run a script upon starting the game which checks for Race and Class and adds traits and raises skills accordingly.

As far as recreating some of these hard coded traits....
(my Dwarfs have a similar effect to the fighters melee specialist)
shield_expert, firearm_expert, melee_expert and armor_expert can all be replicated by altering a shield/weapons stats onEquip and then changing them back onUnequip, for example
SpoilerShow

Code: Select all

defineObject{
       	name = "plague_axe",		
       	baseObject = "skullcleave",
		tags = { "weapon", "axe" },
       		components = {
       	{
          	class ="Item",
          	uiName = "Plague Axe",
          	gfxAtlas = "assets/textures/gui/items_2.tga",
          	gfxIndex = 94,
          	weight = 2.6,
          	impactSound = "impact_blade",
		secondaryAction = "chop",
		gameEffect = [[
		- 15% Chance to blind
		- Free Sockets 1/1]],
          	traits = { "axe", "heavy_weapon"},
       	   	description = "A hand axe carried by skeleton warriors and executioners. Blood and grime stain the head of this axe.",
		onEquipItem = function(self, champion, slot)
	
			if slot == 1 or slot == 2 then 
	
				if champion:getRace() == "dwarf" then	
					self.go.chop:setEnergyCost(8)			
				end

			end
		end

,
		onUnequipItem = function(self, champion, slot)
	
			if slot == 1 or slot == 2 then 
	
				if champion:getRace() == "dwarf" then				
					self.go.chop:setEnergyCost(15)
				
				end
			end
		
end,
	},
	{
		class = "EquipmentItem",
		slot = 1,
		vitality = -1,
		strength = -1,
		healthRegenerationRate = -50,
	},
       	{
          	class = "MeleeAttack",
          	attackPower = 11,
          	accuracy = 0,
          	swipe = "horizontal",
          	attackSound = "swipe_heavy",
          	cooldown = 4.5,
          	baseDamageStat = "strength",
         	damageType = "physical",
		causeCondition = "blinded",
		conditionChance = 15,
		requirements = {"heavy_weapons", 1}
       	},
	{
          	class = "MeleeAttack",
		name = "chop",
		uiName = "Chop",
		buildup = 1.0,
          	attackPower = 25,
          	accuracy = 0,
          	swipe = "vertical",
		causeCondition = "blinded",
		conditionChance = 25,
          	attackSound = "swipe_special",
		energyCost = 15,
          	cooldown = 5.0,
          	baseDamageStat = "strength",
         	damageType = "physical",
		requirements = {"heavy_weapons", 1, "athletics", 1},
		gameEffect = "A useful technique for chopping firewood... or severing the limbs of an enemy.",
		onAttack = function(self,champion,hand)
			champion:playDamageSound()
             	end,
       	},
       	}
    }	
Hand caster is simple and doesnt need replicating
I do not know how to replicate the rogur dual wield though...
(if anyone does know how to hack into the dual wield mechanis I would love to know)

When defining traits, they can be made available at character creation or not, can be Race specific or not and can be hidden or not.....
SpoilerShow

Code: Select all

defineTrait{
	name = "fast_metabolism",
	uiName = "Fast Metabolism",
	--iconAtlas = "assets/textures/gui/skills.tga",
	icon = 54,
	charGen = true,
	requiredRace = "lizardman",
        hidden = false,
	description = "Health Regeneration +10% and Food consumption +25%. Potions also have varying effects on you.",
	onRecomputeStats = function(champion, level)
		if level > 0 then
			champion:addStatModifier("food_rate", 25)
			champion:addStatModifier("health_regeneration_rate", 10)
		end
	end,
}
EG - Only selectable by Lizardman, can be chosen at character creation and is not hidden (will display under traits in champion sheet)

As a side thing when defining custom conditions - I have found the "hidden" option for traits very useful when creating custom conditions (status effects).
Through the conditions onStart hook, add a similarly named but hidden trait to make use of the hooks like
onComputeAccuracy, onComputeCritChance etc (traits have access to but conditions do not).

Also, to save you the peril, here is the "traitManager" script (paste into a script entity in dungeon) that minmay created to effectively manage adding and removing traits
(so they arent removed when they should be) This was critical for me as I was adding and removing heaps of traits through spells and equiping items
SpoilerShow

Code: Select all

--created by minmay for assistance with Labyrinth of Lies

-- USAGE: Instead of calling champion:addTrait and
-- champion:removeTrait, call traitManager.addTrait and
-- traitManager.removeTrait. This will prevent equipment swapping
-- from destroying permanent traits and the like.
-- For example, instead of champion:addTrait("tough",true) call
-- traitManager.addTrait(champion,"tough",true).
-- Note: You shouldn't (and can't) use this script for skill
-- traits (such as quick_strike) as the counts would be
-- rendered inaccurate anyway by players increasing their skills.

TRAIT_LIST = {	      -- do not include traits gained through skills or hidden hard coded traits
athletic = true,
agile = true,
healthy = true,
strong_mind = true,
tough = true,
aura = true,
aggressive = true,
evasive = true,
natural_armor = true,
endurance = true,
}

traits = {}

-- add a trait and increase "level" of that trait by 1
function addTrait(champion,trait,silent)
	if not TRAIT_LIST[trait] then
		print("warning: invalid trait: "..trait)
	end

	if traits[champion:getOrdinal()][trait] == 0 then
		champion:addTrait(trait,silent)
	end
	traits[champion:getOrdinal()][trait] = traits[champion:getOrdinal()][trait] + 1
end

-- decrease "level" of a trait by 1, removing it if it reaches 0
function removeTrait(champion,trait)
	--local name = champion:getName() 
	if traits[champion:getOrdinal()][trait] == 1 then
		champion:removeTrait(trait)
		--hudPrint(""..name.." gained the agile trait.")
	end
	traits[champion:getOrdinal()][trait] = traits[champion:getOrdinal()][trait] - 1
end

-- get the traits the party started with
function gatherInitialTraits()
	for i = 1, 4 do
		local champion = party.party:getChampion(i)
		traits[champion:getOrdinal()] = {}
		for trait,dummy in pairs(TRAIT_LIST) do
			if champion:hasTrait(trait) then
				traits[champion:getOrdinal()][trait] = 1
			else
				traits[champion:getOrdinal()][trait] = 0
			end
		end
	end
end
gatherInitialTraits()

Hope this all helps a bit :D
Post Reply