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.192 by root, Mon Jul 30 02:16:16 2007 UTC vs.
Revision 1.205 by root, Thu Aug 9 03:40:02 2007 UTC

144our $SETUP_KEYBOARD; 144our $SETUP_KEYBOARD;
145 145
146our $PL_NOTEBOOK; 146our $PL_NOTEBOOK;
147our $PL_WINDOW; 147our $PL_WINDOW;
148 148
149our $MUSIC_PLAYING_WIDGET;
150our $LICENSE_WIDGET;
151
149our $INVENTORY_PAGE; 152our $INVENTORY_PAGE;
150our $STATS_PAGE; 153our $STATS_PAGE;
151our $SKILL_PAGE; 154our $SKILL_PAGE;
152our $SPELL_PAGE; 155our $SPELL_PAGE;
153our $SPELL_LIST; 156our $SPELL_LIST;
159our $STATWIDS; 162our $STATWIDS;
160 163
161our $SDL_ACTIVE; 164our $SDL_ACTIVE;
162our %SDL_CB; 165our %SDL_CB;
163 166
167our $ALT_ENTER_MESSAGE;
168our $STATUSBOX;
169our $DEBUG_STATUS;
170
171our $INV;
172our $INVR;
173our $INV_RIGHT_HB;
174
175our $PICKUP_CFG;
176
177#############################################################################
178
179sub status {
180 $STATUSBOX->add (CFPlus::asxml $_[0], pri => -10, group => "status", timeout => 10, fg => [1, 1, 0, 1]);
181}
182
183sub debug {
184 $DEBUG_STATUS->set_text ($_[0]);
185}
186
187sub message {
188 my ($para) = @_;
189 $MESSAGE_WINDOW->message ($para);
190}
191
192#############################################################################
193#TODO: maybe move into own audio module...
194
164our $SDL_MIXER; 195our $SDL_MIXER;
196
165our $MUSIC_DEFAULT = "in_a_heartbeat.ogg"; 197our $MUSIC_DEFAULT = "in_a_heartbeat.ogg";
166our @MUSIC_WANT; 198our $MUSIC_WANT; # arryref of ambient music we want to play
199our @MUSIC_HAVE; # ambient music we have on disk
167our $MUSIC_START; 200our $MUSIC_START;
201our @MUSIC_JINGLE; # which jingles to play next
168our $MUSIC_PLAYING_DATA; 202our $MUSIC_PLAYING_DATA;
169our $MUSIC_PLAYING_META; 203our $MUSIC_PLAYING_META;
170our $MUSIC_PLAYER; 204our $MUSIC_PLAYER;
171our $MUSIC_RESUME = 30; # resume music when players less than these many seconds before 205our $MUSIC_RESUME = 30; # resume music when played less than these many seconds before
172our @SOUNDS; # event => file mapping 206
173our %AUDIO_CHUNKS; # audio files 207our %AUDIO_CHUNK; # audio "files"
208our %AUDIO_PLAY; # which audio faces should be played
174 209
175our $ALT_ENTER_MESSAGE; 210sub audio_channel_finished {
176our $STATUSBOX; 211 my ($channel) = @_;
177our $DEBUG_STATUS;
178 212
179our $INV; 213# warn "channel $channel finished\n";#d#
180our $INVR;
181our $INV_RIGHT_HB;
182
183our $PICKUP_CFG;
184
185sub status {
186 $STATUSBOX->add (CFPlus::asxml $_[0], pri => -10, group => "status", timeout => 10, fg => [1, 1, 0, 1]);
187} 214}
188 215
189sub debug { 216sub audio_sound_push($) {
190 $DEBUG_STATUS->set_text ($_[0]);
191}
192
193sub message {
194 my ($para) = @_; 217 my ($face) = @_;
195 $MESSAGE_WINDOW->message ($para); 218
219 $CFG->{effects_enable}
220 or return;
221
222 if (my $chunk = $AUDIO_CHUNK{$face}) {
223 for (grep $_->[0] >= Event::time, @{(delete $AUDIO_PLAY{$face}) || []}) {
224 my (undef, $dx, $dy, $vol) = @$_;
225
226 my $channel = CFPlus::Channel::find;
227 $channel->volume ($vol * $CFG->{effects_volume} * 128 / 255);
228 $dx = $dx / 10 * 255;
229 $channel->set_panning (255 - $dx, 255 + $dx);
230
231# my $angle = $dx ? : $dx < 0 ?
232# my $distance = -$vol;
233# $channel->set_position ($angle, $distance);
234
235 $chunk->play ($channel);
236 }
237 } else {
238 # sound_meta not set means data is in flight either way
239 my $meta = $CONN->{sound_meta}{$face}
240 or return;
241
242 # if its a jingle, play it as ambient music
243 if ($meta->{meta}{jingle}) {
244 if (delete $AUDIO_PLAY{$face}) { # take the jingle out of the sound queue
245 push @MUSIC_JINGLE, $meta; # push it oto the music/jingle queue
246 &audio_music_push ($face);
247 }
248 } else {
249 # fetch from database
250 CFPlus::DB::get res_data => $meta->{name}, sub {
251 my $rwops = new CFPlus::RW $_[0];
252 my $chunk = new CFPlus::MixChunk $rwops
253 or Carp::confess "sound face " . (JSON::XS::to_json $meta) . " unloadable: " . CFPlus::Mix_GetError;
254 $chunk->volume (($meta->{meta}{volume} || 1) * 128);
255 $AUDIO_CHUNK{$face} = $chunk;
256
257 audio_sound_push ($face);
258 };
259 }
260 }
196} 261}
262
263sub audio_sound_play {
264 my ($face, $dx, $dy, $vol) = @_;
265
266 $SDL_MIXER
267 or return;
268 $CFG->{effects_enable}
269 or return;
270
271 my $queue = $AUDIO_PLAY{$face} ||= [];
272 push @$queue, [Event::time + 0.2, $dx, $dy, $vol]; # delay sound by max. 0.2s
273 audio_sound_push $face
274 unless @$queue > 1;
275}
276
277sub audio_music_set_meta {
278 my ($meta) = @_;
279
280 $MUSIC_PLAYING_META = $meta;
281 $MUSIC_PLAYING_WIDGET->set_markup (
282 "<b>Name</b>: " . (CFPlus::asxml $meta->{meta}{name}) . "\n"
283 . "<b>Author</b>: " . (CFPlus::asxml $meta->{meta}{author}) . "\n"
284 . "<b>Source</b>: " . (CFPlus::asxml $meta->{meta}{source}) . "\n"
285 . "<b>License</b>: " . (CFPlus::asxml $meta->{meta}{license})
286 );
287}
288
289sub audio_music_update_volume {
290 return unless $MUSIC_PLAYING_META;
291 my $volume = $MUSIC_PLAYING_META->{meta}{volume} || 1;
292 my $base = $MUSIC_PLAYING_META->{meta}{jingle} ? 1 : $CFG->{bgm_volume};
293 CFPlus::MixMusic::volume $base * $volume * 128;
294}
295
296sub audio_music_start {
297 my $meta = $MUSIC_PLAYING_META;
298
299 CFPlus::DB::get res_data => $meta->{name}, sub {
300 return unless $SDL_MIXER;
301
302 # music might have changed...
303 $meta eq $MUSIC_PLAYING_META
304 or return &audio_music_start ();
305
306 audio_music_update_volume;
307
308 $MUSIC_PLAYING_DATA = \$_[0];
309
310 my $rwops = $meta->{path}
311 ? new_from_file CFPlus::RW $meta->{path}
312 : new CFPlus::RW $$MUSIC_PLAYING_DATA;
313
314 $MUSIC_PLAYER = new CFPlus::MixMusic $rwops
315 or Carp::confess "music face $meta->{face} unloadable: " . CFPlus::Mix_GetError;
316
317 my $NOW = time;
318
319 if ($MUSIC_PLAYING_META->{stop_time} > $NOW - $MUSIC_RESUME) {
320 my $pos = $MUSIC_PLAYING_META->{stop_pos};
321 $MUSIC_PLAYER->fade_in_pos (0, 1000, $pos);
322 $MUSIC_START = time - $pos;
323 } else {
324 $MUSIC_PLAYER->play (0);
325 $MUSIC_START = time;
326 }
327
328 delete $meta->{stop_time};
329 delete $meta->{stop_pos};
330 }
331}
332
333sub audio_music_push {
334 return unless $SDL_MIXER;
335
336 my $fade_out;
337
338 if (@MUSIC_JINGLE) {
339 @MUSIC_HAVE = $MUSIC_JINGLE[0];
340 $fade_out = 333;
341 } else {
342 return unless $CFG->{bgm_enable};
343
344 my @have =
345 grep $_,
346 map $CONN->{music_meta}{$_},
347 @$MUSIC_WANT;
348
349 @MUSIC_HAVE = @have
350 if @have;
351
352 # default MUSIC_HAVE == MUSIC_DEFAULT
353 @MUSIC_HAVE = { path => CFPlus::find_rcfile "music/$MUSIC_DEFAULT" } unless @MUSIC_HAVE;
354 $fade_out = 1000;
355 }
356
357 # if the currently playing song is acceptable, let it continue
358 return if grep $MUSIC_PLAYING_META == $_, @MUSIC_HAVE;
359
360 my $NOW = time;
361
362 if ($MUSIC_PLAYING_META) {
363 $MUSIC_PLAYING_META->{stop_time} = $NOW;
364 $MUSIC_PLAYING_META->{stop_pos} = $NOW - $MUSIC_START;
365 CFPlus::MixMusic::fade_out $fade_out;
366 } else {
367 # sort by stop time, oldest first
368 @MUSIC_HAVE = sort { $a->{stop_time} <=> $b->{stop_time} } @MUSIC_HAVE;
369
370 # if the most recently-played piece played very recently,
371 # resume it, else choose the oldest piece for rotation.
372 audio_music_set_meta
373 $MUSIC_HAVE[-1]{stop_time} > $NOW - $MUSIC_RESUME
374 ? $MUSIC_HAVE[-1]
375 : $MUSIC_HAVE[0];
376
377 audio_music_start;
378 }
379}
380
381sub audio_music_set_ambient {
382 my ($songs) = @_;
383
384 $MUSIC_WANT = $songs;
385 audio_music_push;
386}
387
388sub audio_music_finished {
389 # we compress multiple jingles of the same type
390 shift @MUSIC_JINGLE
391 while @MUSIC_JINGLE && $MUSIC_PLAYING_META == $MUSIC_JINGLE[0];
392
393 $MUSIC_PLAYING_WIDGET->clear;
394
395 undef $MUSIC_PLAYER;
396 undef $MUSIC_PLAYING_META;
397 undef $MUSIC_PLAYING_DATA;
398
399 audio_music_push;
400}
401
402sub audio_init {
403 if ($CFG->{audio_enable}) {
404 $ENV{MIX_EFFECTSMAXSPEED} = 1;
405 $SDL_MIXER = !CFPlus::Mix_OpenAudio;
406
407 unless ($SDL_MIXER) {
408 status "Unable to open sound device: there will be no sound";
409 return;
410 }
411
412 CFPlus::Mix_AllocateChannels 16;
413
414 audio_music_finished;
415 } else {
416 undef $SDL_MIXER;
417 }
418}
419
420sub audio_shutdown {
421 undef $MUSIC_PLAYER;
422 undef $MUSIC_PLAYING_META;
423 undef $MUSIC_PLAYING_DATA;
424
425 $MUSIC_WANT = [];
426 @MUSIC_JINGLE = ();
427 %AUDIO_PLAY = ();
428 %AUDIO_CHUNK = ();
429
430 CFPlus::Mix_CloseAudio if $SDL_MIXER;
431 undef $SDL_MIXER;
432}
433
434#############################################################################
197 435
198sub destroy_query_dialog { 436sub destroy_query_dialog {
199 (delete $_[0]{query_dialog})->destroy 437 (delete $_[0]{query_dialog})->destroy
200 if $_[0]{query_dialog}; 438 if $_[0]{query_dialog};
201} 439}
481 $SETUP_DIALOG->show; 719 $SETUP_DIALOG->show;
482 $PL_WINDOW->hide; 720 $PL_WINDOW->hide;
483 $SPELL_LIST->clear_spells; 721 $SPELL_LIST->clear_spells;
484 $CFPlus::UI::ROOT->emit (stop_game => ! ! $CONN); 722 $CFPlus::UI::ROOT->emit (stop_game => ! ! $CONN);
485 723
486 &audio_music_set ([]); 724 &audio_music_set_ambient ([]);
487 725
488 return unless $CONN; 726 return unless $CONN;
489 727
490 status "connection closed"; 728 status "connection closed";
491 729
624} 862}
625 863
626sub audio_setup { 864sub audio_setup {
627 my $vbox = new CFPlus::UI::VBox; 865 my $vbox = new CFPlus::UI::VBox;
628 866
629 $vbox->add (my $table = new CFPlus::UI::Table expand => 1, col_expand => [0, 1]); 867 $vbox->add (my $table = new CFPlus::UI::Table expand => 1, col_expand => [0, 0, 1]);
630 868
631 my $row = 0; 869 my $row = 0;
632 870
633 $table->add_at (0, $row, new CFPlus::UI::Label valign => 0, align => 1, text => "Audio Enable"); 871 $table->add_at (0, $row, new CFPlus::UI::Label valign => 0, align => 1, text => "Audio Enable");
634 $table->add_at (1, $row++, new CFPlus::UI::CheckBox 872 $table->add_at (1, $row++, new CFPlus::UI::CheckBox
638 ); 876 );
639# $table->add_at (0, 9, new CFPlus::UI::Label valign => 0, align => 1, text => "Effects Volume"); 877# $table->add_at (0, 9, new CFPlus::UI::Label valign => 0, align => 1, text => "Effects Volume");
640# $table->add_at (1, 8, new CFPlus::UI::Slider range => [$CFG->{effects_volume}, 0, 128, 1], on_changed => sub { 878# $table->add_at (1, 8, new CFPlus::UI::Slider range => [$CFG->{effects_volume}, 0, 128, 1], on_changed => sub {
641# $CFG->{effects_volume} = $_[1]; 879# $CFG->{effects_volume} = $_[1];
642# }); 880# });
881
882 $table->add_at (0, $row, new CFPlus::UI::Label valign => 0, align => 1, text => "Sound Effects");
883 $table->add_at (1, $row, new CFPlus::UI::CheckBox
884 expand => 1, state => $CFG->{effects_enable},
885 tooltip => "If enabled, sound effects are enabled. If disabled, no sound effects will be played.",
886 on_changed => sub {
887 $CFG->{effects_enable} = $_[1];
888 $CONN->update_fx_want if $CONN;
889 0
890 }
891 );
892 $table->add_at (2, $row++, new CFPlus::UI::Slider
893 expand => 1, range => [$CFG->{effects_volume}, 0, 1, 0, 1/128],
894 tooltip => "The relative volume of sound effects. Best audio quality is achieved if this "
895 . "is set highest (rightmost) and you use your operating system volume setting. Changes are instant.",
896 on_changed => sub { $CFG->{effects_volume} = $_[1]; 0 }
897 );
898
643 $table->add_at (0, $row, new CFPlus::UI::Label valign => 0, align => 1, text => "Background Music"); 899 $table->add_at (0, $row, new CFPlus::UI::Label valign => 0, align => 1, text => "Background Music");
644 $table->add_at (1, $row++, my $hbox = new CFPlus::UI::HBox); 900 $table->add_at (1, $row, new CFPlus::UI::CheckBox
645 $hbox->add (new CFPlus::UI::CheckBox
646 expand => 1, state => $CFG->{bgm_enable}, 901 expand => 1, state => $CFG->{bgm_enable},
647 tooltip => "If enabled, playing of background music is enabled. If disabled, no background music will be played.", 902 tooltip => "If enabled, playing of background music is enabled. If disabled, no background music will be played.",
648 on_changed => sub { $CFG->{bgm_enable} = $_[1]; 0 } 903 on_changed => sub {
904 $CFG->{bgm_enable} = $_[1];
905 $CONN->update_fx_want if $CONN;
906 0
907 }
649 ); 908 );
650 $hbox->add (new CFPlus::UI::Slider 909 $table->add_at (2, $row++, new CFPlus::UI::Slider
651 expand => 1, range => [$CFG->{bgm_volume}, 0, 1, 0, 1/128], 910 expand => 1, range => [$CFG->{bgm_volume}, 0, 1, 0, 1/128],
652 tooltip => "The volume of the background music. Changes are instant.", 911 tooltip => "The volume of the background music. Changes are instant.",
653 on_changed => sub { $CFG->{bgm_volume} = $_[1]; CFPlus::MixMusic::volume $_[1] * 128; 0 } 912 on_changed => sub { $CFG->{bgm_volume} = $_[1]; audio_music_update_volume; 0 }
654 ); 913 );
655 914
656 $table->add_at (1, $row++, new CFPlus::UI::Button 915 $table->add_at (1, $row++, new CFPlus::UI::Button
657 expand => 1, align => 0, text => "Apply", 916 c_colspan => 2, expand => 1, align => 0, text => "Apply",
658 tooltip => "Apply the audio settings", 917 tooltip => "Apply the audio settings",
659 on_activate => sub { 918 on_activate => sub {
660 audio_shutdown (); 919 audio_shutdown ();
661 audio_init (); 920 audio_init ();
662 0 921 0
733 $table->add_at (0, 4, new CFPlus::UI::Button text => "die on click(tm)", on_activate => sub { &CFPlus::debug() } ); 992 $table->add_at (0, 4, new CFPlus::UI::Button text => "die on click(tm)", on_activate => sub { &CFPlus::debug() } );
734 993
735 $table->add_at (0, 5, new CFPlus::UI::TextEdit text => "line1\0152\0153");#d# 994 $table->add_at (0, 5, new CFPlus::UI::TextEdit text => "line1\0152\0153");#d#
736 995
737 $table->add_at (7,7, my $t = new CFPlus::UI::Table expand => 0); 996 $table->add_at (7,7, my $t = new CFPlus::UI::Table expand => 0);
738 $t->add_at (0,0, new CFPlus::UI::Label text => "a a a a", rowspan => 1, colspan => 2); 997 $t->add_at (0,0, new CFPlus::UI::Label text => "a a a a", c_rowspan => 1, c_colspan => 2);
739 $t->add_at (2,0, new CFPlus::UI::Label text => "b\nb", rowspan => 2, colspan => 1); 998 $t->add_at (2,0, new CFPlus::UI::Label text => "b\nb", c_rowspan => 2, c_colspan => 1);
740 $t->add_at (1,2, new CFPlus::UI::Label text => "c c c c", rowspan => 1, colspan => 2); 999 $t->add_at (1,2, new CFPlus::UI::Label text => "c c c c", c_rowspan => 1, c_colspan => 2);
741 $t->add_at (0,1, new CFPlus::UI::Label text => "d\nd", rowspan => 2, colspan => 1); 1000 $t->add_at (0,1, new CFPlus::UI::Label text => "d\nd", c_rowspan => 2, c_colspan => 1);
742 $t->add_at (1,1, new CFPlus::UI::Label text => "e"); 1001 $t->add_at (1,1, new CFPlus::UI::Label text => "e");
743 1002
744 $table->add_at (7, 6, my $c = new CFPlus::UI::Canvas); 1003 $table->add_at (7, 6, my $c = new CFPlus::UI::Canvas);
745 1004
746 $c->add_items ({ 1005 $c->add_items ({
1353 CFPlus::Protocol::set_opencont ($::CONN, 0, "Floor"); 1612 CFPlus::Protocol::set_opencont ($::CONN, 0, "Floor");
1354 1613
1355 $hb 1614 $hb
1356} 1615}
1357 1616
1617sub media_window {
1618 my $vb = new CFPlus::UI::VBox;
1619
1620 $vb->add (new CFPlus::UI::FancyFrame
1621 label => "Currently playing music",
1622 child => new CFPlus::UI::ScrolledWindow scroll_x => 1, scroll_y => 0,
1623 child => ($MUSIC_PLAYING_WIDGET = new CFPlus::UI::Label ellipsise => 0, fontsize => 0.8),
1624 );
1625
1626 $vb->add (new CFPlus::UI::FancyFrame
1627 label => "Other media used in this session",
1628 expand => 1,
1629 child => ($LICENSE_WIDGET = new CFPlus::UI::TextScroller
1630 expand => 1, fontsize => 0.8, padding_x => 4, padding_y => 4),
1631 );
1632
1633 $vb
1634}
1635
1636sub add_license {
1637 my ($meta) = @_;
1638
1639 $meta = $meta->{meta}
1640 or return;
1641
1642 $meta->{license} || $meta->{author} || $meta->{source}
1643 or return;
1644
1645 $LICENSE_WIDGET->add_paragraph ({
1646 fg => [1, 1, 1, 1],
1647 markup => "<small>"
1648 . "<b>Name:</b> " . (CFPlus::asxml $meta->{name}) . "\n"
1649 . "<b>Author:</b> " . (CFPlus::asxml $meta->{author}) . "\n"
1650 . "<b>Source:</b> " . (CFPlus::asxml $meta->{source}) . "\n"
1651 . "<b>License:</b> " . (CFPlus::asxml $meta->{license}) . "\n"
1652 . "</small>",
1653 });
1654 $LICENSE_WIDGET->scroll_to_bottom;
1655}
1656
1358sub toggle_player_page { 1657sub toggle_player_page {
1359 my ($widget) = @_; 1658 my ($widget) = @_;
1360 1659
1361 if ($PL_WINDOW->{visible} && $PL_NOTEBOOK->get_current_page == $widget) { 1660 if ($PL_WINDOW->{visible} && $PL_NOTEBOOK->get_current_page == $widget) {
1362 $PL_WINDOW->hide; 1661 $PL_WINDOW->hide;
1399 $ntb->add_tab ( 1698 $ntb->add_tab (
1400 "Inventory (F5)" => $INVENTORY_PAGE = inventory_widget, 1699 "Inventory (F5)" => $INVENTORY_PAGE = inventory_widget,
1401 "Toggles the inventory window, where you can manage your loot (or treasures :). " 1700 "Toggles the inventory window, where you can manage your loot (or treasures :). "
1402 . "You can also hit the <b>Tab</b>-key to show/hide the Inventory." 1701 . "You can also hit the <b>Tab</b>-key to show/hide the Inventory."
1403 ); 1702 );
1404 $ntb->add_tab (Pickup => autopickup_setup, 1703 $ntb->add_tab (Pickup => autopickup_setup,
1405 "Configure autopickup settings, i.e. which items you will pick up automatically when walking (or running) over them."); 1704 "Configure autopickup settings, i.e. which items you will pick up automatically when walking (or running) over them.");
1705
1706 $ntb->add_tab (Media => media_window,
1707 "License, Author and Source info for media sent by the server.");
1406 1708
1407 $ntb->set_current_page ($INVENTORY_PAGE); 1709 $ntb->set_current_page ($INVENTORY_PAGE);
1408 1710
1409 $plwin->add ($ntb); 1711 $plwin->add ($ntb);
1410 $plwin 1712 $plwin
1787 CFPlus::OpenGL::shutdown; 2089 CFPlus::OpenGL::shutdown;
1788 2090
1789 undef $SDL_ACTIVE; 2091 undef $SDL_ACTIVE;
1790} 2092}
1791 2093
1792sub audio_channel_finished {
1793 my ($channel) = @_;
1794
1795# warn "channel $channel finished\n";#d#
1796}
1797
1798our %AUDIO_PLAY;
1799our %AUDIO_CHUNK;
1800
1801sub audio_sound_push($) {
1802 my ($face) = @_;
1803
1804 if (my $chunk = $AUDIO_CHUNK{$face}) {
1805 for (grep $_->[0] >= Event::time, @{(delete $AUDIO_PLAY{$face}) || []}) {
1806 my (undef, $dx, $dy, $vol) = @$_;
1807
1808 my $channel = $chunk->play
1809 or return;
1810
1811 $channel->volume (128 + $vol);
1812 $dx = $dx / 10 * 255;
1813 $channel->set_panning ((min 255, 255 - $dx), (min 255, 255 + $dx));
1814# my $angle = $dx ? : $dx < 0 ?
1815# my $distance = -$vol;
1816# $channel->set_position ($angle, $distance);
1817 }
1818 } else {
1819 # sound_meta not set means data is in flight either way
1820 my $meta = $CONN->{sound_meta}{$face}
1821 or return;
1822
1823 # fetch from database
1824 CFPlus::DB::get res_data => $meta->{name}, sub {
1825 my $vol = $meta->{meta}{volume} || 100;
1826 my $rwops = new CFPlus::RW $_[0];
1827 my $chunk = new CFPlus::MixChunk $rwops;
1828 $chunk->volume ($vol * 128 / 100);
1829 $AUDIO_CHUNK{$face} = $chunk;
1830
1831 audio_sound_push ($face);
1832 };
1833 }
1834}
1835
1836sub audio_sound_play {
1837 my ($face, $dx, $dy, $vol) = @_;
1838
1839 $SDL_MIXER
1840 or return;
1841
1842 my $queue = $AUDIO_PLAY{$face} ||= [];
1843 push @$queue, [Event::time + 0.2, $dx, $dy, $vol]; # delay sound by max. 0.2s
1844 audio_sound_push $face
1845 unless @$queue > 1;
1846}
1847
1848sub audio_music_set {
1849 my ($songs) = @_;
1850
1851 my @want =
1852 grep $_,
1853 map $CONN->{music_meta}{$_},
1854 @$songs;
1855
1856 if (@want) {
1857 @MUSIC_WANT = @want;
1858 &audio_music_changed ();
1859 }
1860}
1861
1862sub audio_music_start {
1863 my $meta = $MUSIC_PLAYING_META;
1864
1865 CFPlus::DB::get res_data => $meta->{name}, sub {
1866 return unless $SDL_MIXER;
1867
1868 # music might have changed...
1869 $meta eq $MUSIC_PLAYING_META
1870 or return &audio_music_start ();
1871
1872 $MUSIC_PLAYING_DATA = \$_[0];
1873
1874 my $rwops = $meta->{path}
1875 ? new_from_file CFPlus::RW $meta->{path}
1876 : new CFPlus::RW $$MUSIC_PLAYING_DATA;
1877
1878 $MUSIC_PLAYER = new CFPlus::MixMusic $rwops
1879 or ((warn CFPlus::Mix_GetError), return); # pretty fatal error
1880
1881 my $NOW = time;
1882
1883 if ($MUSIC_PLAYING_META->{stop_time} > $NOW - $MUSIC_RESUME) {
1884 my $pos = $MUSIC_PLAYING_META->{stop_pos};
1885 $MUSIC_PLAYER->fade_in_pos (0, 1000, $pos);
1886 $MUSIC_START = time - $pos;
1887 } else {
1888 $MUSIC_PLAYER->play (0);
1889 $MUSIC_START = time;
1890 }
1891
1892 delete $MUSIC_PLAYING_META->{stop_time};
1893 delete $MUSIC_PLAYING_META->{stop_pos};
1894 }
1895}
1896
1897sub audio_music_changed {
1898 return unless $CFG->{bgm_enable};
1899 return unless $SDL_MIXER;
1900
1901 # default MUSIC_WANT == MUSIC_DEFAULT
1902 @MUSIC_WANT = { path => CFPlus::find_rcfile "music/$MUSIC_DEFAULT" } unless @MUSIC_WANT;
1903
1904 # if the currently playing song is acceptable, let it continue
1905 return if $MUSIC_PLAYING_META
1906 && grep $MUSIC_PLAYING_META == $_, @MUSIC_WANT;
1907
1908 my $NOW = time;
1909
1910 if ($MUSIC_PLAYING_META) {
1911 $MUSIC_PLAYING_META->{stop_time} = $NOW;
1912 $MUSIC_PLAYING_META->{stop_pos} = $NOW - $MUSIC_START;
1913 CFPlus::MixMusic::fade_out 1000;
1914 } else {
1915 # sort by stop time, oldest first
1916 @MUSIC_WANT = sort { $a->{stop_time} <=> $b->{stop_time} } @MUSIC_WANT;
1917
1918 # if the most recently-played piece played very recently,
1919 # resume it, else choose the oldest piece for rotation.
1920 $MUSIC_PLAYING_META =
1921 $MUSIC_WANT[-1]{stop_time} > $NOW - $MUSIC_RESUME
1922 ? $MUSIC_WANT[-1]
1923 : $MUSIC_WANT[0];
1924
1925 audio_music_start;
1926 }
1927}
1928
1929sub audio_music_finished {
1930 undef $MUSIC_PLAYER;
1931 undef $MUSIC_PLAYING_META;
1932 undef $MUSIC_PLAYING_DATA;
1933
1934 audio_music_changed;
1935}
1936
1937sub audio_init {
1938 if ($CFG->{audio_enable}) {
1939 $ENV{MIX_EFFECTSMAXSPEED} = 1;
1940 $SDL_MIXER = !CFPlus::Mix_OpenAudio;
1941
1942 unless ($SDL_MIXER) {
1943 status "Unable to open sound device: there will be no sound";
1944 return;
1945 }
1946
1947 CFPlus::Mix_AllocateChannels 16;
1948 CFPlus::MixMusic::volume $CFG->{bgm_volume} * 128;
1949
1950 audio_music_finished;
1951 } else {
1952 undef $SDL_MIXER;
1953 }
1954}
1955
1956sub audio_shutdown {
1957 CFPlus::Mix_CloseAudio if $SDL_MIXER;
1958 undef $SDL_MIXER;
1959 @SOUNDS = ();
1960 %AUDIO_CHUNKS = ();
1961}
1962
1963my %animate_object; 2094my %animate_object;
1964my $animate_timer; 2095my $animate_timer;
1965 2096
1966my $fps = 9; 2097my $fps = 9;
1967
1968my %demo;#d#
1969 2098
1970sub force_refresh { 2099sub force_refresh {
1971 $fps = $fps * 0.95 + 1 / (($NOW - $LAST_REFRESH) || 0.1) * 0.05; 2100 $fps = $fps * 0.95 + 1 / (($NOW - $LAST_REFRESH) || 0.1) * 0.05;
1972 debug sprintf "%3.2f", $fps if $ENV{CFPLUS_DEBUG} & 4; 2101 debug sprintf "%3.2f", $fps if $ENV{CFPLUS_DEBUG} & 4;
1973 2102
2058 2187
2059 CFPlus::UI::set_layout ($::CFG->{layout}); 2188 CFPlus::UI::set_layout ($::CFG->{layout});
2060 2189
2061 my %DEF_CFG = ( 2190 my %DEF_CFG = (
2062 sdl_mode => 0, 2191 sdl_mode => 0,
2063 width => 640,
2064 height => 480,
2065 fullscreen => 0, 2192 fullscreen => 0,
2066 fast => 0, 2193 fast => 0,
2067 map_scale => 1, 2194 map_scale => 1,
2068 fow_enable => 1, 2195 fow_enable => 1,
2069 fow_intensity => 0, 2196 fow_intensity => 0,
2073 gauge_fontsize => 1, 2200 gauge_fontsize => 1,
2074 gauge_size => 0.35, 2201 gauge_size => 0.35,
2075 stat_fontsize => 0.7, 2202 stat_fontsize => 0.7,
2076 mapsize => 100, 2203 mapsize => 100,
2077 audio_enable => 1, 2204 audio_enable => 1,
2205 effects_enable => 1,
2206 effects_volume => 1,
2078 bgm_enable => 1, 2207 bgm_enable => 1,
2079 bgm_volume => 0.25, 2208 bgm_volume => 0.5,
2080 output_sync => 1, 2209 output_sync => 1,
2081 output_count => 1, 2210 output_count => 1,
2082 output_rate => "", 2211 output_rate => "",
2083 pickup => 0, 2212 pickup => 0,
2084 inv_sort => "mtime", 2213 inv_sort => "mtime",
2162Event::loop; 2291Event::loop;
2163#CFPlus::SDL_Quit; 2292#CFPlus::SDL_Quit;
2164#CFPlus::_exit 0; 2293#CFPlus::_exit 0;
2165 2294
2166END { 2295END {
2296 video_shutdown;
2297 audio_shutdown;
2167 CFPlus::SDL_Quit; 2298 CFPlus::SDL_Quit;
2168 CFPlus::DB::Server::stop; 2299 CFPlus::DB::Server::stop;
2169} 2300}
2170 2301
2171=head1 NAME 2302=head1 NAME
2172 2303
2173cfplus - A Crossfire+ and Crossfire game client 2304cfplus - A Crossfire TRT and Crossfire game client
2174 2305
2175=head1 SYNOPSIS 2306=head1 SYNOPSIS
2176 2307
2177Just run it - no commandline arguments are supported. 2308Just run it - no commandline arguments are supported.
2178 2309
2179=head1 USAGE 2310=head1 USAGE
2180 2311
2181cfplus utilises OpenGL for all UI elements and the game. It is supposed to be used 2312cfplus utilises OpenGL for all UI elements and the game. It is supposed to
2182fullscreen and interactively. 2313be used in fullscreen mode and interactively.
2183 2314
2184=head1 DEBUGGING 2315=head1 DEBUGGING
2185 2316
2186 2317
2187CFPLUS_DEBUG - environment variable 2318CFPLUS_DEBUG - environment variable

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines