File: messages.lua

package info (click to toggle)
widelands 2%3A1.3-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 684,084 kB
  • sloc: cpp: 196,737; ansic: 19,395; python: 8,515; sh: 1,734; xml: 700; makefile: 46; lisp: 25
file content (350 lines) | stat: -rw-r--r-- 13,077 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
-- RST
-- messages.lua
-- ------------
--
-- Functions to send messages to the player and to add objectives to campaigns.
--
-- To make these functions available include this file at the beginning
-- of a script via:
--
-- .. code-block:: lua
--
--    include "scripting/messages.lua"
--

include "scripting/coroutine.lua"
include "scripting/richtext.lua"
include "scripting/richtext_scenarios.lua"
include "scripting/table.lua"
include "scripting/ui.lua"

-- RST
-- .. function:: send_to_inbox(player, title, body, parameters)
--
--    Sends a message to the inbox of a player.
--    If the popup parameter is true and the player is in roadbuilding mode,
--    the message is sent after the player leaves the roadbuilding mode
--    (only in singleplayer)
--
--    :arg player: the recipient of the message
--    :type player: :class:`wl.game.Player`
--    :arg title: the localized title of the message
--    :type title: :class:`string`
--    :arg body: the localized body of the message. You can use rt functions here.
--    :type body: :class:`string`
--    :arg parameters: Array of message parameters as defined in the Lua interface,
--                     for :meth:`wl.game.Player.send_to_inbox`, e.g. ``{field=f,popup=true}``.
--                     The popup parameter must be set.
--    :type parameters: :const:`table`
--

function send_to_inbox(player, title, body, parameters)
   if (parameters["popup"]) then
      wait_for_roadbuilding()
   end
   player:send_to_inbox(title, body, parameters)
end


-- RST
-- .. function:: send_to_all_inboxes(text[, heading])
--
--    Sends a message to the inbox of all players and show it instantly.
--    This is mainly used for winconditions to show the status.
--
--    :arg text: the localized body of the message. You can use
--               :ref:`richtext functions <richtext.lua>` here.
--               E.g. ``p(_("text"))``.
--    :type text: :class:`string`
--    :arg heading: the localized title of the message (optional)
--    :type heading: :class:`string`
--
function send_to_all_inboxes(text, heading)
   push_textdomain("widelands")
   for idx,plr in ipairs(wl.Game().players) do
      if (heading ~= nil and heading ~= "") then
         send_to_inbox(plr, _("Status"), text, {popup=true, heading=heading})
      else
         send_to_inbox(plr, _("Status"), text, {popup=true})
      end
   end
   pop_textdomain()
end


-- RST
-- .. function:: message_box(player, title, message, parameters)
--
--    Waits if player is in building mode, then shows a scenario message box.
--    Usually you want to use :meth:`campaign_message_box` which has more options,
--    e.g. positioning of message boxes.
--
--    :arg player: the recipient of the message
--    :type player: :class:`wl.game.Player`
--    :arg title: the localized title of the message
--    :type title: :class:`string`
--    :arg message: the localized body of the message. You must use
--                 :ref:`richtext functions <richtext.lua>` here,
--                 e.g. ``p(_("message"))``
--    :type message: :class:`string`
--    :arg parameters: Array of message parameters as defined in the Lua interface,
--                     for :meth:`wl.game.Player.message_box`, e.g. ``{field=f}``.
--    :type parameters: :const:`array`
--

function message_box(player, title, body, parameters)
   wait_for_roadbuilding()
   -- In case the user input was forbidden for some reason, allow him to close the message box.
   -- While the message box is shown, the user cannot do anything else anyway.
   local user_input = wl.ui.get_user_input_allowed()
   wl.ui.set_user_input_allowed(true)
   player:message_box(title, rt(body), parameters)
   wl.ui.set_user_input_allowed(user_input)
end

-- RST
-- .. function:: campaign_message_box({message, [opts]}, [sleeptime])
--
--    Pause a game and show a message box for player 1. Since this function can
--    have several options there is an example below this description.
--
--    :arg table message, [opts]: The message consist of the ``title``, the ``body``
--           and optional parameters. Note that the ``body`` must be formatted
--           using the :ref:`richtext functions <richtext.lua>`,
--           e.g. ``p(_("message"))``
--
--           **[opts]** can be a separated list of key value pairs defined by
--           :meth:`wl.game.Player.message_box` and the following ones:
--
--                  **position** - A string that indicates at which border of the screen the message box shall appear.
--                  Can be "top", "bottom", "right", "left" or a combination (e.g. "topright").
--                  Overrides posx and posy. Default: Center. If only one direction is indicated,
--                  the other one stays centered.
--
--                  **scroll_back** - If true, the view scrolls/jumps back to where it came from. If false, the new
--                  location stays on the screen when the message box is closed. Default: False.
--
--                  **show_instantly** - If true, the message box is shown immediately. If false, this function will
--                  wait until the player leaves the roadbuilding mode. Be aware that this can be very interruptive.
--                  Default: :type false:.
--
--                  **allow_next_scenario** - If set to ``true``, show a button that allows starting
--                                            the next scenario at once. Defaults to ``false``.
--
--    :arg int sleeptime: ms spent sleeping after the message has been dismissed by the player
--
--    Example:
-- .. code-block:: lua
--
--    local scroll_to_field = map:get_field(47, 10)
--    campaign_message_box({title = "The title",     -- title of the window
--                          body = p("The body"),    -- text inside the window
--                          w = 200,                 -- width (wl.game.Player.message_box())
--                          h = 150,                 -- height (wl.game.Player.message_box())
--                          position = "topleft",
--                          field = scroll_to_field, -- see wl.game.Player.message_box()
--                          scroll_back = true       -- only useful if 'field' was set
--                         },
--                         200                      -- optional sleeptime
--                        )
--
-- In the campaigns of this game the table of **message** is defined in
-- a separate file called `texts.lua`.
--

function campaign_message_box(message, sleeptime)
   message.show_instantly = message.show_instantly or false
   message.scroll_back = message.scroll_back or false
   message.h = message.h or styles.get_size("campaign_message_box_default_h")
   message.w = message.w or styles.get_size("campaign_message_box_default_w")

   if message.position then
      local window = wl.ui.MapView()
      if string.find(message.position,"top") then
         -- Set it a bit lower than 0 to prevent overlap with top texts
         message.posy = styles.get_size("campaign_message_box_top_pos_y")
      elseif string.find(message.position, "bottom") then
         message.posy = window.height - message.h
      else
         message.posy = math.floor((window.height - message.h) / 2)
      end
      if string.find(message.position, "left") then
         message.posx = 0
      elseif string.find(message.position, "right") then
         message.posx = window.width - message.w
      else
         message.posx = math.floor((window.width - message.w) / 2)
      end
   end

   local center_pixel

   if message.field then
      -- This is necessary. Otherwise, we would scroll and then wait until the road is finished.
      -- In this time, could user can scroll elsewhere, giving weird results.
      if not message.show_instantly then
         wait_for_roadbuilding()
      end
      center_pixel = scroll_to_field(message.field);
   end

   if message.show_instantly then
      -- message_box takes care of this, but player:message_box does not
      local user_input = wl.ui.get_user_input_allowed()
      wl.ui.set_user_input_allowed(true)
      wl.Game().players[1]:message_box(message.title, rt(message.body), message)
      wl.ui.set_user_input_allowed(user_input)
   else
      message_box(wl.Game().players[1], message.title, message.body, message)
   end

   if (message.field and message.scroll_back) then
      scroll_to_map_pixel(center_pixel);
   end

   if sleeptime then sleep(sleeptime) end
end


-- RST
-- .. function:: messagebox_h_step(steps)
--
--    Helper function to get a height for a messagebox that is changed relative to the default
--    in a way that can still follow the scaling of themes.
--
--    :arg steps: The number of steps by which to increase or decrease the height
--    :type steps: signed int

