Page 1 of 1

More mutually exclusive talent nonsense!

Posted: Thu Sep 16, 2010 1:40 am
by FinalParagon
I found myself really busy with all manner of things, but recently picked up T-Engine again. Time for a question very related to my last one.

The problem this time isn't that I can't set talents as mutually exclusive, it's that the engine only fully recognizes this for the last talent in any given set.

For example, Knights have three masteries: Swordsmanship, Lancing and Archery. A point in any one should forbid the Knight from raising any other. What actually happens is as follows:
A POINT IN SWORDSMANSHIP: Properly forbids the other two.
A POINT IN LANCING: Forbids only Archery.
A POINT IN ARCHERY: Prevents nothing.

Additionally, the raise talent dialog disappears whenever the first two would be highlighted. It's still navigable, it reappears when any other talent is highlighted and you can still allocate points to those two talents if they're selected even though you can't actually see the dialog.

It's fairly clear what the problem is. The three talents are defined in that order (Swordsmanship, Lancing, Archery), but requirements for talents are read in at the same time as that talent is defined. This works fine for sequential requirements, but as soon as a loop in requirements occurs (In this case, talents mutually requiring not the other talents), it only recognizes the requirements which include talents already defined, and there's no way to reorder their definitions to prevent this.

So that's the problem, the question is: What's the solution? Altering the requirements using some sort of mutator function after all the talents have been defined seems like the easiest way to do it, but I don't see any obvious way of doing so.

Re: More mutually exclusive talent nonsense!

Posted: Thu Sep 16, 2010 5:30 am
by yufra
I think what might be getting you is that there is a set of requirements that are handled outside of the require table. The first value in the type table is the string that identifies the talent category. The second value minus one is the number of talents in the same category that need to be known before this talent can be learned, and this may be what is tripping you up. If you either get rid of the second value entirely or set them all to 1 then you should be able to learn them independently, and then the require.talents can properly remove the others once you learn one talent.

If this doesn't work, maybe post the code so I can take a look at that?

Re: More mutually exclusive talent nonsense!

Posted: Thu Sep 16, 2010 3:30 pm
by FinalParagon
Yeah, all of them are set to '1'. Actually, every talent has this set to one, since I'm only using talent categories as headers to separate like skills.

So here's their definitions as of right now. None of them have actual effects yet, but that hasn't affected any other talent in this way (or at all) while I've been testing.

Code: Select all

-- Swordsmanship - Stronger sword attacks.
newTalent{
	name = "Swordsmanship",
	type = {"Fighter/Warfare-Tactics", 1},
	points = 10,
	mode = "passive",
	info = function(self, t)
		return "Swords are often the weapons of heroes, owing to their tremendous versatility. Some Knights choose to specialize in the use of Swords, significantly increasing their Damage with them. Specializing in Swords opens up special Sword techniques, but prevents you from specializing in Lances or Bows."
	end,
	require = { talent = { { Talents.T_LANCING, false }, { Talents.T_ARCHERY, false }, }, },
}

-- Lancing - Stronger spear attacks.
newTalent{
	name = "Lancing",
	type = {"Fighter/Warfare-Tactics", 1},
	points = 10,
	mode = "passive",
	info = function(self, t)
		return "Lances are long and powerful, designed to focus immense energy into devestating thrusts. Some Knights choose to specialize in the use of Lances, increasing both their Damage and Pierce with them. Specializing in Lances opens up special Lance techniques, but prevents you from specializing in Swords or Bows."
	end,
	require = { talent = { { Talents.T_SWORDSMANSHIP, false }, { Talents.T_ARCHERY, false }, }, },
}

-- Archery - Stronger bow attacks.
newTalent{
	name = "Archery",
	type = {"Fighter/Warfare-Tactics", 1},
	points = 10,
	mode = "passive",
	info = function(self, t)
		return "The easiest way to survive is to avoid getting hit in the first place, and as such, some Knights choose to specialize in the use of Bows, increasing their Accuracy and Pierce with them. Specializing in Bows opens up special Bow techniques, but prevents you from specializing in Swords or Lances."
	end,
	require = { talent = { { Talents.T_SWORDSMANSHIP, false }, { Talents.T_LANCING, false }, }, },
}
stdout.txt shows an error about nil values, and that, plus the fact that it only acknowledges these requirements if the requirement was defined earlier than the current talent (Again, Archery works perfectly fine, Lancing half-works, Swordsmanship not at all), tell me that it's not acknowledging, say, T_LANCING in Swordsmanship, because Lancing technically doesn't exist when Swordsmanship is first loaded in.

Re: More mutually exclusive talent nonsense!

Posted: Thu Sep 16, 2010 4:23 pm
by yufra
I understand now, thanks for the explanation. I don't think the current ActorTalents.lua can support this behavior in an elegant fashion, and will first suggest a hack to get it working now and then a suggestion for DG to alter ActorTalents.lua.

The Hack
Remove the require table from the newEntity function calls. Then at the very bottom of the talent file add:

Code: Select all

-- Hack adding the requirements after all the talents have been defined
local talent = Talents:getTalentFromId(Talents.T_SWORDSMANSHIP)
talent.require = { talent = { { Talents.T_LANCING, false }, { Talents.T_ARCHERY, false }, }, }
local talent = Talents:getTalentFromId(Talents.T_LANCING)
talent.require = { talent = { { Talents.T_SWORDSMANSHIP, false }, { Talents.T_ARCHERY, false }, }, }
local talent = Talents:getTalentFromId(Talents.T_ARCHERY)
talent.require = { talent = { { Talents.T_SWORDSMANSHIP, false }, { Talents.T_LANCING, false }, }, }
Ugly, but it works.

The Suggestion
ActorTalents would benefit from gaining the resolve function from Entity.lua. Either a custom resolver could be written, or the resolver.generic could be used as follows:

Code: Select all

newTalent{
...
	require = { 
		talent = resolvers.generic(function(Talents, t)
			t.require.talent = { Talents.T_LANCING, false }, { Talents.T_ARCHERY, false }, }, }
		end,
	}
...
}
Assuming of course I have my signatures right. Thoughts DG?

Re: More mutually exclusive talent nonsense!

Posted: Thu Sep 16, 2010 4:31 pm
by FinalParagon
That's exactly what I was trying to figure out how to do. It works perfectly now, thanks a bunch!

Re: More mutually exclusive talent nonsense!

Posted: Thu Sep 16, 2010 5:26 pm
by darkgod
Resolves cant really work on talents since they are not resolved but I'll find a way :)

Re: More mutually exclusive talent nonsense!

Posted: Thu Sep 16, 2010 5:51 pm
by Patryn
I'm not into lua, but AFAIK many languages offer the possibility to define a function/class/whatever before actually setting the function body. Especially with an interpreter language this seems kinda handy for exactly this reason. ;)

I can hardly believe lua hasn't anything like that... *wondering*