Skip to content

Commit 5b46376

Browse files
committed
Add tournament sound
1 parent 3dc4310 commit 5b46376

18 files changed

Lines changed: 134 additions & 21 deletions

File tree

services/app/apps/codebattle/assets/js/__tests__/UserSettings.test.jsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ const preloadedState = {
2626
soundSettings: {
2727
type: 'standard',
2828
level: 6,
29+
tournamentLevel: 4,
2930
},
3031
id: 11,
3132
name: 'Diman',
@@ -104,6 +105,7 @@ describe('UserSettings test cases', () => {
104105
style_lang: '',
105106
sound_settings: {
106107
level: 6,
108+
tournament_level: 4,
107109
type: 'standard',
108110
},
109111
},
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
const tournamentSounds = {
2+
started: '/assets/audio/tournament/tournament_start.wav',
3+
roundStarted: '/assets/audio/tournament/round_start.wav',
4+
roundFinished: '/assets/audio/tournament/round_finish.wav',
5+
finished: '/assets/audio/tournament/tournament_finish.wav',
6+
};
7+
8+
export default tournamentSounds;

services/app/apps/codebattle/assets/js/widgets/lib/sound.js

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,28 @@ const audioConfigs = {
2323
const soundSettings = Gon.getAsset('current_user').sound_settings;
2424
const soundType = soundSettings.type;
2525
const defaultSoundLevel = soundSettings.level * 0.1;
26+
const tournamentSoundLevel = isUndefined(soundSettings.tournament_level)
27+
? defaultSoundLevel
28+
: soundSettings.tournament_level * 0.1;
2629

2730
const audio = (type = soundType, volume = defaultSoundLevel) => new Howl({
2831
src: audioPaths[type],
2932
sprite: audioConfigs[type]?.sprite,
3033
volume,
3134
});
3235

36+
const assetPlayers = {};
37+
const getAssetPlayer = (path) => {
38+
if (!assetPlayers[path]) {
39+
assetPlayers[path] = new Howl({
40+
src: path,
41+
volume: defaultSoundLevel,
42+
});
43+
}
44+
45+
return assetPlayers[path];
46+
};
47+
3348
const sound = {
3449
play: (type, soundLevel) => {
3550
const isMute = JSON.parse(localStorage.getItem('ui_mute_sound') || false);
@@ -38,6 +53,20 @@ const sound = {
3853
Howler.volume(isUndefined(soundLevel) ? defaultSoundLevel : soundLevel);
3954
soundEffect.play(type);
4055
},
56+
playAsset: (path, soundLevel) => {
57+
const isMute = JSON.parse(localStorage.getItem('ui_mute_sound') || false);
58+
if (soundType === 'silent' || isMute) return;
59+
Howler.volume(isUndefined(soundLevel) ? defaultSoundLevel : soundLevel);
60+
getAssetPlayer(path).play();
61+
},
62+
playTournamentAsset: (path) => {
63+
const isMute = JSON.parse(localStorage.getItem('ui_mute_sound') || false);
64+
if (soundType === 'silent' || isMute) return;
65+
Howler.volume(tournamentSoundLevel);
66+
const player = getAssetPlayer(path);
67+
player.volume(1);
68+
player.play();
69+
},
4170
stop: () => Howler.stop(),
4271
toggle: (volume = defaultSoundLevel) => {
4372
Howler.volume(volume);

services/app/apps/codebattle/assets/js/widgets/machines/game.js

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { channelTopics } from '../../socket';
44
import GameStateCodes from '../config/gameStateCodes';
55
import speedModes from '../config/speedModes';
66
import subscriptionTypes from '../config/subscriptionTypes';
7+
import tournamentSounds from '../config/tournamentSounds';
78
import sound from '../lib/sound';
89

910
const { send } = actions;
@@ -380,8 +381,12 @@ export const config = {
380381
soundTimeIsOver: () => {
381382
sound.play('time_is_over');
382383
},
383-
soundTournamentRoundCreated: () => {
384-
sound.play('round_created');
384+
soundTournamentRoundCreated: (_ctx, { payload }) => {
385+
if (payload?.tournament?.currentRoundPosition === 0) {
386+
sound.playTournamentAsset(tournamentSounds.started);
387+
} else {
388+
sound.playTournamentAsset(tournamentSounds.roundStarted);
389+
}
385390
},
386391
soundRematchUpdateStatus: () => { },
387392
blockGameRoomAfterCheck: () => { },

services/app/apps/codebattle/assets/js/widgets/machines/spectator.js

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { assign, actions } from 'xstate';
22

33
import GameStateCodes from '../config/gameStateCodes';
4+
import tournamentSounds from '../config/tournamentSounds';
45
import sound from '../lib/sound';
56

67
import editor, { config as editorConfig } from './editor';
@@ -195,8 +196,12 @@ export const config = {
195196
soundTimeIsOver: () => {
196197
sound.play('time_is_over');
197198
},
198-
soundTournamentRoundCreated: () => {
199-
sound.play('round_created');
199+
soundTournamentRoundCreated: (_ctx, { payload }) => {
200+
if (payload?.tournament?.currentRoundPosition === 0) {
201+
sound.playTournamentAsset(tournamentSounds.started);
202+
} else {
203+
sound.playTournamentAsset(tournamentSounds.roundStarted);
204+
}
200205
},
201206
soundRematchUpdateStatus: () => { },
202207
blockGameRoomAfterCheck: () => { },

services/app/apps/codebattle/assets/js/widgets/middlewares/Tournament.js

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,10 @@ import groupBy from 'lodash/groupBy';
66

77
import { PanelModeCodes } from '@/pages/tournament/ControlPanel';
88

9+
import TournamentStates from '../config/tournament';
10+
import tournamentSounds from '../config/tournamentSounds';
911
import TournamentTypes from '../config/tournamentTypes';
12+
import sound from '../lib/sound';
1013
import { actions } from '../slices';
1114

1215
import Channel from './Channel';
@@ -64,6 +67,7 @@ const initTournamentChannel = (currentChannel) => (dispatch) => {
6467
export const connectToTournament = (newTournamentId) => (dispatch) => {
6568
setTournamentChannel(newTournamentId);
6669
initTournamentChannel(channel)(dispatch);
70+
let lastRoundPosition = 0;
6771

6872
const handleUpdate = (response) => {
6973
dispatch(actions.updateTournamentData(response.tournament));
@@ -87,21 +91,33 @@ export const connectToTournament = (newTournamentId) => (dispatch) => {
8791
};
8892

8993
const handleTournamentRoundCreated = (response) => {
94+
const currentRoundPosition = response.tournament?.currentRoundPosition || lastRoundPosition;
95+
const isFirstRound = currentRoundPosition === 0;
96+
lastRoundPosition = currentRoundPosition;
97+
98+
if (isFirstRound) {
99+
sound.playTournamentAsset(tournamentSounds.started);
100+
} else {
101+
sound.playTournamentAsset(tournamentSounds.roundStarted);
102+
}
90103
dispatch(actions.updateTournamentData(response.tournament));
91104
};
92105

93106
const handleRoundFinished = (response) => {
107+
if (response.tournament?.state !== TournamentStates.finished) {
108+
sound.playTournamentAsset(tournamentSounds.roundFinished);
109+
}
94110
dispatch(
95111
actions.updateTournamentData({
96112
...response.tournament,
97-
topPlayerIds: response.topPlayerIds,
113+
topPlayerIds: response.topPlayerIds || [],
98114
playersPageNumber: 1,
99115
playersPageSize: 20,
100116
}),
101117
);
102118

103-
dispatch(actions.updateTournamentPlayers(compact(response.players)));
104-
dispatch(actions.updateTopPlayers(compact(response.players)));
119+
dispatch(actions.updateTournamentPlayers(compact(response.players || [])));
120+
dispatch(actions.updateTopPlayers(compact(response.players || [])));
105121
};
106122

107123
const handleTournamentRestarted = (response) => {
@@ -133,6 +149,7 @@ export const connectToTournament = (newTournamentId) => (dispatch) => {
133149
};
134150

135151
const handleTournamentFinished = (response) => {
152+
sound.playTournamentAsset(tournamentSounds.finished);
136153
dispatch(actions.updateTournamentData(response.tournament));
137154
};
138155

services/app/apps/codebattle/assets/js/widgets/middlewares/TournamentAdmin.js

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@ import Gon from 'gon';
33
import { camelizeKeys } from 'humps';
44
import compact from 'lodash/compact';
55

6+
import TournamentStates from '../config/tournament';
7+
import tournamentSounds from '../config/tournamentSounds';
8+
import sound from '../lib/sound';
69
import { actions } from '../slices';
710

811
import Channel from './Channel';
@@ -36,6 +39,7 @@ const initTournamentChannel = (dispatch, isAdminWidged = false) => {
3639
ranking: response.ranking || { entries: [] },
3740
players: {},
3841
playersPageSize: 20,
42+
channel: { online: true },
3943
}),
4044
);
4145
}
@@ -59,6 +63,7 @@ const initTournamentChannel = (dispatch, isAdminWidged = false) => {
5963
export const connectToTournament = (newTournamentId, isAdminWidged = false) => (dispatch) => {
6064
setTournamentChannel(newTournamentId);
6165
initTournamentChannel(dispatch, isAdminWidged);
66+
let lastRoundPosition = 0;
6267

6368
const handleUpdate = (response) => {
6469
dispatch(actions.updateTournamentData(response.tournament));
@@ -93,21 +98,33 @@ export const connectToTournament = (newTournamentId, isAdminWidged = false) => (
9398
};
9499

95100
const handleTournamentRoundCreated = (response) => {
101+
const currentRoundPosition = response.tournament?.currentRoundPosition || lastRoundPosition;
102+
const isFirstRound = currentRoundPosition === 0;
103+
lastRoundPosition = currentRoundPosition;
104+
105+
if (isFirstRound) {
106+
sound.playTournamentAsset(tournamentSounds.started);
107+
} else {
108+
sound.playTournamentAsset(tournamentSounds.roundStarted);
109+
}
96110
dispatch(actions.updateTournamentData(response.tournament));
97111
};
98112

99113
const handleRoundFinished = (response) => {
114+
if (response.tournament?.state !== TournamentStates.finished) {
115+
sound.playTournamentAsset(tournamentSounds.roundFinished);
116+
}
100117
dispatch(
101118
actions.updateTournamentData({
102119
...response.tournament,
103-
topPlayerIds: response.topPlayerIds,
120+
topPlayerIds: response.topPlayerIds || [],
104121
playersPageNumber: 1,
105122
playersPageSize: 20,
106123
}),
107124
);
108125

109-
dispatch(actions.updateTournamentPlayers(compact(response.players)));
110-
dispatch(actions.updateTopPlayers(compact(response.players)));
126+
dispatch(actions.updateTournamentPlayers(compact(response.players || [])));
127+
dispatch(actions.updateTopPlayers(compact(response.players || [])));
111128
};
112129

113130
const handleTournamentRestarted = (response) => {
@@ -139,6 +156,7 @@ export const connectToTournament = (newTournamentId, isAdminWidged = false) => (
139156
};
140157

141158
const handleTournamentFinished = (response) => {
159+
sound.playTournamentAsset(tournamentSounds.finished);
142160
dispatch(actions.updateTournamentData(response.tournament));
143161
};
144162

services/app/apps/codebattle/assets/js/widgets/pages/settings/UserSettingsForm.jsx

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ function UserSettingsForm({ onSubmit, settings }) {
119119
soundSettings: {
120120
type: settings.soundSettings.type,
121121
level: settings.soundSettings.level,
122+
tournamentLevel: settings.soundSettings.tournamentLevel ?? settings.soundSettings.level,
122123
},
123124
clan: settings.clan || '',
124125
langView: views.code,
@@ -293,6 +294,25 @@ function UserSettingsForm({ onSubmit, settings }) {
293294
<Icon.Volume2 />
294295
</div>
295296

297+
<div className="h6 ml-2">Select tournament sound level</div>
298+
<div className="ml-2 mb-3 d-flex align-items-center">
299+
<Icon.VolumeX />
300+
<Field
301+
component={Slider}
302+
type="range"
303+
min={0}
304+
max={10}
305+
name="soundSettings.tournamentLevel"
306+
disabled={values.soundSettings.type === 'silent'}
307+
onInput={(e) => {
308+
handleChange(e);
309+
playSound(values.soundSettings.type, e.target.value * 0.1);
310+
}}
311+
className="ml-3 mr-3 form-control"
312+
/>
313+
<Icon.Volume2 />
314+
</div>
315+
296316
<div className="d-flex justify-content-center">
297317
<button
298318
disabled={!dirty || !isValid}

services/app/apps/codebattle/assets/js/widgets/pages/tournament/Tournament.jsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -154,11 +154,11 @@ function Tournament() {
154154
]);
155155

156156
useEffect(() => {
157-
const tournamentChannel = connectToTournament(tournament?.id)(dispatch);
157+
const tournamentChannel = dispatch(connectToTournament(tournament?.id));
158158

159159
if (canModerate) {
160-
const tournamentAdminChannel = connectToTournamentAdmin(tournament?.id)(
161-
dispatch,
160+
const tournamentAdminChannel = dispatch(
161+
connectToTournamentAdmin(tournament?.id, true),
162162
);
163163

164164
return () => {
@@ -299,7 +299,7 @@ function Tournament() {
299299
breakState={tournament.breakState}
300300
currentUserId={currentUserId}
301301
isLive={tournament.isLive}
302-
isOnline={tournament.channel.online}
302+
isOnline={tournament.channel?.online ?? false}
303303
isOver={isOver}
304304
canModerate={canModerate}
305305
lastRoundEndedAt={tournament.lastRoundEndedAt}

services/app/apps/codebattle/assets/js/widgets/pages/tournamentPlayer/TournamentPlayer.jsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -236,7 +236,7 @@ function TournamentPlayer({ spectatorMachine }) {
236236

237237
useEffect(() => {
238238
if (tournament.id) {
239-
const channel = connectToTournament(tournament.id)(dispatch);
239+
const channel = dispatch(connectToTournament(tournament.id));
240240

241241
return () => {
242242
channel.leave();

0 commit comments

Comments
 (0)