initial pass on the post-game card reward screen. The loser's cards float up above the board to be taken by the winner. Just mockup right now - it's always player 2's cards and you don't actually take them.

This commit is contained in:
trunksbomb
2026-03-23 13:05:18 -04:00
parent 316ffebe1f
commit e5d3b5d233
6 changed files with 218 additions and 42 deletions

View File

@@ -49,8 +49,6 @@ public final class DuelTableAnimationResolver {
session.beginOpponentAnimation(); session.beginOpponentAnimation();
table.startMoveAnimation(opponentMove, DuelTableBlockEntity.OWNER_SECOND); table.startMoveAnimation(opponentMove, DuelTableBlockEntity.OWNER_SECOND);
player.displayClientMessage(Component.literal("Training Duelist answers with " + opponentMove.playedCardName() + ".").withStyle(ChatFormatting.GRAY), false);
sendBattleLog(player, opponentMove, ChatFormatting.GRAY);
} }
static void handleAfterOpponentAnimation(Level level, BlockPos pos, DuelTableBlockEntity table, DuelSession session) { static void handleAfterOpponentAnimation(Level level, BlockPos pos, DuelTableBlockEntity table, DuelSession session) {
@@ -70,9 +68,6 @@ public final class DuelTableAnimationResolver {
} }
session.returnToPlaying(); session.returnToPlaying();
player.displayClientMessage(session.boardSummary(), false);
player.displayClientMessage(Component.literal("Your turn. Hold one of your remaining duel cards and click an open space.").withStyle(ChatFormatting.YELLOW), false);
player.displayClientMessage(session.handSummary(), false);
} }
public static void startAiTurn(DuelTableBlockEntity table, DuelSession session, ServerPlayer player) { public static void startAiTurn(DuelTableBlockEntity table, DuelSession session, ServerPlayer player) {
@@ -98,22 +93,16 @@ public final class DuelTableAnimationResolver {
session.beginOpponentAnimation(); session.beginOpponentAnimation();
} }
table.startMoveAnimation(aiMove, owner); table.startMoveAnimation(aiMove, owner);
player.displayClientMessage(Component.literal((owner == DuelTableBlockEntity.OWNER_FIRST ? "Blue AI" : "Red AI") + " plays " + aiMove.playedCardName() + ".")
.withStyle(ChatFormatting.GRAY), false);
sendBattleLog(player, aiMove, ChatFormatting.GRAY);
} }
private static void enterOverview(DuelTableBlockEntity table, DuelSession session, ServerPlayer player) { private static void enterOverview(DuelTableBlockEntity table, DuelSession session, ServerPlayer player) {
session.enterOverview(); session.enterOverview();
table.setRewardCards(session.opponentRewardCards().stream()
.map(cardId -> CardItem.createCardStack(cardId, TriadItems.TRIAD_CARD.get()))
.toList());
table.removeBoardCardsOwnedBy(DuelTableBlockEntity.OWNER_SECOND);
table.startOverviewSweepAnimation(); table.startOverviewSweepAnimation();
player.displayClientMessage(session.resultSummary().copy().withStyle(ChatFormatting.AQUA), false); player.displayClientMessage(session.resultSummary().copy().withStyle(ChatFormatting.AQUA), false);
player.displayClientMessage(session.overviewMessage().copy().withStyle(ChatFormatting.YELLOW), false);
}
private static void sendBattleLog(ServerPlayer player, MoveResult moveResult, ChatFormatting color) {
for (String line : moveResult.battleLog()) {
player.displayClientMessage(Component.literal(line).withStyle(color), false);
}
} }
private static ServerPlayer getPlayer(Level level, DuelSession session) { private static ServerPlayer getPlayer(Level level, DuelSession session) {

View File

@@ -18,6 +18,7 @@ import net.minecraft.core.BlockPos;
import net.minecraft.core.HolderLookup; import net.minecraft.core.HolderLookup;
import net.minecraft.core.NonNullList; import net.minecraft.core.NonNullList;
import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.Tag;
import net.minecraft.network.Connection; import net.minecraft.network.Connection;
import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket; import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket;
import net.minecraft.network.chat.Component; import net.minecraft.network.chat.Component;
@@ -30,6 +31,7 @@ import net.minecraft.world.level.block.state.BlockState;
public class DuelTableBlockEntity extends BlockEntity { public class DuelTableBlockEntity extends BlockEntity {
public static final int SLOT_COUNT = 9; public static final int SLOT_COUNT = 9;
public static final int REWARD_SLOT_COUNT = 5;
public static final int OWNER_NONE = 0; public static final int OWNER_NONE = 0;
public static final int OWNER_FIRST = 1; public static final int OWNER_FIRST = 1;
public static final int OWNER_SECOND = 2; public static final int OWNER_SECOND = 2;
@@ -39,6 +41,7 @@ public class DuelTableBlockEntity extends BlockEntity {
private static final int CLEAR_WAVE_DURATION = 10; private static final int CLEAR_WAVE_DURATION = 10;
private final NonNullList<ItemStack> boardCards = NonNullList.withSize(SLOT_COUNT, ItemStack.EMPTY); private final NonNullList<ItemStack> boardCards = NonNullList.withSize(SLOT_COUNT, ItemStack.EMPTY);
private final NonNullList<ItemStack> rewardCards = NonNullList.withSize(REWARD_SLOT_COUNT, ItemStack.EMPTY);
private final int[] ownerSlots = new int[SLOT_COUNT]; private final int[] ownerSlots = new int[SLOT_COUNT];
private final int[] slotAges = new int[SLOT_COUNT]; private final int[] slotAges = new int[SLOT_COUNT];
private final ArrayDeque<AnimationStep> pendingAnimations = new ArrayDeque<>(); private final ArrayDeque<AnimationStep> pendingAnimations = new ArrayDeque<>();
@@ -62,6 +65,20 @@ public class DuelTableBlockEntity extends BlockEntity {
return boardCards.get(slot); return boardCards.get(slot);
} }
public ItemStack getRewardCard(int slot) {
return slot >= 0 && slot < rewardCards.size() ? rewardCards.get(slot) : ItemStack.EMPTY;
}
public int rewardCardCount() {
int count = 0;
for (ItemStack rewardCard : rewardCards) {
if (!rewardCard.isEmpty()) {
count++;
}
}
return count;
}
public int ownerAt(int slot) { public int ownerAt(int slot) {
return ownerSlots[slot]; return ownerSlots[slot];
} }
@@ -167,11 +184,28 @@ public class DuelTableBlockEntity extends BlockEntity {
} }
pendingAnimations.clear(); pendingAnimations.clear();
clearAnimationState(); clearAnimationState();
clearRewardCards();
firstParticipantId = null; firstParticipantId = null;
secondParticipantId = null; secondParticipantId = null;
sync(); sync();
} }
public void removeBoardCardsOwnedBy(int owner) {
boolean changed = false;
for (int index = 0; index < boardCards.size(); index++) {
if (ownerSlots[index] != owner || boardCards.get(index).isEmpty()) {
continue;
}
boardCards.set(index, ItemStack.EMPTY);
ownerSlots[index] = OWNER_NONE;
slotAges[index] = 0;
changed = true;
}
if (changed) {
sync();
}
}
public void dropBoardCards(Level level, BlockPos pos) { public void dropBoardCards(Level level, BlockPos pos) {
for (int slot = 0; slot < boardCards.size(); slot++) { for (int slot = 0; slot < boardCards.size(); slot++) {
ItemStack stack = boardCards.get(slot); ItemStack stack = boardCards.get(slot);
@@ -184,11 +218,52 @@ public class DuelTableBlockEntity extends BlockEntity {
} }
pendingAnimations.clear(); pendingAnimations.clear();
clearAnimationState(); clearAnimationState();
dropRewardCards(level, pos);
firstParticipantId = null; firstParticipantId = null;
secondParticipantId = null; secondParticipantId = null;
sync(); sync();
} }
public void setRewardCards(List<ItemStack> stacks) {
clearRewardCards();
for (int index = 0; index < rewardCards.size() && index < stacks.size(); index++) {
ItemStack stack = stacks.get(index);
if (!stack.isEmpty()) {
rewardCards.set(index, stack.copyWithCount(1));
}
}
sync();
}
public ItemStack takeRewardCard(int slot) {
if (slot < 0 || slot >= rewardCards.size()) {
return ItemStack.EMPTY;
}
ItemStack taken = rewardCards.get(slot);
if (taken.isEmpty()) {
return ItemStack.EMPTY;
}
rewardCards.set(slot, ItemStack.EMPTY);
sync();
return taken;
}
public void clearRewardCards() {
for (int index = 0; index < rewardCards.size(); index++) {
rewardCards.set(index, ItemStack.EMPTY);
}
}
public void dropRewardCards(Level level, BlockPos pos) {
for (int slot = 0; slot < rewardCards.size(); slot++) {
ItemStack stack = rewardCards.get(slot);
if (!stack.isEmpty()) {
Block.popResource(level, pos, stack);
rewardCards.set(slot, ItemStack.EMPTY);
}
}
}
public void startMoveAnimation(MoveResult moveResult, int owner) { public void startMoveAnimation(MoveResult moveResult, int owner) {
pendingAnimations.clear(); pendingAnimations.clear();
clearAnimationState(); clearAnimationState();
@@ -280,6 +355,9 @@ public class DuelTableBlockEntity extends BlockEntity {
protected void saveAdditional(CompoundTag tag, HolderLookup.Provider registries) { protected void saveAdditional(CompoundTag tag, HolderLookup.Provider registries) {
super.saveAdditional(tag, registries); super.saveAdditional(tag, registries);
ContainerHelper.saveAllItems(tag, boardCards, registries); ContainerHelper.saveAllItems(tag, boardCards, registries);
CompoundTag rewardTag = new CompoundTag();
ContainerHelper.saveAllItems(rewardTag, rewardCards, registries);
tag.put("RewardCards", rewardTag);
tag.putIntArray("OwnerSlots", ownerSlots); tag.putIntArray("OwnerSlots", ownerSlots);
tag.putIntArray("SlotAges", slotAges); tag.putIntArray("SlotAges", slotAges);
saveAnimation(tag); saveAnimation(tag);
@@ -297,6 +375,9 @@ public class DuelTableBlockEntity extends BlockEntity {
super.loadAdditional(tag, registries); super.loadAdditional(tag, registries);
clearBoardContents(); clearBoardContents();
ContainerHelper.loadAllItems(tag, boardCards, registries); ContainerHelper.loadAllItems(tag, boardCards, registries);
if (tag.contains("RewardCards", Tag.TAG_COMPOUND)) {
ContainerHelper.loadAllItems(tag.getCompound("RewardCards"), rewardCards, registries);
}
loadOwnerData(tag); loadOwnerData(tag);
loadAnimation(tag); loadAnimation(tag);
loadTableAnimation(tag); loadTableAnimation(tag);
@@ -306,6 +387,9 @@ public class DuelTableBlockEntity extends BlockEntity {
public CompoundTag getUpdateTag(HolderLookup.Provider registries) { public CompoundTag getUpdateTag(HolderLookup.Provider registries) {
CompoundTag tag = super.getUpdateTag(registries); CompoundTag tag = super.getUpdateTag(registries);
ContainerHelper.saveAllItems(tag, boardCards, registries); ContainerHelper.saveAllItems(tag, boardCards, registries);
CompoundTag rewardTag = new CompoundTag();
ContainerHelper.saveAllItems(rewardTag, rewardCards, registries);
tag.put("RewardCards", rewardTag);
tag.putIntArray("OwnerSlots", ownerSlots); tag.putIntArray("OwnerSlots", ownerSlots);
tag.putIntArray("SlotAges", slotAges); tag.putIntArray("SlotAges", slotAges);
saveAnimation(tag); saveAnimation(tag);
@@ -330,6 +414,9 @@ public class DuelTableBlockEntity extends BlockEntity {
if (tag != null) { if (tag != null) {
clearBoardContents(); clearBoardContents();
ContainerHelper.loadAllItems(tag, boardCards, registries); ContainerHelper.loadAllItems(tag, boardCards, registries);
if (tag.contains("RewardCards", Tag.TAG_COMPOUND)) {
ContainerHelper.loadAllItems(tag.getCompound("RewardCards"), rewardCards, registries);
}
loadOwnerData(tag); loadOwnerData(tag);
loadAnimation(tag); loadAnimation(tag);
loadTableAnimation(tag); loadTableAnimation(tag);
@@ -344,6 +431,7 @@ public class DuelTableBlockEntity extends BlockEntity {
} }
pendingAnimations.clear(); pendingAnimations.clear();
clearAnimationState(); clearAnimationState();
clearRewardCards();
firstParticipantId = null; firstParticipantId = null;
secondParticipantId = null; secondParticipantId = null;
} }

View File

@@ -15,6 +15,7 @@ import net.minecraft.world.item.ItemStack;
public class DuelTableBlockEntityRenderer implements BlockEntityRenderer<DuelTableBlockEntity> { public class DuelTableBlockEntityRenderer implements BlockEntityRenderer<DuelTableBlockEntity> {
private static final float TABLE_CARD_Y = 1.066F; private static final float TABLE_CARD_Y = 1.066F;
private static final float REWARD_CARD_Y = 1.75F;
private static final float IDLE_BOB_HEIGHT = 0.012F; private static final float IDLE_BOB_HEIGHT = 0.012F;
private static final float IDLE_BOB_SPEED = 0.08F; private static final float IDLE_BOB_SPEED = 0.08F;
@@ -44,7 +45,7 @@ public class DuelTableBlockEntityRenderer implements BlockEntityRenderer<DuelTab
y += (float) Math.sin(progress * Math.PI) * 0.08F; y += (float) Math.sin(progress * Math.PI) * 0.08F;
extraFlip = 360.0F * progress; extraFlip = 360.0F * progress;
} }
} else if (!blockEntity.hasActiveAnimation()) { } else {
y += idleOffset; y += idleOffset;
} }
if (blockEntity.hasOverviewSweepAnimation()) { if (blockEntity.hasOverviewSweepAnimation()) {
@@ -71,6 +72,40 @@ public class DuelTableBlockEntityRenderer implements BlockEntityRenderer<DuelTab
TriadCardItemRenderer.renderCard(stack, poseStack, buffer, perspectivePalette(blockEntity, blockEntity.ownerAt(slot))); TriadCardItemRenderer.renderCard(stack, poseStack, buffer, perspectivePalette(blockEntity, blockEntity.ownerAt(slot)));
poseStack.popPose(); poseStack.popPose();
} }
renderRewardCards(blockEntity, partialTick, poseStack, buffer);
}
private static void renderRewardCards(DuelTableBlockEntity blockEntity, float partialTick, PoseStack poseStack, MultiBufferSource buffer) {
int rewardCount = blockEntity.rewardCardCount();
if (rewardCount <= 0) {
return;
}
int rewardIndex = 0;
for (int slot = 0; slot < DuelTableBlockEntity.REWARD_SLOT_COUNT; slot++) {
ItemStack rewardStack = blockEntity.getRewardCard(slot);
if (rewardStack.isEmpty()) {
continue;
}
BoardLocalSpace.SlotCenter center = BoardLocalSpace.rewardCenter(
rewardIndex,
blockEntity.getBlockState().getValue(DuelTableBlock.FACING),
rewardCount);
float manifestProgress = blockEntity.hasOverviewSweepAnimation()
? Math.max(0.2F, blockEntity.overviewSweepSlotProgress(Math.min(slot, DuelTableBlockEntity.SLOT_COUNT - 1), partialTick))
: 1.0F;
float y = 1.0F + (REWARD_CARD_Y - 1.0F) * manifestProgress + (float) Math.sin((Minecraft.getInstance().level == null ? 0.0F : (Minecraft.getInstance().level.getGameTime() + partialTick) * 0.08F) + rewardIndex * 0.7F) * 0.01F;
poseStack.pushPose();
poseStack.translate(center.x(), y, center.z());
poseStack.mulPose(Axis.YP.rotationDegrees(blockEntity.getBlockState().getValue(DuelTableBlock.FACING).toYRot()));
poseStack.scale(0.3F, 0.3F, 0.3F);
TriadCardItemRenderer.renderCard(rewardStack, poseStack, buffer, perspectivePalette(blockEntity, DuelTableBlockEntity.OWNER_SECOND));
poseStack.popPose();
rewardIndex++;
}
} }
private static float idleBob(DuelTableBlockEntity blockEntity, int slot, float partialTick) { private static float idleBob(DuelTableBlockEntity blockEntity, int slot, float partialTick) {

View File

@@ -36,6 +36,31 @@ public final class BoardLocalSpace {
}; };
} }
public static SlotCenter rewardCenter(int index, Direction boardFacing, int count) {
if (count <= 0) {
return new SlotCenter(0.5F, 0.22F);
}
float columnProgress = count == 1 ? 0.5F : -0.04F + (1.08F * index / (count - 1.0F));
float rowProgress = 0.15F;
HorizontalVector bottomVector = vectorFor(boardFacing);
HorizontalVector rightVector = vectorFor(rightDirection(boardFacing));
float x = 0.5F + bottomVector.x() * (rowProgress - 0.5F) + rightVector.x() * (columnProgress - 0.5F);
float z = 0.5F + bottomVector.z() * (rowProgress - 0.5F) + rightVector.z() * (columnProgress - 0.5F);
return new SlotCenter(x, z);
}
public static int rewardIndexForHit(BlockHitResult hitResult, Direction boardFacing, int count) {
double localX = hitResult.getLocation().x - hitResult.getBlockPos().getX();
double localZ = hitResult.getLocation().z - hitResult.getBlockPos().getZ();
for (int index = 0; index < count; index++) {
SlotCenter center = rewardCenter(index, boardFacing, count);
if (Math.abs(localX - center.x()) <= 0.07D && Math.abs(localZ - center.z()) <= 0.12D) {
return index;
}
}
return -1;
}
private static double projectProgress(double localX, double localZ, Direction direction) { private static double projectProgress(double localX, double localZ, Direction direction) {
HorizontalVector vector = vectorFor(direction); HorizontalVector vector = vectorFor(direction);
double offsetX = localX - 0.5D; double offsetX = localX - 0.5D;

View File

@@ -28,6 +28,7 @@ public final class DuelSession {
private final MatchParticipant opponentParticipant; private final MatchParticipant opponentParticipant;
private final TriadMatch match; private final TriadMatch match;
private final List<ResourceLocation> refundablePlayerCards; private final List<ResourceLocation> refundablePlayerCards;
private final List<ResourceLocation> opponentStartingCards;
private final boolean refundCardsOnEnd; private final boolean refundCardsOnEnd;
private final boolean aiVsAi; private final boolean aiVsAi;
private final BlockPos tablePos; private final BlockPos tablePos;
@@ -46,6 +47,9 @@ public final class DuelSession {
this.opponentParticipant = new MatchParticipant(UUID.nameUUIDFromBytes(("opponent:" + playerId).getBytes()), "Training Duelist"); this.opponentParticipant = new MatchParticipant(UUID.nameUUIDFromBytes(("opponent:" + playerId).getBytes()), "Training Duelist");
this.match = new TriadMatch(playerParticipant, opponentParticipant, playerHand, opponentHand, TriadRuleSet.CLASSIC_OPEN); this.match = new TriadMatch(playerParticipant, opponentParticipant, playerHand, opponentHand, TriadRuleSet.CLASSIC_OPEN);
this.refundablePlayerCards = List.copyOf(refundablePlayerCards); this.refundablePlayerCards = List.copyOf(refundablePlayerCards);
this.opponentStartingCards = opponentHand.stream()
.map(card -> card.definition().id())
.toList();
this.refundCardsOnEnd = refundCardsOnEnd; this.refundCardsOnEnd = refundCardsOnEnd;
this.aiVsAi = aiVsAi; this.aiVsAi = aiVsAi;
this.tablePos = tablePos.immutable(); this.tablePos = tablePos.immutable();
@@ -210,7 +214,7 @@ public final class DuelSession {
} }
public Component overviewMessage() { public Component overviewMessage() {
return Component.literal("Duel overview. Right-click the table to finish and return cards."); return Component.literal("Duel overview. Right-click a floating red card to take it, or right-click the table to finish.");
} }
public List<ResourceLocation> refundablePlayerCards() { public List<ResourceLocation> refundablePlayerCards() {
@@ -245,6 +249,10 @@ public final class DuelSession {
return refundCardsOnEnd; return refundCardsOnEnd;
} }
public List<ResourceLocation> opponentRewardCards() {
return List.copyOf(opponentStartingCards);
}
public boolean isAtTable(BlockPos blockPos) { public boolean isAtTable(BlockPos blockPos) {
return tablePos.equals(blockPos); return tablePos.equals(blockPos);
} }

View File

@@ -56,19 +56,31 @@ public class DuelTableBlock extends BaseEntityBlock {
} }
try { try {
if (hitResult.getDirection() != Direction.UP) {
player.displayClientMessage(Component.literal("Click the top face of the Duel Table to target a board space.").withStyle(ChatFormatting.YELLOW), false);
return ItemInteractionResult.CONSUME;
}
Direction tableFacing = state.getValue(FACING);
DuelTableBlockEntity table = getTableEntity(level, pos); DuelTableBlockEntity table = getTableEntity(level, pos);
if (table == null) { if (table == null) {
player.displayClientMessage(Component.literal("Duel table storage is unavailable.").withStyle(ChatFormatting.RED), false); player.displayClientMessage(Component.literal("Duel table storage is unavailable.").withStyle(ChatFormatting.RED), false);
return ItemInteractionResult.CONSUME; return ItemInteractionResult.CONSUME;
} }
Direction tableFacing = state.getValue(FACING);
DuelSession session = DuelSessionManager.get(player); DuelSession session = DuelSessionManager.get(player);
if (session != null && session.isInOverview()) {
if (tryTakeRewardCard(level, pos, player, hitResult, tableFacing)) {
return ItemInteractionResult.CONSUME;
}
if (hitResult.getDirection() != Direction.UP) {
return ItemInteractionResult.CONSUME;
}
completeOverview(level, pos, player, session);
return ItemInteractionResult.CONSUME;
}
if (hitResult.getDirection() != Direction.UP) {
player.displayClientMessage(Component.literal("Click the top face of the Duel Table to target a board space.").withStyle(ChatFormatting.YELLOW), false);
return ItemInteractionResult.CONSUME;
}
if (session == null) { if (session == null) {
boolean aiVsAi = stack.isEmpty(); boolean aiVsAi = stack.isEmpty();
try { try {
@@ -86,24 +98,15 @@ public class DuelTableBlock extends BaseEntityBlock {
} }
} else { } else {
player.displayClientMessage(session.startMessage().copy().withStyle(ChatFormatting.GOLD), false); player.displayClientMessage(session.startMessage().copy().withStyle(ChatFormatting.GOLD), false);
player.displayClientMessage(session.handSummary(), false);
} }
return ItemInteractionResult.CONSUME; return ItemInteractionResult.CONSUME;
} }
if (session.isInOverview()) {
completeOverview(level, pos, player, session);
return ItemInteractionResult.CONSUME;
}
if (table.hasActiveAnimation() || session.isAnimating()) { if (table.hasActiveAnimation() || session.isAnimating()) {
player.displayClientMessage(Component.literal("Wait for the current card animation to finish.").withStyle(ChatFormatting.YELLOW), false);
return ItemInteractionResult.CONSUME; return ItemInteractionResult.CONSUME;
} }
if (!stack.is(TriadItems.TRIAD_CARD.get())) { if (!stack.is(TriadItems.TRIAD_CARD.get())) {
player.displayClientMessage(Component.literal("Hold a Triad Card from your duel hand to play your turn.").withStyle(ChatFormatting.YELLOW), false);
player.displayClientMessage(session.handSummary(), false);
return ItemInteractionResult.CONSUME; return ItemInteractionResult.CONSUME;
} }
@@ -116,8 +119,6 @@ public class DuelTableBlock extends BaseEntityBlock {
MoveResult playerMove = session.playPlayerCard(cardData.cardId(), hitResult, player.getAbilities().instabuild, tableFacing); MoveResult playerMove = session.playPlayerCard(cardData.cardId(), hitResult, player.getAbilities().instabuild, tableFacing);
if (!playerMove.valid()) { if (!playerMove.valid()) {
player.displayClientMessage(Component.literal("Move rejected: " + playerMove.errorMessage()).withStyle(ChatFormatting.RED), false); player.displayClientMessage(Component.literal("Move rejected: " + playerMove.errorMessage()).withStyle(ChatFormatting.RED), false);
player.displayClientMessage(session.boardSummary().copy().withStyle(ChatFormatting.DARK_GRAY), false);
player.displayClientMessage(session.handSummary(), false);
return ItemInteractionResult.CONSUME; return ItemInteractionResult.CONSUME;
} }
@@ -133,8 +134,6 @@ public class DuelTableBlock extends BaseEntityBlock {
session.beginPlayerAnimation(); session.beginPlayerAnimation();
table.startMoveAnimation(playerMove, DuelTableBlockEntity.OWNER_FIRST); table.startMoveAnimation(playerMove, DuelTableBlockEntity.OWNER_FIRST);
player.displayClientMessage(Component.literal("You play " + playerMove.playedCardName() + "."), false);
sendBattleLog(player, playerMove, ChatFormatting.DARK_AQUA);
return ItemInteractionResult.CONSUME; return ItemInteractionResult.CONSUME;
} catch (Exception exception) { } catch (Exception exception) {
MineTriad.LOGGER.error("Duel table interaction failed", exception); MineTriad.LOGGER.error("Duel table interaction failed", exception);
@@ -209,12 +208,6 @@ public class DuelTableBlock extends BaseEntityBlock {
return table.setCard(moveResult.playedCell().index(), CardItem.createCardStack(moveResult.playedCardId(), TriadItems.TRIAD_CARD.get()), owner); return table.setCard(moveResult.playedCell().index(), CardItem.createCardStack(moveResult.playedCardId(), TriadItems.TRIAD_CARD.get()), owner);
} }
private static void sendBattleLog(Player player, MoveResult moveResult, ChatFormatting color) {
for (String line : moveResult.battleLog()) {
player.displayClientMessage(Component.literal(line).withStyle(color), false);
}
}
private static DuelTableBlockEntity getTableEntity(Level level, BlockPos pos) { private static DuelTableBlockEntity getTableEntity(Level level, BlockPos pos) {
BlockEntity blockEntity = level.getBlockEntity(pos); BlockEntity blockEntity = level.getBlockEntity(pos);
return blockEntity instanceof DuelTableBlockEntity duelTableBlockEntity ? duelTableBlockEntity : null; return blockEntity instanceof DuelTableBlockEntity duelTableBlockEntity ? duelTableBlockEntity : null;
@@ -235,4 +228,42 @@ public class DuelTableBlock extends BaseEntityBlock {
table.startClearWaveAnimation(); table.startClearWaveAnimation();
} }
} }
private static boolean tryTakeRewardCard(Level level, BlockPos pos, Player player, BlockHitResult hitResult, Direction tableFacing) {
DuelTableBlockEntity table = getTableEntity(level, pos);
if (table == null || table.rewardCardCount() <= 0) {
return false;
}
int rewardIndex = com.trunksbomb.minetriad.game.BoardLocalSpace.rewardIndexForHit(hitResult, tableFacing, table.rewardCardCount());
if (rewardIndex < 0) {
return false;
}
int actualSlot = actualRewardSlot(table, rewardIndex);
if (actualSlot < 0) {
return false;
}
ItemStack reward = table.takeRewardCard(actualSlot);
if (reward.isEmpty()) {
return false;
}
return true;
}
private static int actualRewardSlot(DuelTableBlockEntity table, int rewardIndex) {
int visibleIndex = 0;
for (int slot = 0; slot < DuelTableBlockEntity.REWARD_SLOT_COUNT; slot++) {
if (table.getRewardCard(slot).isEmpty()) {
continue;
}
if (visibleIndex == rewardIndex) {
return slot;
}
visibleIndex++;
}
return -1;
}
} }