Merge lp:~widelands-dev/widelands/editor_help into lp:widelands

Proposed by GunChleoc
Status: Merged
Merged at revision: 7826
Proposed branch: lp:~widelands-dev/widelands/editor_help
Merge into: lp:widelands
Diff against target: 3411 lines (+1923/-150)
63 files modified
data/scripting/editor/format_editor.lua (+54/-0)
data/scripting/editor/terrain_help.lua (+76/-0)
data/scripting/editor/tree_help.lua (+44/-0)
data/scripting/lunit.lua (+11/-0)
data/tribes/buildings/trainingsites/atlanteans/labyrinth/init.lua (+2/-2)
data/world/immovables/trees/alder/init.lua (+1/-0)
data/world/immovables/trees/aspen/init.lua (+1/-0)
data/world/immovables/trees/beech/init.lua (+1/-0)
data/world/immovables/trees/birch/init.lua (+1/-0)
data/world/immovables/trees/cirrus/init.lua (+2/-0)
data/world/immovables/trees/larch/init.lua (+1/-0)
data/world/immovables/trees/liana/init.lua (+2/-0)
data/world/immovables/trees/maple/init.lua (+1/-0)
data/world/immovables/trees/mushroom_dark/init.lua (+2/-0)
data/world/immovables/trees/mushroom_green/init.lua (+2/-0)
data/world/immovables/trees/mushroom_red/init.lua (+2/-0)
data/world/immovables/trees/oak/init.lua (+1/-0)
data/world/immovables/trees/palm_borassus/init.lua (+1/-0)
data/world/immovables/trees/palm_coconut/init.lua (+1/-0)
data/world/immovables/trees/palm_date/init.lua (+1/-0)
data/world/immovables/trees/palm_oil/init.lua (+1/-0)
data/world/immovables/trees/palm_roystonea/init.lua (+1/-0)
data/world/immovables/trees/rowan/init.lua (+1/-0)
data/world/immovables/trees/spruce/init.lua (+1/-0)
data/world/immovables/trees/twine/init.lua (+2/-0)
data/world/immovables/trees/umbrella_green/init.lua (+2/-0)
data/world/immovables/trees/umbrella_red/init.lua (+3/-1)
data/world/resources/init.lua (+7/-4)
src/editor/CMakeLists.txt (+2/-0)
src/editor/editorinteractive.cc (+33/-13)
src/editor/editorinteractive.h (+3/-0)
src/editor/tools/editor_info_tool.cc (+1/-1)
src/editor/ui_menus/categorized_item_selection_menu.h (+1/-1)
src/editor/ui_menus/editor_help.cc (+224/-0)
src/editor/ui_menus/editor_help.h (+109/-0)
src/editor/ui_menus/editor_tool_change_resources_options_menu.cc (+2/-2)
src/logic/field.h (+2/-0)
src/logic/map_objects/immovable.cc (+21/-5)
src/logic/map_objects/immovable.h (+7/-2)
src/logic/map_objects/terrain_affinity.cc (+38/-15)
src/logic/map_objects/terrain_affinity.h (+4/-0)
src/logic/map_objects/tribes/worker.cc (+1/-1)
src/logic/map_objects/world/resource_description.cc (+3/-2)
src/logic/map_objects/world/resource_description.h (+5/-1)
src/logic/map_objects/world/terrain_description.cc (+6/-2)
src/logic/map_objects/world/terrain_description.h (+4/-1)
src/logic/map_objects/world/world.cc (+1/-1)
src/logic/map_objects/world/world.h (+1/-1)
src/map_io/map_terrain_packet.cc (+1/-1)
src/scripting/lua_bases.cc (+91/-8)
src/scripting/lua_bases.h (+3/-0)
src/scripting/lua_game.cc (+3/-2)
src/scripting/lua_map.cc (+564/-33)
src/scripting/lua_map.h (+149/-0)
src/scripting/lua_root.cc (+63/-10)
src/scripting/lua_root.h (+2/-0)
src/wui/encyclopedia_window.cc (+22/-24)
src/wui/encyclopedia_window.h (+1/-1)
src/wui/game_main_menu_save_game.cc (+7/-3)
test/maps/lua_persistence.wmf/scripting/test_persistence.lua (+6/-0)
test/maps/lua_testsuite.wmf/scripting/immovables_descriptions.lua (+137/-13)
test/maps/lua_testsuite.wmf/scripting/init.lua (+1/-0)
test/maps/lua_testsuite.wmf/scripting/terrains_resources_descriptions.lua (+180/-0)
To merge this branch: bzr merge lp:~widelands-dev/widelands/editor_help
Reviewer Review Type Date Requested Status
SirVer code, testing Approve
GunChleoc Needs Resubmitting
kaputtnik (community) functionality Approve
Review via email: mp+283900@code.launchpad.net

Commit message

Exposed terrain and resource descriptions to the Lua interface and added tree and terrain help to the editor.

Description of the change

Added tree and terrain help to the editor.

The design is discussed in the forum:

https://wl.widelands.org/forum/topic/1870/

We are also thinking of making terrains on the map clickable to popup a smaller help window, or maybe adding it to the info tool, but that can be done in a separate branch.

To post a comment you must log in.
Revision history for this message
bunnybot (widelandsofficial) wrote :

Hi, I am bunnybot (https://github.com/widelands/bunnybot).

I am keeping the source branch lp:~widelands-dev/widelands/editor_help mirrored to https://github.com/widelands/widelands/tree/_widelands_dev_widelands_editor_help

You can give me commands by starting a line with @bunnybot <command>. I understand:
 merge: Merges the source branch into the target branch, closing the merge proposal. I will use the proposed commit message if it is set.

Revision history for this message
kaputtnik (franku) wrote :

Works well :-) If possible move the resource image(s) for "Default: ..." to the left. If it is on the right and all other images are left aligned, it looks a bit lost on the right side.

Revision history for this message
GunChleoc (gunchleoc) wrote :

I see your point - done :)

Revision history for this message
bunnybot (widelandsofficial) wrote :

Continuous integration builds have changed state:

Travis build 404. State: passed. Details: https://travis-ci.org/widelands/widelands/builds/104893035.
Appveyor build 311. State: failed. Details: https://ci.appveyor.com/project/widelands-dev/widelands/build/_widelands_dev_widelands_editor_help-311.

Revision history for this message
bunnybot (widelandsofficial) wrote :

Continuous integration builds have changed state:

Travis build 444. State: passed. Details: https://travis-ci.org/widelands/widelands/builds/105656855.
Appveyor build 341. State: success. Details: https://ci.appveyor.com/project/widelands-dev/widelands/build/_widelands_dev_widelands_editor_help-341.

Revision history for this message
kaputtnik (franku) wrote :

The current state isn't the best choice, but it will help a lot when designing a map regarding trees.

So for build 19 i think it's good :-)

review: Approve (functionality)
Revision history for this message
bunnybot (widelandsofficial) wrote :

Continuous integration builds have changed state:

Travis build 483. State: failed. Details: https://travis-ci.org/widelands/widelands/builds/106161900.
Appveyor build 355. State: success. Details: https://ci.appveyor.com/project/widelands-dev/widelands/build/_widelands_dev_widelands_editor_help-355.

Revision history for this message
bunnybot (widelandsofficial) wrote :

Continuous integration builds have changed state:

Travis build 497. State: passed. Details: https://travis-ci.org/widelands/widelands/builds/106265191.
Appveyor build 379. State: success. Details: https://ci.appveyor.com/project/widelands-dev/widelands/build/_widelands_dev_widelands_editor_help-379.

Revision history for this message
SirVer (sirver) wrote :

I started reviewing this now, I got through all the Lua files and fixed a couple of nits and left NCOMs (accidentally some with my username, but they are all yours :)).

I hope to get around to the .cc files later.

Revision history for this message
GunChleoc (gunchleoc) wrote :

Thanks!

I'll wait until you're done with the .cc files, so we won't be both playing with the branch at the same time.

Revision history for this message
SirVer (sirver) wrote :

Finished code review. I have some reservation about the API design in the Lua part. I think we should not rely on passing around so many strings, instead pass around the structured objects already.

review: Needs Fixing
Revision history for this message
bunnybot (widelandsofficial) wrote :

Continuous integration builds have changed state:

Travis build 616. State: passed. Details: https://travis-ci.org/widelands/widelands/builds/107568619.
Appveyor build 473. State: failed. Details: https://ci.appveyor.com/project/widelands-dev/widelands/build/_widelands_dev_widelands_editor_help-473.

Revision history for this message
GunChleoc (gunchleoc) wrote :

Putting this on hold to save Travis some work.

Revision history for this message
GunChleoc (gunchleoc) wrote :

This is ready for the next round now. I have made a separate commit for each issue.

There are still some NOCOMs left that can either go or that I need some information for.

Revision history for this message
bunnybot (widelandsofficial) wrote :

Continuous integration builds have changed state:

Travis build 616. State: passed. Details: https://travis-ci.org/widelands/widelands/builds/107568619.
Appveyor build 473. State: failed. Details: https://ci.appveyor.com/project/widelands-dev/widelands/build/_widelands_dev_widelands_editor_help-473.

Revision history for this message
kaputtnik (franku) wrote :

Works :-)

One thing is curious: In "Terrains tab" either the up/down arrow keys are working nor the mouse wheel in the left list. In "Trees tab" both are working for the left list.

Revision history for this message
GunChleoc (gunchleoc) wrote :

Mousewheel has been sort of broken since we moved to SDL2.

Revision history for this message
SirVer (sirver) wrote :

Did the code review - nearly there, only a few NOCOM remain.

review: Needs Fixing
Revision history for this message
GunChleoc (gunchleoc) wrote :

Thanks for the code review - the branch is ready again.

Note that I had to change a function from protected to public.

review: Needs Resubmitting
Revision history for this message
SirVer (sirver) wrote :

lgtm.

review: Approve (code, testing)
Revision history for this message
bunnybot (widelandsofficial) wrote :

Continuous integration builds have changed state:

Travis build 681. State: failed. Details: https://travis-ci.org/widelands/widelands/builds/109002021.
Appveyor build 533. State: failed. Details: https://ci.appveyor.com/project/widelands-dev/widelands/build/_widelands_dev_widelands_editor_help-533.

Revision history for this message
bunnybot (widelandsofficial) wrote :

Continuous integration builds have changed state:

Travis build 681. State: failed. Details: https://travis-ci.org/widelands/widelands/builds/109002021.
Appveyor build 533. State: success. Details: https://ci.appveyor.com/project/widelands-dev/widelands/build/_widelands_dev_widelands_editor_help-533.

Revision history for this message
bunnybot (widelandsofficial) wrote :

Continuous integration builds have changed state:

Travis build 686. State: passed. Details: https://travis-ci.org/widelands/widelands/builds/109135916.
Appveyor build 538. State: success. Details: https://ci.appveyor.com/project/widelands-dev/widelands/build/_widelands_dev_widelands_editor_help-538.

Revision history for this message
GunChleoc (gunchleoc) wrote :

@bunnybot merge

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== added directory 'data/scripting/editor'
2=== added file 'data/scripting/editor/format_editor.lua'
3--- data/scripting/editor/format_editor.lua 1970-01-01 00:00:00 +0000
4+++ data/scripting/editor/format_editor.lua 2016-02-14 10:01:52 +0000
5@@ -0,0 +1,54 @@
6+-- RST
7+-- format_editor.lua
8+-- ---------------
9+
10+-- Functions used in the ingame editor help windows for formatting the text and pictures.
11+
12+include "scripting/formatting.lua"
13+
14+-- RST
15+-- .. function picture_li(imagepath, text)
16+--
17+-- Places a paragraph of text to the right of an image
18+
19+-- :arg imagepath: the full path to the image file
20+-- :arg text: the text to be placed next to the image
21+--
22+-- :returns: the text wrapped in a paragraph and placed next to the image
23+function picture_li(imagepath, text)
24+ return "<rt image=" .. imagepath .. " image-align=left>"
25+ .. p(text) .. "</rt>"
26+end
27+
28+-- RST
29+-- .. function spacer()
30+--
31+-- Adds a little space between two paragraphs
32+--
33+-- :returns: a small empty paragraph
34+function spacer()
35+ return rt(p("font-size=3", ""))
36+end
37+
38+-- RST
39+-- .. function text_line(t1, t2[, imgstr = nil])
40+--
41+-- Creates a line of h3 formatted text followed by normal text and an image.
42+--
43+-- :arg t1: text in h3 format.
44+-- :arg t2: text in p format.
45+-- :arg imgstr: image aligned right.
46+-- :returns: header followed by normal text and image.
47+--
48+function text_line(t1, t2, imgstr)
49+ if imgstr then
50+ return "<rt text-align=left image=" .. imgstr ..
51+ " image-align=right><p font-size=13 font-color=D1D1D1>" ..
52+ t1 .. "</p><p line-spacing=3 font-size=12>" ..
53+ t2 .. "<br></p><p font-size=8> <br></p></rt>"
54+ else
55+ return "<rt text-align=left><p font-size=13 font-color=D1D1D1>" ..
56+ t1 .. "</p><p line-spacing=3 font-size=12>" ..
57+ t2 .. "<br></p><p font-size=8> <br></p></rt>"
58+ end
59+end
60
61=== added file 'data/scripting/editor/terrain_help.lua'
62--- data/scripting/editor/terrain_help.lua 1970-01-01 00:00:00 +0000
63+++ data/scripting/editor/terrain_help.lua 2016-02-14 10:01:52 +0000
64@@ -0,0 +1,76 @@
65+-- RST
66+-- terrain_help.lua
67+-- -------------
68+
69+
70+-- This file returns a formatted entry for the terrain help in the editor.
71+
72+include "scripting/editor/format_editor.lua"
73+
74+return {
75+ func = function(terrain_name)
76+ set_textdomain("widelands")
77+ local world = wl.World();
78+ local terrain = wl.Editor():get_terrain_description(terrain_name)
79+
80+ local result = picture_li(terrain.representative_image, "")
81+
82+ -- Resources
83+ local valid_resources = terrain.valid_resources
84+ if (#valid_resources > 0) then
85+ result = result .. spacer() .. rt(h2(_"Resources"))
86+ if (#valid_resources > 0) then
87+ -- TRANSLATORS: A header in the editor help
88+ result = result .. rt(h3(ngettext(
89+ "Valid Resource:", "Valid Resources:", #valid_resources)))
90+ for count, resource in pairs(valid_resources) do
91+ result = result .. picture_li(
92+ resource.representative_image, resource.descname)
93+ end
94+ end
95+
96+ local default_resource = terrain.default_resource
97+ if (default_resource ~= nil) then
98+ -- TRANSLATORS: e.g. "5x Water"
99+ result = result .. text_line(_"Default:", _"%1%x %2%":bformat(
100+ terrain.default_resource_amount, default_resource.descname))
101+ end
102+ end
103+
104+ -- Trees
105+ local tree_list = {}
106+ for i, immovable in ipairs(world.immovable_descriptions) do
107+ if (immovable:has_attribute("tree")) then
108+ local probability = immovable:probability_to_grow(terrain)
109+ if (probability > 0.01) then
110+ -- sort the trees by percentage
111+ i = 1
112+ while (tree_list[i] and (tree_list[i].probability > probability)) do
113+ i = i + 1
114+ end
115+
116+ for j = #tree_list, i, -1 do
117+ tree_list[j+1] = tree_list[j]
118+ end
119+ tree_list[i] = {tree = immovable, probability = probability}
120+ end
121+ end
122+ end
123+
124+ local tree_string = ""
125+ for k,v in ipairs(tree_list) do
126+ tree_string = tree_string .. picture_li(v.tree.representative_image,
127+ v.tree.species .. ("<br>%2.1f%%"):bformat(100 * v.probability)) .. spacer()
128+ end
129+
130+ -- TRANSLATORS: A header in the editor help
131+ result = result .. spacer() .. rt(h2(_"Probability of trees growing")) .. spacer()
132+
133+ if (tree_string ~="") then
134+ result = result .. tree_string
135+ else
136+ result = result .. rt(p(_"No trees will grow here."))
137+ end
138+ return result
139+ end
140+}
141
142=== added file 'data/scripting/editor/tree_help.lua'
143--- data/scripting/editor/tree_help.lua 1970-01-01 00:00:00 +0000
144+++ data/scripting/editor/tree_help.lua 2016-02-14 10:01:52 +0000
145@@ -0,0 +1,44 @@
146+-- RST
147+-- tree_help.lua
148+-- -------------
149+
150+-- This file returns a formatted entry for the tree help in the editor.
151+
152+include "scripting/editor/format_editor.lua"
153+
154+return {
155+ func = function(tree_name)
156+ set_textdomain("widelands")
157+ local world = wl.World();
158+ local tree = wl.Editor():get_immovable_description(tree_name)
159+ local result = picture_li(tree.representative_image, "")
160+
161+ -- TRANSLATORS: A header in the editor help. Terrains preferred by a type of tree.
162+ result = result .. rt(p("font-size=3", "")) .. rt(h2(_"Preferred terrains")) .. spacer()
163+ terrain_list = {}
164+ for i, terrain in ipairs(world.terrain_descriptions) do
165+ local probability = tree:probability_to_grow(terrain)
166+ if (probability > 0.01) then
167+ -- sort the terrains by percentage
168+ i = 1
169+ while (terrain_list[i] and (terrain_list[i].probability > probability)) do
170+ i = i + 1
171+ end
172+
173+ for j = #terrain_list, i, -1 do
174+ terrain_list[j+1] = terrain_list[j]
175+ end
176+ terrain_list[i] = {terrain = terrain, probability = probability}
177+ end
178+ end
179+
180+ for k,v in ipairs(terrain_list) do
181+ -- TRANSLATORS: Terrain name (Climate)
182+ result = result .. picture_li(v.terrain.representative_image,
183+ (_"%1% (%2%)"):bformat(v.terrain.descname, v.terrain.editor_category.descname) ..
184+ "<br>" .. ("%2.1f%%"):bformat(100 * v.probability)
185+ ) .. spacer()
186+ end
187+ return result
188+ end
189+}
190
191=== modified file 'data/scripting/lunit.lua'
192--- data/scripting/lunit.lua 2015-10-31 11:59:04 +0000
193+++ data/scripting/lunit.lua 2016-02-14 10:01:52 +0000
194@@ -110,6 +110,17 @@
195 return actual
196 end
197
198+-- For testing float numbers - they can turn out to be a bit different from system
199+-- to system, so we need a tolerance range.
200+function assert_near(expected, actual, tolerance, msg)
201+ lunit_stats_inc("assertions")
202+ lunit_check_msg("assert_equal", msg)
203+ lunit_do_assert(expected + tolerance >= actual, "expected '"..tostring(expected).."' with a tolerance of '"..tostring(tolerance).."' but was '"..tostring(actual).."'", msg)
204+ lunit_do_assert(expected - tolerance <= actual, "expected '"..tostring(expected).."' with a tolerance of '"..tostring(tolerance).."' but was '"..tostring(actual).."'", msg)
205+ return actual
206+end
207+
208+
209 function assert_match(pattern, actual, msg)
210 lunit_stats_inc("assertions")
211 lunit_check_msg("assert_match", msg)
212
213=== modified file 'data/tribes/buildings/trainingsites/atlanteans/labyrinth/init.lua'
214--- data/tribes/buildings/trainingsites/atlanteans/labyrinth/init.lua 2016-01-02 21:39:43 +0000
215+++ data/tribes/buildings/trainingsites/atlanteans/labyrinth/init.lua 2016-02-14 10:01:52 +0000
216@@ -34,8 +34,8 @@
217 },
218
219 aihints = {
220- prohibited_till=900,
221- forced_after=1500,
222+ prohibited_till = 900,
223+ forced_after = 1500,
224 trainingsite_type = "basic",
225 very_weak_ai_limit = 1,
226 weak_ai_limit = 2
227
228=== modified file 'data/world/immovables/trees/alder/init.lua'
229--- data/world/immovables/trees/alder/init.lua 2016-01-28 05:24:34 +0000
230+++ data/world/immovables/trees/alder/init.lua 2016-02-14 10:01:52 +0000
231@@ -87,6 +87,7 @@
232 world:new_immovable_type{
233 name = "alder_summer_old",
234 descname = _ "Alder (Old)",
235+ species = _ "Alder",
236 editor_category = "trees_deciduous",
237 size = "small",
238 attributes = { "tree" },
239
240=== modified file 'data/world/immovables/trees/aspen/init.lua'
241--- data/world/immovables/trees/aspen/init.lua 2016-01-28 05:24:34 +0000
242+++ data/world/immovables/trees/aspen/init.lua 2016-02-14 10:01:52 +0000
243@@ -82,6 +82,7 @@
244 world:new_immovable_type{
245 name = "aspen_summer_old",
246 descname = _ "Aspen (Old)",
247+ species = _ "Aspen",
248 editor_category = "trees_deciduous",
249 size = "small",
250 attributes = { "tree" },
251
252=== modified file 'data/world/immovables/trees/beech/init.lua'
253--- data/world/immovables/trees/beech/init.lua 2016-01-28 05:24:34 +0000
254+++ data/world/immovables/trees/beech/init.lua 2016-02-14 10:01:52 +0000
255@@ -79,6 +79,7 @@
256 world:new_immovable_type{
257 name = "beech_summer_old",
258 descname = _ "Beech (Old)",
259+ species = _ "Beech",
260 editor_category = "trees_deciduous",
261 size = "small",
262 attributes = { "tree" },
263
264=== modified file 'data/world/immovables/trees/birch/init.lua'
265--- data/world/immovables/trees/birch/init.lua 2016-01-28 05:24:34 +0000
266+++ data/world/immovables/trees/birch/init.lua 2016-02-14 10:01:52 +0000
267@@ -82,6 +82,7 @@
268 world:new_immovable_type{
269 name = "birch_summer_old",
270 descname = _ "Birch (Old)",
271+ species = _ "Birch",
272 editor_category = "trees_deciduous",
273 size = "small",
274 attributes = { "tree" },
275
276=== modified file 'data/world/immovables/trees/cirrus/init.lua'
277--- data/world/immovables/trees/cirrus/init.lua 2015-11-03 18:18:27 +0000
278+++ data/world/immovables/trees/cirrus/init.lua 2016-02-14 10:01:52 +0000
279@@ -83,6 +83,8 @@
280 name = "cirrus_wasteland_old",
281 -- TRANSLATORS: This is a fictitious tree. Be creative if you want.
282 descname = _ "Cirrus Tree (Old)",
283+ -- TRANSLATORS: This is a fictitious tree. Be creative if you want.
284+ species = _ "Cirrus Tree",
285 editor_category = "trees_wasteland",
286 size = "small",
287 attributes = { "tree" },
288
289=== modified file 'data/world/immovables/trees/larch/init.lua'
290--- data/world/immovables/trees/larch/init.lua 2016-01-28 05:24:34 +0000
291+++ data/world/immovables/trees/larch/init.lua 2016-02-14 10:01:52 +0000
292@@ -79,6 +79,7 @@
293 world:new_immovable_type{
294 name = "larch_summer_old",
295 descname = _ "Larch (Old)",
296+ species = _ "Larch",
297 editor_category = "trees_coniferous",
298 size = "small",
299 attributes = { "tree" },
300
301=== modified file 'data/world/immovables/trees/liana/init.lua'
302--- data/world/immovables/trees/liana/init.lua 2015-11-03 18:18:27 +0000
303+++ data/world/immovables/trees/liana/init.lua 2016-02-14 10:01:52 +0000
304@@ -86,6 +86,8 @@
305 name = "liana_wasteland_old",
306 -- TRANSLATORS: This is a fictitious tree. Be creative if you want.
307 descname = _ "Liana Tree (Old)",
308+ -- TRANSLATORS: This is a fictitious tree. Be creative if you want.
309+ species = _ "Liana Tree",
310 editor_category = "trees_wasteland",
311 size = "small",
312 attributes = { "tree" },
313
314=== modified file 'data/world/immovables/trees/maple/init.lua'
315--- data/world/immovables/trees/maple/init.lua 2016-01-28 05:24:34 +0000
316+++ data/world/immovables/trees/maple/init.lua 2016-02-14 10:01:52 +0000
317@@ -79,6 +79,7 @@
318 world:new_immovable_type{
319 name = "maple_winter_old",
320 descname = _ "Maple (Old)",
321+ species = _ "Maple",
322 editor_category = "trees_deciduous",
323 size = "small",
324 attributes = { "tree" },
325
326=== modified file 'data/world/immovables/trees/mushroom_dark/init.lua'
327--- data/world/immovables/trees/mushroom_dark/init.lua 2015-11-03 18:18:27 +0000
328+++ data/world/immovables/trees/mushroom_dark/init.lua 2016-02-14 10:01:52 +0000
329@@ -83,6 +83,8 @@
330 name = "mushroom_dark_wasteland_old",
331 -- TRANSLATORS: This is a fictitious tree. Be creative if you want.
332 descname = _ "Dark Mushroom Tree (Old)",
333+ -- TRANSLATORS: This is a fictitious tree. Be creative if you want.
334+ species = _ "Dark Mushroom Tree",
335 editor_category = "trees_wasteland",
336 size = "small",
337 attributes = { "tree" },
338
339=== modified file 'data/world/immovables/trees/mushroom_green/init.lua'
340--- data/world/immovables/trees/mushroom_green/init.lua 2015-11-03 18:18:27 +0000
341+++ data/world/immovables/trees/mushroom_green/init.lua 2016-02-14 10:01:52 +0000
342@@ -83,6 +83,8 @@
343 name = "mushroom_green_wasteland_old",
344 -- TRANSLATORS: This is a fictitious tree. Be creative if you want.
345 descname = _ "Green Mushroom Tree (Old)",
346+ -- TRANSLATORS: This is a fictitious tree. Be creative if you want.
347+ species = _ "Green Mushroom Tree",
348 editor_category = "trees_wasteland",
349 size = "small",
350 attributes = { "tree" },
351
352=== modified file 'data/world/immovables/trees/mushroom_red/init.lua'
353--- data/world/immovables/trees/mushroom_red/init.lua 2015-11-03 18:18:27 +0000
354+++ data/world/immovables/trees/mushroom_red/init.lua 2016-02-14 10:01:52 +0000
355@@ -86,6 +86,8 @@
356 name = "mushroom_red_wasteland_old",
357 -- TRANSLATORS: This is a fictitious tree. Be creative if you want.
358 descname = _ "Red Mushroom Tree (Old)",
359+ -- TRANSLATORS: This is a fictitious tree. Be creative if you want.
360+ species = _ "Red Mushroom Tree",
361 editor_category = "trees_wasteland",
362 size = "small",
363 attributes = { "tree" },
364
365=== modified file 'data/world/immovables/trees/oak/init.lua'
366--- data/world/immovables/trees/oak/init.lua 2016-01-28 05:24:34 +0000
367+++ data/world/immovables/trees/oak/init.lua 2016-02-14 10:01:52 +0000
368@@ -79,6 +79,7 @@
369 world:new_immovable_type{
370 name = "oak_summer_old",
371 descname = _ "Oak (Old)",
372+ species = _ "Oak",
373 editor_category = "trees_deciduous",
374 size = "small",
375 attributes = { "tree" },
376
377=== modified file 'data/world/immovables/trees/palm_borassus/init.lua'
378--- data/world/immovables/trees/palm_borassus/init.lua 2016-01-28 05:24:34 +0000
379+++ data/world/immovables/trees/palm_borassus/init.lua 2016-02-14 10:01:52 +0000
380@@ -79,6 +79,7 @@
381 world:new_immovable_type{
382 name = "palm_borassus_desert_old",
383 descname = _ "Borassus Palm (Old)",
384+ species = _ "Borassus Palm",
385 editor_category = "trees_palm",
386 size = "small",
387 attributes = { "tree" },
388
389=== modified file 'data/world/immovables/trees/palm_coconut/init.lua'
390--- data/world/immovables/trees/palm_coconut/init.lua 2016-01-28 05:24:34 +0000
391+++ data/world/immovables/trees/palm_coconut/init.lua 2016-02-14 10:01:52 +0000
392@@ -79,6 +79,7 @@
393 world:new_immovable_type{
394 name = "palm_coconut_desert_old",
395 descname = _ "Coconut Palm (Old)",
396+ species = _ "Coconut Palm",
397 editor_category = "trees_palm",
398 size = "small",
399 attributes = { "tree" },
400
401=== modified file 'data/world/immovables/trees/palm_date/init.lua'
402--- data/world/immovables/trees/palm_date/init.lua 2016-01-28 05:24:34 +0000
403+++ data/world/immovables/trees/palm_date/init.lua 2016-02-14 10:01:52 +0000
404@@ -82,6 +82,7 @@
405 world:new_immovable_type{
406 name = "palm_date_desert_old",
407 descname = _ "Date Palm (Old)",
408+ species = _ "Date Palm",
409 editor_category = "trees_palm",
410 size = "small",
411 attributes = { "tree" },
412
413=== modified file 'data/world/immovables/trees/palm_oil/init.lua'
414--- data/world/immovables/trees/palm_oil/init.lua 2016-01-28 05:24:34 +0000
415+++ data/world/immovables/trees/palm_oil/init.lua 2016-02-14 10:01:52 +0000
416@@ -83,6 +83,7 @@
417 world:new_immovable_type{
418 name = "palm_oil_desert_old",
419 descname = _ "Oil Palm (Old)",
420+ species = _ "Oil Palm",
421 editor_category = "trees_palm",
422 size = "small",
423 attributes = { "tree" },
424
425=== modified file 'data/world/immovables/trees/palm_roystonea/init.lua'
426--- data/world/immovables/trees/palm_roystonea/init.lua 2016-01-28 05:24:34 +0000
427+++ data/world/immovables/trees/palm_roystonea/init.lua 2016-02-14 10:01:52 +0000
428@@ -79,6 +79,7 @@
429 world:new_immovable_type{
430 name = "palm_roystonea_desert_old",
431 descname = _ "Roystonea regia Palm (Old)",
432+ species = _ "Roystonea regia Palm",
433 editor_category = "trees_palm",
434 size = "small",
435 attributes = { "tree" },
436
437=== modified file 'data/world/immovables/trees/rowan/init.lua'
438--- data/world/immovables/trees/rowan/init.lua 2016-01-28 05:24:34 +0000
439+++ data/world/immovables/trees/rowan/init.lua 2016-02-14 10:01:52 +0000
440@@ -82,6 +82,7 @@
441 world:new_immovable_type{
442 name = "rowan_summer_old",
443 descname = _ "Rowan (Old)",
444+ species = _ "Rowan",
445 editor_category = "trees_deciduous",
446 size = "small",
447 attributes = { "tree" },
448
449=== modified file 'data/world/immovables/trees/spruce/init.lua'
450--- data/world/immovables/trees/spruce/init.lua 2016-01-28 05:24:34 +0000
451+++ data/world/immovables/trees/spruce/init.lua 2016-02-14 10:01:52 +0000
452@@ -79,6 +79,7 @@
453 world:new_immovable_type{
454 name = "spruce_summer_old",
455 descname = _ "Spruce (Old)",
456+ species = _ "Spruce",
457 editor_category = "trees_coniferous",
458 size = "small",
459 attributes = { "tree" },
460
461=== modified file 'data/world/immovables/trees/twine/init.lua'
462--- data/world/immovables/trees/twine/init.lua 2015-11-03 18:18:27 +0000
463+++ data/world/immovables/trees/twine/init.lua 2016-02-14 10:01:52 +0000
464@@ -83,6 +83,8 @@
465 name = "twine_wasteland_old",
466 -- TRANSLATORS: This is a fictitious tree. Be creative if you want.
467 descname = _ "Twine Tree (Old)",
468+ -- TRANSLATORS: This is a fictitious tree. Be creative if you want.
469+ species = _ "Twine Tree",
470 editor_category = "trees_wasteland",
471 size = "small",
472 attributes = { "tree" },
473
474=== modified file 'data/world/immovables/trees/umbrella_green/init.lua'
475--- data/world/immovables/trees/umbrella_green/init.lua 2015-11-03 18:18:27 +0000
476+++ data/world/immovables/trees/umbrella_green/init.lua 2016-02-14 10:01:52 +0000
477@@ -83,6 +83,8 @@
478 name = "umbrella_green_wasteland_old",
479 -- TRANSLATORS: This is a fictitious tree. Be creative if you want.
480 descname = _ "Green Umbrella Tree (Old)",
481+ -- TRANSLATORS: This is a fictitious tree. Be creative if you want.
482+ species = _ "Green Umbrella Tree",
483 editor_category = "trees_wasteland",
484 size = "small",
485 attributes = { "tree" },
486
487=== modified file 'data/world/immovables/trees/umbrella_red/init.lua'
488--- data/world/immovables/trees/umbrella_red/init.lua 2015-11-03 18:18:27 +0000
489+++ data/world/immovables/trees/umbrella_red/init.lua 2016-02-14 10:01:52 +0000
490@@ -1,4 +1,4 @@
491-dirname = path.dirname(__file__)
492+sedirname = path.dirname(__file__)
493
494 terrain_affinity = {
495 preferred_temperature = 110,
496@@ -86,6 +86,8 @@
497 name = "umbrella_red_wasteland_old",
498 -- TRANSLATORS: This is a fictitious tree. Be creative if you want.
499 descname = _ "Red Umbrella Tree (Old)",
500+ -- TRANSLATORS: This is a fictitious tree. Be creative if you want.
501+ species = _ "Red Umbrella Tree",
502 editor_category = "trees_wasteland",
503 size = "small",
504 attributes = { "tree" },
505
506=== modified file 'data/world/resources/init.lua'
507--- data/world/resources/init.lua 2016-01-11 22:13:36 +0000
508+++ data/world/resources/init.lua 2016-02-14 10:01:52 +0000
509@@ -9,6 +9,8 @@
510 max_amount = 20,
511 -- A geologist can find it, otherwise false (see Fish)
512 detectable = true,
513+ -- This represents the resource in menus etc.
514+ representative_image = pics_dir .. "coal4.png",
515 -- Picture that is used to indicate the amount of resource on the map
516 -- [5] means amount 0 to 5; next line means amount 6 to 10 and so on
517 -- The picture with highest number is additionally used in ui
518@@ -25,6 +27,7 @@
519 descname = _ "Gold",
520 max_amount = 20,
521 detectable = true,
522+ representative_image = pics_dir .. "gold4.png",
523 editor_pictures = {
524 [5] = pics_dir .. "gold1.png",
525 [10] = pics_dir .. "gold2.png",
526@@ -38,6 +41,7 @@
527 descname = _ "Iron",
528 max_amount = 20,
529 detectable = true,
530+ representative_image = pics_dir .. "iron4.png",
531 editor_pictures = {
532 [5] = pics_dir .. "iron1.png",
533 [10] = pics_dir .. "iron2.png",
534@@ -51,6 +55,7 @@
535 descname = _ "Stones",
536 max_amount = 20,
537 detectable = true,
538+ representative_image = pics_dir .. "stones4.png",
539 editor_pictures = {
540 [5] = pics_dir .. "stones1.png",
541 [10] = pics_dir .. "stones2.png",
542@@ -64,6 +69,7 @@
543 descname = _ "Water",
544 max_amount = 50,
545 detectable = true,
546+ representative_image = pics_dir .. "water4.png",
547 editor_pictures = {
548 [10] = pics_dir .."water1.png",
549 [20] = pics_dir .."water2.png",
550@@ -77,14 +83,11 @@
551 descname = _ "Fish",
552 max_amount = 20,
553 detectable = false,
554+ representative_image = pics_dir .. "fish.png",
555 editor_pictures = {
556 [5] = pics_dir .. "fish1.png",
557 [10] = pics_dir .. "fish2.png",
558 [15] = pics_dir .. "fish3.png",
559 [1000] = pics_dir .. "fish4.png",
560- -- Clutch: The editor chooses the image with the highest number for the
561- -- UI. So we keep a nice picture for this purpose at the top of this
562- -- list.
563- [1001] = pics_dir .. "fish.png",
564 }
565 }
566
567=== modified file 'src/editor/CMakeLists.txt'
568--- src/editor/CMakeLists.txt 2016-01-14 22:17:50 +0000
569+++ src/editor/CMakeLists.txt 2016-02-14 10:01:52 +0000
570@@ -47,6 +47,8 @@
571 tools/editor_tool_action.h
572 tools/multi_select.h
573 ui_menus/categorized_item_selection_menu.h
574+ ui_menus/editor_help.cc
575+ ui_menus/editor_help.h
576 ui_menus/editor_main_menu.cc
577 ui_menus/editor_main_menu.h
578 ui_menus/editor_main_menu_load_map.cc
579
580=== modified file 'src/editor/editorinteractive.cc'
581--- src/editor/editorinteractive.cc 2016-02-04 13:53:42 +0000
582+++ src/editor/editorinteractive.cc 2016-02-14 10:01:52 +0000
583@@ -30,6 +30,7 @@
584 #include "base/scoped_timer.h"
585 #include "base/warning.h"
586 #include "editor/tools/editor_delete_immovable_tool.h"
587+#include "editor/ui_menus/editor_help.h"
588 #include "editor/ui_menus/editor_main_menu.h"
589 #include "editor/ui_menus/editor_main_menu_load_map.h"
590 #include "editor/ui_menus/editor_main_menu_save_map.h"
591@@ -82,7 +83,7 @@
592 // Ok, we're doing something. First remove the current overlays.
593 if (note.old_resource != Widelands::kNoResource) {
594 const std::string str =
595- world.get_resource(note.old_resource)->get_editor_pic(note.old_amount);
596+ world.get_resource(note.old_resource)->editor_image(note.old_amount);
597 const Image* pic = g_gr->images().get(str);
598 field_overlay_manager->remove_overlay(note.fc, pic);
599 }
600@@ -91,7 +92,7 @@
601 const auto resource_type = note.fc.field->get_resources();
602 if (amount > 0 && resource_type != Widelands::kNoResource) {
603 const std::string str =
604- world.get_resource(note.fc.field->get_resources())->get_editor_pic(amount);
605+ world.get_resource(note.fc.field->get_resources())->editor_image(amount);
606 const Image* pic = g_gr->images().get(str);
607 field_overlay_manager->register_overlay(note.fc, pic, 0);
608 }
609@@ -107,36 +108,39 @@
610 tools_(new Tools()),
611 history_(new EditorHistory(undo_, redo_)),
612
613-#define INIT_BUTTON(picture, name, tooltip) \
614+#define INIT_BUTTON(image, name, tooltip) \
615 TOOLBAR_BUTTON_COMMON_PARAMETERS(name), \
616- g_gr->images().get("images/wui/" picture ".png"), \
617+ g_gr->images().get(image), \
618 tooltip \
619
620 toggle_main_menu_
621 (INIT_BUTTON
622- ("menus/menu_toggle_menu", "menu", _("Menu"))),
623+ ("images/wui/menus/menu_toggle_menu.png", "menu", _("Menu"))),
624 toggle_tool_menu_
625 (INIT_BUTTON
626- ("editor/editor_menu_toggle_tool_menu", "tools", _("Tools"))),
627+ ("images/wui/editor/editor_menu_toggle_tool_menu.png", "tools", _("Tools"))),
628 toggle_toolsize_menu_
629 (INIT_BUTTON
630- ("editor/editor_menu_set_toolsize_menu", "toolsize",
631+ ("images/wui/editor/editor_menu_set_toolsize_menu.png", "toolsize",
632 _("Tool Size"))),
633 toggle_minimap_
634 (INIT_BUTTON
635- ("menus/menu_toggle_minimap", "minimap", _("Minimap"))),
636+ ("images/wui/menus/menu_toggle_minimap.png", "minimap", _("Minimap"))),
637 toggle_buildhelp_
638 (INIT_BUTTON
639- ("menus/menu_toggle_buildhelp", "buildhelp", _("Show Building Spaces (on/off)"))),
640+ ("images/wui/menus/menu_toggle_buildhelp.png", "buildhelp", _("Show Building Spaces (on/off)"))),
641 toggle_player_menu_
642 (INIT_BUTTON
643- ("editor/editor_menu_player_menu", "players", _("Players"))),
644+ ("images/wui/editor/editor_menu_player_menu.png", "players", _("Players"))),
645 undo_
646 (INIT_BUTTON
647- ("editor/editor_undo", "undo", _("Undo"))),
648+ ("images/wui/editor/editor_undo.png", "undo", _("Undo"))),
649 redo_
650 (INIT_BUTTON
651- ("editor/editor_redo", "redo", _("Redo")))
652+ ("images/wui/editor/editor_redo.png", "redo", _("Redo"))),
653+ toggle_help_
654+ (INIT_BUTTON
655+ ("images/ui_basic/menu_help.png", "help", _("Help")))
656 {
657 toggle_main_menu_.sigclicked.connect(boost::bind(&EditorInteractive::toggle_mainmenu, this));
658 toggle_tool_menu_.sigclicked.connect(boost::bind(&EditorInteractive::tool_menu_btn, this));
659@@ -146,6 +150,7 @@
660 toggle_player_menu_.sigclicked.connect(boost::bind(&EditorInteractive::toggle_playermenu, this));
661 undo_.sigclicked.connect([this] {history_->undo_action(egbase().world());});
662 redo_.sigclicked.connect([this] {history_->redo_action(egbase().world());});
663+ toggle_help_.sigclicked.connect(boost::bind(&EditorInteractive::toggle_help, this));
664
665 toolbar_.set_layout_toplevel(true);
666 toolbar_.add(&toggle_main_menu_, UI::Align::kLeft);
667@@ -156,6 +161,7 @@
668 toolbar_.add(&toggle_player_menu_, UI::Align::kLeft);
669 toolbar_.add(&undo_, UI::Align::kLeft);
670 toolbar_.add(&redo_, UI::Align::kLeft);
671+ toolbar_.add(&toggle_help_, UI::Align::kLeft);
672 adjust_toolbar_position();
673
674 #ifndef NDEBUG
675@@ -195,7 +201,7 @@
676 iterate_Map_FCoords(map, extent, fc) {
677 if (uint8_t const amount = fc.field->get_resources_amount()) {
678 const std::string& immname =
679- egbase().world().get_resource(fc.field->get_resources())->get_editor_pic(amount);
680+ egbase().world().get_resource(fc.field->get_resources())->editor_image(amount);
681 if (immname.size())
682 mutable_field_overlay_manager()->register_overlay(fc, g_gr->images().get(immname), 4);
683 }
684@@ -360,6 +366,14 @@
685 }
686 }
687
688+void EditorInteractive::toggle_help() {
689+ if (helpmenu_.window)
690+ delete helpmenu_.window;
691+ else
692+ new EditorHelp(*this, helpmenu_);
693+}
694+
695+
696
697 bool EditorInteractive::handle_key(bool const down, SDL_Keysym const code) {
698 bool handled = InteractiveBase::handle_key(down, code);
699@@ -487,6 +501,12 @@
700 history_->redo_action(egbase().world());
701 handled = true;
702 break;
703+
704+ case SDLK_F1:
705+ toggle_help();
706+ handled = true;
707+ break;
708+
709 default:
710 break;
711 }
712
713=== modified file 'src/editor/editorinteractive.h'
714--- src/editor/editorinteractive.h 2016-01-16 15:57:31 +0000
715+++ src/editor/editorinteractive.h 2016-02-14 10:01:52 +0000
716@@ -150,6 +150,7 @@
717 void toolsize_menu_btn();
718 void toggle_mainmenu();
719 void toggle_playermenu();
720+ void toggle_help();
721
722 // state variables
723 bool need_save_;
724@@ -173,6 +174,7 @@
725 UI::UniqueWindow::Registry immovablemenu_;
726 UI::UniqueWindow::Registry bobmenu_;
727 UI::UniqueWindow::Registry resourcesmenu_;
728+ UI::UniqueWindow::Registry helpmenu_;
729
730 UI::Button toggle_main_menu_;
731 UI::Button toggle_tool_menu_;
732@@ -182,6 +184,7 @@
733 UI::Button toggle_player_menu_;
734 UI::Button undo_;
735 UI::Button redo_;
736+ UI::Button toggle_help_;
737 };
738
739 #endif // end of include guard: WL_EDITOR_EDITORINTERACTIVE_H
740
741=== modified file 'src/editor/tools/editor_info_tool.cc'
742--- src/editor/tools/editor_info_tool.cc 2016-01-06 19:11:20 +0000
743+++ src/editor/tools/editor_info_tool.cc 2016-02-14 10:01:52 +0000
744@@ -115,7 +115,7 @@
745 /** TRANSLATORS: You can also translate this as "Category: %s" or "Property: %s" */
746 buf += "• " + (boost::format(_("Is: %s"))
747 % i18n::localize_list(terrain_is_strings, i18n::ConcatenateWith::AMPERSAND)).str() + "\n";
748- buf += "• " + (boost::format(_("Editor Category: %s")) % ter.editor_category().descname()).str() + "\n";
749+ buf += "• " + (boost::format(_("Editor Category: %s")) % ter.editor_category()->descname()).str() + "\n";
750
751 // *** Resources info
752 buf += std::string("\n") + _("Resources:") + "\n";
753
754=== modified file 'src/editor/ui_menus/categorized_item_selection_menu.h'
755--- src/editor/ui_menus/categorized_item_selection_menu.h 2016-02-08 20:04:17 +0000
756+++ src/editor/ui_menus/categorized_item_selection_menu.h 2016-02-14 10:01:52 +0000
757@@ -94,7 +94,7 @@
758
759 std::vector<int> item_indices;
760 for (size_t j = 0; j < descriptions_.size(); ++j) {
761- if (descriptions_.get(j).editor_category().name() != category.name()) {
762+ if (descriptions_.get(j).editor_category()->name() != category.name()) {
763 continue;
764 }
765 item_indices.push_back(j);
766
767=== added file 'src/editor/ui_menus/editor_help.cc'
768--- src/editor/ui_menus/editor_help.cc 1970-01-01 00:00:00 +0000
769+++ src/editor/ui_menus/editor_help.cc 2016-02-14 10:01:52 +0000
770@@ -0,0 +1,224 @@
771+/*
772+ * Copyright (C) 2015-2016 by the Widelands Development Team
773+ *
774+ * This program is free software; you can redistribute it and/or
775+ * modify it under the terms of the GNU General Public License
776+ * as published by the Free Software Foundation; either version 2
777+ * of the License, or (at your option) any later version.
778+ *
779+ * This program is distributed in the hope that it will be useful,
780+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
781+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
782+ * GNU General Public License for more details.
783+ *
784+ * You should have received a copy of the GNU General Public License
785+ * along with this program; if not, write to the Free Software
786+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
787+ *
788+ */
789+
790+#include "editor/ui_menus/editor_help.h"
791+
792+#include <algorithm>
793+#include <map>
794+#include <memory>
795+#include <string>
796+#include <vector>
797+
798+#include <boost/format.hpp>
799+
800+#include "base/i18n.h"
801+#include "editor/editorinteractive.h"
802+#include "graphic/graphic.h"
803+#include "graphic/texture.h"
804+#include "io/filesystem/layered_filesystem.h"
805+#include "logic/map_objects/world/editor_category.h"
806+#include "logic/map_objects/world/terrain_description.h"
807+#include "logic/map_objects/world/world.h"
808+#include "scripting/lua_interface.h"
809+#include "scripting/lua_table.h"
810+
811+namespace {
812+
813+#define WINDOW_WIDTH std::min(700, g_gr->get_xres() - 40)
814+#define WINDOW_HEIGHT std::min(550, g_gr->get_yres() - 40)
815+
816+constexpr int kPadding = 5;
817+constexpr int kTabHeight = 35;
818+
819+const std::string heading(const std::string& text) {
820+ return ((boost::format("<rt><p font-size=18 font-weight=bold font-color=D1D1D1>"
821+ "%s<br></p><p font-size=8> <br></p></rt>") %
822+ text).str());
823+}
824+
825+} // namespace
826+
827+inline EditorInteractive& EditorHelp::eia() const {
828+ return dynamic_cast<EditorInteractive&>(*get_parent());
829+}
830+
831+EditorHelp::EditorHelp(EditorInteractive& parent, UI::UniqueWindow::Registry& registry)
832+ : UI::UniqueWindow(&parent, "encyclopedia", &registry, WINDOW_WIDTH, WINDOW_HEIGHT, _("Help")),
833+ tabs_(this, 0, 0, nullptr) {
834+
835+ const int contents_height = WINDOW_HEIGHT - kTabHeight - 2 * kPadding;
836+ const int contents_width = WINDOW_WIDTH / 2 - 1.5 * kPadding;
837+
838+ std::vector<std::unique_ptr<HelpTab>> tab_definitions;
839+
840+ tab_definitions.push_back(
841+ std::unique_ptr<HelpTab>(new HelpTab("terrains",
842+ "images/wui/editor/editor_menu_tool_set_terrain.png",
843+ _("Terrains"),
844+ "scripting/editor/terrain_help.lua",
845+ HelpEntry::Type::kTerrain)));
846+
847+ tab_definitions.push_back(
848+ std::unique_ptr<HelpTab>(new HelpTab("trees",
849+ "world/immovables/trees/alder/old/idle_0.png",
850+ _("Trees"),
851+ "scripting/editor/tree_help.lua",
852+ HelpEntry::Type::kTree)));
853+
854+ for (const auto& tab : tab_definitions) {
855+ // Make sure that all paths exist
856+ if (!g_fs->file_exists(tab->script_path)) {
857+ throw wexception("Script path %s for tab %s does not exist!",
858+ tab->script_path.c_str(),
859+ tab->key.c_str());
860+ }
861+ if (!g_fs->file_exists(tab->image_filename)) {
862+ throw wexception("Image path %s for tab %s does not exist!",
863+ tab->image_filename.c_str(),
864+ tab->key.c_str());
865+ }
866+
867+ wrapper_boxes_.insert(std::make_pair(
868+ tab->key, std::unique_ptr<UI::Box>(new UI::Box(&tabs_, 0, 0, UI::Box::Horizontal))));
869+
870+ boxes_.insert(
871+ std::make_pair(tab->key,
872+ std::unique_ptr<UI::Box>(new UI::Box(
873+ wrapper_boxes_.at(tab->key).get(), 0, 0, UI::Box::Horizontal))));
874+
875+ lists_.insert(
876+ std::make_pair(tab->key,
877+ std::unique_ptr<UI::Listselect<Widelands::DescriptionIndex>>(
878+ new UI::Listselect<Widelands::DescriptionIndex>(
879+ boxes_.at(tab->key).get(), 0, 0, contents_width, contents_height))));
880+ lists_.at(tab->key)->selected.connect(
881+ boost::bind(&EditorHelp::entry_selected, this, tab->key, tab->script_path, tab->type));
882+
883+ contents_.insert(
884+ std::make_pair(tab->key,
885+ std::unique_ptr<UI::MultilineTextarea>(new UI::MultilineTextarea(
886+ boxes_.at(tab->key).get(), 0, 0, contents_width, contents_height))));
887+
888+ boxes_.at(tab->key)->add(lists_.at(tab->key).get(), UI::Align::kLeft);
889+ boxes_.at(tab->key)->add_space(kPadding);
890+ boxes_.at(tab->key)->add(contents_.at(tab->key).get(), UI::Align::kLeft);
891+
892+ wrapper_boxes_.at(tab->key)->add_space(kPadding);
893+ wrapper_boxes_.at(tab->key)->add(boxes_.at(tab->key).get(), UI::Align::kLeft);
894+
895+ tabs_.add("editor_help_" + tab->key,
896+ g_gr->images().get(tab->image_filename),
897+ wrapper_boxes_.at(tab->key).get(),
898+ tab->tooltip);
899+ }
900+ tabs_.set_size(WINDOW_WIDTH, WINDOW_HEIGHT);
901+
902+ fill_terrains();
903+ fill_trees();
904+
905+ if (get_usedefaultpos()) {
906+ center_to_parent();
907+ }
908+}
909+
910+void EditorHelp::fill_entries(const char* key, std::vector<HelpEntry>* entries) {
911+ std::sort(entries->begin(), entries->end());
912+ for (uint32_t i = 0; i < entries->size(); i++) {
913+ HelpEntry cur = (*entries)[i];
914+ lists_.at(key)->add(cur.descname, cur.index, cur.icon);
915+ }
916+ lists_.at(key)->select(0);
917+}
918+
919+void EditorHelp::fill_terrains() {
920+ const Widelands::World& world = eia().egbase().world();
921+ std::vector<HelpEntry> entries;
922+
923+ for (Widelands::DescriptionIndex i = 0; i < world.terrains().size(); ++i) {
924+ const Widelands::TerrainDescription& terrain = world.terrain_descr(i);
925+ upcast(Image const, icon, &terrain.get_texture(0));
926+ /** TRANSLATORS: Terrain name + editor category, e.g. Steppe (Summer) */
927+ HelpEntry entry(i, (boost::format(_("%1% (%2%)"))
928+ % terrain.descname().c_str()
929+ % terrain.editor_category()->descname()).str(), icon);
930+ entries.push_back(entry);
931+ }
932+ fill_entries("terrains", &entries);
933+}
934+
935+void EditorHelp::fill_trees() {
936+ const Widelands::World& world = eia().egbase().world();
937+ std::vector<HelpEntry> entries;
938+
939+ for (Widelands::DescriptionIndex i = 0; i < world.get_nr_immovables(); ++i) {
940+ const Widelands::ImmovableDescr* immovable = world.get_immovable_descr(i);
941+ uint32_t attribute_id = immovable->get_attribute_id("tree");
942+ if (immovable->has_attribute(attribute_id)) {
943+ const Image* icon = immovable->representative_image();
944+ HelpEntry entry(i, immovable->species(), icon);
945+ entries.push_back(entry);
946+ }
947+ }
948+ fill_entries("trees", &entries);
949+}
950+
951+void EditorHelp::entry_selected(const std::string& key,
952+ const std::string& script_path,
953+ const HelpEntry::Type& type) {
954+ try {
955+ std::unique_ptr<LuaTable> table(eia().egbase().lua().run_script(script_path));
956+ std::unique_ptr<LuaCoroutine> cr(table->get_coroutine("func"));
957+
958+ std::string descname = "";
959+
960+ switch (type) {
961+ case (HelpEntry::Type::kTerrain): {
962+ const Widelands::TerrainDescription& descr =
963+ eia().egbase().world().terrain_descr(lists_.at(key)->get_selected());
964+ /** TRANSLATORS: Terrain name + editor category, e.g. Steppe (Summer) */
965+ descname = (boost::format(_("%1% (%2%)"))
966+ % descr.descname().c_str()
967+ % descr.editor_category()->descname()).str();
968+ cr->push_arg(descr.name());
969+ break;
970+ }
971+ case (HelpEntry::Type::kTree): {
972+ const Widelands::ImmovableDescr* descr =
973+ eia().egbase().world().get_immovable_descr(lists_.at(key)->get_selected());
974+ descname = descr->species();
975+ cr->push_arg(descr->name());
976+ break;
977+ }
978+ default:
979+ throw wexception("EditorHelp: No Type defined for tab.");
980+ }
981+
982+ cr->resume();
983+ const std::string help_text = cr->pop_string();
984+
985+ // We add the heading here instead of in Lua, so that the content can be
986+ // reused in a standalone window that will have the heading as a window
987+ // title.
988+ contents_.at(key)->set_text((boost::format("%s%s") % heading(descname) % help_text).str());
989+
990+ } catch (LuaError& err) {
991+ contents_.at(key)->set_text(err.what());
992+ }
993+ contents_.at(key)->scroll_to_top();
994+}
995
996=== added file 'src/editor/ui_menus/editor_help.h'
997--- src/editor/ui_menus/editor_help.h 1970-01-01 00:00:00 +0000
998+++ src/editor/ui_menus/editor_help.h 2016-02-14 10:01:52 +0000
999@@ -0,0 +1,109 @@
1000+/*
1001+ * Copyright (C) 2015-2016 by the Widelands Development Team
1002+ *
1003+ * This program is free software; you can redistribute it and/or
1004+ * modify it under the terms of the GNU General Public License
1005+ * as published by the Free Software Foundation; either version 2
1006+ * of the License, or (at your option) any later version.
1007+ *
1008+ * This program is distributed in the hope that it will be useful,
1009+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1010+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1011+ * GNU General Public License for more details.
1012+ *
1013+ * You should have received a copy of the GNU General Public License
1014+ * along with this program; if not, write to the Free Software
1015+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
1016+ *
1017+ */
1018+
1019+#ifndef WL_EDITOR_UI_MENUS_EDITOR_HELP_H
1020+#define WL_EDITOR_UI_MENUS_EDITOR_HELP_H
1021+
1022+#include <map>
1023+#include <memory>
1024+#include <vector>
1025+
1026+#include "logic/map_objects/map_object.h"
1027+#include "ui_basic/box.h"
1028+#include "ui_basic/listselect.h"
1029+#include "ui_basic/multilinetextarea.h"
1030+#include "ui_basic/table.h"
1031+#include "ui_basic/tabpanel.h"
1032+#include "ui_basic/unique_window.h"
1033+#include "ui_basic/window.h"
1034+
1035+class EditorInteractive;
1036+
1037+struct EditorHelp : public UI::UniqueWindow {
1038+ EditorHelp(EditorInteractive&, UI::UniqueWindow::Registry&);
1039+
1040+private:
1041+ struct HelpEntry {
1042+ enum class Type {
1043+ kTerrain,
1044+ kTree
1045+ };
1046+
1047+ HelpEntry(const HelpEntry& other) : HelpEntry(other.index, other.descname, other.icon) {
1048+ }
1049+
1050+ HelpEntry(const Widelands::DescriptionIndex init_index,
1051+ const std::string& init_descname,
1052+ const Image* init_icon)
1053+ : index(init_index), descname(init_descname), icon(init_icon) {
1054+ }
1055+ Widelands::DescriptionIndex index;
1056+ std::string descname;
1057+ const Image* icon;
1058+
1059+ bool operator<(const HelpEntry& other) const {
1060+ return descname < other.descname;
1061+ }
1062+ };
1063+
1064+ struct HelpTab {
1065+ HelpTab(const std::string& _key,
1066+ const std::string& _image_filename,
1067+ const std::string& _tooltip,
1068+ const std::string& _script_path,
1069+ const EditorHelp::HelpEntry::Type _type)
1070+ : key(_key),
1071+ image_filename(_image_filename),
1072+ tooltip(_tooltip),
1073+ script_path(_script_path),
1074+ type(_type) {
1075+ }
1076+ const std::string key;
1077+ const std::string image_filename;
1078+ const std::string tooltip;
1079+ const std::string script_path;
1080+ const EditorHelp::HelpEntry::Type type;
1081+ };
1082+
1083+ EditorInteractive& eia() const;
1084+
1085+ // Fill table of contents
1086+ void fill_entries(const char* key, std::vector<HelpEntry>* entries);
1087+ void fill_terrains();
1088+ void fill_trees();
1089+
1090+ // Update contents when an entry is selected
1091+ void entry_selected(const std::string& key,
1092+ const std::string& script_path,
1093+ const HelpEntry::Type& type);
1094+
1095+ // UI elements
1096+ UI::TabPanel tabs_;
1097+
1098+ // Wrapper boxes so we can add some padding
1099+ std::map<std::string, std::unique_ptr<UI::Box>> wrapper_boxes_;
1100+ // Main contents boxes for each tab
1101+ std::map<std::string, std::unique_ptr<UI::Box>> boxes_;
1102+ // A tab's table of contents
1103+ std::map<std::string, std::unique_ptr<UI::Listselect<Widelands::DescriptionIndex>>> lists_;
1104+ // The contents shown when an entry is selected in a tab
1105+ std::map<std::string, std::unique_ptr<UI::MultilineTextarea>> contents_;
1106+};
1107+
1108+#endif // end of include guard: WL_EDITOR_UI_MENUS_EDITOR_HELP_H
1109
1110=== modified file 'src/editor/ui_menus/editor_tool_change_resources_options_menu.cc'
1111--- src/editor/ui_menus/editor_tool_change_resources_options_menu.cc 2016-01-29 08:37:22 +0000
1112+++ src/editor/ui_menus/editor_tool_change_resources_options_menu.cc 2016-02-14 10:01:52 +0000
1113@@ -139,7 +139,7 @@
1114 // Find the maximal width and height for the resource pictures.
1115 int resource_pic_max_width = 0, resource_pic_max_height = 0;
1116 for (Widelands::DescriptionIndex i = 0; i < nr_resources; ++i) {
1117- const Image* pic = g_gr->images().get(world.get_resource(i)->get_editor_pic(100000));
1118+ const Image* pic = g_gr->images().get(world.get_resource(i)->representative_image());
1119 resource_pic_max_width = std::max(resource_pic_max_width, pic->width());
1120 resource_pic_max_height = std::max(resource_pic_max_height, pic->height());
1121 }
1122@@ -170,7 +170,7 @@
1123 m_radiogroup.add_button
1124 (this,
1125 pos,
1126- g_gr->images().get(world.get_resource(i)->get_editor_pic(100000)));
1127+ g_gr->images().get(world.get_resource(i)->representative_image()));
1128 }
1129 pos.y += resource_pic_max_height + vspacing();
1130
1131
1132=== modified file 'src/logic/field.h'
1133--- src/logic/field.h 2016-01-14 22:09:24 +0000
1134+++ src/logic/field.h 2016-02-14 10:01:52 +0000
1135@@ -134,7 +134,9 @@
1136 uint16_t get_caps() const {return caps;}
1137
1138 Terrains get_terrains() const {return terrains;}
1139+ // The terrain on the downward triangle
1140 DescriptionIndex terrain_d () const {return terrains.d;}
1141+ // The terrain on the triangle to the right
1142 DescriptionIndex terrain_r () const {return terrains.r;}
1143 void set_terrains(const Terrains & i) {terrains = i;}
1144 void set_terrain
1145
1146=== modified file 'src/logic/map_objects/immovable.cc'
1147--- src/logic/map_objects/immovable.cc 2016-02-07 16:54:31 +0000
1148+++ src/logic/map_objects/immovable.cc 2016-02-14 10:01:52 +0000
1149@@ -199,7 +199,8 @@
1150 MapObjectDescr(
1151 MapObjectType::IMMOVABLE, table.get_string("name"), init_descname, table),
1152 size_(BaseImmovable::NONE),
1153- owner_type_(input_type) {
1154+ owner_type_(input_type),
1155+ editor_category_(nullptr) {
1156 if (!is_animation_known("idle")) {
1157 throw GameDataError("Immovable %s has no idle animation", table.get_string("name").c_str());
1158 }
1159@@ -213,8 +214,23 @@
1160 }
1161
1162 if (table.has_key("attributes")) {
1163- add_attributes(table.get_table("attributes")->
1164- array_entries<std::string>(), {MapObject::Attribute::RESI});
1165+ std::vector<std::string> attributes = table.get_table("attributes")->array_entries<std::string>();
1166+ add_attributes(attributes, {MapObject::Attribute::RESI});
1167+
1168+ // Old trees get an extra species name so we can use it in help lists.
1169+ bool is_tree = false;
1170+ for (const std::string& attribute : attributes) {
1171+ if (attribute == "tree") {
1172+ is_tree = true;
1173+ break;
1174+ }
1175+ }
1176+ if (is_tree) {
1177+ if (!table.has_key("species")) {
1178+ throw wexception("Immovable '%s' with type 'tree' must define a species", name().c_str());
1179+ }
1180+ species_ = table.get_string("species");
1181+ }
1182 }
1183
1184 std::unique_ptr<LuaTable> programs = table.get_table("programs");
1185@@ -257,8 +273,8 @@
1186 }
1187 }
1188
1189-const EditorCategory& ImmovableDescr::editor_category() const {
1190- return *editor_category_;
1191+const EditorCategory* ImmovableDescr::editor_category() const {
1192+ return editor_category_;
1193 }
1194
1195 bool ImmovableDescr::has_terrain_affinity() const {
1196
1197=== modified file 'src/logic/map_objects/immovable.h'
1198--- src/logic/map_objects/immovable.h 2016-02-07 09:30:20 +0000
1199+++ src/logic/map_objects/immovable.h 2016-02-14 10:01:52 +0000
1200@@ -129,9 +129,12 @@
1201
1202 const Buildcost & buildcost() const {return buildcost_;}
1203
1204+ // Returns the editor category, or nullptr if the immovable has no editor category
1205+ // (e.g. Tribe immovables never have one).
1206+ const EditorCategory* editor_category() const;
1207
1208- // Returns the editor category.
1209- const EditorCategory& editor_category() const;
1210+ // A basic localized name for the immovable, used by trees
1211+ const std::string& species() const {return species_;}
1212
1213 // Every immovable that can 'grow' needs to have terrain affinity defined,
1214 // all others do not. Returns true if this one has it defined.
1215@@ -152,6 +155,8 @@
1216 /// \see ActConstruction
1217 Buildcost buildcost_;
1218
1219+ std::string species_;
1220+
1221 private:
1222 // Common constructor functions for tribes and world.
1223 ImmovableDescr(const std::string& init_descname, const LuaTable&, MapObjectDescr::OwnerType type);
1224
1225=== modified file 'src/logic/map_objects/terrain_affinity.cc'
1226--- src/logic/map_objects/terrain_affinity.cc 2015-11-28 22:29:26 +0000
1227+++ src/logic/map_objects/terrain_affinity.cc 2016-02-14 10:01:52 +0000
1228@@ -37,6 +37,30 @@
1229 return a * a;
1230 }
1231
1232+// Helper function for probability_to_grow
1233+// Calculates the probability to grow for the given affinity and terrain values
1234+double calculate_probability_to_grow(const TerrainAffinity& affinity,
1235+ double terrain_humidity,
1236+ double terrain_fertility,
1237+ double terrain_temperature) {
1238+
1239+ constexpr double kHumidityWeight = 0.500086642549548;
1240+ constexpr double kFertilityWeight = 0.5292268046607387;
1241+ constexpr double kTemperatureWeight = 61.31300863608306;
1242+
1243+ const double sigma_humidity = (1. - affinity.pickiness());
1244+ const double sigma_temperature = (1. - affinity.pickiness());
1245+ const double sigma_fertility = (1. - affinity.pickiness());
1246+
1247+ return exp((-pow2((affinity.preferred_fertility() - terrain_fertility) /
1248+ (kFertilityWeight * sigma_fertility)) -
1249+ pow2((affinity.preferred_humidity() - terrain_humidity) /
1250+ (kHumidityWeight * sigma_humidity)) -
1251+ pow2((affinity.preferred_temperature() - terrain_temperature) /
1252+ (kTemperatureWeight * sigma_temperature))) /
1253+ 2);
1254+}
1255+
1256 } // namespace
1257
1258 TerrainAffinity::TerrainAffinity(const LuaTable& table, const std::string& immovable_name)
1259@@ -111,21 +135,20 @@
1260 average(ln.field->terrain_r());
1261 }
1262
1263- constexpr double kHumidityWeight = 0.500086642549548;
1264- constexpr double kFertilityWeight = 0.5292268046607387;
1265- constexpr double kTemperatureWeight = 61.31300863608306;
1266-
1267- const double sigma_humidity = (1. - affinity.pickiness());
1268- const double sigma_temperature = (1. - affinity.pickiness());
1269- const double sigma_fertility = (1. - affinity.pickiness());
1270-
1271- return exp((-pow2((affinity.preferred_fertility() - terrain_fertility) /
1272- (kFertilityWeight * sigma_fertility)) -
1273- pow2((affinity.preferred_humidity() - terrain_humidity) /
1274- (kHumidityWeight * sigma_humidity)) -
1275- pow2((affinity.preferred_temperature() - terrain_temperature) /
1276- (kTemperatureWeight * sigma_temperature))) /
1277- 2);
1278+ return calculate_probability_to_grow(affinity,
1279+ terrain_humidity,
1280+ terrain_fertility,
1281+ terrain_temperature);
1282+}
1283+
1284+
1285+double probability_to_grow(const TerrainAffinity& affinity,
1286+ const TerrainDescription& terrain) {
1287+
1288+ return calculate_probability_to_grow(affinity,
1289+ terrain.humidity(),
1290+ terrain.fertility(),
1291+ terrain.temperature());
1292 }
1293
1294 } // namespace Widelands
1295
1296=== modified file 'src/logic/map_objects/terrain_affinity.h'
1297--- src/logic/map_objects/terrain_affinity.h 2015-11-28 22:29:26 +0000
1298+++ src/logic/map_objects/terrain_affinity.h 2016-02-14 10:01:52 +0000
1299@@ -69,6 +69,10 @@
1300 (const TerrainAffinity& immovable_affinity, const FCoords& fcoords,
1301 const Map& map, const DescriptionMaintainer<TerrainDescription>& terrains);
1302
1303+// Probability to grow for a single terrain
1304+double probability_to_grow
1305+ (const TerrainAffinity& immovable_affinity, const TerrainDescription& terrain);
1306+
1307 } // namespace Widelands
1308
1309 #endif // end of include guard: WL_LOGIC_MAP_OBJECTS_TERRAIN_AFFINITY_H
1310
1311=== modified file 'src/logic/map_objects/tribes/worker.cc'
1312--- src/logic/map_objects/tribes/worker.cc 2016-02-07 09:30:20 +0000
1313+++ src/logic/map_objects/tribes/worker.cc 2016-02-14 10:01:52 +0000
1314@@ -926,7 +926,7 @@
1315 if (rdescr && rdescr->detectable() && position.field->get_resources_amount()) {
1316 const std::string message =
1317 (boost::format("<rt image=%s><p font-face=serif font-size=14>%s</p></rt>")
1318- % rdescr->get_editor_pic(rdescr->max_amount())
1319+ % rdescr->representative_image()
1320 % _("A geologist found resources.")).str();
1321
1322 Message::Type message_type = Message::Type::kGeologists;
1323
1324=== modified file 'src/logic/map_objects/world/resource_description.cc'
1325--- src/logic/map_objects/world/resource_description.cc 2015-11-28 22:29:26 +0000
1326+++ src/logic/map_objects/world/resource_description.cc 2016-02-14 10:01:52 +0000
1327@@ -31,7 +31,8 @@
1328 : name_(table.get_string("name")),
1329 descname_(table.get_string("descname")),
1330 detectable_(table.get_bool("detectable")),
1331- max_amount_(table.get_int("max_amount")) {
1332+ max_amount_(table.get_int("max_amount")),
1333+ representative_image_(table.get_string("representative_image")) {
1334
1335 std::unique_ptr<LuaTable> st = table.get_table("editor_pictures");
1336 const std::set<int> keys = st->keys<int>();
1337@@ -44,7 +45,7 @@
1338 }
1339 }
1340
1341-const std::string & ResourceDescription::get_editor_pic
1342+const std::string & ResourceDescription::editor_image
1343 (uint32_t const amount) const
1344 {
1345 uint32_t bestmatch = 0;
1346
1347=== modified file 'src/logic/map_objects/world/resource_description.h'
1348--- src/logic/map_objects/world/resource_description.h 2015-11-28 22:29:26 +0000
1349+++ src/logic/map_objects/world/resource_description.h 2016-02-14 10:01:52 +0000
1350@@ -53,13 +53,17 @@
1351
1352 /// Returns the path to the image that should be used in the editor to
1353 /// represent an 'amount' of this resource.
1354- const std::string& get_editor_pic(uint32_t amount) const;
1355+ const std::string& editor_image(uint32_t amount) const;
1356+
1357+ /// Returns the path to the image that should be used in menus to represent this resource
1358+ const std::string& representative_image() const {return representative_image_;}
1359
1360 private:
1361 const std::string name_;
1362 const std::string descname_;
1363 const bool detectable_;
1364 const int32_t max_amount_;
1365+ const std::string representative_image_;
1366 std::vector<EditorPicture> editor_pictures_;
1367
1368 DISALLOW_COPY_AND_ASSIGN(ResourceDescription);
1369
1370=== modified file 'src/logic/map_objects/world/terrain_description.cc'
1371--- src/logic/map_objects/world/terrain_description.cc 2016-01-28 05:24:34 +0000
1372+++ src/logic/map_objects/world/terrain_description.cc 2016-02-14 10:01:52 +0000
1373@@ -210,8 +210,8 @@
1374 return descname_;
1375 }
1376
1377-const EditorCategory& TerrainDescription::editor_category() const {
1378- return *editor_category_;
1379+const EditorCategory* TerrainDescription::editor_category() const {
1380+ return editor_category_;
1381 }
1382
1383 DescriptionIndex TerrainDescription::get_valid_resource(uint8_t index) const {
1384@@ -222,6 +222,10 @@
1385 return valid_resources_.size();
1386 }
1387
1388+std::vector<uint8_t> TerrainDescription::valid_resources() const {
1389+ return valid_resources_;
1390+}
1391+
1392 bool TerrainDescription::is_resource_valid(const int res) const {
1393 for (const uint8_t resource_index : valid_resources_) {
1394 if (resource_index == res) {
1395
1396=== modified file 'src/logic/map_objects/world/terrain_description.h'
1397--- src/logic/map_objects/world/terrain_description.h 2016-01-13 07:27:55 +0000
1398+++ src/logic/map_objects/world/terrain_description.h 2016-02-14 10:01:52 +0000
1399@@ -94,6 +94,9 @@
1400 /// Returns the number of valid resources.
1401 int get_num_valid_resources() const;
1402
1403+ /// Returns the the valid resources.
1404+ std::vector<uint8_t> valid_resources() const;
1405+
1406 /// Returns true if this resource can be found in this terrain type.
1407 bool is_resource_valid(int32_t res) const;
1408
1409@@ -109,7 +112,7 @@
1410 int32_t dither_layer() const;
1411
1412 /// Returns the editor category.
1413- const EditorCategory& editor_category() const;
1414+ const EditorCategory* editor_category() const;
1415
1416 /// Parameters for terrain affinity of immovables.
1417 /// Temperature is in arbitrary units.
1418
1419=== modified file 'src/logic/map_objects/world/world.cc'
1420--- src/logic/map_objects/world/world.cc 2016-01-23 14:57:53 +0000
1421+++ src/logic/map_objects/world/world.cc 2016-02-14 10:01:52 +0000
1422@@ -119,7 +119,7 @@
1423 return *terrains_->get_mutable(i);
1424 }
1425
1426-TerrainDescription const* World::get_ter(char const* const name) const {
1427+const TerrainDescription* World::terrain_descr(const std::string& name) const {
1428 int32_t const i = terrains_->get_index(name);
1429 return i != INVALID_INDEX ? terrains_->get_mutable(i) : nullptr;
1430 }
1431
1432=== modified file 'src/logic/map_objects/world/world.h'
1433--- src/logic/map_objects/world/world.h 2016-01-13 07:27:55 +0000
1434+++ src/logic/map_objects/world/world.h 2016-02-14 10:01:52 +0000
1435@@ -50,7 +50,7 @@
1436 // becomes a pure container.
1437 const DescriptionMaintainer<TerrainDescription>& terrains() const;
1438 TerrainDescription& terrain_descr(DescriptionIndex i) const;
1439- TerrainDescription const* get_ter(char const* const name) const;
1440+ const TerrainDescription* terrain_descr(const std::string& name) const;
1441
1442 DescriptionIndex get_bob(char const* const l) const;
1443 BobDescr const* get_bob_descr(DescriptionIndex index) const;
1444
1445=== modified file 'src/map_io/map_terrain_packet.cc'
1446--- src/map_io/map_terrain_packet.cc 2015-11-28 22:29:26 +0000
1447+++ src/map_io/map_terrain_packet.cc 2016-02-14 10:01:52 +0000
1448@@ -61,7 +61,7 @@
1449 }
1450 const std::string new_terrain_name =
1451 lookup_table.lookup_terrain(old_terrain_name);
1452- if (!world.get_ter(new_terrain_name.c_str())) {
1453+ if (!world.terrain_descr(new_terrain_name)) {
1454 throw GameDataError("Terrain '%s' exists in map, not in world!", new_terrain_name.c_str());
1455 }
1456 smap[id] = world.terrains().get_index(new_terrain_name.c_str());
1457
1458=== modified file 'src/scripting/lua_bases.cc'
1459--- src/scripting/lua_bases.cc 2016-02-12 16:58:41 +0000
1460+++ src/scripting/lua_bases.cc 2016-02-14 10:01:52 +0000
1461@@ -27,6 +27,7 @@
1462 #include "logic/map_objects/tribes/tribe_descr.h"
1463 #include "logic/map_objects/tribes/tribes.h"
1464 #include "logic/map_objects/tribes/ware_descr.h"
1465+#include "logic/map_objects/world/world.h"
1466 #include "logic/player.h"
1467 #include "scripting/factory.h"
1468 #include "scripting/globals.h"
1469@@ -78,10 +79,13 @@
1470
1471 const char LuaEditorGameBase::className[] = "EditorGameBase";
1472 const MethodType<LuaEditorGameBase> LuaEditorGameBase::Methods[] = {
1473+ METHOD(LuaEditorGameBase, get_immovable_description),
1474 METHOD(LuaEditorGameBase, get_building_description),
1475 METHOD(LuaEditorGameBase, get_tribe_description),
1476 METHOD(LuaEditorGameBase, get_ware_description),
1477 METHOD(LuaEditorGameBase, get_worker_description),
1478+ METHOD(LuaEditorGameBase, get_resource_description),
1479+ METHOD(LuaEditorGameBase, get_terrain_description),
1480 {nullptr, nullptr},
1481 };
1482 const PropertyType<LuaEditorGameBase> LuaEditorGameBase::Properties[] = {
1483@@ -150,11 +154,42 @@
1484 */
1485
1486 /* RST
1487+ .. function:: get_immovable_description(immovable_name)
1488+
1489+ :arg immovable_name: the name of the immovable
1490+
1491+ Returns the ImmovableDescription for the named object.
1492+
1493+ (RO) The :class:`~wl.Game.Immovable_description`.
1494+*/
1495+int LuaEditorGameBase::get_immovable_description(lua_State* L) {
1496+ if (lua_gettop(L) != 2) {
1497+ report_error(L, "Wrong number of arguments");
1498+ }
1499+ const std::string immovable_name = luaL_checkstring(L, 2);
1500+ EditorGameBase& egbase = get_egbase(L);
1501+ const World& world = egbase.world();
1502+ DescriptionIndex idx = world.get_immovable_index(immovable_name);
1503+ if (idx != INVALID_INDEX) {
1504+ const ImmovableDescr* descr = world.get_immovable_descr(idx);
1505+ return to_lua<LuaMaps::LuaImmovableDescription>(L, new LuaMaps::LuaImmovableDescription(descr));
1506+ }
1507+ const Tribes& tribes = egbase.tribes();
1508+ idx = tribes.immovable_index(immovable_name);
1509+ if (!tribes.immovable_exists(idx)) {
1510+ report_error(L, "Immovable %s does not exist", immovable_name.c_str());
1511+ }
1512+ const ImmovableDescr* descr = tribes.get_immovable_descr(idx);
1513+ return to_lua<LuaMaps::LuaImmovableDescription>(L, new LuaMaps::LuaImmovableDescription(descr));
1514+}
1515+
1516+
1517+/* RST
1518 .. function:: get_building_description(building_description.name)
1519
1520 :arg building_name: the name of the building
1521
1522- Registers a building description so Lua can reference it from the game.
1523+ Returns the description for the given building.
1524
1525 (RO) The :class:`~wl.Game.Building_description`.
1526 */
1527@@ -178,7 +213,7 @@
1528
1529 :arg tribe_name: the name of the tribe
1530
1531- Registers a tribe description so Lua can reference it from the game.
1532+ Returns the tribe description of the given tribe.
1533
1534 (RO) The :class:`~wl.Game.Tribe_description`.
1535 */
1536@@ -202,7 +237,7 @@
1537
1538 :arg ware_name: the name of the ware
1539
1540- Registers a ware description so Lua can reference it from the game.
1541+ Returns the ware description for the given ware.
1542
1543 (RO) The :class:`~wl.Game.Ware_description`.
1544 */
1545@@ -226,7 +261,7 @@
1546
1547 :arg worker_name: the name of the worker
1548
1549- Registers a worker description so Lua can reference it from the game.
1550+ Returs the worker desciption for the given worker.
1551
1552 (RO) The :class:`~wl.Game.Worker_description`.
1553 */
1554@@ -244,6 +279,53 @@
1555 return LuaMaps::upcasted_map_object_descr_to_lua(L, worker_description);
1556 }
1557
1558+/* RST
1559+ .. function:: get_resource_description(resource_name)
1560+
1561+ :arg resource_name: the name of the resource
1562+
1563+ Returns the resource description for the given resource.
1564+
1565+ (RO) The :class:`~wl.Game.Resource_description`.
1566+*/
1567+int LuaEditorGameBase::get_resource_description(lua_State* L) {
1568+ if (lua_gettop(L) != 2) {
1569+ report_error(L, "Wrong number of arguments");
1570+ }
1571+ const std::string resource_name = luaL_checkstring(L, 2);
1572+ const World& world = get_egbase(L).world();
1573+ const DescriptionIndex idx = world.get_resource(resource_name.c_str());
1574+
1575+ if (idx == INVALID_INDEX) {
1576+ report_error(L, "Resource %s does not exist", resource_name.c_str());
1577+ }
1578+
1579+ const ResourceDescription* descr = world.get_resource(idx);
1580+ return to_lua<LuaMaps::LuaResourceDescription>(L, new LuaMaps::LuaResourceDescription(descr));
1581+}
1582+
1583+/* RST
1584+ .. function:: get_terrain_description(terrain_name)
1585+
1586+ :arg terrain_name: the name of the terrain
1587+
1588+ Returns a given terrain description for the given terrain.
1589+
1590+ (RO) The :class:`~wl.Game.Terrain_description`.
1591+*/
1592+int LuaEditorGameBase::get_terrain_description(lua_State* L) {
1593+ if (lua_gettop(L) != 2) {
1594+ report_error(L, "Wrong number of arguments");
1595+ }
1596+ const std::string terrain_name = luaL_checkstring(L, 2);
1597+ const TerrainDescription* descr = get_egbase(L).world().terrain_descr(terrain_name);
1598+ if (!descr) {
1599+ report_error(L, "Terrain %s does not exist", terrain_name.c_str());
1600+ }
1601+ return to_lua<LuaMaps::LuaTerrainDescription>(L, new LuaMaps::LuaTerrainDescription(descr));
1602+}
1603+
1604+
1605 /*
1606 ==========================================================
1607 C METHODS
1608@@ -498,7 +580,8 @@
1609 if (lua_gettop(L) >= 5)
1610 force = luaL_checkboolean(L, 5);
1611
1612- const Tribes& tribes = get_egbase(L).tribes();
1613+ EditorGameBase& egbase = get_egbase(L);
1614+ const Tribes& tribes = egbase.tribes();
1615
1616 if (!tribes.building_exists(name)) {
1617 report_error(L, "Unknown Building: '%s'", name.c_str());
1618@@ -514,14 +597,14 @@
1619 Building * b = nullptr;
1620 if (force) {
1621 if (constructionsite) {
1622- b = &get(L, get_egbase(L)).force_csite
1623+ b = &get(L, egbase).force_csite
1624 (c->coords(), building_index, former_buildings);
1625 } else {
1626- b = &get(L, get_egbase(L)).force_building
1627+ b = &get(L, egbase).force_building
1628 (c->coords(), former_buildings);
1629 }
1630 } else {
1631- b = get(L, get_egbase(L)).build
1632+ b = get(L, egbase).build
1633 (c->coords(), building_index, constructionsite, former_buildings);
1634 }
1635 if (!b)
1636
1637=== modified file 'src/scripting/lua_bases.h'
1638--- src/scripting/lua_bases.h 2016-02-12 16:58:41 +0000
1639+++ src/scripting/lua_bases.h 2016-02-14 10:01:52 +0000
1640@@ -58,10 +58,13 @@
1641 /*
1642 * Lua methods
1643 */
1644+ int get_immovable_description(lua_State * L);
1645 int get_building_description(lua_State * L);
1646 int get_tribe_description(lua_State * L);
1647 int get_ware_description(lua_State * L);
1648 int get_worker_description(lua_State * L);
1649+ int get_resource_description(lua_State * L);
1650+ int get_terrain_description(lua_State * L);
1651
1652 /*
1653 * C methods
1654
1655=== modified file 'src/scripting/lua_game.cc'
1656--- src/scripting/lua_game.cc 2016-02-12 16:58:41 +0000
1657+++ src/scripting/lua_game.cc 2016-02-14 10:01:52 +0000
1658@@ -886,14 +886,15 @@
1659 void LuaPlayer::m_parse_building_list
1660 (lua_State * L, const TribeDescr & tribe, std::vector<DescriptionIndex> & rv)
1661 {
1662- const Tribes& tribes = get_egbase(L).tribes();
1663+ EditorGameBase& egbase = get_egbase(L);
1664+ const Tribes& tribes = egbase.tribes();
1665 if (lua_isstring(L, -1)) {
1666 std::string opt = luaL_checkstring(L, -1);
1667 if (opt != "all") {
1668 report_error(L, "'%s' was not understood as argument!", opt.c_str());
1669 }
1670 // Only act on buildings that the tribe has or could conquer
1671- const TribeDescr& tribe_descr = get(L, get_egbase(L)).tribe();
1672+ const TribeDescr& tribe_descr = get(L, egbase).tribe();
1673 for (size_t i = 0; i < tribes.nrbuildings(); ++i) {
1674 const DescriptionIndex& building_index = static_cast<DescriptionIndex>(i);
1675 const BuildingDescr& descr = *tribe_descr.get_building_descr(building_index);
1676
1677=== modified file 'src/scripting/lua_map.cc'
1678--- src/scripting/lua_map.cc 2016-02-13 11:25:41 +0000
1679+++ src/scripting/lua_map.cc 2016-02-14 10:01:52 +0000
1680@@ -31,11 +31,13 @@
1681 #include "logic/findimmovable.h"
1682 #include "logic/map_objects/checkstep.h"
1683 #include "logic/map_objects/immovable.h"
1684+#include "logic/map_objects/terrain_affinity.h"
1685 #include "logic/map_objects/tribes/carrier.h"
1686 #include "logic/map_objects/tribes/ship.h"
1687 #include "logic/map_objects/tribes/soldier.h"
1688 #include "logic/map_objects/tribes/tribes.h"
1689 #include "logic/map_objects/tribes/warelist.h"
1690+#include "logic/map_objects/world/editor_category.h"
1691 #include "logic/map_objects/world/resource_description.h"
1692 #include "logic/map_objects/world/terrain_description.h"
1693 #include "logic/map_objects/world/world.h"
1694@@ -605,6 +607,8 @@
1695 return CAST_TO_LUA(WorkerDescr, LuaWorkerDescription);
1696 case MapObjectType::SOLDIER:
1697 return CAST_TO_LUA(WorkerDescr, LuaWorkerDescription);
1698+ case MapObjectType::IMMOVABLE:
1699+ return CAST_TO_LUA(ImmovableDescr, LuaImmovableDescription);
1700 default:
1701 return CAST_TO_LUA(MapObjectDescr, LuaMapObjectDescription);
1702 }
1703@@ -1406,6 +1410,210 @@
1704 return 1;
1705 }
1706
1707+
1708+/* RST
1709+ImmovableDescription
1710+--------------------
1711+
1712+.. class:: ImmovableDescription
1713+
1714+ A static description of a base immovable, so it can be used in help files
1715+ without having to access an actual immovable on the map.
1716+ See also class MapObjectDescription for more properties.
1717+*/
1718+const char LuaImmovableDescription::className[] = "ImmovableDescription";
1719+const MethodType<LuaImmovableDescription> LuaImmovableDescription::Methods[] = {
1720+ METHOD(LuaImmovableDescription, has_attribute),
1721+ METHOD(LuaImmovableDescription, probability_to_grow),
1722+ {nullptr, nullptr},
1723+};
1724+const PropertyType<LuaImmovableDescription> LuaImmovableDescription::Properties[] = {
1725+ PROP_RO(LuaImmovableDescription, species),
1726+ PROP_RO(LuaImmovableDescription, build_cost),
1727+ PROP_RO(LuaImmovableDescription, editor_category),
1728+ PROP_RO(LuaImmovableDescription, terrain_affinity),
1729+ PROP_RO(LuaImmovableDescription, owner_type),
1730+ PROP_RO(LuaImmovableDescription, size),
1731+ {nullptr, nullptr, nullptr},
1732+};
1733+
1734+
1735+void LuaImmovableDescription::__persist(lua_State* L) {
1736+ const ImmovableDescr* descr = get();
1737+ PERS_STRING("name", descr->name());
1738+}
1739+
1740+void LuaImmovableDescription::__unpersist(lua_State* L) {
1741+ std::string name;
1742+ UNPERS_STRING("name", name);
1743+ const World& world = get_egbase(L).world();
1744+ DescriptionIndex idx = world.get_immovable_index(name);
1745+ if (idx == INVALID_INDEX) {
1746+ throw LuaError((boost::format("Immovable '%s' doesn't exist.") % name).str());
1747+ }
1748+ set_description_pointer(world.get_immovable_descr(idx));
1749+}
1750+
1751+
1752+/* RST
1753+ .. attribute:: the species name of a tree for editor lists
1754+
1755+ (RO) the localized species name of the immovable, or an empty string if it has none.
1756+*/
1757+int LuaImmovableDescription::get_species(lua_State * L) {
1758+ lua_pushstring(L, get()->species());
1759+ return 1;
1760+}
1761+
1762+
1763+/* RST
1764+ .. attribute:: build_cost
1765+
1766+ (RO) a table of ware-to-count pairs, describing the build cost for the
1767+ immovable.
1768+*/
1769+int LuaImmovableDescription::get_build_cost(lua_State * L) {
1770+ return wares_or_workers_map_to_lua(L, get()->buildcost(), MapObjectType::WARE);
1771+}
1772+
1773+/* RST
1774+ .. attribute:: the name and descname of the editor category of this immovable
1775+
1776+ (RO) a table with "name" and "descname" entries for the editor category, or nil if it has none.
1777+*/
1778+int LuaImmovableDescription::get_editor_category(lua_State * L) {
1779+ const EditorCategory* editor_category = get()->editor_category();
1780+ if (editor_category != nullptr) {
1781+ lua_newtable(L);
1782+ lua_pushstring(L, "name");
1783+ lua_pushstring(L, editor_category->name());
1784+ lua_settable(L, -3);
1785+ lua_pushstring(L, "descname");
1786+ lua_pushstring(L, editor_category->descname());
1787+ lua_settable(L, -3);
1788+ } else {
1789+ lua_pushnil(L);
1790+ }
1791+ return 1;
1792+}
1793+
1794+/* RST
1795+ .. attribute:: returns the terrain affinity values for this immovable
1796+
1797+ (RO) a table containing numbers labeled as pickiness, preferred_fertility,
1798+ preferred_humidity, and preferred_temperature,
1799+ or nil if the immovable has no terrain affinity.
1800+*/
1801+int LuaImmovableDescription::get_terrain_affinity(lua_State * L) {
1802+ if (get()->has_terrain_affinity()) {
1803+ const TerrainAffinity& affinity = get()->terrain_affinity();
1804+ lua_newtable(L);
1805+ lua_pushstring(L, "pickiness");
1806+ lua_pushnumber(L, affinity.pickiness());
1807+ lua_settable(L, -3);
1808+ lua_pushstring(L, "preferred_fertility");
1809+ lua_pushnumber(L, affinity.preferred_fertility());
1810+ lua_settable(L, -3);
1811+ lua_pushstring(L, "preferred_humidity");
1812+ lua_pushnumber(L, affinity.preferred_humidity());
1813+ lua_settable(L, -3);
1814+ lua_pushstring(L, "preferred_temperature");
1815+ lua_pushnumber(L, affinity.preferred_temperature());
1816+ lua_settable(L, -3);
1817+ } else {
1818+ lua_pushnil(L);
1819+ }
1820+ return 1;
1821+}
1822+
1823+
1824+/* RST
1825+ .. attribute:: the owner type of this immovable
1826+
1827+ (RO) "world" for world immovables and "tribe" for tribe immovables.
1828+*/
1829+int LuaImmovableDescription::get_owner_type(lua_State * L) {
1830+ switch (get()->owner_type()) {
1831+ case MapObjectDescr::OwnerType::kWorld:
1832+ lua_pushstring(L, "world");
1833+ break;
1834+ case MapObjectDescr::OwnerType::kTribe:
1835+ lua_pushstring(L, "tribe");
1836+ break;
1837+ default:
1838+ NEVER_HERE();
1839+ }
1840+ return 1;
1841+}
1842+
1843+
1844+/* RST
1845+ .. attribute:: size
1846+
1847+ (RO) the size of the immovable as an int.
1848+*/
1849+int LuaImmovableDescription::get_size(lua_State * L) {
1850+ // TODO(GunChleoc): see this todo, that is also mentioned below for
1851+ // buildings. I think we can do that now, every description is wrapped I
1852+ // think. Essentially that means every instance of something on the map
1853+ // (like a building) get's a .description that has the static data for the
1854+ // building/immovable. maybe in a followup branch, but definitvely before b19, since that is backwards
1855+ // incompatible.
1856+ // TODO(SirVer): size should be similar to
1857+ // https://wl.widelands.org/docs/wl/autogen_wl_map/#wl.map.BaseImmovable.size.
1858+ // In fact, as soon as all descriptions are wrapped (also for other
1859+ // immovables besides buildings) we should get rid of BaseImmovable.size.
1860+ lua_pushinteger(L, get()->get_size());
1861+ return 1;
1862+}
1863+
1864+/*
1865+ ==========================================================
1866+ METHODS
1867+ ==========================================================
1868+ */
1869+
1870+/* RST
1871+ .. method:: whether the immovable has the given attribute
1872+
1873+ :arg attribute_name: The attribute that we are checking for.
1874+ :type attribute_name: :class:`string`
1875+
1876+ (RO) true if the immovable has the attribute, false otherwise.
1877+*/
1878+int LuaImmovableDescription::has_attribute(lua_State * L) {
1879+ if (lua_gettop(L) != 2) {
1880+ report_error(L, "Takes only one argument.");
1881+ }
1882+ const uint32_t attribute_id = get()->get_attribute_id(luaL_checkstring(L, 2));
1883+ lua_pushboolean(L, get()->has_attribute(attribute_id));
1884+ return 1;
1885+}
1886+
1887+/* RST
1888+ .. method:: probability_to_grow
1889+
1890+ :arg terrain: The terrain that we are checking the probability for.
1891+ :type terrain: :class:`wl.map.TerrainDescription`
1892+
1893+ (RO) A double describing the probability that this tree will grow on the given terrain.
1894+ Returns nil if this immovable tree has no terrain affinity (all trees should have one).
1895+*/
1896+int LuaImmovableDescription::probability_to_grow(lua_State * L) {
1897+ if (lua_gettop(L) != 2) {
1898+ report_error(L, "Takes only one argument.");
1899+ }
1900+ if (get()->has_terrain_affinity()) {
1901+ const TerrainDescription* terrain = (*get_user_class<LuaMaps::LuaTerrainDescription>(L, 2))->get();
1902+ lua_pushnumber(L, Widelands::probability_to_grow(get()->terrain_affinity(), *terrain));
1903+ } else {
1904+ lua_pushnil(L);
1905+ }
1906+ return 1;
1907+}
1908+
1909+
1910+
1911 /* RST
1912 BuildingDescription
1913 -------------------
1914@@ -1540,8 +1748,9 @@
1915 int LuaBuildingDescription::get_enhanced_from(lua_State * L) {
1916 if (get()->is_enhanced()) {
1917 const DescriptionIndex& enhanced_from = get()->enhanced_from();
1918- assert(get_egbase(L).tribes().building_exists(enhanced_from));
1919- return upcasted_map_object_descr_to_lua(L, get_egbase(L).tribes().get_building_descr(enhanced_from));
1920+ EditorGameBase& egbase = get_egbase(L);
1921+ assert(egbase.tribes().building_exists(enhanced_from));
1922+ return upcasted_map_object_descr_to_lua(L, egbase.tribes().get_building_descr(enhanced_from));
1923 }
1924 lua_pushnil(L);
1925 return 0;
1926@@ -2271,8 +2480,9 @@
1927 void LuaWareDescription::__unpersist(lua_State* L) {
1928 std::string name;
1929 UNPERS_STRING("name", name);
1930- DescriptionIndex idx = get_egbase(L).tribes().safe_ware_index(name.c_str());
1931- set_description_pointer(get_egbase(L).tribes().get_ware_descr(idx));
1932+ const Tribes& tribes = get_egbase(L).tribes();
1933+ DescriptionIndex idx = tribes.safe_ware_index(name.c_str());
1934+ set_description_pointer(tribes.get_ware_descr(idx));
1935 }
1936
1937
1938@@ -2311,7 +2521,7 @@
1939
1940
1941 /* RST
1942- .. attribute:: is_construction_material
1943+ .. .. method:: is_construction_material
1944
1945 :arg tribename: the name of the tribe that this ware gets checked for
1946 :type tribename: :class:`string`
1947@@ -2477,6 +2687,312 @@
1948 ==========================================================
1949 */
1950
1951+/* RST
1952+ResourceDescription
1953+--------------------
1954+.. class:: ResourceDescription
1955+
1956+ A static description of a resource.
1957+*/
1958+const char LuaResourceDescription::className[] = "ResourceDescription";
1959+const MethodType<LuaResourceDescription> LuaResourceDescription::Methods[] = {
1960+ METHOD(LuaResourceDescription, editor_image),
1961+ {nullptr, nullptr},
1962+};
1963+const PropertyType<LuaResourceDescription> LuaResourceDescription::Properties[] = {
1964+ PROP_RO(LuaResourceDescription, name),
1965+ PROP_RO(LuaResourceDescription, descname),
1966+ PROP_RO(LuaResourceDescription, is_detectable),
1967+ PROP_RO(LuaResourceDescription, max_amount),
1968+ PROP_RO(LuaResourceDescription, representative_image),
1969+ {nullptr, nullptr, nullptr},
1970+};
1971+
1972+void LuaResourceDescription::__persist(lua_State* L) {
1973+ const Widelands::ResourceDescription* descr = get();
1974+ PERS_STRING("name", descr->name());
1975+}
1976+
1977+void LuaResourceDescription::__unpersist(lua_State* L) {
1978+ std::string name;
1979+ UNPERS_STRING("name", name);
1980+ const World& world = get_egbase(L).world();
1981+ const ResourceDescription* descr = world.get_resource(world.safe_resource_index(name.c_str()));
1982+ set_description_pointer(descr);
1983+}
1984+
1985+/*
1986+ ==========================================================
1987+ PROPERTIES
1988+ ==========================================================
1989+ */
1990+
1991+/* RST
1992+ .. attribute:: name
1993+
1994+ (RO) the :class:`string` internal name of this resource
1995+*/
1996+
1997+int LuaResourceDescription::get_name(lua_State * L) {
1998+ lua_pushstring(L, get()->name());
1999+ return 1;
2000+}
2001+
2002+/* RST
2003+ .. attribute:: descname
2004+
2005+ (RO) the :class:`string` display name of this resource
2006+*/
2007+
2008+int LuaResourceDescription::get_descname(lua_State * L) {
2009+ lua_pushstring(L, get()->descname());
2010+ return 1;
2011+}
2012+
2013+/* RST
2014+ .. attribute:: is_detectable
2015+
2016+ (RO) true if geologists can find this resource
2017+*/
2018+
2019+int LuaResourceDescription::get_is_detectable(lua_State * L) {
2020+ lua_pushboolean(L, get()->detectable());
2021+ return 1;
2022+}
2023+
2024+/* RST
2025+ .. attribute:: max_amount
2026+
2027+ (RO) the maximum amount of this resource that a terrain can have
2028+*/
2029+
2030+int LuaResourceDescription::get_max_amount(lua_State * L) {
2031+ lua_pushinteger(L, get()->max_amount());
2032+ return 1;
2033+}
2034+
2035+/* RST
2036+ .. attribute:: representative_image
2037+
2038+ (RO) the :class:`string` path to the image representing this resource in the GUI
2039+*/
2040+int LuaResourceDescription::get_representative_image(lua_State * L) {
2041+ lua_pushstring(L, get()->representative_image());
2042+ return 1;
2043+}
2044+
2045+
2046+/*
2047+ ==========================================================
2048+ METHODS
2049+ ==========================================================
2050+ */
2051+
2052+/* RST
2053+ .. method:: editor_image(amount)
2054+
2055+ :arg amount: The amount of the resource what we want an overlay image for
2056+
2057+ (RO) the :class:`string` path to the image representing the specified amount of this resource
2058+*/
2059+int LuaResourceDescription::editor_image(lua_State * L) {
2060+ if (lua_gettop(L) != 2) {
2061+ report_error(L, "Takes only one argument.");
2062+ }
2063+ const uint32_t amount = luaL_checkuint32(L, 2);
2064+ lua_pushstring(L, get()->editor_image(amount));
2065+ return 1;
2066+}
2067+
2068+/* RST
2069+TerrainDescription
2070+--------------------
2071+.. class:: TerrainDescription
2072+
2073+ A static description of a terrain.
2074+*/
2075+const char LuaTerrainDescription::className[] = "TerrainDescription";
2076+const MethodType<LuaTerrainDescription> LuaTerrainDescription::Methods[] = {
2077+ {nullptr, nullptr},
2078+};
2079+const PropertyType<LuaTerrainDescription> LuaTerrainDescription::Properties[] = {
2080+ PROP_RO(LuaTerrainDescription, name),
2081+ PROP_RO(LuaTerrainDescription, descname),
2082+ PROP_RO(LuaTerrainDescription, default_resource),
2083+ PROP_RO(LuaTerrainDescription, default_resource_amount),
2084+ PROP_RO(LuaTerrainDescription, editor_category),
2085+ PROP_RO(LuaTerrainDescription, fertility),
2086+ PROP_RO(LuaTerrainDescription, humidity),
2087+ PROP_RO(LuaTerrainDescription, representative_image),
2088+ PROP_RO(LuaTerrainDescription, temperature),
2089+ PROP_RO(LuaTerrainDescription, valid_resources),
2090+ {nullptr, nullptr, nullptr},
2091+};
2092+
2093+void LuaTerrainDescription::__persist(lua_State* L) {
2094+ const Widelands::TerrainDescription* descr = get();
2095+ PERS_STRING("name", descr->name());
2096+}
2097+
2098+void LuaTerrainDescription::__unpersist(lua_State* L) {
2099+ std::string name;
2100+ UNPERS_STRING("name", name);
2101+ set_description_pointer(get_egbase(L).world().terrain_descr(name));
2102+}
2103+
2104+/*
2105+ ==========================================================
2106+ PROPERTIES
2107+ ==========================================================
2108+ */
2109+
2110+/* RST
2111+ .. attribute:: name
2112+
2113+ (RO) the :class:`string` internal name of this terrain
2114+*/
2115+
2116+int LuaTerrainDescription::get_name(lua_State * L) {
2117+ lua_pushstring(L, get()->name());
2118+ return 1;
2119+}
2120+
2121+/* RST
2122+ .. attribute:: descname
2123+
2124+ (RO) the :class:`string` display name of this terrain
2125+*/
2126+
2127+int LuaTerrainDescription::get_descname(lua_State * L) {
2128+ lua_pushstring(L, get()->descname());
2129+ return 1;
2130+}
2131+
2132+/* RST
2133+ .. attribute:: get_default_resource
2134+
2135+ (RO) the :class:`wl.map.ResourceDescription` for the default resource provided by this terrain, or
2136+ nil if the terrain has no default resource.
2137+*/
2138+
2139+int LuaTerrainDescription::get_default_resource(lua_State * L) {
2140+ int res_index = get()->get_default_resource();
2141+ const World& world = get_egbase(L).world();
2142+ if (res_index != Widelands::kNoResource && res_index < world.get_nr_resources()) {
2143+ to_lua<LuaMaps::LuaResourceDescription>
2144+ (L, new LuaMaps::LuaResourceDescription(world.get_resource(res_index)));
2145+ } else {
2146+ lua_pushnil(L);
2147+ }
2148+ return 1;
2149+}
2150+
2151+/* RST
2152+ .. attribute:: default_resource_amount
2153+
2154+ (RO) the int amount of the default resource provided by this terrain.
2155+*/
2156+
2157+int LuaTerrainDescription::get_default_resource_amount(lua_State * L) {
2158+ lua_pushinteger(L, get()->get_default_resource_amount());
2159+ return 1;
2160+}
2161+
2162+
2163+/* RST
2164+ .. attribute:: the name and descname of the editor category of this terrain
2165+
2166+ (RO) a table with "name" and "descname" entries for the editor category, or nil if it has none.
2167+*/
2168+int LuaTerrainDescription::get_editor_category(lua_State * L) {
2169+ const EditorCategory* editor_category = get()->editor_category();
2170+ if (editor_category != nullptr) {
2171+ lua_newtable(L);
2172+ lua_pushstring(L, "name");
2173+ lua_pushstring(L, editor_category->name());
2174+ lua_settable(L, -3);
2175+ lua_pushstring(L, "descname");
2176+ lua_pushstring(L, editor_category->descname());
2177+ lua_settable(L, -3);
2178+ } else {
2179+ lua_pushnil(L);
2180+ }
2181+ return 1;
2182+}
2183+
2184+/* RST
2185+ .. attribute:: fertility
2186+
2187+ (RO) the :class:`double` fertility value for this terrain
2188+*/
2189+
2190+int LuaTerrainDescription::get_fertility(lua_State * L) {
2191+ lua_pushnumber(L, get()->fertility());
2192+ return 1;
2193+}
2194+
2195+/* RST
2196+ .. attribute:: humidity
2197+
2198+ (RO) the :class:`double` humidity value for this terrain
2199+*/
2200+
2201+int LuaTerrainDescription::get_humidity(lua_State * L) {
2202+ lua_pushnumber(L, get()->humidity());
2203+ return 1;
2204+}
2205+
2206+/* RST
2207+ .. attribute:: representative_image
2208+
2209+ (RO) the :class:`string` file path to a representative image
2210+*/
2211+
2212+int LuaTerrainDescription::get_representative_image(lua_State * L) {
2213+ lua_pushstring(L, get()->texture_paths().front());
2214+ return 1;
2215+}
2216+
2217+/* RST
2218+ .. attribute:: temperature
2219+
2220+ (RO) the :class:`double` temperature value for this terrain
2221+*/
2222+
2223+int LuaTerrainDescription::get_temperature(lua_State * L) {
2224+ lua_pushnumber(L, get()->temperature());
2225+ return 1;
2226+}
2227+
2228+
2229+/* RST
2230+ .. attribute:: valid_resources
2231+
2232+ (RO) a list of :class:`wl.map.ResourceDescription` with all valid resources for this terrain.
2233+*/
2234+
2235+int LuaTerrainDescription::get_valid_resources(lua_State * L) {
2236+ const World& world = get_egbase(L).world();
2237+ lua_newtable(L);
2238+ int index = 1;
2239+ for (uint8_t res_index : get()->valid_resources()) {
2240+ if (res_index != Widelands::kNoResource && res_index < world.get_nr_resources()) {
2241+ lua_pushint32(L, index++);
2242+ to_lua<LuaMaps::LuaResourceDescription>
2243+ (L, new LuaMaps::LuaResourceDescription(world.get_resource(res_index)));
2244+ lua_settable(L, -3);
2245+ }
2246+ }
2247+ return 1;
2248+}
2249+
2250+
2251+/*
2252+ ==========================================================
2253+ METHODS
2254+ ==========================================================
2255+ */
2256+
2257
2258
2259 /* RST
2260@@ -3338,10 +3854,10 @@
2261 */
2262 int LuaWarehouse::get_expedition_in_progress(lua_State * L) {
2263
2264- Warehouse* wh = get(L, get_egbase(L));
2265+ EditorGameBase& egbase = get_egbase(L);
2266
2267- if (is_a(Game, &get_egbase(L))) {
2268- PortDock* pd = wh->get_portdock();
2269+ if (is_a(Game, &egbase)) {
2270+ PortDock* pd = get(L, egbase)->get_portdock();
2271 if (pd) {
2272 if (pd->expedition_started()){
2273 return 1;
2274@@ -3425,19 +3941,20 @@
2275 */
2276 int LuaWarehouse::start_expedition(lua_State* L) {
2277
2278- Warehouse* Wh = get(L, get_egbase(L));
2279+ EditorGameBase& egbase = get_egbase(L);
2280+ Warehouse* wh = get(L, egbase);
2281
2282- if (!Wh) {
2283+ if (!wh) {
2284 return 0;
2285 }
2286
2287- if (upcast(Game, game, &get_egbase(L))) {
2288- PortDock* pd = Wh->get_portdock();
2289+ if (upcast(Game, game, &egbase)) {
2290+ PortDock* pd = wh->get_portdock();
2291 if (!pd) {
2292 return 0;
2293 }
2294 if (!pd->expedition_started()){
2295- game->send_player_start_or_cancel_expedition(*Wh);
2296+ game->send_player_start_or_cancel_expedition(*wh);
2297 return 1;
2298 }
2299 }
2300@@ -3455,19 +3972,20 @@
2301 */
2302 int LuaWarehouse::cancel_expedition(lua_State* L) {
2303
2304- Warehouse* Wh = get(L, get_egbase(L));
2305+ EditorGameBase& egbase = get_egbase(L);
2306+ Warehouse* wh = get(L, egbase);
2307
2308- if (!Wh) {
2309+ if (!wh) {
2310 return 0;
2311 }
2312
2313- if (upcast(Game, game, &get_egbase(L))) {
2314- PortDock* pd = Wh->get_portdock();
2315+ if (upcast(Game, game, &egbase)) {
2316+ PortDock* pd = wh->get_portdock();
2317 if (!pd) {
2318 return 0;
2319 }
2320 if (pd->expedition_started()){
2321- game->send_player_start_or_cancel_expedition(*Wh);
2322+ game->send_player_start_or_cancel_expedition(*wh);
2323 return 1;
2324 }
2325 }
2326@@ -3901,8 +4419,9 @@
2327 */
2328 // UNTESTED sink states
2329 int LuaShip::get_state(lua_State* L) {
2330- if (is_a(Game, &get_egbase(L))) {
2331- switch (get(L, get_egbase(L))->get_ship_state()) {
2332+ EditorGameBase& egbase = get_egbase(L);
2333+ if (is_a(Game, &egbase)) {
2334+ switch (get(L, egbase)->get_ship_state()) {
2335 case Ship::TRANSPORT:
2336 lua_pushstring(L, "transport");
2337 break;
2338@@ -3934,8 +4453,9 @@
2339 }
2340
2341 int LuaShip::get_scouting_direction(lua_State* L) {
2342- if (is_a(Game, &get_egbase(L))) {
2343- switch (get(L, get_egbase(L))->get_scouting_direction()) {
2344+ EditorGameBase& egbase = get_egbase(L);
2345+ if (is_a(Game, &egbase)) {
2346+ switch (get(L, egbase)->get_scouting_direction()) {
2347 case WalkingDir::WALK_NE:
2348 lua_pushstring(L, "ne");
2349 break;
2350@@ -3963,7 +4483,8 @@
2351 }
2352
2353 int LuaShip::set_scouting_direction(lua_State* L) {
2354- if (upcast(Game, game, &get_egbase(L))) {
2355+ EditorGameBase& egbase = get_egbase(L);
2356+ if (upcast(Game, game, &egbase)) {
2357 std::string dirname = luaL_checkstring(L, 3);
2358 WalkingDir dir = WalkingDir::IDLE;
2359
2360@@ -3982,7 +4503,7 @@
2361 } else {
2362 return 0;
2363 }
2364- game->send_player_ship_scouting_direction(*get(L, get_egbase(L)), dir);
2365+ game->send_player_ship_scouting_direction(*get(L, egbase), dir);
2366 return 1;
2367 }
2368 return 0;
2369@@ -3997,8 +4518,9 @@
2370
2371 */
2372 int LuaShip::get_island_explore_direction(lua_State* L) {
2373- if (is_a(Game, &get_egbase(L))) {
2374- switch (get(L, get_egbase(L))->get_island_explore_direction()) {
2375+ EditorGameBase& egbase = get_egbase(L);
2376+ if (is_a(Game, &egbase)) {
2377+ switch (get(L, egbase)->get_island_explore_direction()) {
2378 case IslandExploreDirection::kCounterClockwise:
2379 lua_pushstring(L, "ccw");
2380 break;
2381@@ -4014,8 +4536,9 @@
2382 }
2383
2384 int LuaShip::set_island_explore_direction(lua_State* L) {
2385- if (upcast(Game, game, &get_egbase(L))) {
2386- Ship* ship = get(L, get_egbase(L));
2387+ EditorGameBase& egbase = get_egbase(L);
2388+ if (upcast(Game, game, &egbase)) {
2389+ Ship* ship = get(L, egbase);
2390 std::string dir = luaL_checkstring(L, 3);
2391 if (dir == "ccw"){
2392 game->send_player_ship_explore_island(*ship, IslandExploreDirection::kCounterClockwise);
2393@@ -4110,9 +4633,10 @@
2394 :returns: true/false
2395 */
2396 int LuaShip::build_colonization_port(lua_State* L) {
2397- Ship* ship = get(L, get_egbase(L));
2398+ EditorGameBase& egbase = get_egbase(L);
2399+ Ship* ship = get(L, egbase);
2400 if (ship->get_ship_state() == Widelands::Ship::EXP_FOUNDPORTSPACE) {
2401- if (upcast(Game, game, &get_egbase(L))) {
2402+ if (upcast(Game, game, &egbase)) {
2403 game->send_player_ship_construct_port(*ship, ship->exp_port_spaces().front());
2404 return 1;
2405 }
2406@@ -4461,7 +4985,7 @@
2407 }
2408 int LuaField::set_resource(lua_State * L) {
2409 auto& egbase = get_egbase(L);
2410- int32_t res = get_egbase(L).world().get_resource
2411+ int32_t res = egbase.world().get_resource
2412 (luaL_checkstring(L, -1));
2413
2414 if (res == Widelands::INVALID_INDEX)
2415@@ -4487,16 +5011,16 @@
2416 return 1;
2417 }
2418 int LuaField::set_resource_amount(lua_State * L) {
2419+ EditorGameBase& egbase = get_egbase(L);
2420 auto c = fcoords(L);
2421 int32_t res = c.field->get_resources();
2422 int32_t amount = luaL_checkint32(L, -1);
2423- const ResourceDescription * resDesc = get_egbase(L).world().get_resource(res);
2424+ const ResourceDescription * resDesc = egbase.world().get_resource(res);
2425 int32_t max_amount = resDesc ? resDesc->max_amount() : 0;
2426
2427 if (amount < 0 || amount > max_amount)
2428 report_error(L, "Illegal amount: %i, must be >= 0 and <= %i", amount, max_amount);
2429
2430- EditorGameBase & egbase = get_egbase(L);
2431 auto& map = egbase.map();
2432 if (is_a(Game, &egbase)) {
2433 map.set_resources(c, amount);
2434@@ -4943,6 +5467,10 @@
2435 register_class<LuaTribeDescription>(L, "map");
2436 register_class<LuaMapObjectDescription>(L, "map");
2437
2438+ register_class<LuaImmovableDescription>(L, "map", true);
2439+ add_parent<LuaImmovableDescription, LuaMapObjectDescription>(L);
2440+ lua_pop(L, 1); // Pop the meta table
2441+
2442 register_class<LuaBuildingDescription>(L, "map", true);
2443 add_parent<LuaBuildingDescription, LuaMapObjectDescription>(L);
2444 lua_pop(L, 1); // Pop the meta table
2445@@ -4986,6 +5514,9 @@
2446 add_parent<LuaWorkerDescription, LuaMapObjectDescription>(L);
2447 lua_pop(L, 1); // Pop the meta table
2448
2449+ register_class<LuaResourceDescription>(L, "map");
2450+ register_class<LuaTerrainDescription>(L, "map");
2451+
2452 register_class<LuaField>(L, "map");
2453 register_class<LuaPlayerSlot>(L, "map");
2454 register_class<LuaMapObject>(L, "map");
2455
2456=== modified file 'src/scripting/lua_map.h'
2457--- src/scripting/lua_map.h 2016-02-12 16:58:41 +0000
2458+++ src/scripting/lua_map.h 2016-02-14 10:01:52 +0000
2459@@ -35,6 +35,7 @@
2460 #include "logic/map_objects/tribes/trainingsite.h"
2461 #include "logic/map_objects/tribes/warehouse.h"
2462 #include "logic/map_objects/tribes/worker.h"
2463+#include "logic/map_objects/world/terrain_description.h"
2464 #include "scripting/lua.h"
2465 #include "scripting/luna.h"
2466
2467@@ -43,8 +44,10 @@
2468 class SoldierDescr;
2469 class BuildingDescr;
2470 class Bob;
2471+ class ResourceDescription;
2472 class WareDescr;
2473 class WorkerDescr;
2474+ class TerrainDescription;
2475 class TribeDescr;
2476 }
2477
2478@@ -203,6 +206,47 @@
2479 return static_cast<const Widelands::klass*>(LuaMapObjectDescription::get()); \
2480 }
2481
2482+class LuaImmovableDescription : public LuaMapObjectDescription {
2483+public:
2484+ LUNA_CLASS_HEAD(LuaImmovableDescription);
2485+
2486+ virtual ~LuaImmovableDescription() {}
2487+
2488+ LuaImmovableDescription() {}
2489+ LuaImmovableDescription(const Widelands::ImmovableDescr* const immovabledescr)
2490+ : LuaMapObjectDescription(immovabledescr) {
2491+ }
2492+ LuaImmovableDescription(lua_State* L) : LuaMapObjectDescription(L) {
2493+ }
2494+
2495+ void __persist(lua_State * L) override;
2496+ void __unpersist(lua_State * L) override;
2497+
2498+ /*
2499+ * Properties
2500+ */
2501+ int get_species(lua_State *);
2502+ int get_build_cost(lua_State *);
2503+ int get_editor_category(lua_State *);
2504+ int get_terrain_affinity(lua_State *);
2505+ int get_owner_type(lua_State *);
2506+ int get_size(lua_State *);
2507+
2508+ /*
2509+ * Lua methods
2510+ */
2511+ int has_attribute(lua_State *);
2512+ int probability_to_grow(lua_State *);
2513+
2514+ /*
2515+ * C methods
2516+ */
2517+
2518+private:
2519+ CASTED_GET_DESCRIPTION(ImmovableDescr)
2520+};
2521+
2522+
2523 class LuaBuildingDescription : public LuaMapObjectDescription {
2524 public:
2525 LUNA_CLASS_HEAD(LuaBuildingDescription);
2526@@ -515,6 +559,111 @@
2527
2528 #undef CASTED_GET_DESCRIPTION
2529
2530+
2531+class LuaResourceDescription : public LuaMapModuleClass {
2532+public:
2533+ LUNA_CLASS_HEAD(LuaResourceDescription);
2534+
2535+ virtual ~LuaResourceDescription() {}
2536+
2537+ LuaResourceDescription() : resourcedescr_(nullptr) {}
2538+ LuaResourceDescription(const Widelands::ResourceDescription* const resourcedescr)
2539+ : resourcedescr_(resourcedescr) {}
2540+ LuaResourceDescription(lua_State* L) : resourcedescr_(nullptr) {
2541+ report_error(L, "Cannot instantiate a 'LuaResourceDescription' directly!");
2542+ }
2543+
2544+ void __persist(lua_State * L) override;
2545+ void __unpersist(lua_State * L) override;
2546+
2547+ /*
2548+ * Properties
2549+ */
2550+ int get_name(lua_State *);
2551+ int get_descname(lua_State *);
2552+ int get_is_detectable(lua_State *);
2553+ int get_max_amount(lua_State *);
2554+ int get_representative_image(lua_State *);
2555+
2556+ /*
2557+ * Lua methods
2558+ */
2559+
2560+ int editor_image(lua_State *);
2561+
2562+ /*
2563+ * C methods
2564+ */
2565+protected:
2566+ const Widelands::ResourceDescription* get() const {
2567+ assert(resourcedescr_ != nullptr);
2568+ return resourcedescr_;
2569+ }
2570+ // For persistence.
2571+ void set_description_pointer(const Widelands::ResourceDescription* pointer) {
2572+ resourcedescr_ = pointer;
2573+ }
2574+
2575+private:
2576+ const Widelands::ResourceDescription* resourcedescr_;
2577+};
2578+
2579+
2580+
2581+class LuaTerrainDescription : public LuaMapModuleClass {
2582+public:
2583+ LUNA_CLASS_HEAD(LuaTerrainDescription);
2584+
2585+ virtual ~LuaTerrainDescription() {}
2586+
2587+ LuaTerrainDescription() : terraindescr_(nullptr) {}
2588+ LuaTerrainDescription(const Widelands::TerrainDescription* const terraindescr)
2589+ : terraindescr_(terraindescr) {}
2590+ LuaTerrainDescription(lua_State* L) : terraindescr_(nullptr) {
2591+ report_error(L, "Cannot instantiate a 'LuaTerrainDescription' directly!");
2592+ }
2593+
2594+ void __persist(lua_State * L) override;
2595+ void __unpersist(lua_State * L) override;
2596+
2597+ /*
2598+ * Properties
2599+ */
2600+ int get_name(lua_State *);
2601+ int get_descname(lua_State *);
2602+ int get_default_resource(lua_State *);
2603+ int get_default_resource_amount(lua_State *);
2604+ int get_editor_category(lua_State *);
2605+ int get_fertility(lua_State *);
2606+ int get_humidity(lua_State *);
2607+ int get_representative_image(lua_State *);
2608+ int get_temperature(lua_State *);
2609+ int get_valid_resources(lua_State *);
2610+
2611+ /*
2612+ * Lua methods
2613+ */
2614+
2615+ /*
2616+ * C methods
2617+ */
2618+ const Widelands::TerrainDescription* get() const {
2619+ assert(terraindescr_ != nullptr);
2620+ return terraindescr_;
2621+ }
2622+
2623+protected:
2624+
2625+ // For persistence.
2626+ void set_description_pointer(const Widelands::TerrainDescription* pointer) {
2627+ terraindescr_ = pointer;
2628+ }
2629+
2630+private:
2631+ const Widelands::TerrainDescription* terraindescr_;
2632+};
2633+
2634+
2635 #define CASTED_GET(klass) \
2636 Widelands:: klass * get(lua_State * L, Widelands::EditorGameBase & egbase) { \
2637 return static_cast<Widelands:: klass *> \
2638
2639=== modified file 'src/scripting/lua_root.cc'
2640--- src/scripting/lua_root.cc 2016-01-28 05:24:34 +0000
2641+++ src/scripting/lua_root.cc 2016-02-14 10:01:52 +0000
2642@@ -318,6 +318,8 @@
2643 {0, 0},
2644 };
2645 const PropertyType<LuaWorld> LuaWorld::Properties[] = {
2646+ PROP_RO(LuaWorld, immovable_descriptions),
2647+ PROP_RO(LuaWorld, terrain_descriptions),
2648 {0, 0, 0},
2649 };
2650
2651@@ -345,6 +347,47 @@
2652 */
2653
2654 /* RST
2655+ .. attribute:: immovable_descriptions
2656+
2657+ Returns a list of all the immovables that are available in the world.
2658+
2659+ (RO) a list of :class:`LuaImmovableDescription` objects
2660+*/
2661+int LuaWorld::get_immovable_descriptions(lua_State* L) {
2662+ const World& world = get_egbase(L).world();
2663+ lua_newtable(L);
2664+ int index = 1;
2665+ for (DescriptionIndex i = 0; i < world.get_nr_immovables(); ++i) {
2666+ lua_pushint32(L, index++);
2667+ to_lua<LuaMaps::LuaImmovableDescription>(
2668+ L, new LuaMaps::LuaImmovableDescription(world.get_immovable_descr(i)));
2669+ lua_settable(L, -3);
2670+ }
2671+ return 1;
2672+}
2673+
2674+
2675+/* RST
2676+ .. attribute:: terrain_descriptions
2677+
2678+ Returns a list of all the terrains that are available in the world.
2679+
2680+ (RO) a list of :class:`LuaTerrainDescription` objects
2681+*/
2682+int LuaWorld::get_terrain_descriptions(lua_State* L) {
2683+ const World& world = get_egbase(L).world();
2684+ lua_newtable(L);
2685+ int index = 1;
2686+ for (DescriptionIndex i = 0; i < world.terrains().size(); ++i) {
2687+ lua_pushint32(L, index++);
2688+ to_lua<LuaMaps::LuaTerrainDescription>(L, new LuaMaps::LuaTerrainDescription(&world.terrain_descr(i)));
2689+ lua_settable(L, -3);
2690+ }
2691+ return 1;
2692+}
2693+
2694+
2695+/* RST
2696 .. method:: new_resource_type(table)
2697
2698 Adds a new resource type that can be in the different maps. Takes a
2699@@ -559,7 +602,8 @@
2700
2701 try {
2702 LuaTable table(L); // Will pop the table eventually.
2703- get_egbase(L).mutable_tribes()->add_constructionsite_type(table, get_egbase(L));
2704+ EditorGameBase& egbase = get_egbase(L);
2705+ egbase.mutable_tribes()->add_constructionsite_type(table, egbase);
2706 } catch (std::exception& e) {
2707 report_error(L, "%s", e.what());
2708 }
2709@@ -581,7 +625,8 @@
2710
2711 try {
2712 LuaTable table(L); // Will pop the table eventually.
2713- get_egbase(L).mutable_tribes()->add_dismantlesite_type(table, get_egbase(L));
2714+ EditorGameBase& egbase = get_egbase(L);
2715+ egbase.mutable_tribes()->add_dismantlesite_type(table, egbase);
2716 } catch (std::exception& e) {
2717 report_error(L, "%s", e.what());
2718 }
2719@@ -604,7 +649,8 @@
2720
2721 try {
2722 LuaTable table(L); // Will pop the table eventually.
2723- get_egbase(L).mutable_tribes()->add_militarysite_type(table, get_egbase(L));
2724+ EditorGameBase& egbase = get_egbase(L);
2725+ egbase.mutable_tribes()->add_militarysite_type(table, egbase);
2726 } catch (std::exception& e) {
2727 report_error(L, "%s", e.what());
2728 }
2729@@ -626,7 +672,8 @@
2730
2731 try {
2732 LuaTable table(L); // Will pop the table eventually.
2733- get_egbase(L).mutable_tribes()->add_productionsite_type(table, get_egbase(L));
2734+ EditorGameBase& egbase = get_egbase(L);
2735+ egbase.mutable_tribes()->add_productionsite_type(table, egbase);
2736 } catch (std::exception& e) {
2737 report_error(L, "%s", e.what());
2738 }
2739@@ -648,7 +695,8 @@
2740
2741 try {
2742 LuaTable table(L); // Will pop the table eventually.
2743- get_egbase(L).mutable_tribes()->add_trainingsite_type(table, get_egbase(L));
2744+ EditorGameBase& egbase = get_egbase(L);
2745+ egbase.mutable_tribes()->add_trainingsite_type(table, egbase);
2746 } catch (std::exception& e) {
2747 report_error(L, "%s", e.what());
2748 }
2749@@ -670,7 +718,8 @@
2750
2751 try {
2752 LuaTable table(L); // Will pop the table eventually.
2753- get_egbase(L).mutable_tribes()->add_warehouse_type(table, get_egbase(L));
2754+ EditorGameBase& egbase = get_egbase(L);
2755+ egbase.mutable_tribes()->add_warehouse_type(table, egbase);
2756 } catch (std::exception& e) {
2757 report_error(L, "%s", e.what());
2758 }
2759@@ -758,7 +807,8 @@
2760
2761 try {
2762 LuaTable table(L); // Will pop the table eventually.
2763- get_egbase(L).mutable_tribes()->add_carrier_type(table, get_egbase(L));
2764+ EditorGameBase& egbase = get_egbase(L);
2765+ egbase.mutable_tribes()->add_carrier_type(table, egbase);
2766 } catch (std::exception& e) {
2767 report_error(L, "%s", e.what());
2768 }
2769@@ -780,7 +830,8 @@
2770
2771 try {
2772 LuaTable table(L); // Will pop the table eventually.
2773- get_egbase(L).mutable_tribes()->add_soldier_type(table, get_egbase(L));
2774+ EditorGameBase& egbase = get_egbase(L);
2775+ egbase.mutable_tribes()->add_soldier_type(table, egbase);
2776 } catch (std::exception& e) {
2777 report_error(L, "%s", e.what());
2778 }
2779@@ -802,7 +853,8 @@
2780
2781 try {
2782 LuaTable table(L); // Will pop the table eventually.
2783- get_egbase(L).mutable_tribes()->add_worker_type(table, get_egbase(L));
2784+ EditorGameBase& egbase = get_egbase(L);
2785+ egbase.mutable_tribes()->add_worker_type(table, egbase);
2786 } catch (std::exception& e) {
2787 report_error(L, "%s", e.what());
2788 }
2789@@ -825,7 +877,8 @@
2790
2791 try {
2792 LuaTable table(L); // Will pop the table eventually.
2793- get_egbase(L).mutable_tribes()->add_tribe(table, get_egbase(L));
2794+ EditorGameBase& egbase = get_egbase(L);
2795+ egbase.mutable_tribes()->add_tribe(table, egbase);
2796 } catch (std::exception& e) {
2797 report_error(L, "%s", e.what());
2798 }
2799
2800=== modified file 'src/scripting/lua_root.h'
2801--- src/scripting/lua_root.h 2015-09-04 11:11:50 +0000
2802+++ src/scripting/lua_root.h 2016-02-14 10:01:52 +0000
2803@@ -107,6 +107,8 @@
2804 /*
2805 * Properties
2806 */
2807+ int get_immovable_descriptions(lua_State* L);
2808+ int get_terrain_descriptions(lua_State* L);
2809
2810 /*
2811 * Lua methods
2812
2813=== modified file 'src/wui/encyclopedia_window.cc'
2814--- src/wui/encyclopedia_window.cc 2016-01-29 08:37:22 +0000
2815+++ src/wui/encyclopedia_window.cc 2016-02-14 10:01:52 +0000
2816@@ -42,20 +42,14 @@
2817 #include "scripting/lua_table.h"
2818 #include "wui/interactive_player.h"
2819
2820+namespace {
2821+
2822 #define WINDOW_WIDTH std::min(700, g_gr->get_xres() - 40)
2823 #define WINDOW_HEIGHT std::min(550, g_gr->get_yres() - 40)
2824
2825 constexpr int kPadding = 5;
2826 constexpr int kTabHeight = 35;
2827
2828-using namespace Widelands;
2829-
2830-inline InteractivePlayer& EncyclopediaWindow::iaplayer() const {
2831- return dynamic_cast<InteractivePlayer&>(*get_parent());
2832-}
2833-
2834-namespace {
2835-
2836 struct EncyclopediaTab {
2837 EncyclopediaTab(const std::string& _key,
2838 const std::string& _image_filename,
2839@@ -83,6 +77,10 @@
2840
2841 } // namespace
2842
2843+inline InteractivePlayer& EncyclopediaWindow::iaplayer() const {
2844+ return dynamic_cast<InteractivePlayer&>(*get_parent());
2845+}
2846+
2847 EncyclopediaWindow::EncyclopediaWindow(InteractivePlayer& parent, UI::UniqueWindow::Registry& registry)
2848 : UI::UniqueWindow(
2849 &parent, "encyclopedia", &registry, WINDOW_WIDTH, WINDOW_HEIGHT, _("Tribal Encyclopedia")),
2850@@ -171,58 +169,58 @@
2851 }
2852 }
2853
2854-void EncyclopediaWindow::fill_entries(const char* key, std::vector<EncyclopediaEntry>& entries) {
2855- std::sort(entries.begin(), entries.end());
2856- for (uint32_t i = 0; i < entries.size(); i++) {
2857- EncyclopediaEntry cur = entries[i];
2858+void EncyclopediaWindow::fill_entries(const char* key, std::vector<EncyclopediaEntry>* entries) {
2859+ std::sort(entries->begin(), entries->end());
2860+ for (uint32_t i = 0; i < entries->size(); i++) {
2861+ EncyclopediaEntry cur = (*entries)[i];
2862 lists_.at(key)->add(cur.descname, cur.index, cur.icon);
2863 }
2864 lists_.at(key)->select(0);
2865 }
2866
2867 void EncyclopediaWindow::fill_buildings() {
2868- const Tribes& tribes = iaplayer().egbase().tribes();
2869- const TribeDescr& tribe = iaplayer().player().tribe();
2870+ const Widelands::Tribes& tribes = iaplayer().egbase().tribes();
2871+ const Widelands::TribeDescr& tribe = iaplayer().player().tribe();
2872 std::vector<EncyclopediaEntry> entries;
2873
2874 for (Widelands::DescriptionIndex i = 0; i < tribes.nrbuildings(); ++i) {
2875- const BuildingDescr* building = tribes.get_building_descr(i);
2876- if (tribe.has_building(i) || building->type() == MapObjectType::MILITARYSITE) {
2877+ const Widelands::BuildingDescr* building = tribes.get_building_descr(i);
2878+ if (tribe.has_building(i) || building->type() == Widelands::MapObjectType::MILITARYSITE) {
2879 EncyclopediaEntry entry(i, building->descname(), building->icon());
2880 entries.push_back(entry);
2881 }
2882 }
2883- fill_entries("buildings", entries);
2884+ fill_entries("buildings", &entries);
2885 }
2886
2887 void EncyclopediaWindow::fill_wares() {
2888- const TribeDescr& tribe = iaplayer().player().tribe();
2889+ const Widelands::TribeDescr& tribe = iaplayer().player().tribe();
2890 std::vector<EncyclopediaEntry> entries;
2891
2892 for (const Widelands::DescriptionIndex& i : tribe.wares()) {
2893- const WareDescr* ware = tribe.get_ware_descr(i);
2894+ const Widelands::WareDescr* ware = tribe.get_ware_descr(i);
2895 EncyclopediaEntry entry(i, ware->descname(), ware->icon());
2896 entries.push_back(entry);
2897 }
2898- fill_entries("wares", entries);
2899+ fill_entries("wares", &entries);
2900 }
2901
2902 void EncyclopediaWindow::fill_workers() {
2903- const TribeDescr& tribe = iaplayer().player().tribe();
2904+ const Widelands::TribeDescr& tribe = iaplayer().player().tribe();
2905 std::vector<EncyclopediaEntry> entries;
2906
2907 for (const Widelands::DescriptionIndex& i : tribe.workers()) {
2908- const WorkerDescr* worker = tribe.get_worker_descr(i);
2909+ const Widelands::WorkerDescr* worker = tribe.get_worker_descr(i);
2910 EncyclopediaEntry entry(i, worker->descname(), worker->icon());
2911 entries.push_back(entry);
2912 }
2913- fill_entries("workers", entries);
2914+ fill_entries("workers", &entries);
2915 }
2916
2917 void EncyclopediaWindow::entry_selected(const std::string& key,
2918 const std::string& script_path,
2919 const Widelands::MapObjectType& type) {
2920- const TribeDescr& tribe = iaplayer().player().tribe();
2921+ const Widelands::TribeDescr& tribe = iaplayer().player().tribe();
2922 try {
2923 std::unique_ptr<LuaTable> table(iaplayer().egbase().lua().run_script(script_path));
2924 std::unique_ptr<LuaCoroutine> cr(table->get_coroutine("func"));
2925
2926=== modified file 'src/wui/encyclopedia_window.h'
2927--- src/wui/encyclopedia_window.h 2016-01-17 09:54:31 +0000
2928+++ src/wui/encyclopedia_window.h 2016-02-14 10:01:52 +0000
2929@@ -59,7 +59,7 @@
2930 InteractivePlayer& iaplayer() const;
2931
2932 // Fill table of contents
2933- void fill_entries(const char* key, std::vector<EncyclopediaEntry>& entries);
2934+ void fill_entries(const char* key, std::vector<EncyclopediaEntry>* entries);
2935 void fill_buildings();
2936 void fill_wares();
2937 void fill_workers();
2938
2939=== modified file 'src/wui/game_main_menu_save_game.cc'
2940--- src/wui/game_main_menu_save_game.cc 2016-01-31 10:57:58 +0000
2941+++ src/wui/game_main_menu_save_game.cc 2016-02-14 10:01:52 +0000
2942@@ -33,9 +33,7 @@
2943 #include "logic/playersmanager.h"
2944 #include "wui/interactive_gamebase.h"
2945
2946-InteractiveGameBase & GameMainMenuSaveGame::igbase() {
2947- return dynamic_cast<InteractiveGameBase&>(*get_parent());
2948-}
2949+namespace {
2950
2951 #define WINDOW_WIDTH 440
2952 #define WINDOW_HEIGHT 440
2953@@ -52,6 +50,12 @@
2954 #define DELETE_Y (CANCEL_Y - BUTTON_HEIGHT - VSPACING)
2955 #define OK_Y (DELETE_Y - BUTTON_HEIGHT - VSPACING)
2956
2957+} // namespace
2958+
2959+InteractiveGameBase & GameMainMenuSaveGame::igbase() {
2960+ return dynamic_cast<InteractiveGameBase&>(*get_parent());
2961+}
2962+
2963 GameMainMenuSaveGame::GameMainMenuSaveGame
2964 (InteractiveGameBase & parent, UI::UniqueWindow::Registry & registry)
2965 :
2966
2967=== modified file 'test/maps/lua_persistence.wmf/scripting/test_persistence.lua'
2968--- test/maps/lua_persistence.wmf/scripting/test_persistence.lua 2016-01-28 05:24:34 +0000
2969+++ test/maps/lua_persistence.wmf/scripting/test_persistence.lua 2016-02-14 10:01:52 +0000
2970@@ -33,6 +33,9 @@
2971 building_descr = game:get_building_description("barbarians_lumberjacks_hut")
2972 ware_descr = game:get_ware_description("ax")
2973 worker_descr = game:get_worker_description("barbarians_lumberjack")
2974+ immovable_descr = game:get_immovable_description("alder_summer_sapling")
2975+ resource_descr = game:get_resource_description("coal")
2976+ terrain_descr = game:get_terrain_description("wiese1")
2977
2978 corout = coroutine.create(function()
2979 local a = 100
2980@@ -101,6 +104,9 @@
2981 assert_equal("barbarians_lumberjacks_hut", building_descr.name)
2982 assert_equal("ax", ware_descr.name)
2983 assert_equal("barbarians_lumberjack", worker_descr.name)
2984+ assert_equal("alder_summer_sapling", immovable_descr.name)
2985+ assert_equal("coal", resource_descr.name)
2986+ assert_equal("wiese1", terrain_descr.name)
2987
2988 assert_equal(global_value_1, false)
2989 assert_thread(corout)
2990
2991=== modified file 'test/maps/lua_testsuite.wmf/scripting/immovables_descriptions.lua'
2992--- test/maps/lua_testsuite.wmf/scripting/immovables_descriptions.lua 2016-01-28 05:24:34 +0000
2993+++ test/maps/lua_testsuite.wmf/scripting/immovables_descriptions.lua 2016-02-14 10:01:52 +0000
2994@@ -13,12 +13,136 @@
2995 end)
2996 end
2997
2998+
2999+-- =======================================================
3000+-- ***************** ImmovableDescription *****************
3001+-- =======================================================
3002+
3003+function test_descr:test_immovable_descr()
3004+ assert_error("Unknown immovable", function() egbase:get_immovable_description("XXX") end)
3005+ assert_error("Wrong number of parameters: 2", function()
3006+ egbase:get_immovable_description("XXX", "YYY")
3007+ end)
3008+ assert_error("Wrong number of parameters: 3", function()
3009+ egbase:get_immovable_description("XXX","YYY","ZZZ")
3010+ end)
3011+end
3012+
3013+function test_descr:test_immovable_species()
3014+ assert_equal("", egbase:get_immovable_description("bush1").species)
3015+ assert_equal("", egbase:get_immovable_description("cornfield_ripe").species)
3016+ assert_equal("", egbase:get_immovable_description("alder_summer_sapling").species)
3017+ assert_equal("Alder", egbase:get_immovable_description("alder_summer_old").species)
3018+end
3019+
3020+function test_descr:test_immovable_build_cost()
3021+ local build_cost = egbase:get_immovable_description(
3022+ "atlanteans_shipconstruction").build_cost
3023+ assert_equal(10, build_cost["planks"])
3024+ assert_equal(2, build_cost["log"])
3025+ assert_equal(4, build_cost["spidercloth"])
3026+ assert_equal(nil, build_cost["wine"])
3027+
3028+ local total_cost = function(t)
3029+ local cost = 0
3030+ for name, count in pairs(t) do
3031+ cost = cost + count
3032+ end
3033+ return cost
3034+ end
3035+ assert_equal(16, total_cost(build_cost))
3036+end
3037+
3038+function test_descr:test_immovable_editor_category()
3039+ assert_equal("plants", egbase:get_immovable_description("bush1").editor_category.name)
3040+ assert_equal("Plants", egbase:get_immovable_description("bush1").editor_category.descname)
3041+ assert_equal(nil, egbase:get_immovable_description("cornfield_ripe").editor_category)
3042+ assert_equal("trees_deciduous", egbase:get_immovable_description(
3043+ "alder_summer_sapling").editor_category.name)
3044+ assert_equal("Deciduous Trees", egbase:get_immovable_description(
3045+ "alder_summer_sapling").editor_category.descname)
3046+ assert_equal("trees_deciduous", egbase:get_immovable_description(
3047+ "alder_summer_old").editor_category.name)
3048+end
3049+
3050+function test_descr:test_immovable_terrain_affinity()
3051+ assert_equal(nil, egbase:get_immovable_description("bush1").terrain_affinity)
3052+ assert_equal(nil, egbase:get_immovable_description("cornfield_ripe").terrain_affinity)
3053+
3054+ local aff_alder_sapling = egbase:get_immovable_description("alder_summer_sapling").terrain_affinity
3055+ local aff_alder_old = egbase:get_immovable_description("alder_summer_old").terrain_affinity
3056+ local aff_mushroom_red_pole = egbase:get_immovable_description("mushroom_red_wasteland_pole").terrain_affinity
3057+ local aff_umbrella_green_mature = egbase:get_immovable_description("umbrella_green_wasteland_mature").terrain_affinity
3058+
3059+ -- Pickiness
3060+ assert_near(0.6, aff_alder_sapling["pickiness"], 0.01)
3061+ assert_equal(aff_alder_sapling["pickiness"], aff_alder_old["pickiness"])
3062+ assert_near(0.6, aff_mushroom_red_pole["pickiness"], 0.01)
3063+ assert_near(0.8, aff_umbrella_green_mature["pickiness"], 0.01)
3064+
3065+ -- preferred_fertility
3066+ assert_near(0.6, aff_alder_sapling["preferred_fertility"], 0.01)
3067+ assert_equal(aff_alder_sapling["preferred_fertility"], aff_alder_old["preferred_fertility"])
3068+ assert_near(0.85, aff_mushroom_red_pole["preferred_fertility"], 0.01)
3069+ assert_near(0.85, aff_umbrella_green_mature["preferred_fertility"], 0.01)
3070+
3071+ -- preferred_humidity
3072+ assert_near(0.65, aff_alder_sapling["preferred_humidity"], 0.01)
3073+ assert_equal(aff_alder_sapling["preferred_humidity"], aff_alder_old["preferred_humidity"])
3074+ assert_near(0.35, aff_mushroom_red_pole["preferred_humidity"], 0.01)
3075+ assert_near(0.2, aff_umbrella_green_mature["preferred_humidity"], 0.01)
3076+
3077+ -- preferred_temperature
3078+ assert_equal(125, aff_alder_sapling["preferred_temperature"])
3079+ assert_equal(aff_alder_sapling["preferred_temperature"], aff_alder_old["preferred_temperature"])
3080+ assert_equal(80, aff_mushroom_red_pole["preferred_temperature"])
3081+ assert_equal(110, aff_umbrella_green_mature["preferred_temperature"])
3082+end
3083+
3084+function test_descr:test_immovable_owner_type()
3085+ assert_equal("world", egbase:get_immovable_description("bush1").owner_type)
3086+ assert_equal("tribe", egbase:get_immovable_description("cornfield_ripe").owner_type)
3087+ assert_equal("world", egbase:get_immovable_description("alder_summer_sapling").owner_type)
3088+ assert_equal("world", egbase:get_immovable_description("alder_summer_old").owner_type)
3089+end
3090+
3091+function test_descr:test_immovable_size()
3092+ assert_equal(0, egbase:get_immovable_description("bush1").size)
3093+ assert_equal(1, egbase:get_immovable_description("cornfield_ripe").size)
3094+ assert_equal(1, egbase:get_immovable_description("alder_summer_sapling").size)
3095+ assert_equal(1, egbase:get_immovable_description("alder_summer_old").size)
3096+end
3097+
3098+function test_descr:test_immovable_has_attribute()
3099+ assert_equal(false, egbase:get_immovable_description("bush1"):has_attribute("tree"))
3100+ assert_equal(false, egbase:get_immovable_description("alder_summer_sapling"):has_attribute("tree"))
3101+ assert_equal(true, egbase:get_immovable_description("alder_summer_old"):has_attribute("tree"))
3102+end
3103+
3104+function test_descr:test_immovable_probability_to_grow()
3105+ local terrain = egbase:get_terrain_description("wiese1")
3106+ assert_equal(nil, egbase:get_immovable_description("bush1"):probability_to_grow(terrain))
3107+
3108+ local alder = egbase:get_immovable_description("alder_summer_sapling")
3109+ assert_near(0.51, alder:probability_to_grow(terrain), 0.01)
3110+
3111+ terrain = egbase:get_terrain_description("wasteland_beach")
3112+ assert_near(0.0022, alder:probability_to_grow(terrain), 0.0001)
3113+
3114+ terrain = egbase:get_terrain_description("desert_forested_mountain2")
3115+ assert_near(0.66, alder:probability_to_grow(terrain), 0.01)
3116+
3117+ terrain = egbase:get_terrain_description("winter_water")
3118+ assert_near(0.000037, alder:probability_to_grow(terrain), 0.000001)
3119+end
3120+
3121+
3122 -- =======================================================
3123 -- ***************** BuildingDescription *****************
3124 -- =======================================================
3125
3126 function test_descr:test_building_descr()
3127- assert_error("Wrong building", function() egbase:get_building_description("XXX") end)
3128+ assert_error("Unknown building", function() egbase:get_building_description("XXX") end)
3129 assert_error("Wrong number of parameters: 2", function() egbase:get_building_description("XXX", "YYY") end)
3130 assert_error("Wrong number of parameters: 3", function() egbase:get_building_description("XXX","YYY","ZZZ") end)
3131 end
3132@@ -26,10 +150,10 @@
3133
3134 -- This is actually a property of MapOjectDescription
3135 function test_descr:test_descname()
3136- assert_equal(_"Lumberjack’s Hut", egbase:get_building_description("barbarians_lumberjacks_hut").descname)
3137- assert_equal(_"Battle Arena", egbase:get_building_description("barbarians_battlearena").descname)
3138- assert_equal(_"Fortress", egbase:get_building_description("barbarians_fortress").descname)
3139- assert_equal(_"Coal Mine", egbase:get_building_description("barbarians_coalmine").descname)
3140+ assert_equal("Lumberjack’s Hut", egbase:get_building_description("barbarians_lumberjacks_hut").descname)
3141+ assert_equal("Battle Arena", egbase:get_building_description("barbarians_battlearena").descname)
3142+ assert_equal("Fortress", egbase:get_building_description("barbarians_fortress").descname)
3143+ assert_equal("Coal Mine", egbase:get_building_description("barbarians_coalmine").descname)
3144 end
3145
3146 -- This is actually a property of MapOjectDescription
3147@@ -157,7 +281,7 @@
3148
3149 -- This is actually a property of MapOjectDescription
3150 function test_descr:test_descname()
3151- assert_equal(_"Coal Mine", egbase:get_building_description("barbarians_coalmine").descname)
3152+ assert_equal("Coal Mine", egbase:get_building_description("barbarians_coalmine").descname)
3153 end
3154
3155 -- This is actually a property of MapOjectDescription
3156@@ -208,7 +332,7 @@
3157
3158 -- This is actually a property of MapOjectDescription
3159 function test_descr:test_descname()
3160- assert_equal(_"Sentry", egbase:get_building_description("barbarians_sentry").descname)
3161+ assert_equal("Sentry", egbase:get_building_description("barbarians_sentry").descname)
3162 end
3163
3164 -- This is actually a property of MapOjectDescription
3165@@ -237,7 +361,7 @@
3166
3167 -- This is actually a property of MapOjectDescription
3168 function test_descr:test_descname()
3169- assert_equal(_"Battle Arena", egbase:get_building_description("barbarians_battlearena").descname)
3170+ assert_equal("Battle Arena", egbase:get_building_description("barbarians_battlearena").descname)
3171 end
3172
3173 -- This is actually a property of MapOjectDescription
3174@@ -298,7 +422,7 @@
3175
3176 -- This is actually a property of MapOjectDescription
3177 function test_descr:test_descname()
3178- assert_equal(_"Warehouse", egbase:get_building_description("barbarians_warehouse").descname)
3179+ assert_equal("Warehouse", egbase:get_building_description("barbarians_warehouse").descname)
3180 end
3181
3182 -- This is actually a property of MapOjectDescription
3183@@ -321,13 +445,13 @@
3184 -- =======================================================
3185
3186 function test_descr:test_ware_descr()
3187- assert_error("Wrong ware", function() egbase:get_ware_description("XXX") end)
3188+ assert_error("Unknown ware", function() egbase:get_ware_description("XXX") end)
3189 assert_error("Wrong number of parameters: 2", function() egbase:get_ware_description("XXX","YYY") end)
3190 end
3191
3192 -- This is actually a property of MapOjectDescription
3193 function test_descr:test_descname()
3194- assert_equal(_"Thatch Reed", egbase:get_ware_description("thatch_reed").descname)
3195+ assert_equal("Thatch Reed", egbase:get_ware_description("thatch_reed").descname)
3196 end
3197
3198 -- This is actually a property of MapOjectDescription
3199@@ -395,13 +519,13 @@
3200 -- =======================================================
3201
3202 function test_descr:test_worker_descr()
3203- assert_error("Wrong worker", function() egbase:get_worker_description("XXX") end)
3204+ assert_error("Unknown worker", function() egbase:get_worker_description("XXX") end)
3205 assert_error("Wrong number of parameters: 2", function() egbase:get_worker_description("XXX","YYY") end)
3206 end
3207
3208 -- This is actually a property of MapOjectDescription
3209 function test_descr:test_descname()
3210- assert_equal(_"Miner", egbase:get_worker_description("barbarians_miner").descname)
3211+ assert_equal("Miner", egbase:get_worker_description("barbarians_miner").descname)
3212 end
3213
3214 -- This is actually a property of MapOjectDescription
3215
3216=== modified file 'test/maps/lua_testsuite.wmf/scripting/init.lua'
3217--- test/maps/lua_testsuite.wmf/scripting/init.lua 2015-10-31 12:11:44 +0000
3218+++ test/maps/lua_testsuite.wmf/scripting/init.lua 2016-02-14 10:01:52 +0000
3219@@ -33,6 +33,7 @@
3220
3221 include "map:scripting/immovables.lua"
3222 include "map:scripting/immovables_descriptions.lua"
3223+include "map:scripting/terrains_resources_descriptions.lua"
3224 include "map:scripting/tribes_descriptions.lua"
3225
3226 if not wl.editor then
3227
3228=== added file 'test/maps/lua_testsuite.wmf/scripting/terrains_resources_descriptions.lua'
3229--- test/maps/lua_testsuite.wmf/scripting/terrains_resources_descriptions.lua 1970-01-01 00:00:00 +0000
3230+++ test/maps/lua_testsuite.wmf/scripting/terrains_resources_descriptions.lua 2016-02-14 10:01:52 +0000
3231@@ -0,0 +1,180 @@
3232+set_textdomain("tribes")
3233+
3234+test_terrains_resource_descr = lunit.TestCase("Terrains and resources descriptions test")
3235+
3236+-- =======================================================
3237+-- ***************** ResourceDescription *****************
3238+-- =======================================================
3239+
3240+function test_terrains_resource_descr:test_resource_descr()
3241+ assert_error("Wrong terrain", function() egbase:get_resource_description("XXX") end)
3242+ assert_error("Wrong number of parameters: 2", function()
3243+ egbase:get_resource_description("XXX", "YYY")
3244+ end)
3245+ assert_error("Wrong number of parameters: 3", function()
3246+ egbase:get_resource_description("XXX","YYY","ZZZ")
3247+ end)
3248+end
3249+
3250+function test_terrains_resource_descr:test_resource_descname()
3251+ assert_equal("Coal", egbase:get_resource_description("coal").descname)
3252+ assert_equal("Stones", egbase:get_resource_description("stones").descname)
3253+ assert_equal("Water", egbase:get_resource_description("water").descname)
3254+ assert_equal("Fish", egbase:get_resource_description("fish").descname)
3255+end
3256+
3257+function test_terrains_resource_descr:test_resource_name()
3258+ assert_equal("coal", egbase:get_resource_description("coal").name)
3259+ assert_equal("stones", egbase:get_resource_description("stones").name)
3260+ assert_equal("water", egbase:get_resource_description("water").name)
3261+ assert_equal("fish", egbase:get_resource_description("fish").name)
3262+end
3263+
3264+function test_terrains_resource_descr:test_resource_is_detectable()
3265+ assert_equal(true, egbase:get_resource_description("coal").is_detectable)
3266+ assert_equal(true, egbase:get_resource_description("stones").is_detectable)
3267+ assert_equal(true, egbase:get_resource_description("water").is_detectable)
3268+ assert_equal(false, egbase:get_resource_description("fish").is_detectable)
3269+end
3270+
3271+function test_terrains_resource_descr:test_resource_max_amount()
3272+ assert_equal(20, egbase:get_resource_description("coal").max_amount)
3273+ assert_equal(20, egbase:get_resource_description("stones").max_amount)
3274+ assert_equal(50, egbase:get_resource_description("water").max_amount)
3275+ assert_equal(20, egbase:get_resource_description("fish").max_amount)
3276+end
3277+
3278+function test_terrains_resource_descr:test_resource_representative_image()
3279+ assert_equal("world/resources/pics/coal4.png",
3280+ egbase:get_resource_description("coal").representative_image)
3281+ assert_equal("world/resources/pics/stones4.png",
3282+ egbase:get_resource_description("stones").representative_image)
3283+ assert_equal("world/resources/pics/water4.png",
3284+ egbase:get_resource_description("water").representative_image)
3285+ assert_equal("world/resources/pics/fish.png",
3286+ egbase:get_resource_description("fish").representative_image)
3287+end
3288+
3289+function test_terrains_resource_descr:test_resource_editor_image()
3290+ assert_equal("world/resources/pics/coal1.png",
3291+ egbase:get_resource_description("coal"):editor_image(0))
3292+ assert_equal("world/resources/pics/coal1.png",
3293+ egbase:get_resource_description("coal"):editor_image(5))
3294+ assert_equal("world/resources/pics/coal2.png",
3295+ egbase:get_resource_description("coal"):editor_image(6))
3296+ assert_equal("world/resources/pics/coal2.png",
3297+ egbase:get_resource_description("coal"):editor_image(10))
3298+ assert_equal("world/resources/pics/coal3.png",
3299+ egbase:get_resource_description("coal"):editor_image(15))
3300+ assert_equal("world/resources/pics/coal4.png",
3301+ egbase:get_resource_description("coal"):editor_image(16))
3302+ assert_equal("world/resources/pics/coal4.png",
3303+ egbase:get_resource_description("coal"):editor_image(1000))
3304+end
3305+
3306+-- =======================================================
3307+-- ***************** TerrainDescription ******************
3308+-- =======================================================
3309+
3310+function test_terrains_resource_descr:test_terrain_descr()
3311+ assert_error("Wrong terrain", function() egbase:get_terrain_description("XXX") end)
3312+ assert_error("Wrong number of parameters: 2",
3313+ function() egbase:get_terrain_description("XXX", "YYY") end)
3314+ assert_error("Wrong number of parameters: 3",
3315+ function() egbase:get_terrain_description("XXX","YYY","ZZZ") end)
3316+end
3317+
3318+function test_terrains_resource_descr:test_terrain_descname()
3319+ assert_equal("Meadow",
3320+ egbase:get_terrain_description("wiese1").descname)
3321+ assert_equal("Beach",
3322+ egbase:get_terrain_description("wasteland_beach").descname)
3323+ assert_equal("Forested Mountain",
3324+ egbase:get_terrain_description("desert_forested_mountain2").descname)
3325+ assert_equal("Water",
3326+ egbase:get_terrain_description("winter_water").descname)
3327+end
3328+
3329+function test_terrains_resource_descr:test_terrain_name()
3330+ assert_equal("wiese1", egbase:get_terrain_description("wiese1").name)
3331+ assert_equal("wasteland_beach",
3332+ egbase:get_terrain_description("wasteland_beach").name)
3333+ assert_equal("desert_forested_mountain2",
3334+ egbase:get_terrain_description("desert_forested_mountain2").name)
3335+ assert_equal("winter_water",
3336+ egbase:get_terrain_description("winter_water").name)
3337+end
3338+
3339+function test_terrains_resource_descr:test_terrain_default_resource()
3340+ assert_equal("water", egbase:get_terrain_description("wiese1").default_resource.name)
3341+ assert_equal(nil, egbase:get_terrain_description("wasteland_beach").default_resource)
3342+ assert_equal(nil,
3343+ egbase:get_terrain_description("desert_forested_mountain2").default_resource)
3344+ assert_equal("fish",
3345+ egbase:get_terrain_description("winter_water").default_resource.name)
3346+end
3347+
3348+function test_terrains_resource_descr:test_terrain_default_resource_amount()
3349+ assert_equal(10, egbase:get_terrain_description("wiese1").default_resource_amount)
3350+ assert_equal(0, egbase:get_terrain_description("wasteland_beach").default_resource_amount)
3351+ assert_equal(0, egbase:get_terrain_description(
3352+ "desert_forested_mountain2").default_resource_amount)
3353+ assert_equal(4, egbase:get_terrain_description(
3354+ "winter_water").default_resource_amount)
3355+end
3356+
3357+function test_terrains_resource_descr:test_terrain_editor_category()
3358+ assert_equal("green", egbase:get_terrain_description("wiese1").editor_category.name)
3359+ assert_equal("Summer", egbase:get_terrain_description("wiese1").editor_category.descname)
3360+ assert_equal("wasteland",
3361+ egbase:get_terrain_description("wasteland_beach").editor_category.name)
3362+ assert_equal("Wasteland",
3363+ egbase:get_terrain_description("wasteland_beach").editor_category.descname)
3364+ assert_equal("desert",
3365+ egbase:get_terrain_description("desert_forested_mountain2").editor_category.name)
3366+ assert_equal("Desert",
3367+ egbase:get_terrain_description("desert_forested_mountain2").editor_category.descname)
3368+ assert_equal("winter",
3369+ egbase:get_terrain_description("winter_water").editor_category.name)
3370+ assert_equal("Winter",
3371+ egbase:get_terrain_description("winter_water").editor_category.descname)
3372+end
3373+
3374+function test_terrains_resource_descr:test_terrain_fertility()
3375+ assert_near(0.7, egbase:get_terrain_description("wiese1").fertility, 0.01)
3376+ assert_near(0.2, egbase:get_terrain_description("wasteland_beach").fertility, 0.01)
3377+ assert_near(0.5, egbase:get_terrain_description("desert_forested_mountain2").fertility, 0.01)
3378+ assert_near(0.001, egbase:get_terrain_description("winter_water").fertility, 0.0001)
3379+end
3380+
3381+function test_terrains_resource_descr:test_terrain_humidity()
3382+ assert_near(0.6, egbase:get_terrain_description("wiese1").humidity, 0.01)
3383+ assert_near(0.4, egbase:get_terrain_description("wasteland_beach").humidity, 0.01)
3384+ assert_near(0.5, egbase:get_terrain_description("desert_forested_mountain2").humidity, 0.01)
3385+ assert_near(0.999, egbase:get_terrain_description("winter_water").humidity, 0.0001)
3386+end
3387+
3388+function test_terrains_resource_descr:test_terrain_temperature()
3389+ assert_equal(100, egbase:get_terrain_description("wiese1").temperature)
3390+ assert_equal(60, egbase:get_terrain_description("wasteland_beach").temperature)
3391+ assert_equal(120, egbase:get_terrain_description("desert_forested_mountain2").temperature)
3392+ assert_equal(50, egbase:get_terrain_description("winter_water").temperature)
3393+end
3394+
3395+function test_terrains_resource_descr:test_terrain_representative_image()
3396+ assert_equal("world/terrains/pics/green/wiese1_00.png",
3397+ egbase:get_terrain_description("wiese1").representative_image)
3398+ assert_equal("world/terrains/pics/wasteland/strand_00.png",
3399+ egbase:get_terrain_description("wasteland_beach").representative_image)
3400+ assert_equal("world/terrains/pics/desert/forested_mountain2_00.png",
3401+ egbase:get_terrain_description("desert_forested_mountain2").representative_image)
3402+ assert_equal("world/terrains/pics/winter/water_00.png",
3403+ egbase:get_terrain_description("winter_water").representative_image)
3404+end
3405+
3406+function test_terrains_resource_descr:test_valid_resources()
3407+ assert_equal("water", egbase:get_terrain_description("wiese1").valid_resources[1].name)
3408+ assert_equal(0, #egbase:get_terrain_description("wasteland_beach").valid_resources)
3409+ assert_equal(4, #egbase:get_terrain_description("desert_forested_mountain2").valid_resources)
3410+ assert_equal("fish", egbase:get_terrain_description("winter_water").valid_resources[1].name)
3411+end

Subscribers

People subscribed via source and target branches

to status/vote changes: