Page 1 of 1

How hard is it to code LUA?

Posted: Fri Oct 19, 2012 6:58 am
by Parcae2
I am a computer-programming idiot, but I was thinking of trying my hand at a couple of new Wyrmic trees. How do I set about learning to do this?

Re: How hard is it to code LUA?

Posted: Fri Oct 19, 2012 12:26 pm
by lukep
It's pretty easy, IMO. I started from next to no coding experience, and found the talent code to be >90% readable. You can have pretty good results by simply looking at talents similar to what you want, copy/pasting them (with relevant changes) and running the result with the debugging log turned on so that you can fix things easier.

I also recommend creating/using an addon to modify the code; it makes it much easier to maintain, and is the proper way to do it. Just grab an addon (such as the example one), remove the extra files, and place copies of the ones you want to change in the "overload" folder (maintaining file structure). That will replace the files in the main game with the ones in your addon, when it's loaded.

Lastly, don't be afraid of the IRC channel. People there are willing to help, and quite friendly as well.

Re: How hard is it to code LUA?

Posted: Fri Oct 19, 2012 1:53 pm
by Avianpilot
I concur with Luke; I'm still a copy/paster, but in general the code is fairly easy to read. One day I'd like to move beyond that, but for what you want to do it would probably be easiest to do the copy/paste of a similar talent and tweak the numbers. Assuming that you're not going for something totally wild and unique that is.

Re: How hard is it to code LUA?

Posted: Fri Oct 19, 2012 4:22 pm
by Parcae2
OK, I've started coding but I need help.

I am trying to code a talent that enables a wyrmic to seize and fly away with an opponent. This raises two problems:

1. I want to raise the wyrmic's attack and lower its defense with regard to the seized opponent, but ONLY that opponent. (Normally the Flight skill will radically reduce the wyrmic's attack and increase its defense and I want to get rid of those advantages/penalties).
2. I want the seized opponent to say next to the wyrmic at all times. In order to do this, I want to make the engine check whenever the wyrmic moves to see if there is a seized target next to it and, if so, to move the seized target next to the wyrmic's new position. If the wyrmic moves to a tile surrounded by opponents, I want the engine to make the seized opponent swap places with one of the other opponents so as to remain next to the wyrmic.

I don't know how to do any of these things. Help?

Re: How hard is it to code LUA?

Posted: Fri Oct 19, 2012 10:59 pm
by aardvark
Parcae2 wrote:1. I want to raise the wyrmic's attack and lower its defense with regard to the seized opponent, but ONLY that opponent. (Normally the Flight skill will radically reduce the wyrmic's attack and increase its defense and I want to get rid of those advantages/penalties).
A cursory examination of the Cursed talent "Stalk" indicates you probably want to make an "opponent seized" effect and add target checks to class/interface/Combat.lua's attackTargetWith() function. That would take care of the attack part. You'd probably need a second "seized" effect to put on the opponent to handle the defense reduction.
Parcae2 wrote:2. I want the seized opponent to say next to the wyrmic at all times. In order to do this, I want to make the engine check whenever the wyrmic moves to see if there is a seized target next to it and, if so, to move the seized target next to the wyrmic's new position. If the wyrmic moves to a tile surrounded by opponents, I want the engine to make the seized opponent swap places with one of the other opponents so as to remain next to the wyrmic.
The corruption talent "Bone Grab" makes a decent preliminary guide for pulling the opponent with you. Maybe an on_move() function for the Actor doing the seizing would be easiest? You should always have a free space available when moving, since you vacate one when you do. If you allow that teleportation or using the Wyrmic's digging talent will break the hold, then it greatly simplifies free space finding.

That's a fairly complicated set of mechanics for a first stab at talent-making. I hope I helped even a little.

Re: How hard is it to code LUA?

Posted: Sat Oct 20, 2012 12:26 am
by Parcae2
OK, I copy-pasted some stuff from Grappling and made a few modifications, using Seizing and Seized for Grappled and Grappling. Here's what I have for the attack bit:

local effSeizing = self:hasEffect(self.EFF_SEIZING)
if effSeizing and effSeized == target then
atk = atk + 1000
end

local effSeized = self:hasEffect(self.EFF_SEIZED)
if effSeized and effSeizing == target then
atk = atk + 1000
end

The idea is to raise target and actor's attack by 1000 (to make up for the -1000 attack and +1000 defense from Flight).

I don't understand the idea of onMove at all :( Is there a talent that uses it that I could use as an example of that bit?

EDIT: OK, so I stuck this thing in actor.lua under the move function, next to the stuff about moving when confused and so on:

--Seizing a target?

if self:attr("seizing") then

target:pull(self.x, self.y, tg.range)
end)
return true
end,

I feel like there's something I need to add to make sure that the target is a neighboring actor with the Seized attribute.

Re: How hard is it to code LUA?

Posted: Sat Oct 20, 2012 6:49 pm
by aardvark
Parcae2 wrote:I feel like there's something I need to add to make sure that the target is a neighboring actor with the Seized attribute.
Maybe something like:

Code: Select all

		--Seizing a target?

		if self:attr("seizing") then
			if tg.x and tg.y and math.abs(self.x - tg.x) <= 2 and math.abs(self.y - tg.y) <= 2 then
				target:pull(self.x, self.y, tg.range)
			else
				-- disable the talent and remove effects if tg is too far away or non-existent
			end
		end)
		return true
	end,
Presumably, tg is the target gleaned from the "seized" effect in previous (unlisted here) code, so you already know it's seized.

Re: How hard is it to code LUA?

Posted: Sun Oct 21, 2012 12:42 am
by Parcae2
I didn't understand that last sentence at all:/ I'm sorry!

Re: How hard is it to code LUA?

Posted: Sun Oct 21, 2012 10:10 pm
by aardvark
Parcae2 wrote:I didn't understand that last sentence at all:/ I'm sorry!
I'm referring to the variable "tg" as used in your previously posted code. You can't pull a value out of a variable until you set it to one, so I'm assuming tg is a reference to the seized Actor, that it was stored in the seizer's effect, and that you retrieved it from that effect earlier in whatever function your code snippet comes from.

Re: How hard is it to code LUA?

Posted: Mon Oct 22, 2012 1:23 pm
by Parcae2
OK, now all of that makes sense except the part where you assumed that I was competent. No, tg is not currently set to anything. How do I do, uh, those things? The snippet of code is basically just an isolated thingummy in actor.lua, except that I put it under something that looked like a move function.

Re: How hard is it to code LUA?

Posted: Tue Oct 23, 2012 12:57 am
by aardvark
Check out the way the Cursed talent "Stalk" handles its pair of effects (talent defined in data/talents/cursed/endless-hunt.lua, effects in data/timed_effects/mental.lua) for some good ideas on how you might proceed. Note that it has special case code sprinkled all over the module (in Actor.lua and Combat.lua, for instance) that lets it work its magic.

Re: How hard is it to code LUA?

Posted: Tue Oct 23, 2012 6:05 am
by Parcae2
Thank you so much, Aardvark. I'll look as soon as I have a chance.

Re: How hard is it to code LUA?

Posted: Tue Oct 23, 2012 7:01 am
by Parcae2
OK, here's what the code looks like now.

In Actor.lua, under function _M:move(x, y, force)
local moved = false
local ox, oy = self.x, self.y

if force or self:enoughEnergy() then

(which is existing code)

I have added the following:

Code: Select all

if self:hasEffect(self.EFF_SEIZING) then
		-- find seized target and pull it towards actor when actor moves]
		local tgts = {}
		local grids = core.fov.circle_grids(self.x, self.y, self:3, true)
		for x, yy in pairs(grids) do for y, _ in pairs(grids[x]) do
			local a = game.level.map(x, y, Map.ACTOR)
			if a and hasEffect(self.EFF_SEIZED) and (a.x and a.y and math.abs(self.x - a.x) <= 2 and math.abs(self.y - a.y) <= 2) then
			a:pull(self.x, self.y, tg.range)
		end
	end
In physical.lua:

Code: Select all

