|
1 /* $Id$ */ |
|
2 |
|
3 #include "stdafx.h" |
|
4 #include "openttd.h" |
|
5 #include "debug.h" |
|
6 #include "functions.h" |
|
7 #include "strings.h" |
|
8 #include "table/sprites.h" |
|
9 #include "table/strings.h" |
|
10 #include "town.h" |
|
11 #include "window.h" |
|
12 #include "gfx.h" |
|
13 #include "viewport.h" |
|
14 #include "gui.h" |
|
15 #include "command.h" |
|
16 #include "player.h" |
|
17 #include "network/network.h" |
|
18 #include "variables.h" |
|
19 |
|
20 static const Widget _town_authority_widgets[] = { |
|
21 { WWT_CLOSEBOX, RESIZE_NONE, 13, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW}, |
|
22 { WWT_CAPTION, RESIZE_NONE, 13, 11, 316, 0, 13, STR_2022_LOCAL_AUTHORITY, STR_018C_WINDOW_TITLE_DRAG_THIS}, |
|
23 { WWT_PANEL, RESIZE_NONE, 13, 0, 316, 14, 105, 0x0, STR_NULL}, |
|
24 { WWT_PANEL, RESIZE_NONE, 13, 0, 304, 106, 157, 0x0, STR_2043_LIST_OF_THINGS_TO_DO_AT}, |
|
25 { WWT_SCROLLBAR, RESIZE_NONE, 13, 305, 316, 106, 157, 0x0, STR_0190_SCROLL_BAR_SCROLLS_LIST}, |
|
26 { WWT_PANEL, RESIZE_NONE, 13, 0, 316, 158, 209, 0x0, STR_NULL}, |
|
27 { WWT_PUSHTXTBTN, RESIZE_NONE, 13, 0, 316, 210, 221, STR_2042_DO_IT, STR_2044_CARRY_OUT_THE_HIGHLIGHTED}, |
|
28 { WIDGETS_END}, |
|
29 }; |
|
30 |
|
31 extern const byte _town_action_costs[8]; |
|
32 extern void DrawPlayerIcon(PlayerID pid, int x, int y); |
|
33 |
|
34 /** Get a list of available actions to do at a town. |
|
35 * @param *nump if not NULL add put the number of available actions in it |
|
36 * @param pid the player that is querying the town |
|
37 * @param *t the town that is queried |
|
38 * @return bitmasked value of enabled actions |
|
39 */ |
|
40 uint GetMaskOfTownActions(int *nump, PlayerID pid, const Town *t) |
|
41 { |
|
42 int32 avail, ref; |
|
43 int num = 0; |
|
44 uint avail_buttons = 0x7F; // by default all buttons except bribe are enabled. |
|
45 uint buttons = 0; |
|
46 |
|
47 if (pid != PLAYER_SPECTATOR) { |
|
48 uint i; |
|
49 |
|
50 // bribe option enabled? |
|
51 if (_patches.bribe) { |
|
52 // if unwanted, disable everything. |
|
53 if (t->unwanted[pid]) { |
|
54 avail_buttons = 0; |
|
55 } else if (t->ratings[pid] < RATING_BRIBE_MAXIMUM) { |
|
56 SETBIT(avail_buttons, 7); // Allow bribing |
|
57 } |
|
58 } |
|
59 |
|
60 // Things worth more than this are not shown |
|
61 avail = GetPlayer(pid)->player_money + _price.station_value * 200; |
|
62 ref = _price.build_industry >> 8; |
|
63 |
|
64 for (i = 0; i != lengthof(_town_action_costs); i++, avail_buttons >>= 1) { |
|
65 if (HASBIT(avail_buttons, 0) && avail >= _town_action_costs[i] * ref) { |
|
66 SETBIT(buttons, i); |
|
67 num++; |
|
68 } |
|
69 } |
|
70 |
|
71 /* Disable build statue if already built */ |
|
72 if (HASBIT(t->statues, pid)) { |
|
73 CLRBIT(buttons, 4); |
|
74 num--; |
|
75 } |
|
76 |
|
77 } |
|
78 |
|
79 if (nump != NULL) *nump = num; |
|
80 return buttons; |
|
81 } |
|
82 |
|
83 static int GetNthSetBit(uint32 bits, int n) |
|
84 { |
|
85 int i = 0; |
|
86 |
|
87 if (n >= 0) { |
|
88 do { |
|
89 if (bits & 1 && --n < 0) return i; |
|
90 i++; |
|
91 } while (bits >>= 1); |
|
92 } |
|
93 return -1; |
|
94 } |
|
95 |
|
96 static void TownAuthorityWndProc(Window *w, WindowEvent *e) |
|
97 { |
|
98 switch (e->event) { |
|
99 case WE_PAINT: { |
|
100 const Town *t = GetTown(w->window_number); |
|
101 int numact; |
|
102 uint buttons = GetMaskOfTownActions(&numact, _local_player, t); |
|
103 |
|
104 SetVScrollCount(w, numact + 1); |
|
105 |
|
106 if (WP(w,def_d).data_1 != -1 && !HASBIT(buttons, WP(w,def_d).data_1)) |
|
107 WP(w,def_d).data_1 = -1; |
|
108 |
|
109 SetWindowWidgetDisabledState(w, 6, WP(w, def_d).data_1 == -1); |
|
110 |
|
111 { |
|
112 int y; |
|
113 const Player *p; |
|
114 int r; |
|
115 StringID str; |
|
116 |
|
117 SetDParam(0, w->window_number); |
|
118 DrawWindowWidgets(w); |
|
119 |
|
120 DrawString(2, 15, STR_2023_TRANSPORT_COMPANY_RATINGS, 0); |
|
121 |
|
122 // Draw list of players |
|
123 y = 25; |
|
124 FOR_ALL_PLAYERS(p) { |
|
125 if (p->is_active && (HASBIT(t->have_ratings, p->index) || t->exclusivity == p->index)) { |
|
126 DrawPlayerIcon(p->index, 2, y); |
|
127 |
|
128 SetDParam(0, p->name_1); |
|
129 SetDParam(1, p->name_2); |
|
130 SetDParam(2, GetPlayerNameString(p->index, 3)); |
|
131 |
|
132 r = t->ratings[p->index]; |
|
133 (str = STR_3035_APPALLING, r <= RATING_APPALLING) || // Apalling |
|
134 (str++, r <= RATING_VERYPOOR) || // Very Poor |
|
135 (str++, r <= RATING_POOR) || // Poor |
|
136 (str++, r <= RATING_MEDIOCRE) || // Mediocore |
|
137 (str++, r <= RATING_GOOD) || // Good |
|
138 (str++, r <= RATING_VERYGOOD) || // Very Good |
|
139 (str++, r <= RATING_EXCELLENT) || // Excellent |
|
140 (str++, true); // Outstanding |
|
141 |
|
142 SetDParam(4, str); |
|
143 if (t->exclusivity == p->index) // red icon for player with exclusive rights |
|
144 DrawSprite(SPR_BLOT | PALETTE_TO_RED, 18, y); |
|
145 |
|
146 DrawString(28, y, STR_2024, 0); |
|
147 y += 10; |
|
148 } |
|
149 } |
|
150 } |
|
151 |
|
152 // Draw actions list |
|
153 { |
|
154 int y = 107, i; |
|
155 int pos = w->vscroll.pos; |
|
156 |
|
157 if (--pos < 0) { |
|
158 DrawString(2, y, STR_2045_ACTIONS_AVAILABLE, 0); |
|
159 y += 10; |
|
160 } |
|
161 for (i = 0; buttons; i++, buttons >>= 1) { |
|
162 if (pos <= -5) break; |
|
163 |
|
164 if (buttons&1 && --pos < 0) { |
|
165 DrawString(3, y, STR_2046_SMALL_ADVERTISING_CAMPAIGN + i, 6); |
|
166 y += 10; |
|
167 } |
|
168 } |
|
169 } |
|
170 |
|
171 { |
|
172 int i = WP(w,def_d).data_1; |
|
173 |
|
174 if (i != -1) { |
|
175 SetDParam(1, (_price.build_industry >> 8) * _town_action_costs[i]); |
|
176 SetDParam(0, STR_2046_SMALL_ADVERTISING_CAMPAIGN + i); |
|
177 DrawStringMultiLine(2, 159, STR_204D_INITIATE_A_SMALL_LOCAL + i, 313); |
|
178 } |
|
179 } |
|
180 |
|
181 } break; |
|
182 |
|
183 case WE_CLICK: |
|
184 switch (e->we.click.widget) { |
|
185 case 3: { /* listbox */ |
|
186 const Town *t = GetTown(w->window_number); |
|
187 int y = (e->we.click.pt.y - 0x6B) / 10; |
|
188 |
|
189 if (!IS_INT_INSIDE(y, 0, 5)) return; |
|
190 |
|
191 y = GetNthSetBit(GetMaskOfTownActions(NULL, _local_player, t), y + w->vscroll.pos - 1); |
|
192 if (y >= 0) { |
|
193 WP(w,def_d).data_1 = y; |
|
194 SetWindowDirty(w); |
|
195 } |
|
196 break; |
|
197 } |
|
198 |
|
199 case 6: { /* carry out the action */ |
|
200 DoCommandP(GetTown(w->window_number)->xy, w->window_number, WP(w,def_d).data_1, NULL, CMD_DO_TOWN_ACTION | CMD_MSG(STR_00B4_CAN_T_DO_THIS)); |
|
201 break; |
|
202 } |
|
203 } |
|
204 break; |
|
205 |
|
206 case WE_4: |
|
207 SetWindowDirty(w); |
|
208 break; |
|
209 } |
|
210 } |
|
211 |
|
212 static const WindowDesc _town_authority_desc = { |
|
213 WDP_AUTO, WDP_AUTO, 317, 222, |
|
214 WC_TOWN_AUTHORITY,0, |
|
215 WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS, |
|
216 _town_authority_widgets, |
|
217 TownAuthorityWndProc |
|
218 }; |
|
219 |
|
220 static void ShowTownAuthorityWindow(uint town) |
|
221 { |
|
222 Window *w = AllocateWindowDescFront(&_town_authority_desc, town); |
|
223 |
|
224 if (w != NULL) { |
|
225 w->vscroll.cap = 5; |
|
226 WP(w,def_d).data_1 = -1; |
|
227 } |
|
228 } |
|
229 |
|
230 static void TownViewWndProc(Window *w, WindowEvent *e) |
|
231 { |
|
232 Town *t = GetTown(w->window_number); |
|
233 |
|
234 switch (e->event) { |
|
235 case WE_PAINT: |
|
236 // disable renaming town in network games if you are not the server |
|
237 SetWindowWidgetDisabledState(w, 8, _networking && !_network_server); |
|
238 |
|
239 SetDParam(0, t->index); |
|
240 DrawWindowWidgets(w); |
|
241 |
|
242 SetDParam(0, t->population); |
|
243 SetDParam(1, t->num_houses); |
|
244 DrawString(2, 107, STR_2006_POPULATION, 0); |
|
245 |
|
246 SetDParam(0, t->act_pass); |
|
247 SetDParam(1, t->max_pass); |
|
248 DrawString(2, 117, STR_200D_PASSENGERS_LAST_MONTH_MAX, 0); |
|
249 |
|
250 SetDParam(0, t->act_mail); |
|
251 SetDParam(1, t->max_mail); |
|
252 DrawString(2, 127, STR_200E_MAIL_LAST_MONTH_MAX, 0); |
|
253 |
|
254 DrawWindowViewport(w); |
|
255 break; |
|
256 |
|
257 case WE_CLICK: |
|
258 switch (e->we.click.widget) { |
|
259 case 6: /* scroll to location */ |
|
260 ScrollMainWindowToTile(t->xy); |
|
261 break; |
|
262 |
|
263 case 7: /* town authority */ |
|
264 ShowTownAuthorityWindow(w->window_number); |
|
265 break; |
|
266 |
|
267 case 8: /* rename */ |
|
268 SetDParam(0, w->window_number); |
|
269 ShowQueryString(STR_TOWN, STR_2007_RENAME_TOWN, 31, 130, w, CS_ALPHANUMERAL); |
|
270 break; |
|
271 |
|
272 case 9: /* expand town */ |
|
273 ExpandTown(t); |
|
274 break; |
|
275 |
|
276 case 10: /* delete town */ |
|
277 DeleteTown(t); |
|
278 break; |
|
279 } |
|
280 break; |
|
281 |
|
282 case WE_ON_EDIT_TEXT: |
|
283 if (e->we.edittext.str[0] != '\0') { |
|
284 _cmd_text = e->we.edittext.str; |
|
285 DoCommandP(0, w->window_number, 0, NULL, |
|
286 CMD_RENAME_TOWN | CMD_MSG(STR_2008_CAN_T_RENAME_TOWN)); |
|
287 } |
|
288 break; |
|
289 } |
|
290 } |
|
291 |
|
292 |
|
293 static const Widget _town_view_widgets[] = { |
|
294 { WWT_CLOSEBOX, RESIZE_NONE, 13, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW}, |
|
295 { WWT_CAPTION, RESIZE_NONE, 13, 11, 247, 0, 13, STR_2005, STR_018C_WINDOW_TITLE_DRAG_THIS}, |
|
296 { WWT_STICKYBOX, RESIZE_NONE, 13, 248, 259, 0, 13, 0x0, STR_STICKY_BUTTON}, |
|
297 { WWT_PANEL, RESIZE_NONE, 13, 0, 259, 14, 105, 0x0, STR_NULL}, |
|
298 { WWT_INSET, RESIZE_NONE, 13, 2, 257, 16, 103, 0x0, STR_NULL}, |
|
299 { WWT_PANEL, RESIZE_NONE, 13, 0, 259, 106, 137, 0x0, STR_NULL}, |
|
300 { WWT_PUSHTXTBTN, RESIZE_NONE, 13, 0, 85, 138, 149, STR_00E4_LOCATION, STR_200B_CENTER_THE_MAIN_VIEW_ON}, |
|
301 { WWT_PUSHTXTBTN, RESIZE_NONE, 13, 86, 171, 138, 149, STR_2020_LOCAL_AUTHORITY, STR_2021_SHOW_INFORMATION_ON_LOCAL}, |
|
302 { WWT_PUSHTXTBTN, RESIZE_NONE, 13, 172, 259, 138, 149, STR_0130_RENAME, STR_200C_CHANGE_TOWN_NAME}, |
|
303 { WIDGETS_END}, |
|
304 }; |
|
305 |
|
306 static const WindowDesc _town_view_desc = { |
|
307 WDP_AUTO, WDP_AUTO, 260, 150, |
|
308 WC_TOWN_VIEW,0, |
|
309 WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON, |
|
310 _town_view_widgets, |
|
311 TownViewWndProc |
|
312 }; |
|
313 |
|
314 static const Widget _town_view_scen_widgets[] = { |
|
315 { WWT_CLOSEBOX, RESIZE_NONE, 13, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW}, |
|
316 { WWT_CAPTION, RESIZE_NONE, 13, 11, 172, 0, 13, STR_2005, STR_018C_WINDOW_TITLE_DRAG_THIS}, |
|
317 { WWT_STICKYBOX, RESIZE_NONE, 13, 248, 259, 0, 13, 0x0, STR_STICKY_BUTTON}, |
|
318 { WWT_PANEL, RESIZE_NONE, 13, 0, 259, 14, 105, 0x0, STR_NULL}, |
|
319 { WWT_INSET, RESIZE_NONE, 13, 2, 257, 16, 103, 0x0, STR_NULL}, |
|
320 { WWT_PANEL, RESIZE_NONE, 13, 0, 259, 106, 137, 0x0, STR_NULL}, |
|
321 { WWT_PUSHTXTBTN, RESIZE_NONE, 13, 0, 85, 138, 149, STR_00E4_LOCATION, STR_200B_CENTER_THE_MAIN_VIEW_ON}, |
|
322 { WWT_EMPTY, RESIZE_NONE, 0, 0, 0, 0, 0, 0x0, STR_NULL}, |
|
323 { WWT_PUSHTXTBTN, RESIZE_NONE, 13, 173, 247, 0, 13, STR_0130_RENAME, STR_200C_CHANGE_TOWN_NAME}, |
|
324 { WWT_PUSHTXTBTN, RESIZE_NONE, 13, 86, 171, 138, 149, STR_023C_EXPAND, STR_023B_INCREASE_SIZE_OF_TOWN}, |
|
325 { WWT_PUSHTXTBTN, RESIZE_NONE, 13, 172, 259, 138, 149, STR_0290_DELETE, STR_0291_DELETE_THIS_TOWN_COMPLETELY}, |
|
326 { WIDGETS_END}, |
|
327 }; |
|
328 |
|
329 static const WindowDesc _town_view_scen_desc = { |
|
330 WDP_AUTO, WDP_AUTO, 260, 150, |
|
331 WC_TOWN_VIEW,0, |
|
332 WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON, |
|
333 _town_view_scen_widgets, |
|
334 TownViewWndProc |
|
335 }; |
|
336 |
|
337 void ShowTownViewWindow(TownID town) |
|
338 { |
|
339 Window *w; |
|
340 |
|
341 if (_game_mode != GM_EDITOR) { |
|
342 w = AllocateWindowDescFront(&_town_view_desc, town); |
|
343 } else { |
|
344 w = AllocateWindowDescFront(&_town_view_scen_desc, town); |
|
345 } |
|
346 |
|
347 if (w != NULL) { |
|
348 w->flags4 |= WF_DISABLE_VP_SCROLL; |
|
349 AssignWindowViewport(w, 3, 17, 0xFE, 0x56, GetTown(town)->xy, 1); |
|
350 } |
|
351 } |
|
352 |
|
353 static const Widget _town_directory_widgets[] = { |
|
354 { WWT_CLOSEBOX, RESIZE_NONE, 13, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW}, |
|
355 { WWT_CAPTION, RESIZE_NONE, 13, 11, 195, 0, 13, STR_2000_TOWNS, STR_018C_WINDOW_TITLE_DRAG_THIS}, |
|
356 { WWT_STICKYBOX, RESIZE_NONE, 13, 196, 207, 0, 13, 0x0, STR_STICKY_BUTTON}, |
|
357 { WWT_PUSHTXTBTN, RESIZE_NONE, 13, 0, 98, 14, 25, STR_SORT_BY_NAME, STR_SORT_ORDER_TIP}, |
|
358 { WWT_PUSHTXTBTN, RESIZE_NONE, 13, 99, 195, 14, 25, STR_SORT_BY_POPULATION, STR_SORT_ORDER_TIP}, |
|
359 { WWT_PANEL, RESIZE_BOTTOM, 13, 0, 195, 26, 189, 0x0, STR_200A_TOWN_NAMES_CLICK_ON_NAME}, |
|
360 { WWT_SCROLLBAR, RESIZE_BOTTOM, 13, 196, 207, 14, 189, 0x0, STR_0190_SCROLL_BAR_SCROLLS_LIST}, |
|
361 { WWT_PANEL, RESIZE_TB, 13, 0, 195, 190, 201, 0x0, STR_NULL}, |
|
362 { WWT_RESIZEBOX, RESIZE_TB, 13, 196, 207, 190, 201, 0x0, STR_RESIZE_BUTTON}, |
|
363 { WIDGETS_END}, |
|
364 }; |
|
365 |
|
366 |
|
367 // used to get a sorted list of the towns |
|
368 static uint _num_town_sort; |
|
369 |
|
370 static char _bufcache[64]; |
|
371 static const Town* _last_town; |
|
372 |
|
373 static int CDECL TownNameSorter(const void *a, const void *b) |
|
374 { |
|
375 const Town* ta = *(const Town**)a; |
|
376 const Town* tb = *(const Town**)b; |
|
377 char buf1[64]; |
|
378 int r; |
|
379 |
|
380 SetDParam(0, ta->index); |
|
381 GetString(buf1, STR_TOWN, lastof(buf1)); |
|
382 |
|
383 /* If 'b' is the same town as in the last round, use the cached value |
|
384 * We do this to speed stuff up ('b' is called with the same value a lot of |
|
385 * times after eachother) */ |
|
386 if (tb != _last_town) { |
|
387 _last_town = tb; |
|
388 SetDParam(0, tb->index); |
|
389 GetString(_bufcache, STR_TOWN, lastof(_bufcache)); |
|
390 } |
|
391 |
|
392 r = strcmp(buf1, _bufcache); |
|
393 if (_town_sort_order & 1) r = -r; |
|
394 return r; |
|
395 } |
|
396 |
|
397 static int CDECL TownPopSorter(const void *a, const void *b) |
|
398 { |
|
399 const Town* ta = *(const Town**)a; |
|
400 const Town* tb = *(const Town**)b; |
|
401 int r = ta->population - tb->population; |
|
402 if (_town_sort_order & 1) r = -r; |
|
403 return r; |
|
404 } |
|
405 |
|
406 static void MakeSortedTownList(void) |
|
407 { |
|
408 const Town* t; |
|
409 uint n = 0; |
|
410 |
|
411 /* Create array for sorting */ |
|
412 _town_sort = realloc((void*)_town_sort, (GetMaxTownIndex() + 1) * sizeof(_town_sort[0])); |
|
413 if (_town_sort == NULL) error("Could not allocate memory for the town-sorting-list"); |
|
414 |
|
415 FOR_ALL_TOWNS(t) _town_sort[n++] = t; |
|
416 |
|
417 _num_town_sort = n; |
|
418 |
|
419 _last_town = NULL; // used for "cache" |
|
420 qsort((void*)_town_sort, n, sizeof(_town_sort[0]), _town_sort_order & 2 ? TownPopSorter : TownNameSorter); |
|
421 |
|
422 DEBUG(misc, 3, "Resorting towns list"); |
|
423 } |
|
424 |
|
425 |
|
426 static void TownDirectoryWndProc(Window *w, WindowEvent *e) |
|
427 { |
|
428 switch (e->event) { |
|
429 case WE_PAINT: { |
|
430 if (_town_sort_dirty) { |
|
431 _town_sort_dirty = false; |
|
432 MakeSortedTownList(); |
|
433 } |
|
434 |
|
435 SetVScrollCount(w, _num_town_sort); |
|
436 |
|
437 DrawWindowWidgets(w); |
|
438 DoDrawString(_town_sort_order & 1 ? DOWNARROW : UPARROW, (_town_sort_order <= 1) ? 88 : 187, 15, 0x10); |
|
439 |
|
440 { |
|
441 int n = 0; |
|
442 uint16 i = w->vscroll.pos; |
|
443 int y = 28; |
|
444 |
|
445 while (i < _num_town_sort) { |
|
446 const Town* t = _town_sort[i]; |
|
447 |
|
448 assert(t->xy); |
|
449 |
|
450 SetDParam(0, t->index); |
|
451 SetDParam(1, t->population); |
|
452 DrawString(2, y, STR_2057, 0); |
|
453 |
|
454 y += 10; |
|
455 i++; |
|
456 if (++n == w->vscroll.cap) break; // max number of towns in 1 window |
|
457 } |
|
458 SetDParam(0, GetWorldPopulation()); |
|
459 DrawString(3, w->height - 12 + 2, STR_TOWN_POPULATION, 0); |
|
460 } |
|
461 } break; |
|
462 |
|
463 case WE_CLICK: |
|
464 switch (e->we.click.widget) { |
|
465 case 3: { /* Sort by Name ascending/descending */ |
|
466 _town_sort_order = (_town_sort_order == 0) ? 1 : 0; |
|
467 _town_sort_dirty = true; |
|
468 SetWindowDirty(w); |
|
469 } break; |
|
470 |
|
471 case 4: { /* Sort by Population ascending/descending */ |
|
472 _town_sort_order = (_town_sort_order == 2) ? 3 : 2; |
|
473 _town_sort_dirty = true; |
|
474 SetWindowDirty(w); |
|
475 } break; |
|
476 |
|
477 case 5: { /* Click on Town Matrix */ |
|
478 const Town* t; |
|
479 |
|
480 uint16 id_v = (e->we.click.pt.y - 28) / 10; |
|
481 |
|
482 if (id_v >= w->vscroll.cap) return; // click out of bounds |
|
483 |
|
484 id_v += w->vscroll.pos; |
|
485 |
|
486 if (id_v >= _num_town_sort) return; // click out of town bounds |
|
487 |
|
488 t = _town_sort[id_v]; |
|
489 assert(t->xy); |
|
490 ScrollMainWindowToTile(t->xy); |
|
491 break; |
|
492 } |
|
493 } |
|
494 break; |
|
495 |
|
496 case WE_4: |
|
497 SetWindowDirty(w); |
|
498 break; |
|
499 |
|
500 case WE_RESIZE: |
|
501 w->vscroll.cap += e->we.sizing.diff.y / 10; |
|
502 break; |
|
503 } |
|
504 } |
|
505 |
|
506 static const WindowDesc _town_directory_desc = { |
|
507 WDP_AUTO, WDP_AUTO, 208, 202, |
|
508 WC_TOWN_DIRECTORY,0, |
|
509 WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON | WDF_RESIZABLE, |
|
510 _town_directory_widgets, |
|
511 TownDirectoryWndProc |
|
512 }; |
|
513 |
|
514 |
|
515 void ShowTownDirectory(void) |
|
516 { |
|
517 Window *w = AllocateWindowDescFront(&_town_directory_desc, 0); |
|
518 |
|
519 if (w != NULL) { |
|
520 w->vscroll.cap = 16; |
|
521 w->resize.step_height = 10; |
|
522 w->resize.height = w->height - 10 * 6; // minimum of 10 items in the list, each item 10 high |
|
523 } |
|
524 } |