--- deliantra/Deliantra-Client/bin/cfplus 2007/07/31 02:45:39 1.198 +++ deliantra/Deliantra-Client/bin/cfplus 2007/08/10 04:02:14 1.208 @@ -115,7 +115,6 @@ our $FAST; # fast, low-quality mode, possibly useful for software-rendering our $WANT_REFRESH; -our $CAN_REFRESH; our @SDL_MODES; our $WIDTH; @@ -146,6 +145,9 @@ our $PL_NOTEBOOK; our $PL_WINDOW; +our $MUSIC_PLAYING_WIDGET; +our $LICENSE_WIDGET; + our $INVENTORY_PAGE; our $STATS_PAGE; our $SKILL_PAGE; @@ -213,19 +215,19 @@ sub audio_sound_push($) { my ($face) = @_; + $CFG->{effects_enable} + or return; + + $AUDIO_PLAY{$face} + or return; + if (my $chunk = $AUDIO_CHUNK{$face}) { for (grep $_->[0] >= Event::time, @{(delete $AUDIO_PLAY{$face}) || []}) { my (undef, $dx, $dy, $vol) = @$_; my $channel = CFPlus::Channel::find; - $channel->volume ($vol * 128 / 255); - $dx = $dx / 10 * 255; - $channel->set_panning (255 - $dx, 255 + $dx); - -# my $angle = $dx ? : $dx < 0 ? -# my $distance = -$vol; -# $channel->set_position ($angle, $distance); - + $channel->volume ($vol * $CFG->{effects_volume} * 128 / 255); + $channel->set_position_r ($dx, $dy, 20); $chunk->play ($channel); } } else { @@ -235,14 +237,16 @@ # if its a jingle, play it as ambient music if ($meta->{meta}{jingle}) { - delete $AUDIO_PLAY{$face}; # take the jingle out of the sound queue - push @MUSIC_JINGLE, $meta; # push it oto the music/jingle queue - &audio_music_push ($face); + if (delete $AUDIO_PLAY{$face}) { # take the jingle out of the sound queue + push @MUSIC_JINGLE, $meta; # push it oto the music/jingle queue + &audio_music_push ($face); + } } else { # fetch from database CFPlus::DB::get res_data => $meta->{name}, sub { my $rwops = new CFPlus::RW $_[0]; - my $chunk = new CFPlus::MixChunk $rwops; + my $chunk = new CFPlus::MixChunk $rwops + or Carp::confess "sound face " . (JSON::XS::to_json $meta) . " unloadable: " . CFPlus::Mix_GetError; $chunk->volume (($meta->{meta}{volume} || 1) * 128); $AUDIO_CHUNK{$face} = $chunk; @@ -257,6 +261,8 @@ $SDL_MIXER or return; + $CFG->{effects_enable} + or return; my $queue = $AUDIO_PLAY{$face} ||= []; push @$queue, [Event::time + 0.2, $dx, $dy, $vol]; # delay sound by max. 0.2s @@ -264,6 +270,18 @@ unless @$queue > 1; } +sub audio_music_set_meta { + my ($meta) = @_; + + $MUSIC_PLAYING_META = $meta; + $MUSIC_PLAYING_WIDGET->set_markup ( + "Name: " . (CFPlus::asxml $meta->{meta}{name}) . "\n" + . "Author: " . (CFPlus::asxml $meta->{meta}{author}) . "\n" + . "Source: " . (CFPlus::asxml $meta->{meta}{source}) . "\n" + . "License: " . (CFPlus::asxml $meta->{meta}{license}) + ); +} + sub audio_music_update_volume { return unless $MUSIC_PLAYING_META; my $volume = $MUSIC_PLAYING_META->{meta}{volume} || 1; @@ -290,7 +308,7 @@ : new CFPlus::RW $$MUSIC_PLAYING_DATA; $MUSIC_PLAYER = new CFPlus::MixMusic $rwops - or ((warn CFPlus::Mix_GetError), return); # pretty fatal error + or Carp::confess "music face $meta->{face} unloadable: " . CFPlus::Mix_GetError; my $NOW = time; @@ -303,8 +321,8 @@ $MUSIC_START = time; } - delete $MUSIC_PLAYING_META->{stop_time}; - delete $MUSIC_PLAYING_META->{stop_pos}; + delete $meta->{stop_time}; + delete $meta->{stop_pos}; } } @@ -333,8 +351,7 @@ } # if the currently playing song is acceptable, let it continue - return if $MUSIC_PLAYING_META - && grep $MUSIC_PLAYING_META == $_, @MUSIC_HAVE; + return if grep $MUSIC_PLAYING_META == $_, @MUSIC_HAVE; my $NOW = time; @@ -348,7 +365,7 @@ # if the most recently-played piece played very recently, # resume it, else choose the oldest piece for rotation. - $MUSIC_PLAYING_META = + audio_music_set_meta $MUSIC_HAVE[-1]{stop_time} > $NOW - $MUSIC_RESUME ? $MUSIC_HAVE[-1] : $MUSIC_HAVE[0]; @@ -369,6 +386,8 @@ shift @MUSIC_JINGLE while @MUSIC_JINGLE && $MUSIC_PLAYING_META == $MUSIC_JINGLE[0]; + $MUSIC_PLAYING_WIDGET->clear; + undef $MUSIC_PLAYER; undef $MUSIC_PLAYING_META; undef $MUSIC_PLAYING_DATA; @@ -841,7 +860,7 @@ sub audio_setup { my $vbox = new CFPlus::UI::VBox; - $vbox->add (my $table = new CFPlus::UI::Table expand => 1, col_expand => [0, 1]); + $vbox->add (my $table = new CFPlus::UI::Table expand => 1, col_expand => [0, 0, 1]); my $row = 0; @@ -855,21 +874,42 @@ # $table->add_at (1, 8, new CFPlus::UI::Slider range => [$CFG->{effects_volume}, 0, 128, 1], on_changed => sub { # $CFG->{effects_volume} = $_[1]; # }); + + $table->add_at (0, $row, new CFPlus::UI::Label valign => 0, align => 1, text => "Sound Effects"); + $table->add_at (1, $row, new CFPlus::UI::CheckBox + expand => 1, state => $CFG->{effects_enable}, + tooltip => "If enabled, sound effects are enabled. If disabled, no sound effects will be played.", + on_changed => sub { + $CFG->{effects_enable} = $_[1]; + $CONN->update_fx_want if $CONN; + 0 + } + ); + $table->add_at (2, $row++, new CFPlus::UI::Slider + expand => 1, range => [$CFG->{effects_volume}, 0, 1, 0, 1/128], + tooltip => "The relative volume of sound effects. Best audio quality is achieved if this " + . "is set highest (rightmost) and you use your operating system volume setting. Changes are instant.", + on_changed => sub { $CFG->{effects_volume} = $_[1]; 0 } + ); + $table->add_at (0, $row, new CFPlus::UI::Label valign => 0, align => 1, text => "Background Music"); - $table->add_at (1, $row++, my $hbox = new CFPlus::UI::HBox); - $hbox->add (new CFPlus::UI::CheckBox + $table->add_at (1, $row, new CFPlus::UI::CheckBox expand => 1, state => $CFG->{bgm_enable}, tooltip => "If enabled, playing of background music is enabled. If disabled, no background music will be played.", - on_changed => sub { $CFG->{bgm_enable} = $_[1]; 0 } + on_changed => sub { + $CFG->{bgm_enable} = $_[1]; + $CONN->update_fx_want if $CONN; + 0 + } ); - $hbox->add (new CFPlus::UI::Slider + $table->add_at (2, $row++, new CFPlus::UI::Slider expand => 1, range => [$CFG->{bgm_volume}, 0, 1, 0, 1/128], tooltip => "The volume of the background music. Changes are instant.", on_changed => sub { $CFG->{bgm_volume} = $_[1]; audio_music_update_volume; 0 } ); $table->add_at (1, $row++, new CFPlus::UI::Button - expand => 1, align => 0, text => "Apply", + c_colspan => 2, expand => 1, align => 0, text => "Apply", tooltip => "Apply the audio settings", on_activate => sub { audio_shutdown (); @@ -950,10 +990,10 @@ $table->add_at (0, 5, new CFPlus::UI::TextEdit text => "line1\0152\0153");#d# $table->add_at (7,7, my $t = new CFPlus::UI::Table expand => 0); - $t->add_at (0,0, new CFPlus::UI::Label text => "a a a a", rowspan => 1, colspan => 2); - $t->add_at (2,0, new CFPlus::UI::Label text => "b\nb", rowspan => 2, colspan => 1); - $t->add_at (1,2, new CFPlus::UI::Label text => "c c c c", rowspan => 1, colspan => 2); - $t->add_at (0,1, new CFPlus::UI::Label text => "d\nd", rowspan => 2, colspan => 1); + $t->add_at (0,0, new CFPlus::UI::Label text => "a a a a", c_rowspan => 1, c_colspan => 2); + $t->add_at (2,0, new CFPlus::UI::Label text => "b\nb", c_rowspan => 2, c_colspan => 1); + $t->add_at (1,2, new CFPlus::UI::Label text => "c c c c", c_rowspan => 1, c_colspan => 2); + $t->add_at (0,1, new CFPlus::UI::Label text => "d\nd", c_rowspan => 2, c_colspan => 1); $t->add_at (1,1, new CFPlus::UI::Label text => "e"); $table->add_at (7, 6, my $c = new CFPlus::UI::Canvas); @@ -1570,6 +1610,46 @@ $hb } +sub media_window { + my $vb = new CFPlus::UI::VBox; + + $vb->add (new CFPlus::UI::FancyFrame + label => "Currently playing music", + child => new CFPlus::UI::ScrolledWindow scroll_x => 1, scroll_y => 0, + child => ($MUSIC_PLAYING_WIDGET = new CFPlus::UI::Label ellipsise => 0, fontsize => 0.8), + ); + + $vb->add (new CFPlus::UI::FancyFrame + label => "Other media used in this session", + expand => 1, + child => ($LICENSE_WIDGET = new CFPlus::UI::TextScroller + expand => 1, fontsize => 0.8, padding_x => 4, padding_y => 4), + ); + + $vb +} + +sub add_license { + my ($meta) = @_; + + $meta = $meta->{meta} + or return; + + $meta->{license} || $meta->{author} || $meta->{source} + or return; + + $LICENSE_WIDGET->add_paragraph ({ + fg => [1, 1, 1, 1], + markup => "" + . "Name: " . (CFPlus::asxml $meta->{name}) . "\n" + . "Author: " . (CFPlus::asxml $meta->{author}) . "\n" + . "Source: " . (CFPlus::asxml $meta->{source}) . "\n" + . "License: " . (CFPlus::asxml $meta->{license}) . "\n" + . "", + }); + $LICENSE_WIDGET->scroll_to_bottom; +} + sub toggle_player_page { my ($widget) = @_; @@ -1616,9 +1696,12 @@ "Toggles the inventory window, where you can manage your loot (or treasures :). " . "You can also hit the Tab-key to show/hide the Inventory." ); - $ntb->add_tab (Pickup => autopickup_setup, + $ntb->add_tab (Pickup => autopickup_setup, "Configure autopickup settings, i.e. which items you will pick up automatically when walking (or running) over them."); + $ntb->add_tab (Media => media_window, + "License, Author and Source info for media sent by the server."); + $ntb->set_current_page ($INVENTORY_PAGE); $plwin->add ($ntb); @@ -2010,19 +2093,20 @@ my $fps = 9; sub force_refresh { - $fps = $fps * 0.95 + 1 / (($NOW - $LAST_REFRESH) || 0.1) * 0.05; - debug sprintf "%3.2f", $fps if $ENV{CFPLUS_DEBUG} & 4; + if ($ENV{CFPLUS_DEBUG} & 4) { + $fps = $fps * 0.98 + 1 / (($NOW - $LAST_REFRESH) || 0.1) * 0.02; + debug sprintf "%3.2f", $fps; + } $CFPlus::UI::ROOT->draw; - - $WANT_REFRESH = 0; - $CAN_REFRESH = 0; - $LAST_REFRESH = $NOW; - CFPlus::SDL_GL_SwapBuffers; + $LAST_REFRESH = $NOW; + $WANT_REFRESH->stop; } -my $refresh_watcher = Event->timer (after => 0, hard => 0, interval => 1 / $MAX_FPS, cb => sub { +$WANT_REFRESH = Event->idle (min => 0.001, max => 0.06, parked => 1, cb => \&force_refresh); + +my $input = Event->timer (after => 0, hard => 0, interval => 1 / 50, cb => sub { $NOW = time; ($SDL_CB{$_->{type}} || sub { warn "unhandled event $_->{type}" })->($_) @@ -2030,13 +2114,7 @@ if (%animate_object) { $_->animate ($LAST_REFRESH - $NOW) for values %animate_object; - ++$WANT_REFRESH; - } - - if ($WANT_REFRESH) { - force_refresh; - } else { - $CAN_REFRESH = 1; + $WANT_REFRESH->start; } }); @@ -2115,8 +2193,10 @@ stat_fontsize => 0.7, mapsize => 100, audio_enable => 1, + effects_enable => 1, + effects_volume => 1, bgm_enable => 1, - bgm_volume => 0.25, + bgm_volume => 0.5, output_sync => 1, output_count => 1, output_rate => "", @@ -2204,13 +2284,15 @@ #CFPlus::_exit 0; END { + video_shutdown; + audio_shutdown; CFPlus::SDL_Quit; CFPlus::DB::Server::stop; } =head1 NAME -cfplus - A Crossfire+ and Crossfire game client +cfplus - A Crossfire TRT and Crossfire game client =head1 SYNOPSIS @@ -2218,8 +2300,8 @@ =head1 USAGE -cfplus utilises OpenGL for all UI elements and the game. It is supposed to be used -fullscreen and interactively. +cfplus utilises OpenGL for all UI elements and the game. It is supposed to +be used in fullscreen mode and interactively. =head1 DEBUGGING