1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
|
|||||oy
#####R /----------------------------------------\
#####R < Adding new racial powers >
#####R \----------------------------------------/
#####R=== Introduction ===
You *must* download and install my lua example files from
[[[[[Ghttp://www.moppy.co.uk/angband.htm]. And also you should read the
*****lua_intr.txt*0[scripting introduction] file if you haven't already done
so.
The (commented) accompanying script file for this tutorial is
lib\scpt\pheonix.lua. Open it in your text editor!
#####R=== The Racial Power ===
Let's start with something simple. Let's say you wanted your new race (let's
call it "Pheonix") to be able to cast fire balls as their racial power.
#####R=== Starting off ===
If you have a look at pheonix.lua you'll note the first lines are comments.
I'll talk a bit more about comments later, but it's worth pointing out that any
lines of text preceded by a double hyphen ([[[[[B--]) will be ignored by the
scripting engine, and are therefore comments.
After the comments, the first 10 lines of code are as follows:
#####BPHEONIX_POWER = add_power
#####B{
#####B ["name"] = "Fire Breath",
#####B ["desc"] = "You are able to cast fireballs",
#####B ["desc_get"] = "Your beak glows red",
#####B ["desc_lose"] = "Your beak goes cold again",
#####B ["level"] = 10,
#####B ["cost"] = 11,
#####B ["stat"] = A_INT,
#####B ["fail"] = 14,
So, [[[[[BPHEONIX_POWER = add_power] is registering our power. We're giving it
a name (PHEONIX_POWER) and saying that it is defined by calling the special
function [[[[[Badd_power]. This special function is only used to define lua-
scripted
powers, and has attributes which are identified by their inclusion in square
brackets.
Note the following:
- Lua is case sensitive. The name of our power is a constant, will never change
so that's been named with capitals. variables and functions are named all in
lower case. Technically speaking, Lua does not support constants, but we can
emulate them by variables in this way. They don't have to be capitalised, but
if you capitalise all your constants, it makes things easier to read, and
you'll be following normal programming protocol.
- There are no spaces in the name of the power. Use an underscore for spaces
if you need to improve legibility.
[[[[[B"name" = "Fire Breath",] This is the name of the power as it is
displayed in the
U menu, and as you will define it in p_info.txt (more about that later).
[[[[[B"desc" = "You are able to cast fireballs",] This is what would
appear in the
information display list if you drank a potion of self knowledge or
similar.
[[[[[B"desc_get" = "Your beak glows red",] This is the information displayed
when you
gain this power.
[[[[[B"desc_lose" = "Your beak goes cold again",] This is the information
displayed when
you lose this power. Eg After a mutation/corruption.
[[[[[B"level" = 10,] Character level which must be gained in order to use
power,
[[[[[B"cost" = 11,] Amount of mana to cast this power.
[[[[[B"stat" = A_INT,] stat which will define whether it works or not,
[[[[[B"fail" = 14,] how high that stat must be.
So our Pheonix will be able to cast PHEONIX_POWER from clvl 10, at a cost of
11 mana, providing that the player's intelligence is 14 and upwards.
#####R=== The function ===
The next section is a lot longer, so we'll look at it line by line. I'll
strip the comments for the purpose of this helpfile.
#####B["power"] = function()
#####B local ret, dir, damage
#####B ret, dir = get_aim_dir();
#####B if (ret == FALSE) then
#####B return
#####B end
#####B damage = player.lev*3
#####B msg_print("You breathe fire.")
#####B fire_ball(GF_FIRE, dir, damage, 3)
#####Bend,
The [[[[[B"power"] bit is what actually happens when the player accesses this
power
from their 'U' menu. Every function must start with the word [[[[[Bfunction].
Normally, we'd also declare its name at this point, but as this is contained
within the [[[[[Badd_power] function, we just use the word [[[[[Bfunction] The
empty
brackets after this denote that no arguments are passed to the function.
Lets look at the next line.
#####B local ret, dir, damage
The [[[[[Blocal] bit is saying that we're going to declare some local
variables. That
is, that there will be three variables used in this function , that apply
exclusively to this function, and to no others. Global variables are
variables that apply to the whole script, in multiple functions. The three
variables will be called [[[[[Bret] (return), [[[[[Bdir] (direction), and
[[[[[Bdamage]. They will be used to determine the direction the ball
will fire in, and how much damage it will do. We'll see them in use when we add
the third line:
#####B ret, dir = get_aim_dir();
here we're saying that the variables will take their value from the result
of a function. The program performs the function [[[[[Bget_aim_dir] which
essentially asks the player to choose a direction or pick a target.
[[[[[Bget_aim_dir]
assigns the value [[[[[Bret] to either TRUE (if the player correctly selected a
direction) or FALSE (if the player failed to do so (maybe they changed their
mind, or hit the wrong key!)). The value [[[[[Bdir] is the direction which was
selected (or the path to the target if a target was selected). OK so let's add
the next line:
#####B if (ret == FALSE) then return end
This introduces another fundamental scripting concept - [[[[[Bif] statements.
They work just as you would expect them too. You say "if a certain condition is
met, then do the following things."
So in this function we're saying, "if the value of [[[[[Bret] is FALSE then
[[[[[Breturn]."
As I mentioned above, [[[[[Bret] is false if the player aborted (either
deliberately or accidentally) the spell casting whilst choosing a direction
for the spell. The double equals sign are used to mean "is equal to" as a
single equals sign is used for defining variables remember? A single equals
sign is more of a "let x be equal to y" thing.
[[[[[Breturn] means stop the current function. And [[[[[Bend] signifies the
close of the [[[[[Bif]
statement. Every [[[[[Bif] statement must begin with an [[[[[Bif] and finish
with an [[[[[Bend].
So, what our [[[[[Bif] statement is saying is; "if the player failed to specify
a direction or target for the spell, stop the function here."
If the player has correctly specified a direction/target, the function
continues to the next line:
#####B damage = player.lev*3
Here we're saying that the variable [[[[[Bdamage] has a value equal to the
players current character level, multiplied by 3.
#####B msg_print("You breathe fire.")
Fairly easy to see what this does - displays the message "You breathe fire."
I could have put anything there obviously, like [[[[[Bmsg_print("You open]
[[[[[Byour mouth and everyone falls over with the smell of hot curry")] or
some other such rubbish. But note that the message is enclosed within double
quotes. The quotes aren't displayed in the message on screen, but signify the
start and end of the message.
#####B fire_ball(GF_FIRE, dir, damage, 3)
This is the line that casts the spell. it says execute the function
[[[[[Bfire_ball]. Now, this doesn't mean a fireball, it means fire a ball.
There's an important distinction there! All it knows it is doing is firing a
ball, it doesn't know what kind of ball, or where, or how big, or how much
damage.
The [[[[[BGF_FIRE,] bit is what tell us it is a fire ball. If it was
[[[[[BGF_COLD,]
we'd have a cold ball, or [[[[[BGF_CHAOS,] it would be a chaos ball and
so on and so on. A full list of those types can be found in *****lua_gf.txt*0[lua_gf.txt].
[[[[[B dir,] is the direction, from the [[[[[Bget_aim_dir()] bit.
[[[[[B damage,] is the damage. As we've already said, this will be clvl*3.
[[[[[B 3)] is the radius.
and finally...
#####B end,
#####B}
[[[[[Bend,] tells it the function has ended. Every function must finish with
[[[[[Bend].
You should have spotted that after the end of each attribute is a comma. Make
sure you include this, and don't forget the braces at the very very end to
close the [[[[[Badd_power] function.
#####R=== Finishing the LUA file ===
Save this as a text file 'pheonix.lua' Put it into the lib\scrpt directory
of ToME, and open the init.lua file which you'll find in the same
directory.
Add the following line and resave the init.lua file.
#####Btome_dofile("pheonix.lua")
This ensures that ToME loads your file on start-up. Because you've installed
the example scripts, this has all been done for you.
#####R=== A quick word about comments ===
One of the reasons Angband has so many variants is because the source code is
clearly commented. Almost every line of code has an accompanying comment,
explaining what that line does. It's good practice to add comments to any code
or script you write. It's helpful to others who are learning, anyone who takes
over your project, and also to yourself when you come back in a month's time
and can't remember what you did! So comment your code clearly, and well!
You can also add multi line comments which should be enclosed by [[[[[B--[[]
and
#####B]]
#####R=== Tying it all together ===
You'll now need to link this 'U' power to the pheonix race via the
p_info.txt file. Simply add a line within the class definition file that has
the format [[[[[BR:Z:<name>]the name of the power as it appears in the
[[[[[B"name"]
section we did right at the beginning, remember? Seeing as there is no pheonix
race, I've gone ahead and made one up as a demonstration. If you've downloaded
and installed the example files from [[[[[Ghttp://www.moppy.co.uk/angband.htm/]
then
you'll notice you already have the pheonix race available. Printed below is
the p_info.txt entry for it.
#####BR:N:23:Pheonix
#####BR:D:Born from flame, these powerful bird like creatures gain fire related
#####BR:D:abilities as they grow.
#####BR:S:1:0:2:1:-3:2:-5
#####BR:K:-8:15:20:-10:5:-1:-5:-5
#####BR:P:8:130:5:210
#####BR:M:255:70:2:1:20:5:2:1:18:3
#####BR:E:1:1:1:2:1:1
#####BR:C:Warrior | Mage | Priest | Rogue | Ranger | Paladin | Blade |
#####BR:C:Warlock | Chaos-Warrior | Monk | Mindcrafter | High-Mage |
#####BR:C:BeastMaster | Alchemist | Power-Mage | Runecrafter |
#####BR:C:Sorceror | Archer | Illusionist | Druid | Necromancer | Black-Knight
|
#####BR:C:Daemonologist | Weaponmaster | Summoner |
#####BR:Z:Fire Ball
#####BR:R:1:0
#####BR:F:RES_FIRE | FEATHER |
Note the [[[[[BR:Z:] line.
If all is well, you should be able to start ToME now and breathe fire! Once
you get to lvl 10 anyhow. Don't forget, this is the kind of thing wizard mode
was invented for! Ctrl-A and confirm at the prompt, and then 'e' will allow
you to alter stats, including experience. Approx 1000 exp should do to get you
to clvl 10.
Ready for more? How about adding a new *****lua_skil.txt*0[skill] ?
[[[[[gThis file by fearoffours (fearoffours@moppy.co.uk)]
|