ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/Deliantra-Client/bin/cfplus
(Generate patch)

Comparing deliantra/Deliantra-Client/bin/cfplus (file contents):
Revision 1.9 by root, Thu May 25 23:41:45 2006 UTC vs.
Revision 1.23 by root, Sun May 28 02:31:04 2006 UTC

29use Time::HiRes 'time'; 29use Time::HiRes 'time';
30use Pod::POM; 30use Pod::POM;
31use Event; 31use Event;
32 32
33use Crossfire; 33use Crossfire;
34use Crossfire::Protocol; 34use Crossfire::Protocol::Constants;
35 35
36use Compress::LZF; 36use Compress::LZF;
37 37
38use CFClient; 38use CFClient;
39use CFClient::OpenGL ();
40use CFClient::Protocol;
39use CFClient::UI; 41use CFClient::UI;
40use CFClient::MapWidget; 42use CFClient::MapWidget;
41 43
42$Event::DIED = sub { 44$Event::DIED = sub {
43 # TODO: display dialog box or so 45 # TODO: display dialog box or so
50 52
51my $MAX_FPS = 60; 53my $MAX_FPS = 60;
52my $MIN_FPS = 5; # unused as of yet 54my $MIN_FPS = 5; # unused as of yet
53 55
54our $META_SERVER = "crossfire.real-time.com:13326"; 56our $META_SERVER = "crossfire.real-time.com:13326";
55
56our $FACEMAP;
57our $TILECACHE;
58our $MAPCACHE;
59 57
60our $LAST_REFRESH; 58our $LAST_REFRESH;
61our $NOW; 59our $NOW;
62 60
63our $CFG; 61our $CFG;
83our $LOGVIEW; 81our $LOGVIEW;
84our $CONSOLE; 82our $CONSOLE;
85our $METASERVER; 83our $METASERVER;
86our $LOGIN_BUTTON; 84our $LOGIN_BUTTON;
87our $QUIT_DIALOG; 85our $QUIT_DIALOG;
86our $SERVER_SETUP;
88 87
89our $FLOORBOX; 88our $FLOORBOX;
90our $GAUGES; 89our $GAUGES;
91our $STATWIDS; 90our $STATWIDS;
92 91
99 98
100our $ALT_ENTER_MESSAGE; 99our $ALT_ENTER_MESSAGE;
101our $STATUSBOX; 100our $STATUSBOX;
102our $DEBUG_STATUS; 101our $DEBUG_STATUS;
103 102
104our $INVWIN; 103our $INV_WINDOW;
105our $INV; 104our $INV;
106our $INVR; 105our $INVR;
107our $INVR_LBL; 106our $INVR_LBL;
108 107
109sub status { 108sub status {
117} 116}
118 117
119sub start_game { 118sub start_game {
120 status "logging in..."; 119 status "logging in...";
121 120
121 $LOGIN_BUTTON->set_text ("Logout");
122 $SERVER_SETUP->hide;
123
122 my $mapsize = List::Util::min 32, List::Util::max 11, int $WIDTH * $CFG->{mapsize} * 0.01 / 32; 124 my $mapsize = List::Util::min 32, List::Util::max 11, int $WIDTH * $CFG->{mapsize} * 0.01 / 32;
123 125
124 $MAPCACHE = CFClient::db_table "mapcache_$CFG->{host}"; 126 my ($host, $port) = split /:/, $CFG->{host};
127
125 $MAP = new CFClient::Map $mapsize, $mapsize; 128 $MAP = new CFClient::Map $mapsize, $mapsize;
126
127 my ($host, $port) = split /:/, $CFG->{host};
128 129
129 $CONN = eval { 130 $CONN = eval {
130 new conn 131 new CFClient::Protocol
131 host => $host, 132 host => $host,
132 port => $port || 13327, 133 port => $port || 13327,
133 user => $CFG->{user}, 134 user => $CFG->{user},
134 pass => $CFG->{password}, 135 pass => $CFG->{password},
135 mapw => $mapsize, 136 mapw => $mapsize,
136 maph => $mapsize, 137 maph => $mapsize,
137 ; 138
139 map_widget => $MAPWIDGET,
140 logview => $LOGVIEW,
141 statusbox => $STATUSBOX,
142 map => $MAP,
143 mapmap => $MAPMAP,
144
145 sound_play => sub {
146 my ($x, $y, $soundnum, $type) = @_;
147
148 $SDL_MIXER
149 or return;
150
151 my $chunk = $AUDIO_CHUNKS{$SOUNDS[$soundnum]}
152 or return;
153
154 $chunk->play;
155 },
138 }; 156 };
139 157
140 if ($CONN) { 158 if ($CONN) {
141 CFClient::lowdelay fileno $CONN->{fh}; 159 CFClient::lowdelay fileno $CONN->{fh};
142 160
143 $LOGIN_BUTTON->set_text ("Logout");
144 status "login successful"; 161 status "login successful";
145
146 $BUTTONBAR->{children}[1]->emit ("activate")
147 if $BUTTONBAR->{children}[1]->{state};
148
149 } else { 162 } else {
150 status "unable to connect"; 163 status "unable to connect";
151 stop_game(); 164 stop_game();
152 } 165 }
153} 166}
154 167
155sub stop_game { 168sub stop_game {
169 $LOGIN_BUTTON->set_text ("Login");
170 $SERVER_SETUP->show;
171 $INV_WINDOW->hide;
172 $LOGVIEW->hide;
173
156 return unless $CONN; 174 return unless $CONN;
157 175
158 status "connection closed"; 176 status "connection closed";
159 $LOGIN_BUTTON->set_text ("Login"); 177
160 $CONN->destroy; 178 $CONN->destroy;
161 $CONN = 0; # false, does not autovivify 179 $CONN = 0; # false, does not autovivify
162
163 $BUTTONBAR->{children}[1]->emit ("activate")
164 unless $BUTTONBAR->{children}[1]->{state};
165
166 undef $MAPCACHE;
167 undef $MAP;
168} 180}
169 181
170sub client_setup { 182sub client_setup {
171 my $dialog = new CFClient::UI::FancyFrame 183 my $dialog = new CFClient::UI::FancyFrame
184 req_x => 1,
185 req_y => $HEIGHT * (1/8),
186 name => "client_setup",
172 title => "Client Setup", 187 title => "Client Setup",
173 child => (my $vbox = new CFClient::UI::VBox); 188 child => (my $vbox = new CFClient::UI::VBox);
174 $vbox->add (my $table = new CFClient::UI::Table expand => 1, col_expand => [0, 1]); 189 $vbox->add (my $table = new CFClient::UI::Table expand => 1, col_expand => [0, 1]);
175 190
176 $table->add (0, 0, new CFClient::UI::Label valign => 0, align => 1, text => "Video Mode"); 191 $table->add (0, 0, new CFClient::UI::Label valign => 0, align => 1, text => "Video Mode");
191 206
192 $table->add (0, $row, new CFClient::UI::Label valign => 0, align => 1, text => "Fullscreen"); 207 $table->add (0, $row, new CFClient::UI::Label valign => 0, align => 1, text => "Fullscreen");
193 $table->add (1, $row++, new CFClient::UI::CheckBox 208 $table->add (1, $row++, new CFClient::UI::CheckBox
194 state => $CFG->{fullscreen}, 209 state => $CFG->{fullscreen},
195 tooltip => "Bring the client into fullscreen mode.", 210 tooltip => "Bring the client into fullscreen mode.",
196 connect_changed => sub { 211 on_changed => sub {
197 my ($self, $value) = @_; 212 my ($self, $value) = @_;
198 $CFG->{fullscreen} = $value; 213 $CFG->{fullscreen} = $value;
199 } 214 }
200 ); 215 );
201 216
202 $table->add (0, $row, new CFClient::UI::Label valign => 0, align => 1, text => "Fast & Ugly"); 217 $table->add (0, $row, new CFClient::UI::Label valign => 0, align => 1, text => "Fast & Ugly");
203 $table->add (1, $row++, new CFClient::UI::CheckBox 218 $table->add (1, $row++, new CFClient::UI::CheckBox
204 state => $CFG->{fast}, 219 state => $CFG->{fast},
205 tooltip => "Lower the visual quality considerably to speed up rendering.", 220 tooltip => "Lower the visual quality considerably to speed up rendering.",
206 connect_changed => sub { 221 on_changed => sub {
207 my ($self, $value) = @_; 222 my ($self, $value) = @_;
208 $CFG->{fast} = $value; 223 $CFG->{fast} = $value;
209 } 224 }
210 ); 225 );
211 226
212 $table->add (0, $row, new CFClient::UI::Label valign => 0, align => 1, text => "Map Scale"); 227 $table->add (0, $row, new CFClient::UI::Label valign => 0, align => 1, text => "Map Scale");
213 $table->add (1, $row++, new CFClient::UI::Slider 228 $table->add (1, $row++, new CFClient::UI::Slider
214 range => [(log $CFG->{map_scale}) / (log 2), -3, 1, 0, 1], 229 range => [(log $CFG->{map_scale}) / (log 2), -3, 1, 0, 1],
215 tooltip => "Enlarge or shrink the displayed map. Changes are instant.", 230 tooltip => "Enlarge or shrink the displayed map. Changes are instant.",
216 connect_changed => sub { 231 on_changed => sub {
217 my ($self, $value) = @_; 232 my ($self, $value) = @_;
218 $CFG->{map_scale} = 2 ** $value; 233 $CFG->{map_scale} = 2 ** $value;
219 } 234 }
220 ); 235 );
221 236
222 $table->add (0, $row, new CFClient::UI::Label valign => 0, align => 1, text => "Fog of War"); 237 $table->add (0, $row, new CFClient::UI::Label valign => 0, align => 1, text => "Fog of War");
223 $table->add (1, $row++, new CFClient::UI::CheckBox 238 $table->add (1, $row++, new CFClient::UI::CheckBox
224 state => $CFG->{fow_enable}, 239 state => $CFG->{fow_enable},
225 tooltip => "<b>Fog-of-War</b> marks areas that cannot be seen by the player. Changes are instant.", 240 tooltip => "<b>Fog-of-War</b> marks areas that cannot be seen by the player. Changes are instant.",
226 connect_changed => sub { 241 on_changed => sub {
227 my ($self, $value) = @_; 242 my ($self, $value) = @_;
228 $CFG->{fow_enable} = $value; 243 $CFG->{fow_enable} = $value;
229 } 244 }
230 ); 245 );
231 246
232 $table->add (0, $row, new CFClient::UI::Label valign => 0, align => 1, text => "FoW Intensity"); 247 $table->add (0, $row, new CFClient::UI::Label valign => 0, align => 1, text => "FoW Intensity");
233 $table->add (1, $row++, new CFClient::UI::Slider 248 $table->add (1, $row++, new CFClient::UI::Slider
234 range => [$CFG->{fow_intensity}, 0, 1, 0, 1 / 256], 249 range => [$CFG->{fow_intensity}, 0, 1, 0, 1 / 256],
235 tooltip => "<b>Fog of War Lightness.</b> The higher the intensity, the lighter the Fog-of-War color. Changes are instant.", 250 tooltip => "<b>Fog of War Lightness.</b> The higher the intensity, the lighter the Fog-of-War color. Changes are instant.",
236 connect_changed => sub { 251 on_changed => sub {
237 my ($self, $value) = @_; 252 my ($self, $value) = @_;
238 $CFG->{fow_intensity} = $value; 253 $CFG->{fow_intensity} = $value;
239 } 254 }
240 ); 255 );
241 256
242 $table->add (0, $row, new CFClient::UI::Label valign => 0, align => 1, text => "FoW Smooth"); 257 $table->add (0, $row, new CFClient::UI::Label valign => 0, align => 1, text => "FoW Smooth");
243 $table->add (1, $row++, new CFClient::UI::CheckBox 258 $table->add (1, $row++, new CFClient::UI::CheckBox
244 state => $CFG->{fow_smooth}, 259 state => $CFG->{fow_smooth},
245 tooltip => "Smooth the Fog-of-War a bit to make it more realistic. Changes are instant.", 260 tooltip => "Smooth the Fog-of-War a bit to make it more realistic. Changes are instant.",
246 connect_changed => sub { 261 on_changed => sub {
247 my ($self, $value) = @_; 262 my ($self, $value) = @_;
248 $CFG->{fow_smooth} = $value; 263 $CFG->{fow_smooth} = $value;
249 status "Fog of War smoothing requires OpenGL 1.2 or higher" if $CFClient::GL_VERSION < 1.2; 264 status "Fog of War smoothing requires OpenGL 1.2 or higher" if $CFClient::OpenGL::GL_VERSION < 1.2;
250 } 265 }
251 ); 266 );
252 267
253 $table->add (0, $row, new CFClient::UI::Label valign => 0, align => 1, text => "GUI Fontsize"); 268 $table->add (0, $row, new CFClient::UI::Label valign => 0, align => 1, text => "GUI Fontsize");
254 $table->add (1, $row++, new CFClient::UI::Slider 269 $table->add (1, $row++, new CFClient::UI::Slider
255 range => [$CFG->{gui_fontsize}, 0.5, 2, 0, 0.1], 270 range => [$CFG->{gui_fontsize}, 0.5, 2, 0, 0.1],
256 tooltip => "The base font size used by most GUI elements that do not have their own setting.", 271 tooltip => "The base font size used by most GUI elements that do not have their own setting.",
257 connect_changed => sub { $CFG->{gui_fontsize} = $_[1] }, 272 on_changed => sub { $CFG->{gui_fontsize} = $_[1] },
258 ); 273 );
259 274
260 $table->add (0, $row, new CFClient::UI::Label valign => 0, align => 1, text => "Message Fontsize"); 275 $table->add (0, $row, new CFClient::UI::Label valign => 0, align => 1, text => "Message Fontsize");
261 $table->add (1, $row++, new CFClient::UI::Slider 276 $table->add (1, $row++, new CFClient::UI::Slider
262 range => [$CFG->{log_fontsize}, 0.5, 2, 0, 0.1], 277 range => [$CFG->{log_fontsize}, 0.5, 2, 0, 0.1],
263 tooltip => "The font size used by the <b>message/server log</b> window only. Changes are instant.", 278 tooltip => "The font size used by the <b>message/server log</b> window only. Changes are instant.",
264 connect_changed => sub { $LOGVIEW->set_fontsize ($CFG->{log_fontsize} = $_[1]) }, 279 on_changed => sub { $LOGVIEW->set_fontsize ($CFG->{log_fontsize} = $_[1]) },
265 ); 280 );
266 281
267 $table->add (0, $row, new CFClient::UI::Label valign => 0, align => 1, text => "Stats Fontsize"); 282 $table->add (0, $row, new CFClient::UI::Label valign => 0, align => 1, text => "Stats Fontsize");
268 283
269 $table->add (1, $row++, new CFClient::UI::Slider 284 $table->add (1, $row++, new CFClient::UI::Slider
270 range => [$CFG->{stat_fontsize}, 0.5, 2, 0, 0.1], 285 range => [$CFG->{stat_fontsize}, 0.5, 2, 0, 0.1],
271 tooltip => "The font size used by the <b>statistics window</b> only. Changes are instant.", 286 tooltip => "The font size used by the <b>statistics window</b> only. Changes are instant.",
272 connect_changed => sub { 287 on_changed => sub {
273 $CFG->{stat_fontsize} = $_[1]; 288 $CFG->{stat_fontsize} = $_[1];
274 &set_stats_window_fontsize; 289 &set_stats_window_fontsize;
275 } 290 }
276 ); 291 );
277 292
278 $table->add (0, $row, new CFClient::UI::Label valign => 0, align => 1, text => "Gauge fontsize"); 293 $table->add (0, $row, new CFClient::UI::Label valign => 0, align => 1, text => "Gauge fontsize");
279 $table->add (1, $row++, new CFClient::UI::Slider 294 $table->add (1, $row++, new CFClient::UI::Slider
280 range => [$CFG->{gauge_fontsize}, 0.5, 2, 0, 0.1], 295 range => [$CFG->{gauge_fontsize}, 0.5, 2, 0, 0.1],
281 tooltip => "Adjusts the fontsize of the gauges at the bottom right. Changes are instant.", 296 tooltip => "Adjusts the fontsize of the gauges at the bottom right. Changes are instant.",
282 connect_changed => sub { 297 on_changed => sub {
283 $CFG->{gauge_fontsize} = $_[1]; 298 $CFG->{gauge_fontsize} = $_[1];
284 &set_gauge_window_fontsize; 299 &set_gauge_window_fontsize;
285 } 300 }
286 ); 301 );
287 302
288 $table->add (0, $row, new CFClient::UI::Label valign => 0, align => 1, text => "Gauge size"); 303 $table->add (0, $row, new CFClient::UI::Label valign => 0, align => 1, text => "Gauge size");
289 $table->add (1, $row++, new CFClient::UI::Slider 304 $table->add (1, $row++, new CFClient::UI::Slider
290 range => [$CFG->{gauge_size}, 0.2, 0.8], 305 range => [$CFG->{gauge_size}, 0.2, 0.8],
291 tooltip => "Adjust the size of the stats gauges at the bottom right. Changes are instant.", 306 tooltip => "Adjust the size of the stats gauges at the bottom right. Changes are instant.",
292 connect_changed => sub { 307 on_changed => sub {
293 $CFG->{gauge_size} = $_[1]; 308 $CFG->{gauge_size} = $_[1];
294 $GAUGES->{win}->set_size ($WIDTH, int $HEIGHT * $CFG->{gauge_size}); 309 $GAUGES->{win}->set_size ($WIDTH, int $HEIGHT * $CFG->{gauge_size});
295 } 310 }
296 ); 311 );
297 312
298 $table->add (1, $row++, new CFClient::UI::Button 313 $table->add (1, $row++, new CFClient::UI::Button
299 expand => 1, align => 0, text => "Apply", 314 expand => 1, align => 0, text => "Apply",
300 tooltip => "Apply the video settings", 315 tooltip => "Apply the video settings",
301 connect_activate => sub { 316 on_activate => sub {
302 video_shutdown (); 317 video_shutdown ();
303 video_init (); 318 video_init ();
304 } 319 }
305 ); 320 );
306 321
307 $table->add (0, $row, new CFClient::UI::Label valign => 0, align => 1, text => "Audio Enable"); 322 $table->add (0, $row, new CFClient::UI::Label valign => 0, align => 1, text => "Audio Enable");
308 $table->add (1, $row++, new CFClient::UI::CheckBox 323 $table->add (1, $row++, new CFClient::UI::CheckBox
309 state => $CFG->{audio_enable}, 324 state => $CFG->{audio_enable},
310 tooltip => "<b>Master Audio Enable.</b> If enabled, sound effects and music will be played. If disabled, no audio will be used and the soundcard will not be opened.", 325 tooltip => "<b>Master Audio Enable.</b> If enabled, sound effects and music will be played. If disabled, no audio will be used and the soundcard will not be opened.",
311 connect_changed => sub { 326 on_changed => sub {
312 $CFG->{audio_enable} = $_[1]; 327 $CFG->{audio_enable} = $_[1];
313 } 328 }
314 ); 329 );
315# $table->add (0, 9, new CFClient::UI::Label valign => 0, align => 1, text => "Effects Volume"); 330# $table->add (0, 9, new CFClient::UI::Label valign => 0, align => 1, text => "Effects Volume");
316# $table->add (1, 8, new CFClient::UI::Slider range => [$CFG->{effects_volume}, 0, 128, 1], connect_changed => sub { 331# $table->add (1, 8, new CFClient::UI::Slider range => [$CFG->{effects_volume}, 0, 128, 1], on_changed => sub {
317# $CFG->{effects_volume} = $_[1]; 332# $CFG->{effects_volume} = $_[1];
318# }); 333# });
319 $table->add (0, $row, new CFClient::UI::Label valign => 0, align => 1, text => "Background Music"); 334 $table->add (0, $row, new CFClient::UI::Label valign => 0, align => 1, text => "Background Music");
320 $table->add (1, $row++, my $hbox = new CFClient::UI::HBox); 335 $table->add (1, $row++, my $hbox = new CFClient::UI::HBox);
321 $hbox->add (new CFClient::UI::CheckBox 336 $hbox->add (new CFClient::UI::CheckBox
322 expand => 1, state => $CFG->{bgm_enable}, 337 expand => 1, state => $CFG->{bgm_enable},
323 tooltip => "If enabled, playing of background music is enabled. If disabled, no background music will be played.", 338 tooltip => "If enabled, playing of background music is enabled. If disabled, no background music will be played.",
324 connect_changed => sub { 339 on_changed => sub {
325 $CFG->{bgm_enable} = $_[1]; 340 $CFG->{bgm_enable} = $_[1];
326 } 341 }
327 ); 342 );
328 $hbox->add (new CFClient::UI::Slider 343 $hbox->add (new CFClient::UI::Slider
329 expand => 1, range => [$CFG->{bgm_volume}, 0, 1, 0, 1/128], 344 expand => 1, range => [$CFG->{bgm_volume}, 0, 1, 0, 1/128],
330 tooltip => "The volume of the background music. Changes are instant.", 345 tooltip => "The volume of the background music. Changes are instant.",
331 connect_changed => sub { 346 on_changed => sub {
332 $CFG->{bgm_volume} = $_[1]; 347 $CFG->{bgm_volume} = $_[1];
333 CFClient::MixMusic::volume $_[1] * 128; 348 CFClient::MixMusic::volume $_[1] * 128;
334 } 349 }
335 ); 350 );
336 351
337 $table->add (1, $row++, new CFClient::UI::Button 352 $table->add (1, $row++, new CFClient::UI::Button
338 expand => 1, align => 0, text => "Apply", 353 expand => 1, align => 0, text => "Apply",
339 tooltip => "Apply the audio settings", 354 tooltip => "Apply the audio settings",
340 connect_activate => sub { 355 on_activate => sub {
341 audio_shutdown (); 356 audio_shutdown ();
342 audio_init (); 357 audio_init ();
343 } 358 }
344 ); 359 );
345 360
347 $table->add (1, $row++, my $saycmd = new CFClient::UI::Entry 362 $table->add (1, $row++, my $saycmd = new CFClient::UI::Entry
348 text => $CFG->{say_command}, 363 text => $CFG->{say_command},
349 tooltip => "This is the command that will be used if you write a line in the message window entry or press <b>\"</b> in the map window. " 364 tooltip => "This is the command that will be used if you write a line in the message window entry or press <b>\"</b> in the map window. "
350 . "Usually you want to enter something like 'say' or 'shout' or 'gsay' here. " 365 . "Usually you want to enter something like 'say' or 'shout' or 'gsay' here. "
351 . "But you could also set it to <b>tell <i>playername</i></b> to only chat with that user.", 366 . "But you could also set it to <b>tell <i>playername</i></b> to only chat with that user.",
352 connect_changed => sub { 367 on_changed => sub {
353 my ($self, $value) = @_; 368 my ($self, $value) = @_;
354 $CFG->{say_command} = $value; 369 $CFG->{say_command} = $value;
355 } 370 }
356 ); 371 );
357 372
372 387
373sub make_gauge_window { 388sub make_gauge_window {
374 my $gh = int $HEIGHT * $CFG->{gauge_size}; 389 my $gh = int $HEIGHT * $CFG->{gauge_size};
375 390
376 my $win = new CFClient::UI::Frame ( 391 my $win = new CFClient::UI::Frame (
392 req_x => 0,
377 req_y => -1, 393 req_y => -1,
378 user_w => $WIDTH, 394 def_w => $WIDTH,
379 user_h => $gh, 395 def_h => $gh,
380 ); 396 );
381 397
382 $win->add (my $hbox = new CFClient::UI::HBox 398 $win->add (my $hbox = new CFClient::UI::HBox
383 children => [ 399 children => [
384 (new CFClient::UI::HBox expand => 1), 400 (new CFClient::UI::HBox expand => 1),
421 437
422 $win 438 $win
423} 439}
424 440
425sub make_stats_window { 441sub make_stats_window {
426 my $tgw = new CFClient::UI::FancyFrame title => "Stats"; 442 my $tgw = new CFClient::UI::FancyFrame
443 req_y => $HEIGHT * (2/8),
444 req_x => -1,
445 title => "Stats",
446 name => "stats_window";
427 447
428 $tgw->add (new CFClient::UI::Window child => my $vb = new CFClient::UI::VBox); 448 $tgw->add (new CFClient::UI::Window child => my $vb = new CFClient::UI::VBox);
429 $vb->add ($STATWIDS->{title} = new CFClient::UI::Label valign => 0, align => -1, text => "Title:", expand => 1, 449 $vb->add ($STATWIDS->{title} = new CFClient::UI::Label valign => 0, align => -1, text => "Title:", expand => 1,
430 can_hover => 1, can_events => 1, 450 can_hover => 1, can_events => 1,
431 tooltip => "Your name and title. You can change your title by using the <b>title</b> command, if supported by the server."); 451 tooltip => "Your name and title. You can change your title by using the <b>title</b> command, if supported by the server.");
434 tooltip => "The map you are currently on (if supported by the server)."); 454 tooltip => "The map you are currently on (if supported by the server).");
435 455
436 $vb->add (my $hb0 = new CFClient::UI::HBox); 456 $vb->add (my $hb0 = new CFClient::UI::HBox);
437 $hb0->add ($STATWIDS->{weight} = new CFClient::UI::Label valign => 0, align => -1, text => "Weight:", expand => 1, 457 $hb0->add ($STATWIDS->{weight} = new CFClient::UI::Label valign => 0, align => -1, text => "Weight:", expand => 1,
438 can_hover => 1, can_events => 1, 458 can_hover => 1, can_events => 1,
439 tooltip => "This is the amount the Player weights."); 459 tooltip => "The weight of the player including all inventory items.");
440 $hb0->add ($STATWIDS->{m_weight} = new CFClient::UI::Label valign => 0, align => -1, text => "Max weight:", expand => 1, 460 $hb0->add ($STATWIDS->{m_weight} = new CFClient::UI::Label valign => 0, align => -1, text => "Max weight:", expand => 1,
441 can_hover => 1, can_events => 1, 461 can_hover => 1, can_events => 1,
442 tooltip => "The weight limit, you can't carry more than this."); 462 tooltip => "The weight limit: you cannot carry more than this.");
443 463
444 464
445 $vb->add (my $hb = new CFClient::UI::HBox expand => 1); 465 $vb->add (my $hb = new CFClient::UI::HBox expand => 1);
446 $hb->add (my $tbl = new CFClient::UI::Table expand => 1); 466 $hb->add (my $tbl = new CFClient::UI::Table expand => 1);
447 467
537} 557}
538 558
539sub update_stats_window { 559sub update_stats_window {
540 my ($stats) = @_; 560 my ($stats) = @_;
541 561
542 # i love text protocols!!! 562 # I love text protocols...
563
543 my $hp = $stats->{Crossfire::Protocol::CS_STAT_HP} * 1; 564 my $hp = $stats->{+CS_STAT_HP} * 1;
544 my $hp_m = $stats->{Crossfire::Protocol::CS_STAT_MAXHP} * 1; 565 my $hp_m = $stats->{+CS_STAT_MAXHP} * 1;
545 my $sp = $stats->{Crossfire::Protocol::CS_STAT_SP} * 1; 566 my $sp = $stats->{+CS_STAT_SP} * 1;
546 my $sp_m = $stats->{Crossfire::Protocol::CS_STAT_MAXSP} * 1; 567 my $sp_m = $stats->{+CS_STAT_MAXSP} * 1;
547 my $fo = $stats->{Crossfire::Protocol::CS_STAT_FOOD} * 1; 568 my $fo = $stats->{+CS_STAT_FOOD} * 1;
548 my $fo_m = 999; 569 my $fo_m = 999;
549 my $gr = $stats->{Crossfire::Protocol::CS_STAT_GRACE} * 1; 570 my $gr = $stats->{+CS_STAT_GRACE} * 1;
550 my $gr_m = $stats->{Crossfire::Protocol::CS_STAT_MAXGRACE} * 1; 571 my $gr_m = $stats->{+CS_STAT_MAXGRACE} * 1;
551 572
552 $GAUGES->{hp} ->set_value ($hp, $hp_m); 573 $GAUGES->{hp} ->set_value ($hp, $hp_m);
553 $GAUGES->{mana} ->set_value ($sp, $sp_m); 574 $GAUGES->{mana} ->set_value ($sp, $sp_m);
554 $GAUGES->{food} ->set_value ($fo, $fo_m); 575 $GAUGES->{food} ->set_value ($fo, $fo_m);
555 $GAUGES->{grace} ->set_value ($gr, $gr_m); 576 $GAUGES->{grace} ->set_value ($gr, $gr_m);
556 $GAUGES->{exp} ->set_text ("Exp: " . (formsep $stats->{Crossfire::Protocol::CS_STAT_EXP64}) 577 $GAUGES->{exp} ->set_text ("Exp: " . (formsep $stats->{+CS_STAT_EXP64})
557 . " (lvl " . ($stats->{Crossfire::Protocol::CS_STAT_LEVEL} * 1) . ")"); 578 . " (lvl " . ($stats->{+CS_STAT_LEVEL} * 1) . ")");
558 my $rng = $stats->{Crossfire::Protocol::CS_STAT_RANGE}; 579 my $rng = $stats->{+CS_STAT_RANGE};
559 $rng =~ s/^Range: //; # thank you so much dear server 580 $rng =~ s/^Range: //; # thank you so much dear server
560 $GAUGES->{range} ->set_text ("Rng: " . $rng); 581 $GAUGES->{range} ->set_text ("Rng: " . $rng);
561 my $title = $stats->{Crossfire::Protocol::CS_STAT_TITLE}; 582 my $title = $stats->{+CS_STAT_TITLE};
562 $title =~ s/^Player: //; 583 $title =~ s/^Player: //;
563 $STATWIDS->{title} ->set_text ("Title: " . $title); 584 $STATWIDS->{title} ->set_text ("Title: " . $title);
564 585
565 $STATWIDS->{st_str} ->set_text (sprintf "%d", $stats->{5}); 586 $STATWIDS->{st_str} ->set_text (sprintf "%d" , $stats->{+CS_STAT_STR});
566 $STATWIDS->{st_dex} ->set_text (sprintf "%d", $stats->{8}); 587 $STATWIDS->{st_dex} ->set_text (sprintf "%d" , $stats->{+CS_STAT_DEX});
567 $STATWIDS->{st_con} ->set_text (sprintf "%d", $stats->{9}); 588 $STATWIDS->{st_con} ->set_text (sprintf "%d" , $stats->{+CS_STAT_CON});
568 $STATWIDS->{st_int} ->set_text (sprintf "%d", $stats->{6}); 589 $STATWIDS->{st_int} ->set_text (sprintf "%d" , $stats->{+CS_STAT_INT});
569 $STATWIDS->{st_wis} ->set_text (sprintf "%d", $stats->{7}); 590 $STATWIDS->{st_wis} ->set_text (sprintf "%d" , $stats->{+CS_STAT_WIS});
570 $STATWIDS->{st_pow} ->set_text (sprintf "%d", $stats->{22}); 591 $STATWIDS->{st_pow} ->set_text (sprintf "%d" , $stats->{+CS_STAT_POW});
571 $STATWIDS->{st_cha} ->set_text (sprintf "%d", $stats->{10}); 592 $STATWIDS->{st_cha} ->set_text (sprintf "%d" , $stats->{+CS_STAT_CHA});
572 $STATWIDS->{st_wc} ->set_text (sprintf "%d", $stats->{13}); 593 $STATWIDS->{st_wc} ->set_text (sprintf "%d" , $stats->{+CS_STAT_WC});
573 $STATWIDS->{st_ac} ->set_text (sprintf "%d", $stats->{14}); 594 $STATWIDS->{st_ac} ->set_text (sprintf "%d" , $stats->{+CS_STAT_AC});
574 $STATWIDS->{st_dam} ->set_text (sprintf "%d", $stats->{15}); 595 $STATWIDS->{st_dam} ->set_text (sprintf "%d" , $stats->{+CS_STAT_DAM});
575 $STATWIDS->{st_arm} ->set_text (sprintf "%d", $stats->{16}); 596 $STATWIDS->{st_arm} ->set_text (sprintf "%d" , $stats->{+CS_STAT_ARMOUR});
576 $STATWIDS->{st_spd} ->set_text (sprintf "%.1f", $stats->{Crossfire::Protocol::CS_STAT_SPEED}); 597 $STATWIDS->{st_spd} ->set_text (sprintf "%.1f", $stats->{+CS_STAT_SPEED});
577 $STATWIDS->{st_wspd}->set_text (sprintf "%.1f", $stats->{Crossfire::Protocol::CS_STAT_WEAP_SP}); 598 $STATWIDS->{st_wspd}->set_text (sprintf "%.1f", $stats->{+CS_STAT_WEAP_SP});
578 599
579 $STATWIDS->{m_weight}->set_text (sprintf "Max weight: %.1fkg", $stats->{Crossfire::Protocol::CS_STAT_WEIGHT_LIM} / 1000); 600 $STATWIDS->{m_weight}->set_text (sprintf "Max weight: %.1fkg", $stats->{+CS_STAT_WEIGHT_LIM} / 1000);
580 601
602 # TODO: replace by CS_STAT_RES_xxx constants
581 my %tbl = ( 603 my %tbl = (
582 phys => 100, 604 phys => 100,
583 magic => 101, 605 magic => 101,
584 fire => 102, 606 fire => 102,
585 elec => 103, 607 elec => 103,
594 tund => 112, 616 tund => 112,
595 fear => 113, 617 fear => 113,
596 depl => 113, 618 depl => 113,
597 deat => 115, 619 deat => 115,
598 holyw => 116, 620 holyw => 116,
599 blind => 117 621 blind => 117,
600 ); 622 );
601 623
602 for (keys %tbl) {
603 $STATWIDS->{"res_$_"}->set_text (sprintf "%d%", $stats->{$tbl{$_}}); 624 $STATWIDS->{"res_$_"}->set_text (sprintf "%d%", $stats->{$tbl{$_}})
604 } 625 for keys %tbl;
605
606} 626}
607 627
608sub metaserver_dialog { 628sub metaserver_dialog {
609 my $dialog = new CFClient::UI::FancyFrame 629 my $dialog = new CFClient::UI::FancyFrame
610 title => "Server List", 630 title => "Server List",
678 $m = [$users, $host, $uptime, $version, $desc]; 698 $m = [$users, $host, $uptime, $version, $desc];
679 699
680 $y++; 700 $y++;
681 701
682 $table->add (0, $y, new CFClient::UI::VBox children => [ 702 $table->add (0, $y, new CFClient::UI::VBox children => [
683 (new CFClient::UI::Button text => "Use", connect_activate => sub { 703 (new CFClient::UI::Button text => "Use", on_activate => sub {
684 $HOST->set_text ($CFG->{host} = $host); 704 $HOST->set_text ($CFG->{host} = $host);
685 }), 705 }),
686 (new CFClient::UI::Empty expand => 1), 706 (new CFClient::UI::Empty expand => 1),
687 ]); 707 ]);
688 708
693 } 713 }
694 }); 714 });
695} 715}
696 716
697sub server_setup { 717sub server_setup {
698 my $dialog = new CFClient::UI::FancyFrame 718 my $dialog = $SERVER_SETUP = new CFClient::UI::FancyFrame
719 x => $WIDTH * (1/3),
720 y => $HEIGHT * (1/8),
721 name => "server_setup",
699 title => "Server Setup", 722 title => "Server Setup",
700 child => (my $vbox = new CFClient::UI::VBox); 723 child => (my $vbox = new CFClient::UI::VBox),
724 on_visibility_change => sub {
725 my ($self, $visible) = @_;
726 $self->center if $visible;
727 },
701 728 ;
729
702 $vbox->add (my $table = new CFClient::UI::Table expand => 1, col_expand => [0, 1]); 730 $vbox->add (my $table = new CFClient::UI::Table expand => 1, col_expand => [0, 1]);
703 $table->add (0, 2, new CFClient::UI::Label valign => 0, align => 1, text => "Host:Port"); 731 $table->add (0, 2, new CFClient::UI::Label valign => 0, align => 1, text => "Host:Port");
704 732
705 { 733 {
706 $table->add (1, 2, my $vbox = new CFClient::UI::VBox); 734 $table->add (1, 2, my $vbox = new CFClient::UI::VBox);
708 $vbox->add ( 736 $vbox->add (
709 my $HOST = new CFClient::UI::Entry 737 my $HOST = new CFClient::UI::Entry
710 expand => 1, 738 expand => 1,
711 text => $CFG->{host}, 739 text => $CFG->{host},
712 tooltip => "The hostname or ip address of the Crossfire(+) server to connect to", 740 tooltip => "The hostname or ip address of the Crossfire(+) server to connect to",
713 connect_changed => sub { 741 on_changed => sub {
714 my ($self, $value) = @_; 742 my ($self, $value) = @_;
715 $CFG->{host} = $value; 743 $CFG->{host} = $value;
716 } 744 }
717 ); 745 );
718 746
721 $vbox->add (new CFClient::UI::Flopper 749 $vbox->add (new CFClient::UI::Flopper
722 expand => 1, 750 expand => 1,
723 text => "Server List", 751 text => "Server List",
724 other => $METASERVER, 752 other => $METASERVER,
725 tooltip => "Show a list of available crossfire servers", 753 tooltip => "Show a list of available crossfire servers",
726 connect_open => sub { 754 on_open => sub {
727 update_metaserver $HOST; 755 update_metaserver $HOST;
728 } 756 }
729 ); 757 );
730 } 758 }
731 759
732 $table->add (0, 4, new CFClient::UI::Label valign => 0, align => 1, text => "Username"); 760 $table->add (0, 4, new CFClient::UI::Label valign => 0, align => 1, text => "Username");
733 $table->add (1, 4, new CFClient::UI::Entry 761 $table->add (1, 4, new CFClient::UI::Entry
734 text => $CFG->{user}, 762 text => $CFG->{user},
735 tooltip => "The name of your character on the server", 763 tooltip => "The name of your character on the server",
736 connect_changed => sub { 764 on_changed => sub {
737 my ($self, $value) = @_; 765 my ($self, $value) = @_;
738 $CFG->{user} = $value; 766 $CFG->{user} = $value;
739 } 767 }
740 ); 768 );
741 769
742 $table->add (0, 5, new CFClient::UI::Label valign => 0, align => 1, text => "Password"); 770 $table->add (0, 5, new CFClient::UI::Label valign => 0, align => 1, text => "Password");
743 $table->add (1, 5, new CFClient::UI::Entry 771 $table->add (1, 5, new CFClient::UI::Entry
744 text => $CFG->{password}, 772 text => $CFG->{password},
745 hidden => 1, 773 hidden => 1,
746 tooltip => "The password for your character", 774 tooltip => "The password for your character",
747 connect_changed => sub { 775 on_changed => sub {
748 my ($self, $value) = @_; 776 my ($self, $value) = @_;
749 $CFG->{password} = $value; 777 $CFG->{password} = $value;
750 } 778 }
751 ); 779 );
752 780
756 range => [$CFG->{mapsize}, 10, 100, 0, 1], 784 range => [$CFG->{mapsize}, 10, 100, 0, 1],
757 tooltip => "This is the size of the portion of the map update the server sends you. " 785 tooltip => "This is the size of the portion of the map update the server sends you. "
758 . "If you set this to a high value you will be able to see further, " 786 . "If you set this to a high value you will be able to see further, "
759 . "but you also increase bandwidth requirements and latency. " 787 . "but you also increase bandwidth requirements and latency. "
760 . "This option is only used once at log-in.", 788 . "This option is only used once at log-in.",
761 connect_changed => sub { 789 on_changed => sub {
762 my ($self, $value) = @_; 790 my ($self, $value) = @_;
763 791
764 $CFG->{mapsize} = $self->{range}[0] = $value = int $value; 792 $CFG->{mapsize} = $self->{range}[0] = $value = int $value;
765 }, 793 },
766 ); 794 );
773 . "This might increase or create lag, but increases the chances " 801 . "This might increase or create lag, but increases the chances "
774 . "of faces being ready for display when you encounter them. " 802 . "of faces being ready for display when you encounter them. "
775 . "It also uses up server bandwidth on every connect, " 803 . "It also uses up server bandwidth on every connect, "
776 . "so only set it if you really need to prefetch images. " 804 . "so only set it if you really need to prefetch images. "
777 . "This option can be set and unset any time.", 805 . "This option can be set and unset any time.",
778 connect_changed => sub { $CFG->{face_prefetch} = $_[1] }, 806 on_changed => sub { $CFG->{face_prefetch} = $_[1] },
779 ); 807 );
780 808
781 $table->add (0, 9, new CFClient::UI::Label valign => 0, align => 1, text => "Output-Count"); 809 $table->add (0, 9, new CFClient::UI::Label valign => 0, align => 1, text => "Output-Count");
782 $table->add (1, 9, new CFClient::UI::Entry 810 $table->add (1, 9, new CFClient::UI::Entry
783 text => $CFG->{output_count}, 811 text => $CFG->{output_count},
784 tooltip => "Should be set to 1 unless you know what you are doing. This option is only used once at log-in.", 812 tooltip => "Should be set to 1 unless you know what you are doing. This option is only used once at log-in.",
785 connect_changed => sub { $CFG->{output_count} = $_[1] }, 813 on_changed => sub { $CFG->{output_count} = $_[1] },
786 ); 814 );
787 815
788 $table->add (0, 10, new CFClient::UI::Label valign => 0, align => 1, text => "Output-Sync"); 816 $table->add (0, 10, new CFClient::UI::Label valign => 0, align => 1, text => "Output-Sync");
789 $table->add (1, 10, new CFClient::UI::Entry 817 $table->add (1, 10, new CFClient::UI::Entry
790 text => $CFG->{output_sync}, 818 text => $CFG->{output_sync},
791 tooltip => "Should be set to 1 unless you know what you are doing. This option is only used once at log-in.", 819 tooltip => "Should be set to 1 unless you know what you are doing. This option is only used once at log-in.",
792 connect_changed => sub { $CFG->{output_sync} = $_[1] }, 820 on_changed => sub { $CFG->{output_sync} = $_[1] },
793 ); 821 );
794 822
795 $table->add (1, 11, $LOGIN_BUTTON = new CFClient::UI::Button 823 $table->add (1, 11, $LOGIN_BUTTON = new CFClient::UI::Button
796 expand => 1, 824 expand => 1,
797 align => 0, 825 align => 0,
798 text => "Login", 826 text => "Login",
799 connect_activate => sub { 827 on_activate => sub {
800 $CONN ? stop_game 828 $CONN ? stop_game
801 : start_game; 829 : start_game;
802 }, 830 },
803 ); 831 );
804 832
805 $dialog 833 $dialog
806} 834}
807 835
808sub message_window { 836sub message_window {
809 my $window = new CFClient::UI::FancyFrame 837 my $window = new CFClient::UI::FancyFrame
838 name => "message_window",
810 title => "Messages", 839 title => "Messages",
811 border_bg => [1, 1, 1, 1], 840 border_bg => [1, 1, 1, 1],
812 bg => [0, 0, 0, 0.75], 841 bg => [0, 0, 0, 0.75],
842 req_x => -1,
843 req_y => 0,
813 user_w => int $::WIDTH / 3, 844 def_w => int $::WIDTH / 3,
814 user_h => int $::HEIGHT / 5, 845 def_h => int $::HEIGHT / 5,
815 child => (my $vbox = new CFClient::UI::VBox); 846 child => (my $vbox = new CFClient::UI::VBox);
816 847
817 $vbox->add ($LOGVIEW); 848 $vbox->add ($LOGVIEW);
818 849
819 $vbox->add (my $input = new CFClient::UI::Entry 850 $vbox->add (my $input = new CFClient::UI::Entry
820 tooltip => "<b>Chat Box</b>. If you enter a text and press return/enter here, the current <i>communication command</i> " 851 tooltip => "<b>Chat Box</b>. If you enter a text and press return/enter here, the current <i>communication command</i> "
821 . "from the client setup will be prepended (e.g. <b>shout</b>, <b>chat</b>...). " 852 . "from the client setup will be prepended (e.g. <b>shout</b>, <b>chat</b>...). "
822 . "If you prepend a slash (/), you will submit a command instead (similar to IRC). " 853 . "If you prepend a slash (/), you will submit a command instead (similar to IRC). "
823 . "A better way to submit commands (and the occasional chat command) is often the map command completer.", 854 . "A better way to submit commands (and the occasional chat command) is often the map command completer.",
824 connect_focus_in => sub { 855 on_focus_in => sub {
825 my ($input, $prev_focus) = @_; 856 my ($input, $prev_focus) = @_;
826 857
827 delete $input->{refocus_map}; 858 delete $input->{refocus_map};
828 859
829 if ($prev_focus == $MAPWIDGET && $input->{auto_activated}) { 860 if ($prev_focus == $MAPWIDGET && $input->{auto_activated}) {
830 $input->{refocus_map} = 1; 861 $input->{refocus_map} = 1;
831 } 862 }
832 delete $input->{auto_activated}; 863 delete $input->{auto_activated};
833 }, 864 },
834 connect_activate => sub { 865 on_activate => sub {
835 my ($input, $text) = @_; 866 my ($input, $text) = @_;
836 $input->set_text (''); 867 $input->set_text ('');
837 868
838 if ($text =~ /^\/(.*)/) { 869 if ($text =~ /^\/(.*)/) {
839 $::CONN->user_send ($1); 870 $::CONN->user_send ($1);
844 if ($input->{refocus_map}) { 875 if ($input->{refocus_map}) {
845 delete $input->{refocus_map}; 876 delete $input->{refocus_map};
846 $MAPWIDGET->focus_in 877 $MAPWIDGET->focus_in
847 } 878 }
848 }, 879 },
849 connect_escape => sub { 880 on_escape => sub {
850 $MAPWIDGET->focus_in 881 $MAPWIDGET->focus_in
851 }, 882 },
852 ); 883 );
853 884
854 $CONSOLE = { 885 $CONSOLE = {
859 $window 890 $window
860} 891}
861 892
862sub open_quit_dialog { 893sub open_quit_dialog {
863 unless ($QUIT_DIALOG) { 894 unless ($QUIT_DIALOG) {
864
865 $QUIT_DIALOG = new CFClient::UI::FancyFrame title => "Really Quit?"; 895 $QUIT_DIALOG = new CFClient::UI::FancyFrame title => "Really Quit?";
866 896
867 $QUIT_DIALOG->add (my $vb = new CFClient::UI::VBox expand => 1); 897 $QUIT_DIALOG->add (my $vb = new CFClient::UI::VBox expand => 1);
868 898
869 $vb->add (new CFClient::UI::Label 899 $vb->add (new CFClient::UI::Label
873 ); 903 );
874 $vb->add (my $hb = new CFClient::UI::HBox expand => 1); 904 $vb->add (my $hb = new CFClient::UI::HBox expand => 1);
875 $hb->add (new CFClient::UI::Button 905 $hb->add (new CFClient::UI::Button
876 text => "Ok", 906 text => "Ok",
877 expand => 1, 907 expand => 1,
878 connect_activate => sub { $QUIT_DIALOG->hide }, 908 on_activate => sub { $QUIT_DIALOG->hide },
879 ); 909 );
880 $hb->add (new CFClient::UI::Button 910 $hb->add (new CFClient::UI::Button
881 text => "Quit anyway", 911 text => "Quit anyway",
882 expand => 1, 912 expand => 1,
883 connect_activate => sub { exit }, 913 on_activate => sub { exit },
884 ); 914 );
915 }
885 916
917 $QUIT_DIALOG->show;
886 $QUIT_DIALOG->show_centered; 918 $QUIT_DIALOG->center;
887 } else {
888 $QUIT_DIALOG->show_centered;
889 }
890} 919}
891 920
892sub make_inventory_window { 921sub make_inventory_window {
893 my $invwin = new CFClient::UI::FancyFrame 922 my $invwin = $INV_WINDOW = new CFClient::UI::FancyFrame
894 user_w => $WIDTH * (7/8), user_h => $HEIGHT * (7/8), title => "Inventory"; 923 def_w => $WIDTH * 7/8,
924 def_h => $HEIGHT * 7/8,
925 title => "Inventory",
926 name => "inventory_window",
927 on_visibility_change => sub {
928 my ($self, $visible) = @_;
929 $self->center if $visible;
930 },
931 ;
895 932
896 $invwin->add (my $hb = new CFClient::UI::HBox expand => 1); 933 $invwin->add (my $hb = new CFClient::UI::HBox homogeneous => 1);
897 934
898 $hb->add (my $vb1 = new CFClient::UI::VBox expand => 1); 935 $hb->add (my $vb1 = new CFClient::UI::VBox);
899 $vb1->add (my $lbl = new CFClient::UI::Label xalign => 0.5); 936 $vb1->add (new CFClient::UI::Label align => 0, text => "Player");
900 $lbl->set_text ("Player");
901 $vb1->add ($INV = new CFClient::UI::Inventory expand => 1); 937 $vb1->add ($INV = new CFClient::UI::Inventory expand => 1);
902 938
903 $hb->add (my $vb2 = new CFClient::UI::VBox expand => 1); 939 $hb->add (my $vb2 = new CFClient::UI::VBox);
940
941 $vb2->add (my $hb2 = new CFClient::UI::HBox);
904 $vb2->add ($INVR_LBL = new CFClient::UI::Label xalign => 0.5); 942 $hb2->add ($INVR_LBL = new CFClient::UI::Label align => 0, expand => 1, text => "Floor");
905 $INVR_LBL->set_text ("Floor"); 943 $hb2->add (new CFClient::UI::Button
944 text => "Close",
945 tooltip => "Close the currently open container (if one is open)",
946 on_activate => sub {
947 $CONN->send ("apply $CONN->{open_container}")
948 if $CONN->{open_container} != 0;
949 },
950 );
951
906 $vb2->add ($INVR = new CFClient::UI::Inventory expand => 1); 952 $vb2->add ($INVR = new CFClient::UI::Inventory expand => 1);
907 953
908 $invwin 954 $invwin
909} 955}
910 956
911sub make_help_window { 957sub make_help_window {
912 my $win = new CFClient::UI::FancyFrame 958 my $win = new CFClient::UI::FancyFrame
913 user_w => $WIDTH * (7/8), user_h => $HEIGHT * (7/8), title => "Documentation"; 959 def_w => int $WIDTH * 7/8,
960 def_h => int $HEIGHT * 7/8,
961 title => "Documentation";
914 962
915 $win->add (my $vbox = new CFClient::UI::VBox); 963 $win->add (my $vbox = new CFClient::UI::VBox);
916 964
917 $vbox->add (my $buttons = new CFClient::UI::HBox); 965 $vbox->add (my $buttons = new CFClient::UI::HBox);
918 $vbox->add (my $viewer = new CFClient::UI::TextView expand => 1, fontsize => 0.8); 966 $vbox->add (my $viewer = new CFClient::UI::TextView expand => 1, fontsize => 0.8);
925 ) { 973 ) {
926 my ($pod, $label) = @$_; 974 my ($pod, $label) = @$_;
927 975
928 $buttons->add (new CFClient::UI::Button 976 $buttons->add (new CFClient::UI::Button
929 text => $label, 977 text => $label,
930 connect_activate => sub { 978 on_activate => sub {
931 my $parser = new Pod::POM; 979 my $parser = new Pod::POM;
932 my $pom = $parser->parse_file (CFClient::find_rcfile "pod/$pod.pod"); 980 my $pom = $parser->parse_file (CFClient::find_rcfile "pod/$pod.pod");
933 981
934 $viewer->clear; 982 $viewer->clear;
935 983
966 or die "SDL_SetVideoMode failed: " . (CFClient::SDL_GetError) . "\n"; 1014 or die "SDL_SetVideoMode failed: " . (CFClient::SDL_GetError) . "\n";
967 1015
968 $SDL_ACTIVE = 1; 1016 $SDL_ACTIVE = 1;
969 $LAST_REFRESH = time - 0.01; 1017 $LAST_REFRESH = time - 0.01;
970 1018
971 CFClient::gl_init; 1019 CFClient::OpenGL::init;
972 1020
973 $FONTSIZE = int $HEIGHT / 40 * $CFG->{gui_fontsize}; 1021 $FONTSIZE = int $HEIGHT / 40 * $CFG->{gui_fontsize};
974 1022
975 $CFClient::UI::ROOT->configure (0, 0, $WIDTH, $HEIGHT);#d# 1023 $CFClient::UI::ROOT->configure (0, 0, $WIDTH, $HEIGHT);#d#
976 1024
1043 tooltip => "Toggles the inventory window, where you can manage your loot (or treaures :)."); 1091 tooltip => "Toggles the inventory window, where you can manage your loot (or treaures :).");
1044 1092
1045 $BUTTONBAR->add (new CFClient::UI::Button 1093 $BUTTONBAR->add (new CFClient::UI::Button
1046 text => "Save Config", 1094 text => "Save Config",
1047 tooltip => "Saves the options chosen in the client setting, server settings and the window layout to be restored on later runs.", 1095 tooltip => "Saves the options chosen in the client setting, server settings and the window layout to be restored on later runs.",
1048 connect_activate => sub { 1096 on_activate => sub {
1097 $::CFG->{layout} = CFClient::UI::get_layout;
1049 CFClient::write_cfg "$Crossfire::VARDIR/pclientrc"; 1098 CFClient::write_cfg "$Crossfire::VARDIR/pclientrc";
1050 status "Configuration Saved"; 1099 status "Configuration Saved";
1051 }, 1100 },
1052 ); 1101 );
1053 1102
1054 $BUTTONBAR->add (new CFClient::UI::Flopper text => "Help!", other => make_help_window, 1103 $BUTTONBAR->add (new CFClient::UI::Flopper text => "Help!", other => make_help_window,
1055 tooltip => "View Documentation"); 1104 tooltip => "View Documentation");
1056 1105
1057 $BUTTONBAR->add (new CFClient::UI::Button 1106 $BUTTONBAR->add (new CFClient::UI::Button
1058 text => "Quit", 1107 text => "Quit",
1059 tooltip => "Terminates the program", 1108 tooltip => "Terminates the program",
1060 connect_activate => sub { 1109 on_activate => sub {
1061 if ($CONN) { 1110 if ($CONN) {
1062 open_quit_dialog; 1111 open_quit_dialog;
1063 } else { 1112 } else {
1064 exit; 1113 exit;
1065 } 1114 }
1068 1117
1069 $BUTTONBAR->show; 1118 $BUTTONBAR->show;
1070 1119
1071 $STATUSBOX->add ("Set video mode $WIDTH×$HEIGHT", timeout => 10, fg => [1, 1, 1, 0.5]); 1120 $STATUSBOX->add ("Set video mode $WIDTH×$HEIGHT", timeout => 10, fg => [1, 1, 1, 0.5]);
1072 1121
1073 # delay till geometry is constant 1122 $SERVER_SETUP->show;
1074 $CFClient::UI::ROOT->on_post_alloc (startup => sub {
1075 $BUTTONBAR->{children}[1]->emit ("activate"); # pop up server setup
1076 my $widget = $GAUGES->{win};
1077 $widget->move (0, $HEIGHT - $widget->{h});#d# to in toplevel
1078 });
1079 force_refresh ();
1080 } 1123 }
1081} 1124}
1082 1125
1083sub video_shutdown { 1126sub video_shutdown {
1084 undef $SDL_ACTIVE; 1127 undef $SDL_ACTIVE;
1245sub animation_stop { 1288sub animation_stop {
1246 my ($widget) = @_; 1289 my ($widget) = @_;
1247 delete $animate_object{$widget}; 1290 delete $animate_object{$widget};
1248} 1291}
1249 1292
1250@conn::ISA = Crossfire::Protocol::;
1251
1252sub conn::new {
1253 my $class = shift;
1254
1255 my $self = $class->Crossfire::Protocol::new (@_);
1256
1257 $MAPWIDGET->clr_commands;
1258
1259 my $parser = new Pod::POM;
1260 my $pod = $parser->parse_file (CFClient::find_rcfile "pod/command_help.pod");
1261
1262 for my $head2 ($pod->head1->[-2]->head2) {
1263 $head2->title =~ /^(\S+) (?:\s+ \( ([^\)]*) \) )?/x
1264 or next;
1265
1266 my $cmd = $1;
1267 my @args = split /\|/, $2;
1268 @args = (".*") unless @args;
1269
1270 my $text = CFClient::pod_to_pango $head2->content;
1271
1272 for my $arg (@args) {
1273 $arg = $arg eq ".*" ? "" : " $arg";
1274
1275 $MAPWIDGET->add_command ("$cmd$arg", $text);
1276 }
1277 }
1278
1279 $self->{noface} = new_from_file CFClient::Texture
1280 CFClient::find_rcfile "noface.png", minify => 1, mipmap => 1;
1281
1282 $self->{open_container} = 0;
1283
1284 $self
1285}
1286
1287sub conn::stats_update {
1288 my ($self, $stats) = @_;
1289
1290 if (my $exp = $stats->{Crossfire::Protocol::CS_STAT_EXP64}) {
1291 my $diff = $exp - $self->{prev_exp};
1292 $STATUSBOX->add ("$diff experience gained", group => "experience $diff", fg => [0.5, 1, 0.5, 0.8], timeout => 5)
1293 if exists $self->{prev_exp} && $diff;
1294 $self->{prev_exp} = $exp;
1295 }
1296
1297 update_stats_window ($stats);
1298}
1299
1300sub conn::user_send {
1301 my ($self, $command) = @_;
1302
1303 $self->send_command ($command);
1304 status $command;
1305}
1306
1307sub conn::map_scroll {
1308 my ($self, $dx, $dy) = @_;
1309
1310 $MAP->scroll ($dx, $dy);
1311}
1312
1313sub conn::feed_map1a {
1314 my ($self, $data) = @_;
1315
1316# $self->Crossfire::Protocol::feed_map1a ($data);
1317
1318 $MAP->map1a_update ($data);
1319 $MAPWIDGET->update;
1320}
1321
1322sub conn::flush_map {
1323 my ($self) = @_;
1324
1325 my $map_info = delete $self->{map_info}
1326 or return;
1327
1328 my ($hash, $x, $y, $w, $h) = @$map_info;
1329
1330 my $data = $MAP->get_rect ($x, $y, $w, $h);
1331 $MAPCACHE->put ($hash => Compress::LZF::compress $data);
1332 #warn sprintf "SAVEmap[%s] length %d\n", $hash, length $data;#d#
1333}
1334
1335sub conn::map_clear {
1336 my ($self) = @_;
1337
1338 $self->flush_map;
1339 delete $self->{neigh_map};
1340
1341 $MAP->clear;
1342}
1343
1344
1345sub conn::load_map($$$) {
1346 my ($self, $hash, $x, $y) = @_;
1347
1348 if (defined (my $data = $MAPCACHE->get ($hash))) {
1349 $data = Compress::LZF::decompress $data;
1350 #warn sprintf "LOADmap[%s,%d,%d] length %d\n", $hash, $x, $y, length $data;#d#
1351 for my $id ($MAP->set_rect ($x, $y, $data)) {
1352 my $data = $TILECACHE->get ($id)
1353 or next;
1354
1355 $self->set_texture ($id => $data);
1356 }
1357 }
1358}
1359
1360# hardcode /world/world_xxx_xxx map names, the savings are enourmous,
1361# (server resource,s latency, bandwidth), so this hack is warranted.
1362# the right fix is to make real tiled maps with an overview file
1363sub conn::send_mapinfo {
1364 my ($self, $data, $cb) = @_;
1365
1366 if ($self->{map_info}[0] =~ m%^/world/world_(\d\d\d)_(\d\d\d)$%) {
1367 my ($wx, $wy) = ($1, $2);
1368
1369 if ($data =~ /^spatial ([1-4]+)$/) {
1370 my @dx = (0, 0, 1, 0, -1);
1371 my @dy = (0, -1, 0, 1, 0);
1372 my ($dx, $dy);
1373
1374 for (split //, $1) {
1375 $dx += $dx[$_];
1376 $dy += $dy[$_];
1377 }
1378
1379 $cb->(spatial => 15,
1380 $self->{map_info}[1] - $MAP->ox + $dx * 50,
1381 $self->{map_info}[2] - $MAP->oy + $dy * 50,
1382 50, 50,
1383 sprintf "/world/world_%03d_%03d", $wx + $dx, $wy + $dy
1384 );
1385
1386 return;
1387 }
1388 }
1389
1390 $self->Crossfire::Protocol::send_mapinfo ($data, $cb);
1391}
1392
1393# this method does a "flood fill" into every tile direction
1394# it assumes that tiles are arranged in a rectangular grid,
1395# i.e. a map is the same as the left of the right map etc.
1396# failure to comply are harmless and result in display errors
1397# at worst.
1398sub conn::flood_fill {
1399 my ($self, $block, $gx, $gy, $path, $hash, $flags) = @_;
1400
1401 # the server does not allow map paths > 6
1402 return if 7 <= length $path;
1403
1404 my ($x0, $y0, $x1, $y1) = @{$self->{neigh_rect}};
1405
1406 for (
1407 [1, 3, 0, -1],
1408 [2, 4, 1, 0],
1409 [3, 1, 0, 1],
1410 [4, 2, -1, 0],
1411 ) {
1412 my ($tile, $tile2, $dx, $dy) = @$_;
1413
1414 next if $block & (1 << $tile);
1415 my $block = $block | (1 << $tile2);
1416
1417 my $gx = $gx + $dx;
1418 my $gy = $gy + $dy;
1419
1420 next unless $flags & (1 << ($tile - 1));
1421 next if $self->{neigh_grid}{$gx, $gy}++;
1422
1423 my $neigh = $self->{neigh_map}{$hash} ||= [];
1424 if (my $info = $neigh->[$tile]) {
1425 my ($flags, $x, $y, $w, $h, $hash) = @$info;
1426
1427 $self->flood_fill ($block, $gx, $gy, "$path$tile", $hash, $flags)
1428 if $x >= $x0 && $x + $w < $x1 && $y >= $y0 && $y + $h < $y1;
1429
1430 } else {
1431 $self->send_mapinfo ("spatial $path$tile", sub {
1432 my ($mode, $flags, $x, $y, $w, $h, $hash) = @_;
1433
1434 return if $mode ne "spatial";
1435
1436 $x += $MAP->ox;
1437 $y += $MAP->oy;
1438
1439 $self->load_map ($hash, $x, $y)
1440 unless $self->{neigh_map}{$hash}[5]++;#d#
1441
1442 $neigh->[$tile] = [$flags, $x, $y, $w, $h, $hash];
1443
1444 $self->flood_fill ($block, $gx, $gy, "$path$tile", $hash, $flags)
1445 if $x >= $x0 && $x + $w < $x1 && $y >= $y0 && $y + $h < $y1;
1446 });
1447 }
1448 }
1449}
1450
1451sub conn::map_change {
1452 my ($self, $mode, $flags, $x, $y, $w, $h, $hash) = @_;
1453
1454 $self->flush_map;
1455
1456 my ($ox, $oy) = ($::MAP->ox, $::MAP->oy);
1457
1458 my $mapmapw = $MAPMAP->{w};
1459 my $mapmaph = $MAPMAP->{h};
1460
1461 $self->{neigh_rect} = [
1462 $ox - $mapmapw * 0.5, $oy - $mapmapw * 0.5,
1463 $ox + $mapmapw * 0.5 + $w, $oy + $mapmapw * 0.5 + $h,
1464 ];
1465
1466 delete $self->{neigh_grid};
1467
1468 $x += $ox;
1469 $y += $oy;
1470
1471 $self->{map_info} = [$hash, $x, $y, $w, $h];
1472
1473 (my $map = $hash) =~ s/^.*?\/([^\/]+)$/\1/;
1474 $STATWIDS->{map}->set_text ("Map: " . $map);
1475
1476 $self->load_map ($hash, $x, $y);
1477 $self->flood_fill (0, 0, 0, "", $hash, $flags);
1478}
1479
1480sub conn::face_find {
1481 my ($self, $facenum, $face) = @_;
1482
1483 my $hash = "$face->{chksum},$face->{name}";
1484
1485 my $id = $FACEMAP->get ($hash);
1486
1487 unless ($id) {
1488 # create new id for face
1489 # I love transactions
1490 for (1..100) {
1491 my $txn = $CFClient::DB_ENV->txn_begin;
1492 my $status = $FACEMAP->db_get (id => $id, BerkeleyDB::DB_RMW);
1493 if ($status == 0 || $status == BerkeleyDB::DB_NOTFOUND) {
1494 $id = ($id || 16) + 1;
1495 if ($FACEMAP->put (id => $id) == 0
1496 && $FACEMAP->put ($hash => $id) == 0) {
1497 $txn->txn_commit;
1498
1499 goto gotid;
1500 }
1501 }
1502 $txn->abort;
1503 }
1504
1505 CFClient::fatal "maximum number of transaction retries reached - database problems?";
1506 }
1507
1508gotid:
1509 $face->{id} = $id;
1510 $MAP->set_face ($facenum => $id);
1511 $self->{faceid}[$facenum] = $id;#d#
1512
1513 my $face = $TILECACHE->get ($id);
1514
1515 if ($face) {
1516 #$self->face_prefetch;
1517 $face
1518 } else {
1519 my $tex = $self->{noface};
1520 $MAP->set_texture ($id, @$tex{qw(name w h s t)}, @{$tex->{minified}});
1521 undef
1522 };
1523}
1524
1525sub conn::face_update {
1526 my ($self, $facenum, $face) = @_;
1527
1528 $TILECACHE->put ($face->{id} => $face->{image}); #TODO: try to avoid duplicate writes
1529
1530 $self->set_texture ($face->{id} => delete $face->{image});
1531}
1532
1533sub conn::set_texture {
1534 my ($self, $id, $data) = @_;
1535
1536 $self->{texture}[$id] ||= do {
1537 my $tex =
1538 new_from_image CFClient::Texture
1539 $data, minify => 1, mipmap => 1;
1540
1541 $MAP->set_texture ($id, @$tex{qw(name w h s t)}, @{$tex->{minified}});
1542 $MAPWIDGET->update;
1543
1544 $tex
1545 };
1546}
1547
1548sub conn::sound_play {
1549 my ($self, $x, $y, $soundnum, $type) = @_;
1550
1551 $SDL_MIXER
1552 or return;
1553
1554 my $chunk = $AUDIO_CHUNKS{$SOUNDS[$soundnum]}
1555 or return;
1556
1557 $chunk->play;
1558# warn "sound $x,$y,$soundnum,$type\n";#d#
1559}
1560
1561my $LAST_QUERY; # server is stupid, stupid, stupid
1562
1563sub conn::query {
1564 my ($self, $flags, $prompt) = @_;
1565
1566 $prompt = $LAST_QUERY unless length $prompt;
1567 $LAST_QUERY = $prompt;
1568
1569 my $dialog = new CFClient::UI::FancyFrame
1570 title => "Query",
1571 child => my $vbox = new CFClient::UI::VBox;
1572
1573 $vbox->add (new CFClient::UI::Label
1574 max_w => $::WIDTH * 0.4,
1575 ellipsise => 0,
1576 text => $prompt);
1577
1578 if ($flags & Crossfire::Protocol::CS_QUERY_YESNO) {
1579 $vbox->add (my $hbox = new CFClient::HBox);
1580 $hbox->add (new CFClient::Button
1581 text => "No",
1582 connect_activate => sub {
1583 $self->send ("reply n");
1584 $dialog->destroy;
1585 $MAPWIDGET->focus_in;
1586 }
1587 );
1588 $hbox->add (new CFClient::Button
1589 text => "Yes",
1590 connect_activate => sub {
1591 $self->send ("reply y");
1592 $dialog->destroy;
1593 },
1594 );
1595
1596 $dialog->focus_in;
1597
1598 } elsif ($flags & Crossfire::Protocol::CS_QUERY_SINGLECHAR) {
1599 $dialog->{tooltip} = "Press a key (click on the entry to make sure it has keyboard focus)";
1600 $vbox->add (my $entry = new CFClient::UI::Entry
1601 connect_changed => sub {
1602 $self->send ("reply $_[1]");
1603 $dialog->destroy;
1604 },
1605 );
1606
1607 $entry->focus_in;
1608
1609 } else {
1610 $dialog->{tooltip} = "Enter the reply and press return (click on the entry to make sure it has keyboard focus)";
1611
1612 $vbox->add (my $entry = new CFClient::UI::Entry
1613 $flags & Crossfire::Protocol::CS_QUERY_HIDEINPUT ? (hiddenchar => "*") : (),
1614 connect_activate => sub {
1615 $self->send ("reply $_[1]");
1616 $dialog->destroy;
1617 },
1618 );
1619
1620 $entry->focus_in;
1621 }
1622
1623 $dialog->show_centered;
1624}
1625
1626sub conn::drawinfo {
1627 my ($self, $color, $text) = @_;
1628
1629 my @color = (
1630 [1.00, 1.00, 1.00], #[0.00, 0.00, 0.00],
1631 [1.00, 1.00, 1.00],
1632 [0.50, 0.50, 1.00], #[0.00, 0.00, 0.55]
1633 [1.00, 0.00, 0.00],
1634 [1.00, 0.54, 0.00],
1635 [0.11, 0.56, 1.00],
1636 [0.93, 0.46, 0.00],
1637 [0.18, 0.54, 0.34],
1638 [0.56, 0.73, 0.56],
1639 [0.80, 0.80, 0.80],
1640 [0.55, 0.41, 0.13],
1641 [0.99, 0.77, 0.26],
1642 [0.74, 0.65, 0.41],
1643 );
1644
1645 my $time = sprintf "%02d:%02d:%02d", (localtime time)[2,1,0];
1646
1647 $text = CFClient::UI::Label::escape $text;
1648 $text =~ s/\[b\](.*?)\[\/b\]/<b>\1<\/b>/g;
1649 $text =~ s/\[color=(.*?)\](.*?)\[\/color\]/<span foreground='\1'>\2<\/span>/g;
1650
1651 $LOGVIEW->add_paragraph ($color[$color],
1652 join "\n", map "$time $_", split /\n/, $text);
1653
1654 $STATUSBOX->add ($text,
1655 group => $text,
1656 fg => $color[$color],
1657 timeout => 10,
1658 tooltip_font => $::FONT_FIXED,
1659 );
1660}
1661
1662sub conn::drawextinfo {
1663 my ($self, $color, $type, $subtype, $message) = @_;
1664
1665 $self->drawinfo ($color, $message);
1666}
1667
1668sub conn::spell_add {
1669 my ($self, $spell) = @_;
1670
1671 # TODO
1672 # create a widget dynamically, using spell face (CF::Protocol downloads them)
1673 $MAPWIDGET->add_command ("invoke $spell->{name}", CFClient::UI::Label::escape $spell->{message});
1674 $MAPWIDGET->add_command ("cast $spell->{name}", CFClient::UI::Label::escape $spell->{message});
1675}
1676
1677sub conn::spell_delete {
1678 my ($self, $spell) = @_;
1679}
1680
1681sub conn::addme_success {
1682 my ($self) = @_;
1683
1684 $self->send ("command output-sync $CFG->{output_sync}");
1685 $self->send ("command output-count $CFG->{output_count}");
1686
1687 my $parser = new Pod::POM;
1688 my $pod = $parser->parse_file (CFClient::find_rcfile "pod/skill_help.pod");
1689
1690 my %skill_tooltip;
1691
1692 for my $head2 ($pod->head1->[-2]->head2) {
1693 $skill_tooltip{$head2->title} = CFClient::pod_to_pango $head2->content;
1694 }
1695
1696 for my $skill (values %{$self->{skill_info}}) {
1697 $MAPWIDGET->add_command ("ready_skill $skill",
1698 (CFClient::UI::Label::escape "Ready the skill '$skill'\n\n")
1699 . $skill_tooltip{$skill});
1700 $MAPWIDGET->add_command ("use_skill $skill",
1701 (CFClient::UI::Label::escape "Immediately use the skill '$skill'\n\n")
1702 . $skill_tooltip{$skill});
1703 }
1704}
1705
1706sub conn::eof {
1707 $MAPWIDGET->clr_commands;
1708
1709 stop_game;
1710}
1711
1712sub conn::image_info {
1713 my ($self, $numfaces) = @_;
1714
1715 $self->{num_faces} = $numfaces;
1716 $self->{face_prefetch} = [1 .. $numfaces];
1717 $self->face_prefetch;
1718}
1719
1720sub conn::face_prefetch {
1721 my ($self) = @_;
1722
1723 return unless $CFG->{face_prefetch};
1724
1725 if ($self->{num_faces}) {
1726 return if @{ $self->{send_queue} || [] };
1727 my $todo = @{ $self->{face_prefetch} }
1728 or return;
1729
1730 my ($face) = splice @{ $self->{face_prefetch} }, + rand @{ $self->{face_prefetch} }, 1, ();
1731
1732 $self->send ("requestinfo image_sums $face $face");
1733
1734 $STATUSBOX->add (CFClient::UI::Label::escape "prefetching $todo",
1735 group => "prefetch", timeout => 2, fg => [1, 1, 0, 0.5]);
1736 } elsif (!exists $self->{num_faces}) {
1737 $self->send ("requestinfo image_info");
1738
1739 $self->{num_faces} = 0;
1740
1741 $STATUSBOX->add (CFClient::UI::Label::escape "starting to prefetch",
1742 group => "prefetch", timeout => 2, fg => [1, 1, 0, 0.5]);
1743 }
1744}
1745
1746# check once/second for faces that need to be prefetched 1293# check once/second for faces that need to be prefetched
1747# this should, of course, only run on demand, but 1294# this should, of course, only run on demand, but
1748# SDL forces worse things on us.... 1295# SDL forces worse things on us....
1749 1296
1750Event->timer (after => 1, interval => 0.25, cb => sub { 1297Event->timer (after => 1, interval => 0.25, cb => sub {
1751 $CONN->face_prefetch 1298 $CONN->face_prefetch
1752 if $CONN; 1299 if $CONN;
1753}); 1300});
1754
1755sub update_floorbox {
1756 $CFClient::UI::ROOT->on_refresh ($FLOORBOX => sub {
1757 return unless $CONN;
1758
1759 $FLOORBOX->clear;
1760
1761 my $row;
1762 for (@{ $CONN->{container}{0} }) {
1763 if ($row < 7) {
1764 local $_->{face_widget}; # hack to force recreation of widget
1765 local $_->{desc_widget}; # hack to force recreation of widget
1766 CFClient::Item::update_widgets $_;
1767
1768 $FLOORBOX->add (0, $row, $_->{face_widget});
1769 $FLOORBOX->add (1, $row, $_->{desc_widget});
1770
1771 $row++;
1772 } else {
1773 $FLOORBOX->add (1, $row, new CFClient::UI::Label text => "More...");
1774 last;
1775 }
1776 }
1777 });
1778
1779 $WANT_REFRESH++;
1780}
1781
1782sub set_opencont {
1783 my ($conn, $tag, $name) = @_;
1784 $conn->{open_container} = $tag;
1785 $INVR_LBL->set_text ($name);
1786 $INVR->set_items ($conn->{container}{$tag});
1787}
1788
1789sub update_container {
1790 my ($tag) = @_;
1791 $INVR->set_items ($::CONN->{container}{$CONN->{open_container}})
1792 if $tag == $CONN->{open_container};
1793}
1794
1795sub conn::container_add {
1796 my ($self, $tag, $items) = @_;
1797
1798 #d# print "container_add: container $tag ($self->{player}{tag})\n";
1799
1800 if ($tag == 0) {
1801 update_floorbox;
1802 update_container (0);
1803 } elsif ($tag == $self->{player}{tag}) {
1804 $INV->set_items ($self->{container}{$self->{player}{tag}})
1805 } else {
1806 update_container ($tag);
1807 }
1808
1809 # $self-<{player}{tag} => player inv
1810 #use PApp::Util; warn PApp::Util::dumpval $self->{container}{$self->{player}{tag}};
1811}
1812
1813sub conn::container_clear {
1814 my ($self, $tag) = @_;
1815
1816 #d# print "container_clear: container $tag ($self->{player}{tag})\n";
1817
1818 if ($tag == 0) {
1819 update_floorbox;
1820 update_container (0);
1821 } elsif ($tag == $self->{player}{tag}) {
1822 $INV->set_items ($self->{container}{$tag})
1823 }
1824
1825# use PApp::Util; warn PApp::Util::dumpval $self->{container}{0};
1826}
1827
1828sub conn::item_delete {
1829 my ($self, @items) = @_;
1830
1831 for (@items) {
1832 #d# print "item_delete: $_->{tag} from $_->{container} ($self->{player}{tag})\n";
1833
1834 if ($_->{container} == 0) {
1835 update_floorbox;
1836 update_container ($_->{tag});
1837 } elsif ($_->{container} == $self->{player}{tag}) {
1838 $INV->set_items ($self->{container}{$self->{player}{tag}})
1839 } else {
1840 update_container ($_->{tag});
1841 }
1842 }
1843}
1844
1845sub conn::item_update {
1846 my ($self, $item) = @_;
1847
1848 #d# print "item_update: $item->{tag} in $item->{container} ($self->{player}{tag}) ($CONN->{open_container})\n";
1849
1850 if ($item->{tag} == $self->{player}{tag}) {
1851 $STATWIDS->{weight}->set_text (sprintf "Weight: %.1fkg", $item->{weight} / 1000);
1852 return
1853 }
1854
1855 CFClient::Item::update_widgets $item;
1856
1857 if ($item->{tag} == $CONN->{open_container} && not ($item->{flags} & Crossfire::Protocol::F_OPEN)) {
1858 set_opencont ($CONN, 0, "Floor");
1859
1860 } elsif ($item->{flags} & Crossfire::Protocol::F_OPEN) {
1861 set_opencont ($CONN, $item->{tag}, CFClient::Item::desc_string $item);
1862 } else {
1863 if ($item->{container} == 0) {
1864 update_floorbox;
1865 update_container (0);
1866 } elsif ($item->{container} == $self->{player}{tag}) {
1867 $INV->set_items ($self->{container}{$item->{container}})
1868 }
1869 }
1870}
1871 1301
1872%SDL_CB = ( 1302%SDL_CB = (
1873 CFClient::SDL_QUIT => sub { 1303 CFClient::SDL_QUIT => sub {
1874 Event::unloop -1; 1304 Event::unloop -1;
1875 }, 1305 },
1910 1340
1911{ 1341{
1912 local $SIG{__DIE__} = sub { CFClient::fatal $_[0] }; 1342 local $SIG{__DIE__} = sub { CFClient::fatal $_[0] };
1913 1343
1914 CFClient::read_cfg "$Crossfire::VARDIR/pclientrc"; 1344 CFClient::read_cfg "$Crossfire::VARDIR/pclientrc";
1915 1345 CFClient::UI::set_layout ($::CFG->{layout});
1916 $TILECACHE = CFClient::db_table "tilecache";
1917 $FACEMAP = CFClient::db_table "facemap";
1918 1346
1919 my %DEF_CFG = ( 1347 my %DEF_CFG = (
1920 sdl_mode => 0, 1348 sdl_mode => 0,
1921 width => 640, 1349 width => 640,
1922 height => 480, 1350 height => 480,

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines