How hard is it to code LUA?
Moderator: Moderator
How hard is it to code LUA?
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?
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.
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.
-
- Thalore
- Posts: 148
- Joined: Fri Aug 19, 2011 5:06 pm
Re: How hard is it to code LUA?
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?
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?
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?
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: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).
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.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.
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?
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.
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

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?
Maybe something like: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.
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,
Re: How hard is it to code LUA?
I didn't understand that last sentence at all:/ I'm sorry!
Re: How hard is it to code LUA?
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 wrote:I didn't understand that last sentence at all:/ I'm sorry!
Re: How hard is it to code LUA?
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?
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?
Thank you so much, Aardvark. I'll look as soon as I have a chance.
Re: How hard is it to code LUA?
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:
In physical.lua:
(that was mostly copy-pasted from Grappling, as is most of the following)
In the new Flight.lua:
Finally, in Combat.lua, I am adding the following to define startSeizing from the above talent:
I'm sorry that I'm imposing so much. I don't really know what I'm doing, if that wasn't obvious before.
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
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,
}
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,
}
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
Re: How hard is it to code LUA?
Your Actor.lua code should probably go inside theblock. 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?
Code: Select all
if not force and moved and (self.x ~= ox or self.y ~= oy) and not self.did_energy then
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?