forked from DFHack/scripts
-
Notifications
You must be signed in to change notification settings - Fork 4
/
assign-profile.lua
217 lines (185 loc) · 8.01 KB
/
assign-profile.lua
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
-- Set a dwarf's characteristics according to a predefined profile
--@ module = true
local help = [====[
assign-profile
==============
A script to change the characteristics of a unit
according to a profile loaded from a json file.
A profile can describe which attributes, skills, preferences, beliefs,
goals and facets a unit must have. The script relies on the presence
of the other ``assign-...`` modules in this collection: please refer
to the other modules documentation for more specific information.
For information about the json schema, please see the
the "/hack/scripts/dwarf_profiles.json" file.
Usage:
``-help``:
print the help page.
``-unit <UNIT_ID>``:
the target unit ID. If not present, the
target will be the currently selected unit.
``-file <filename>``:
the json file containing the profile to apply.
It's a relative path, starting from the DF
root directory and ending at the json file.
It must begin with a slash. Default value:
"/hack/scripts/dwarf_profiles.json".
``-profile <profile>``:
the profile to apply. It's the name of
the profile as stated in the json file.
``-reset <list of characteristics>``:
the characteristics to be reset/cleared. If not present,
it will not clear or reset any characteristic. If it's a
valid list of characteristic, those characteristics will
be reset, and then, if present in the profile, the new
values will be applied. If set to ``PROFILE``, it will
reset only the characteristics changed in the profile
(and then the new values will be applied). If set to
``ALL``, it will reset EVERY characteristic. Possible
values: ``ALL``, ``PROFILE``, ``ATTRIBUTES``, ``SKILLS``,
``PREFERENCES``, ``BELIEFS``, ``GOALS``, ``FACETS``.
Examples:
``assign-profile -reset ALL``
Resets/clears all the characteristics of the
unit, leaving behind a very bland character.
``assign-profile -profile CARPENTER -reset PROFILE``
Loads and applies the profile called "CARPENTER"
in the default json file, resetting/clearing
all the characteristics listed in the
profile, and then applying the new values.
``assign-profile -file /hack/scripts/military_profiles.json -profile ARCHER -reset ATTRIBUTES``
Loads and applies the profile called "ARCHER"
in the provided json file, keeping all the old
characteristics but the attributes, which will
be reset (and then, if the profile provides some
attributes values, those value will be applied).
]====]
local json = require "json"
local valid_args = {
HELP = "-help",
UNIT = "-unit",
FILE = "-file",
PROFILE = "-profile",
RESET = "-reset",
}
-- add a script here to include it in the profile. The key must be the same as written in the json.
local scripts = {
ATTRIBUTES = reqscript("assign-attributes"),
SKILLS = reqscript("assign-skills"),
PREFERENCES = reqscript("assign-preferences"),
BELIEFS = reqscript("assign-beliefs"),
GOALS = reqscript("assign-goals"),
FACETS = reqscript("assign-facets"),
}
local default_filename = "/hack/scripts/dwarf_profiles.json"
-- ----------------------------------------------- UTILITY FUNCTIONS ------------------------------------------------ --
local function contains(table, value)
for _, v in pairs(table) do
if v == value then
return true
end
end
return false
end
-- ------------------------------------------------- APPLY PROFILE -------------------------------------------------- --
--- Apply the given profile to a unit, erasing or resetting the unit characteristics if requested.
--- :profile: nil, or a table. Each field has a characteristic name as key, and a table suitable to be passed as
--- an argument to the ``assign`` function of the module related to the characteristic.
--- See the modules documentation for more details.
--- :unit: a valid unit id, a df.unit object, or nil. If nil, the currently selected unit will be targeted.
--- :reset: nil, or a table value/boolean. See this script documentation for valid values.
--luacheck: in=string[],df.unit,bool[]
function apply_profile(profile, unit, reset_table)
assert(not profile or type(profile) == "table")
assert(not unit or type(unit) == "number" or type(unit) == "userdata")
assert( not reset_table or type(reset_table) == "table")
profile = profile or {}
reset_table = reset_table or {}
local function apply(characteristic_name, script)
local reset_flag = reset_table.ALL or
reset_table[characteristic_name] ~= nil or
(reset_table.PROFILE and profile[characteristic_name] ~= nil)
script.assign(profile[characteristic_name], unit, reset_flag)
end
for characteristic_name, script in pairs(scripts) do
apply(characteristic_name, script)
end
end
-- --------------------------------------------------- LOAD PROFILE ------------------------------------------------- --
--- Load the given profile, searching it inside the given JSON file (if not nil) or inside the default JSON file.
--- The filename must begin with a slash and must be a relative path starting from the root DF
--- directory and ending at the desired file.
--- Return the parsed profile as a table.
--luacheck: in=string,string
function load_profile(profile_name, filename)
assert(profile_name ~= nil)
local json_file = string.format("%s%s", dfhack.getDFPath(), filename or default_filename)
local profiles = {} --as:string[][]
if dfhack.filesystem.isfile(json_file) then
profiles = json.decode_file(json_file)
else
qerror(string.format("File '%s' not found.", json_file))
end
if profiles[profile_name] then
return profiles[profile_name]
else
qerror(string.format("Profile '%s' not found", profile_name))
end
end
-- ------------------------------------------------------ MAIN ------------------------------------------------------ --
local function main(...)
local args = { ... }
if #args == 0 then
print(help)
return
end
local unit_id
local filename
local profile_name
local reset_table = {}
local i = 1
while i <= #args do
local arg = args[i]
if arg == valid_args.HELP then
print(help)
return
elseif arg == valid_args.UNIT then
i = i + 1 -- consume next arg
local unit_id_str = args[i]
if not unit_id_str then
-- we reached the end of the arguments list
qerror("Missing unit id.")
end
unit_id = tonumber(unit_id_str)
if not unit_id then
qerror("'" .. unit_id_str .. "' is not a valid unit ID.")
end
elseif arg == valid_args.FILE then
i = i + 1 -- consume next arg
filename = args[i]
if not filename then
-- we reached the end of the arguments list
qerror("Missing profile name.")
end
elseif arg == valid_args.PROFILE then
i = i + 1 -- consume next arg
profile_name = args[i]
if not profile_name then
-- we reached the end of the arguments list
qerror("Missing profile name.")
end
elseif arg == valid_args.RESET then
while args[i + 1] and not contains(valid_args, args[i + 1]) do
i = i + 1
reset_table[args[i]:upper()] = true
end
else
qerror("'" .. arg .. "' is not a valid argument.")
end
i = i + 1 -- go to the next argument
end
local profile = load_profile(profile_name, filename)
apply_profile(profile, unit_id, reset_table)
end
if not dfhack_flags.module then
main(...)
end