3
3
import com .google .common .collect .ListMultimap ;
4
4
import com .google .common .collect .Multimaps ;
5
5
import com .lovetropics .lib .BlockBox ;
6
+ import com .lovetropics .lib .entity .FireworkPalette ;
6
7
import com .lovetropics .minigames .common .content .MinigameTexts ;
7
8
import com .lovetropics .minigames .common .content .crafting_bee .ingredient .IngredientDecomposer ;
8
9
import com .lovetropics .minigames .common .core .game .GameException ;
38
39
import net .minecraft .resources .ResourceLocation ;
39
40
import net .minecraft .server .level .ServerLevel ;
40
41
import net .minecraft .server .level .ServerPlayer ;
42
+ import net .minecraft .sounds .SoundEvents ;
43
+ import net .minecraft .sounds .SoundSource ;
44
+ import net .minecraft .util .Mth ;
41
45
import net .minecraft .world .BossEvent ;
42
46
import net .minecraft .world .Container ;
43
47
import net .minecraft .world .InteractionHand ;
60
64
import java .util .List ;
61
65
import java .util .Map ;
62
66
import java .util .Set ;
63
- import java .util .function .Predicate ;
64
67
import java .util .function .Supplier ;
65
68
import java .util .stream .Collectors ;
66
- import java .util .stream .IntStream ;
67
69
import java .util .stream .Stream ;
68
70
69
71
public class CraftingBeeBehavior implements IGameBehavior {
@@ -201,6 +203,11 @@ private Stream<ItemStack> singleDecomposition(Ingredient ingredient) {
201
203
}
202
204
203
205
private ItemStack modifyCraftResult (ServerPlayer player , ItemStack result , CraftingInput craftingInput , CraftingRecipe recipe ) {
206
+ GameTeamKey team = teams .getTeamForPlayer (player );
207
+ if (team == null || teamsWithoutTime .contains (team )) {
208
+ // Don't allow players to use their inventory to craft, either!
209
+ return ItemStack .EMPTY ;
210
+ }
204
211
ItemContainerContents usedItems = ItemContainerContents .fromItems (craftingInput .items ().stream ()
205
212
.filter (stack -> !stack .isEmpty ())
206
213
.map (stack -> stack .copyWithCount (1 ))
@@ -219,7 +226,10 @@ private void onCraft(Player player, ItemStack crafted, Container container) {
219
226
if (team == null || done ) return ;
220
227
221
228
var teamTasks = tasks .get (team );
222
- var task = teamTasks .stream ().filter (c -> ItemStack .isSameItemSameComponents (crafted , c .output )).findFirst ().orElse (null );
229
+
230
+ var craftedStackToCompare = crafted .copy ();
231
+ craftedStackToCompare .remove (CraftingBee .CRAFTED_USING );
232
+ var task = teamTasks .stream ().filter (c -> ItemStack .isSameItemSameComponents (craftedStackToCompare , c .output )).findFirst ().orElse (null );
223
233
224
234
if (task == null || task .done ) return ;
225
235
@@ -234,16 +244,45 @@ private void onCraft(Player player, ItemStack crafted, Container container) {
234
244
game .allPlayers ().sendMessage (CraftingBeeTexts .TEAM_HAS_COMPLETED_RECIPES .apply (teamConfig .styledName (), completed , teamTasks .size ()));
235
245
taskBars .get (team ).setProgress (completed / (float ) teamTasks .size ());
236
246
247
+ PlayerSet teamPlayers = teams .getPlayersForTeam (team );
248
+ teamPlayers .playSound (SoundEvents .FIREWORK_ROCKET_LAUNCH , SoundSource .PLAYERS , 1.0f , 1.0f );
249
+ game .spectators ().playSound (SoundEvents .FIREWORK_ROCKET_LAUNCH , SoundSource .PLAYERS , 1.0f , 1.0f );
250
+
251
+ PlayerSet otherPlayers = PlayerSet .difference (game .participants (), teamPlayers );
252
+ otherPlayers .playSound (SoundEvents .GHAST_SCREAM , SoundSource .PLAYERS , 0.5f , 0.5f );
253
+
237
254
if (completed == teamTasks .size ()) {
238
- game .invoker (GameLogicEvents .GAME_OVER ).onGameWonBy (gameTeam );
255
+ triggerGameOver (new GameWinner .Team (gameTeam ));
256
+ }
257
+ }
239
258
240
- done = true ;
259
+ private void triggerGameOver (GameWinner winner ) {
260
+ done = true ;
261
+ game .invoker (GameLogicEvents .GAME_OVER ).onGameOver (winner );
262
+ game .allPlayers ().forEach (ServerPlayer ::closeContainer );
241
263
242
- game .allPlayers ().forEach (ServerPlayer ::closeContainer );
264
+ game .scheduler ().runAfterSeconds (1.5f , () -> {
265
+ game .allPlayers ().playSound (SoundEvents .RESPAWN_ANCHOR_DEPLETE .value (), SoundSource .PLAYERS , 0.5f , 1.0f );
243
266
244
- game .scheduler ().runAfterSeconds (1.5f , () -> game .allPlayers ().sendMessage (MinigameTexts .TEAM_WON .apply (teamConfig .styledName ()).withStyle (ChatFormatting .GREEN ), true ));
245
- game .scheduler ().runAfterSeconds (5 , () -> game .requestStop (GameStopReason .finished ()));
246
- }
267
+ if (winner instanceof GameWinner .Team (GameTeam team )) {
268
+ for (ServerPlayer winningPlayer : teams .getPlayersForTeam (team .key ())) {
269
+ applyWinningPlayerEffects (winningPlayer , team );
270
+ }
271
+ game .allPlayers ().sendMessage (MinigameTexts .TEAM_WON .apply (team .config ().styledName ()).withStyle (ChatFormatting .GREEN ), true );
272
+ } else {
273
+ game .allPlayers ().sendMessage (MinigameTexts .NOBODY_WON , true );
274
+ }
275
+ });
276
+
277
+ game .scheduler ().runAfterSeconds (8 , () -> game .requestStop (GameStopReason .finished ()));
278
+ }
279
+
280
+ private void applyWinningPlayerEffects (ServerPlayer winningPlayer , GameTeam team ) {
281
+ game .scheduler ().runAfterSeconds (game .random ().nextFloat (), () -> {
282
+ BlockPos fireworksPos = BlockPos .containing (winningPlayer .getEyePosition ()).above ();
283
+ FireworkPalette .forDye (team .config ().dye ()).spawn (fireworksPos , game .level ());
284
+ });
285
+ winningPlayer .setGlowingTag (true );
247
286
}
248
287
249
288
private void tickRunning (IGamePhase game ) {
@@ -261,27 +300,23 @@ private void tickRunning(IGamePhase game) {
261
300
bar .bar .setProgress (0 );
262
301
263
302
teamsWithoutTime .add (team );
264
- teams .getPlayersForTeam (team ).forEach (ServerPlayer ::closeContainer );
303
+
304
+ PlayerSet playersInTeam = teams .getPlayersForTeam (team );
305
+ playersInTeam .forEach (ServerPlayer ::closeContainer );
306
+ playersInTeam .playSound (SoundEvents .END_PORTAL_SPAWN , SoundSource .PLAYERS , 0.5f , 0.25f );
307
+ playersInTeam .showTitle (CraftingBeeTexts .TIME_UP , null , 10 , SharedConstants .TICKS_PER_SECOND * 2 , 10 );
265
308
266
309
if (teamsWithoutTime .size () == tasks .asMap ().size ()) {
267
310
int mx = tasks .asMap ().values ().stream ().mapToInt (craftingTasks -> (int ) craftingTasks .stream ().filter (c -> c .done ).count ())
268
311
.max ().orElse (0 );
269
312
var withMax = tasks .asMap ().entrySet ().stream ().filter (e -> e .getValue ().stream ().filter (c -> c .done ).count () == mx )
270
313
.toList ();
271
314
if (withMax .size () != 1 ) {
272
- game .invoker (GameLogicEvents .GAME_OVER ).onGameOver (new GameWinner .Nobody ());
273
-
274
- game .scheduler ().runAfterSeconds (1.5f , () -> game .allPlayers ().sendMessage (MinigameTexts .NOBODY_WON , true ));
315
+ triggerGameOver (new GameWinner .Nobody ());
275
316
} else {
276
317
var gameTeam = teams .getTeamByKey (withMax .getFirst ().getKey ());
277
- var teamConfig = gameTeam .config ();
278
- game .invoker (GameLogicEvents .GAME_OVER ).onGameWonBy (gameTeam );
279
-
280
- game .scheduler ().runAfterSeconds (1.5f , () -> game .allPlayers ().sendMessage (MinigameTexts .TEAM_WON .apply (teamConfig .styledName ()).withStyle (ChatFormatting .GREEN ), true ));
318
+ triggerGameOver (new GameWinner .Team (gameTeam ));
281
319
}
282
-
283
- done = true ;
284
- game .scheduler ().runAfterSeconds (5 , () -> game .requestStop (GameStopReason .finished ()));
285
320
}
286
321
}
287
322
}
@@ -301,25 +336,42 @@ private InteractionResult useBlock(ServerPlayer player, ServerLevel world, Block
301
336
// don't allow players to use the crafting table after the game was won
302
337
if (world .getBlockState (pos ).is (Blocks .CRAFTING_TABLE ) && (done || teamsWithoutTime .contains (teams .getTeamForPlayer (player )))) {
303
338
return InteractionResult .FAIL ;
304
- } else if (recyclingRegion .contains (pos )) {
305
- var item = player .getItemInHand (hand );
306
- CraftedUsing craftedUsing = item .get (CraftingBee .CRAFTED_USING );
307
- if (craftedUsing == null ) {
308
- return InteractionResult .FAIL ;
309
- }
310
- if (item .getCount () < craftedUsing .count ()) {
311
- return InteractionResult .FAIL ;
312
- }
339
+ }
340
+ ItemStack itemInHand = player .getItemInHand (hand );
341
+ if (recyclingRegion .contains (pos ) && !itemInHand .isEmpty ()) {
342
+ return useRecycler (player , itemInHand );
343
+ }
344
+ return InteractionResult .PASS ;
345
+ }
313
346
314
- item .shrink (craftedUsing .count ());
315
- craftedUsing .items ().stream ().forEach (player ::addItem );
347
+ private InteractionResult useRecycler (ServerPlayer player , ItemStack itemToRecycle ) {
348
+ CraftedUsing craftedUsing = itemToRecycle .get (CraftingBee .CRAFTED_USING );
349
+ if (craftedUsing == null ) {
350
+ player .sendSystemMessage (CraftingBeeTexts .CANNOT_RECYCLE , true );
351
+ player .playNotifySound (SoundEvents .AXE_SCRAPE , SoundSource .BLOCKS , 1.0f , 1.0f );
352
+ return InteractionResult .FAIL ;
353
+ }
354
+ if (itemToRecycle .getCount () < craftedUsing .count ()) {
355
+ player .sendSystemMessage (CraftingBeeTexts .NOT_ENOUGH_TO_RECYCLE .apply (craftedUsing .count (), itemToRecycle .getHoverName ()), true );
356
+ player .playNotifySound (SoundEvents .AXE_SCRAPE , SoundSource .BLOCKS , 1.0f , 1.0f );
357
+ return InteractionResult .FAIL ;
358
+ }
316
359
317
- timerBars . get ( teams . getTeamForPlayer ( player ))
318
- . state ().increaseRemaining (- recyclingPenalty );
360
+ itemToRecycle . shrink ( craftedUsing . count ());
361
+ craftedUsing . items ().stream (). forEach ( player :: addItem );
319
362
320
- return InteractionResult .SUCCESS ;
321
- }
322
- return InteractionResult .PASS ;
363
+ applyTimePenalty (player , recyclingPenalty );
364
+ player .playNotifySound (SoundEvents .UI_STONECUTTER_TAKE_RESULT , SoundSource .BLOCKS , 1.0f , 1.0f );
365
+
366
+ return InteractionResult .SUCCESS ;
367
+ }
368
+
369
+ private void applyTimePenalty (ServerPlayer player , int penalty ) {
370
+ timerBars .get (teams .getTeamForPlayer (player ))
371
+ .state ().increaseRemaining (-penalty );
372
+
373
+ Component subtitle = CraftingBeeTexts .TIME_PENALTY .apply (Mth .positiveCeilDiv (penalty , SharedConstants .TICKS_PER_SECOND ));
374
+ teams .getPlayersOnSameTeam (player ).showTitle (null , subtitle , 10 , 20 , 10 );
323
375
}
324
376
325
377
private void sync (GameTeamKey team ) {
0 commit comments