function messagebox_h_step(steps)
   local rv = styles.get_size("campaign_message_box_default_h") +
              steps * styles.get_size("campaign_message_box_size_step")
   rv = math.max(rv, styles.get_size("campaign_message_box_h_min"))
   rv = math.min(rv, styles.get_size("campaign_message_box_h_max"))
   return rv
end


-- RST
-- .. function:: messagebox_w_step(steps)
--
--    Helper function to get a width for a messagebox that is changed relative to the default
--    in a way that can still follow the scaling of themes.
--
--    :arg steps: The number of steps by which to increase or decrease the width
--    :type steps: signed int

function messagebox_w_step(steps)
   local rv = styles.get_size("campaign_message_box_default_w") +
              steps * styles.get_size("campaign_message_box_size_step")
   rv = math.max(rv, styles.get_size("campaign_message_box_w_min"))
   rv = math.min(rv, styles.get_size("campaign_message_box_w_max"))
   return rv
end


-- RST
-- .. function:: add_campaign_objective(objective)
--
--    Adds an objective to a campaign.
--
--    :arg objective: The objective to be added. If the
--                    variable :attr:`name <wl.game.Objective.name>` exists,
--                    obj_name, obj_title and obj_body are used. Otherwise, it
--                    needs to have a name, title, and body.
--    :type objective: :class:`wl.game.Objective`
--
--    :returns: The new objective.
--

function add_campaign_objective(objective)
   if objective.obj_name then
      return wl.Game().players[1]:add_objective(objective.obj_name, objective.obj_title, rt(objective.obj_body))
   else
      return wl.Game().players[1]:add_objective(objective.name, objective.title, rt(objective.body))
   end
end


-- RST
-- .. function:: new_objectives(...)
--
--    Append an objective text with a header to a dialog box in a nice fashion.
--    For displaying objectives with an extra title when an advisor is talking
--
--    Provides nice formatting for objective texts.
--    The following arguments will be parsed:
--
--       - **number**: the number of objectives described in the body
--       - **body**: the objective text, e.g. created with :func:`objective_text`
--
--    :returns: a rich text object that contains the formatted
--       objective text & title.
--

function new_objectives(...)
   local sum = 0
   local text = ""
   for idx,obj in ipairs{...} do
      text = text .. obj.body
      sum = sum + obj.number
   end

   push_textdomain("widelands")
   local objectives_header = _("New Objective")
   if (sum > 1) then
      objectives_header = _("New Objectives")
   end
   pop_textdomain()

   return
      styles.as_paragraph("wui_objectives_heading",
         img("images/wui/menus/objectives.png") ..  space() ..  objectives_header) ..
      text
end


-- RST
-- .. function:: campaign_message_with_objective(message, objective [,sleeptime])
--
--    Sets message.h and message.w if not set and calls
--    message_box(player, title, body, parameters) for player 1.
--
--    Adds an objective to the scenario afterwards.
--
--
--    :arg message: the message to be sent
--    :type message: :class:`string`
--    :arg objective: The objective to be added. If the variable obj_name exists, obj_name, obj_title and obj_body are used. Otherwise, it needs to have a name, title, and body.
--    :type objective: :class:`wl.game.Objective`
--    :arg sleeptime: ms spent sleeping after the message has been dismissed by the player
--    :type sleeptime: :class:`int`
--
--    :returns: The new objective.
--

function campaign_message_with_objective(message, objective, sleeptime)
   message.body = message.body .. new_objectives(objective)
   campaign_message_box(message, sleeptime)
   return add_campaign_objective(objective)
end


-- RST
-- .. function:: set_objective_done(objective[, sleeptime])
--
--    Sets an objectve as done and sleeps for a bit.
--
--    :arg objective: The objective to be marked as done.
--    :type objective: :class:`wl.game.Objective`
--    :arg sleeptime: The milliseconds to sleep. Defaults to 3000.
--    :type sleeptime: :class:`int`
--

function set_objective_done(objective, sleeptime)
   if not sleeptime then
      sleep(3000)
   else
      sleep(sleeptime)
   end
   objective.done = true
end