… | |
… | |
162 | |
162 | |
163 | our $SDL_MIXER; |
163 | our $SDL_MIXER; |
164 | our $MUSIC_DEFAULT = "in_a_heartbeat.ogg"; |
164 | our $MUSIC_DEFAULT = "in_a_heartbeat.ogg"; |
165 | our @MUSIC_WANT; |
165 | our @MUSIC_WANT; |
166 | our $MUSIC_START; |
166 | our $MUSIC_START; |
167 | our $MUSIC_PLAYING; |
167 | our $MUSIC_PLAYING_DATA; |
|
|
168 | our $MUSIC_PLAYING_META; |
168 | our $MUSIC_PLAYER; |
169 | our $MUSIC_PLAYER; |
169 | our $MUSIC_RESUME = 30; # resume music when players less than these many seconds before |
170 | our $MUSIC_RESUME = 30; # resume music when players less than these many seconds before |
170 | our @SOUNDS; # event => file mapping |
171 | our @SOUNDS; # event => file mapping |
171 | our %AUDIO_CHUNKS; # audio files |
172 | our %AUDIO_CHUNKS; # audio files |
172 | |
173 | |
… | |
… | |
1121 | . "but you also increase bandwidth requirements and latency. " |
1122 | . "but you also increase bandwidth requirements and latency. " |
1122 | . "This option is only used once at log-in.", |
1123 | . "This option is only used once at log-in.", |
1123 | on_changed => sub { my ($self, $value) = @_; $CFG->{mapsize} = $self->{range}[0] = $value = int $value; 0 }, |
1124 | on_changed => sub { my ($self, $value) = @_; $CFG->{mapsize} = $self->{range}[0] = $value = int $value; 0 }, |
1124 | ); |
1125 | ); |
1125 | |
1126 | |
1126 | $table->add_at (0, 8, new CFPlus::UI::Label valign => 0, align => 1, text => "Face Prefetch"); |
|
|
1127 | $table->add_at (1, 8, new CFPlus::UI::CheckBox |
|
|
1128 | state => $CFG->{face_prefetch}, |
|
|
1129 | tooltip => "<b>Background Image Prefetch</b>\n\n" |
|
|
1130 | . "If enabled, the client automatically pre-fetches images from the server. " |
|
|
1131 | . "This might increase or create lag, but increases the chances " |
|
|
1132 | . "of faces being ready for display when you encounter them. " |
|
|
1133 | . "It also uses up server bandwidth on every connect, " |
|
|
1134 | . "so only set it if you really need to prefetch images. " |
|
|
1135 | . "This option can be set and unset any time.", |
|
|
1136 | on_changed => sub { $CFG->{face_prefetch} = $_[1]; 0 }, |
|
|
1137 | ); |
|
|
1138 | |
|
|
1139 | $table->add_at (0, 9, new CFPlus::UI::Label valign => 0, align => 1, text => "Output-Rate"); |
1127 | $table->add_at (0, 8, new CFPlus::UI::Label valign => 0, align => 1, text => "Output-Rate"); |
1140 | $table->add_at (1, 9, new CFPlus::UI::Entry |
1128 | $table->add_at (1, 8, new CFPlus::UI::Entry |
1141 | text => $CFG->{output_rate}, |
1129 | text => $CFG->{output_rate}, |
1142 | tooltip => "The approximate bandwidth in bytes per second that the server should not exceed " |
1130 | tooltip => "The approximate bandwidth in bytes per second that the server should not exceed " |
1143 | . "when sending images, to ensure interactiveness. When 0 or unset, the server " |
1131 | . "when sending images, to ensure interactiveness. When 0 or unset, the server " |
1144 | . "default will be used, which is usually around 100kb/s.", |
1132 | . "default will be used, which is usually around 100kb/s.", |
1145 | on_changed => sub { $CFG->{output_rate} = $_[1]; 0 }, |
1133 | on_changed => sub { $CFG->{output_rate} = $_[1]; 0 }, |
1146 | ); |
1134 | ); |
1147 | |
1135 | |
1148 | $table->add_at (0, 10, new CFPlus::UI::Label valign => 0, align => 1, text => "Output-Count"); |
1136 | $table->add_at (0, 9, new CFPlus::UI::Label valign => 0, align => 1, text => "Output-Count"); |
1149 | $table->add_at (1, 10, new CFPlus::UI::Entry |
1137 | $table->add_at (1, 9, new CFPlus::UI::Entry |
1150 | text => $CFG->{output_count}, |
1138 | text => $CFG->{output_count}, |
1151 | tooltip => "Should be set to 1 unless you know what you are doing. This option is only used once at log-in.", |
1139 | tooltip => "Should be set to 1 unless you know what you are doing. This option is only used once at log-in.", |
1152 | on_changed => sub { $CFG->{output_count} = $_[1]; 0 }, |
1140 | on_changed => sub { $CFG->{output_count} = $_[1]; 0 }, |
1153 | ); |
1141 | ); |
1154 | |
1142 | |
1155 | $table->add_at (0, 11, new CFPlus::UI::Label valign => 0, align => 1, text => "Output-Sync"); |
1143 | $table->add_at (0, 10, new CFPlus::UI::Label valign => 0, align => 1, text => "Output-Sync"); |
1156 | $table->add_at (1, 11, new CFPlus::UI::Entry |
1144 | $table->add_at (1, 10, new CFPlus::UI::Entry |
1157 | text => $CFG->{output_sync}, |
1145 | text => $CFG->{output_sync}, |
1158 | tooltip => "Should be set to 1 unless you know what you are doing. This option is only used once at log-in.", |
1146 | tooltip => "Should be set to 1 unless you know what you are doing. This option is only used once at log-in.", |
1159 | on_changed => sub { $CFG->{output_sync} = $_[1]; 0 }, |
1147 | on_changed => sub { $CFG->{output_sync} = $_[1]; 0 }, |
1160 | ); |
1148 | ); |
1161 | |
1149 | |
1162 | $table->add_at (1, 12, $LOGIN_BUTTON = new CFPlus::UI::Button |
1150 | $table->add_at (1, 11, $LOGIN_BUTTON = new CFPlus::UI::Button |
1163 | expand => 1, |
1151 | expand => 1, |
1164 | align => 0, |
1152 | align => 0, |
1165 | text => "Login", |
1153 | text => "Login", |
1166 | on_activate => sub { |
1154 | on_activate => sub { |
1167 | $CONN ? stop_game |
1155 | $CONN ? stop_game |
… | |
… | |
1830 | &audio_music_changed (); |
1818 | &audio_music_changed (); |
1831 | } |
1819 | } |
1832 | } |
1820 | } |
1833 | |
1821 | |
1834 | sub audio_music_start { |
1822 | sub audio_music_start { |
1835 | my $path = $MUSIC_PLAYING->{path} |
1823 | my $meta = $MUSIC_PLAYING_META; |
1836 | or return; |
|
|
1837 | |
1824 | |
1838 | CFPlus::DB::prefetch_file $path, 1024_000, sub { |
1825 | CFPlus::DB::get res_data => $meta->{name}, sub { |
1839 | return unless $SDL_MIXER; |
1826 | return unless $SDL_MIXER; |
1840 | |
1827 | |
1841 | # music might have changed... |
1828 | # music might have changed... |
1842 | $path eq $MUSIC_PLAYING->{path} |
1829 | $meta eq $MUSIC_PLAYING_META |
1843 | or return &audio_music_start (); |
1830 | or return &audio_music_start (); |
1844 | |
1831 | |
|
|
1832 | $MUSIC_PLAYING_DATA = \$_[0]; |
|
|
1833 | |
|
|
1834 | my $rwops = $meta->{path} |
|
|
1835 | ? new_from_file CFPlus::RW $meta->{path} |
|
|
1836 | : new CFPlus::RW $$MUSIC_PLAYING_DATA; |
|
|
1837 | |
1845 | $MUSIC_PLAYER = new_from_file CFPlus::MixMusic $path; |
1838 | $MUSIC_PLAYER = new CFPlus::MixMusic $rwops |
|
|
1839 | or ((warn CFPlus::Mix_GetError), return); # pretty fatal error |
1846 | |
1840 | |
1847 | my $NOW = time; |
1841 | my $NOW = time; |
1848 | |
1842 | |
1849 | if ($MUSIC_PLAYING->{stop_time} > $NOW - $MUSIC_RESUME) { |
1843 | if ($MUSIC_PLAYING_META->{stop_time} > $NOW - $MUSIC_RESUME) { |
1850 | my $pos = $MUSIC_PLAYING->{stop_pos}; |
1844 | my $pos = $MUSIC_PLAYING_META->{stop_pos}; |
1851 | $MUSIC_PLAYER->fade_in_pos (0, 1000, $pos); |
1845 | $MUSIC_PLAYER->fade_in_pos (0, 1000, $pos); |
1852 | $MUSIC_START = time - $pos; |
1846 | $MUSIC_START = time - $pos; |
1853 | } else { |
1847 | } else { |
1854 | $MUSIC_PLAYER->play (0); |
1848 | $MUSIC_PLAYER->play (0); |
1855 | $MUSIC_START = time; |
1849 | $MUSIC_START = time; |
1856 | } |
1850 | } |
1857 | |
1851 | |
1858 | delete $MUSIC_PLAYING->{stop_time}; |
1852 | delete $MUSIC_PLAYING_META->{stop_time}; |
1859 | delete $MUSIC_PLAYING->{stop_pos}; |
1853 | delete $MUSIC_PLAYING_META->{stop_pos}; |
1860 | } |
1854 | } |
1861 | } |
1855 | } |
1862 | |
1856 | |
1863 | sub audio_music_changed { |
1857 | sub audio_music_changed { |
1864 | return unless $CFG->{bgm_enable}; |
1858 | return unless $CFG->{bgm_enable}; |
… | |
… | |
1866 | |
1860 | |
1867 | # default MUSIC_WANT == MUSIC_DEFAULT |
1861 | # default MUSIC_WANT == MUSIC_DEFAULT |
1868 | @MUSIC_WANT = { path => CFPlus::find_rcfile "music/$MUSIC_DEFAULT" } unless @MUSIC_WANT; |
1862 | @MUSIC_WANT = { path => CFPlus::find_rcfile "music/$MUSIC_DEFAULT" } unless @MUSIC_WANT; |
1869 | |
1863 | |
1870 | # if the currently playing song is acceptable, let it continue |
1864 | # if the currently playing song is acceptable, let it continue |
1871 | return if $MUSIC_PLAYING |
1865 | return if $MUSIC_PLAYING_META |
1872 | && grep $MUSIC_PLAYING->{path} eq $_->{path}, @MUSIC_WANT; |
1866 | && grep $MUSIC_PLAYING_META == $_, @MUSIC_WANT; |
1873 | |
1867 | |
1874 | my $NOW = time; |
1868 | my $NOW = time; |
1875 | |
1869 | |
1876 | if ($MUSIC_PLAYING) { |
1870 | if ($MUSIC_PLAYING_META) { |
1877 | $MUSIC_PLAYING->{stop_time} = $NOW; |
1871 | $MUSIC_PLAYING_META->{stop_time} = $NOW; |
1878 | $MUSIC_PLAYING->{stop_pos} = $NOW - $MUSIC_START; |
1872 | $MUSIC_PLAYING_META->{stop_pos} = $NOW - $MUSIC_START; |
1879 | CFPlus::MixMusic::fade_out 1000; |
1873 | CFPlus::MixMusic::fade_out 1000; |
1880 | } else { |
1874 | } else { |
1881 | # sort by stop time, oldest first |
1875 | # sort by stop time, oldest first |
1882 | @MUSIC_WANT = sort { $a->{stop_time} <=> $b->{stop_time} } @MUSIC_WANT; |
1876 | @MUSIC_WANT = sort { $a->{stop_time} <=> $b->{stop_time} } @MUSIC_WANT; |
1883 | |
1877 | |
1884 | # if the most recently-played piece played very recently, |
1878 | # if the most recently-played piece played very recently, |
1885 | # resume it, else choose the oldest piece for rotation. |
1879 | # resume it, else choose the oldest piece for rotation. |
1886 | $MUSIC_PLAYING = |
1880 | $MUSIC_PLAYING_META = |
1887 | $MUSIC_WANT[-1]{stop_time} > $NOW - $MUSIC_RESUME |
1881 | $MUSIC_WANT[-1]{stop_time} > $NOW - $MUSIC_RESUME |
1888 | ? $MUSIC_WANT[-1] |
1882 | ? $MUSIC_WANT[-1] |
1889 | : $MUSIC_WANT[0]; |
1883 | : $MUSIC_WANT[0]; |
1890 | |
1884 | |
1891 | audio_music_start; |
1885 | audio_music_start; |
1892 | } |
1886 | } |
1893 | } |
1887 | } |
1894 | |
1888 | |
1895 | sub audio_music_finished { |
1889 | sub audio_music_finished { |
1896 | $MUSIC_PLAYING = undef; |
|
|
1897 | undef $MUSIC_PLAYER; |
1890 | undef $MUSIC_PLAYER; |
|
|
1891 | undef $MUSIC_PLAYING_META; |
|
|
1892 | undef $MUSIC_PLAYING_DATA; |
1898 | |
1893 | |
1899 | audio_music_changed; |
1894 | audio_music_changed; |
1900 | } |
1895 | } |
1901 | |
1896 | |
1902 | sub audio_init { |
1897 | sub audio_init { |
1903 | if ($CFG->{audio_enable}) { |
1898 | if ($CFG->{audio_enable}) { |
1904 | if (open my $fh, "<", CFPlus::find_rcfile "sounds/config") { |
1899 | if (open my $fh, "<", CFPlus::find_rcfile "sounds/config") { |
|
|
1900 | $ENV{MIX_EFFECTSMAXSPEED} = 1; |
1905 | $SDL_MIXER = !CFPlus::Mix_OpenAudio; |
1901 | $SDL_MIXER = !CFPlus::Mix_OpenAudio; |
1906 | |
1902 | |
1907 | unless ($SDL_MIXER) { |
1903 | unless ($SDL_MIXER) { |
1908 | status "Unable to open sound device: there will be no sound"; |
1904 | status "Unable to open sound device: there will be no sound"; |
1909 | return; |
1905 | return; |
… | |
… | |
1922 | my ($file, $volume, $event) = split /\s+/, $_, 3; |
1918 | my ($file, $volume, $event) = split /\s+/, $_, 3; |
1923 | |
1919 | |
1924 | push @SOUNDS, "$volume,$file"; |
1920 | push @SOUNDS, "$volume,$file"; |
1925 | |
1921 | |
1926 | $AUDIO_CHUNKS{"$volume,$file"} ||= do { |
1922 | $AUDIO_CHUNKS{"$volume,$file"} ||= do { |
1927 | my $chunk = new_from_file CFPlus::MixChunk CFPlus::find_rcfile "sounds/$file"; |
1923 | my $rwops = new_from_file CFPlus::RW CFPlus::find_rcfile "sounds/$file"; |
|
|
1924 | my $chunk = new CFPlus::MixChunk $rwops; |
1928 | $chunk->volume ($volume * 128 / 100); |
1925 | $chunk->volume ($volume * 128 / 100); |
1929 | $chunk |
1926 | $chunk |
1930 | }; |
1927 | }; |
1931 | } |
1928 | } |
1932 | } else { |
1929 | } else { |
… | |
… | |
1989 | |
1986 | |
1990 | sub animation_stop { |
1987 | sub animation_stop { |
1991 | my ($widget) = @_; |
1988 | my ($widget) = @_; |
1992 | delete $animate_object{$widget}; |
1989 | delete $animate_object{$widget}; |
1993 | } |
1990 | } |
1994 | |
|
|
1995 | # check once/second for faces that need to be prefetched |
|
|
1996 | # this should, of course, only run on demand, but |
|
|
1997 | # SDL forces worse things on us.... |
|
|
1998 | |
|
|
1999 | Event->timer (after => 1, interval => 0.25, cb => sub { |
|
|
2000 | $CONN->face_prefetch |
|
|
2001 | if $CONN; |
|
|
2002 | }); |
|
|
2003 | |
1991 | |
2004 | %SDL_CB = ( |
1992 | %SDL_CB = ( |
2005 | CFPlus::SDL_QUIT => sub { |
1993 | CFPlus::SDL_QUIT => sub { |
2006 | exit; |
1994 | exit; |
2007 | }, |
1995 | }, |
… | |
… | |
2068 | stat_fontsize => 0.7, |
2056 | stat_fontsize => 0.7, |
2069 | mapsize => 100, |
2057 | mapsize => 100, |
2070 | audio_enable => 1, |
2058 | audio_enable => 1, |
2071 | bgm_enable => 1, |
2059 | bgm_enable => 1, |
2072 | bgm_volume => 0.25, |
2060 | bgm_volume => 0.25, |
2073 | face_prefetch => 0, |
|
|
2074 | output_sync => 1, |
2061 | output_sync => 1, |
2075 | output_count => 1, |
2062 | output_count => 1, |
2076 | output_rate => "", |
2063 | output_rate => "", |
2077 | pickup => 0, |
2064 | pickup => 0, |
2078 | inv_sort => "mtime", |
2065 | inv_sort => "mtime", |