newEffect{
	name = "SEIZING", image = "talents/clinch.png",
	desc = "Seizing",
	long_desc = function(self, eff) return ("The target has seized an opponent and carried it away."):format() end,
	type = "physical",
	subtype = { grapple=true, },
	status = "beneficial",
	parameters = {},
	on_gain = function(self, err) return "#Target# seizes its opponent!", "+Seizing" end,
	on_lose = function(self, err) return "#Target# has released the hold.", "-Seizing" end,
	on_timeout = function(self, eff)
		local p = eff.trgt:hasEffect(eff.trgt.EFF_SEIZED)
		if not p or p.src ~= self or core.fov.distance(self.x, self.y, eff.trgt.x, eff.trgt.y) > 1 or eff.trgt.dead or not game.level:hasEntity(eff.trgt) then
			self:removeEffect(self.EFF_SEIZING)
		end
	end,
	activate = function(self, eff)
	end,
	deactivate = function(self, eff)
	end,
}

newEffect{
	name = "SEIZED", image = "talents/grab.png",
	desc = "Seized",
	long_desc = function(self, eff) return ("The target has been carried off by a mighty wyrm to feed its young."):format(eff.power) end,
	type = "physical",
	subtype = { grapple=true, pin=true },
	status = "detrimental",
	parameters = {},
	remove_on_clone = true,
	on_gain = function(self, err) return "#Target# has been carried away!", "+Seized" end,
	on_lose = function(self, err) return "#Target# is no longer being carried.", "-Seized" end,
	activate = function(self, eff)
		eff.tmpid = self:addTemporaryValue("never_move", 1)
	end,
	on_timeout = function(self, eff)
		if core.fov.distance(self.x, self.y, eff.src.x, eff.src.y) > 1 or eff.src.dead or not game.level:hasEntity(eff.src) then
			self:removeEffect(self.EFF_SEIZED)
		end
	end,
	deactivate = function(self, eff)
		self:removeTemporaryValue("never_move", eff.tmpid)
	end,
}
(that was mostly copy-pasted from Grappling, as is most of the following)

In the new Flight.lua:

Code: Select all

newTalent{
	name = "Talon Seize",
	type = {"wild-gift/flight", 2},
	require = gifts_req2,
	points = 5,
	stamina = 100,
	tactical = { ATTACK = 2, DISABLE = 2 },
	getDuration = function(self, t) return 4 + math.floor(self:getTalentLevel(t)) end,
	on_pre_use = function(self, t)
		local p = self:isTalentActive(self.T_SOAR)
		if not p then return end
		return true
	end,
	requires_target = true,
	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 core.fov.distance(self.x, self.y, x, y) > 1 then return nil end

		local seized = false

		-- seize the target
		local hit = self:startSeizing(target)
		return true
	end,
	info = function(self, t)
		return ([[You seize an opponent from the ground.]])
	end,
}
Finally, in Combat.lua, I am adding the following to define startSeizing from the above talent:

Code: Select all

function _M:startSeizing(target)
	-- Breaks the grapple before reapplying
	if self:hasEffect(self.EFF_SEIZING) then
		self:removeEffect(self.EFF_SEIZING, true)
		target:setEffect(target.EFF_SEIZED, {src=self}, true)
		self:setEffect(self.EFF_SEIZING, {trgt=target}, true)
		return true
	elseif target:canBe("pin") then
		target:setEffect(target.EFF_SEIZED, {src=self})
		self:setEffect(self.EFF_SEIZING, {trgt=target})
		return true
	else
		game.logSeen(target, "%s cannot be seized!", target.name:capitalize())
		return false
	end
end
I'm sorry that I'm imposing so much. I don't really know what I'm doing, if that wasn't obvious before.

Re: How hard is it to code LUA?

Posted: Thu Oct 25, 2012 12:01 am
by aardvark
Your Actor.lua code should probably go inside the

Code: Select all

if not force and moved and (self.x ~= ox or self.y ~= oy) and not self.did_energy then
block. That way you can be sure that the player has successfully moved. And since your old position is stored in ox and oy, you have a perfect (open) spot to park your seized captive. Side notes: the self:3 in your core.fov.circle_grids() should almost certainly be just "3" and it looks like you're missing a couple of ends (both fors need them). If you stored a reference to the seized Actor when you used the talent, you could eliminate the search altogether.

For the rest, I couldn't say one way or the other. Except that you probably don't need to worry whether the target can be pinned. Since you're picking them up completely, I'm not sure the normal pinning rules even apply. Maybe a check to see if the seized is much larger than the seizer?