How hard is it to code LUA?

All development conversation and discussion takes place here

Moderator: Moderator

Post Reply
Message
Author
Parcae2
Uruivellas
Posts: 709
Joined: Sat Jan 14, 2012 12:02 am

How hard is it to code LUA?

#1 Post 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?

lukep
Sher'Tul Godslayer
Posts: 1712
Joined: Mon Mar 14, 2011 10:32 am
Location: Canada

Re: How hard is it to code LUA?

#2 Post 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.
Some of my tools for helping make talents:
Melee Talent Creator
Annotated Talent Code (incomplete)

Avianpilot
Thalore
Posts: 148
Joined: Fri Aug 19, 2011 5:06 pm

Re: How hard is it to code LUA?

#3 Post 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.

Parcae2
Uruivellas
Posts: 709
Joined: Sat Jan 14, 2012 12:02 am

Re: How hard is it to code LUA?

#4 Post 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?

aardvark
Wyrmic
Posts: 200
Joined: Wed Aug 22, 2012 12:16 am

Re: How hard is it to code LUA?

#5 Post 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.

Parcae2
Uruivellas
Posts: 709
Joined: Sat Jan 14, 2012 12:02 am

Re: How hard is it to code LUA?

#6 Post 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.

aardvark
Wyrmic
Posts: 200
Joined: Wed Aug 22, 2012 12:16 am

Re: How hard is it to code LUA?

#7 Post 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.

Parcae2
Uruivellas
Posts: 709
Joined: Sat Jan 14, 2012 12:02 am

Re: How hard is it to code LUA?

#8 Post by Parcae2 »

I didn't understand that last sentence at all:/ I'm sorry!

aardvark
Wyrmic
Posts: 200
Joined: Wed Aug 22, 2012 12:16 am

Re: How hard is it to code LUA?

#9 Post 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.

Parcae2
Uruivellas
Posts: 709
Joined: Sat Jan 14, 2012 12:02 am

Re: How hard is it to code LUA?

#10 Post 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.

aardvark
Wyrmic
Posts: 200
Joined: Wed Aug 22, 2012 12:16 am

Re: How hard is it to code LUA?

#11 Post 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.

Parcae2
Uruivellas
Posts: 709
Joined: Sat Jan 14, 2012 12:02 am

Re: How hard is it to code LUA?

#12 Post by Parcae2 »

Thank you so much, Aardvark. I'll look as soon as I have a chance.

Parcae2
Uruivellas
Posts: 709
Joined: Sat Jan 14, 2012 12:02 am

Re: How hard is it to code LUA?

#13 Post 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.

aardvark
Wyrmic
Posts: 200
Joined: Wed Aug 22, 2012 12:16 am

Re: How hard is it to code LUA?

#14 Post 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?

Post Reply