Fixed players being able to join 1v1 limited games after they start to force more rounds

This commit is contained in:
jakub.salavec
2025-04-14 13:32:46 +02:00
parent c2bb9eead0
commit 62334bb638
11 changed files with 73 additions and 21 deletions

View File

@@ -666,6 +666,7 @@ var GempLotrHallUI = Class.extend({
var stage = tournament.getAttribute("stage"); var stage = tournament.getAttribute("stage");
if(stage !== null) if(stage !== null)
stage = stage.toLowerCase(); stage = stage.toLowerCase();
var joinable = tournament.getAttribute("joinable") === "true";
var abandoned = tournament.getAttribute("abandoned") === "true"; var abandoned = tournament.getAttribute("abandoned") === "true";
if (action == "add" || action == "update") { if (action == "add" || action == "update") {
var actionsField = $("<td></td>"); var actionsField = $("<td></td>");
@@ -763,8 +764,7 @@ var GempLotrHallUI = Class.extend({
actionsField.append(but); actionsField.append(but);
} }
else if(!abandoned){ else if(!abandoned){
if(!(type === "table_draft") && (stage === "deck-building" || stage === "drafting" || stage === "awaiting kickoff" if(joinable) {
|| stage === "preparing" || stage === "paused between rounds")) {
var but = $("<button>Join Tournament</button>"); var but = $("<button>Join Tournament</button>");
$(but).button().click(( $(but).button().click((
function(tourneyInfo) { function(tourneyInfo) {

View File

@@ -128,7 +128,7 @@ public class HallCommunicationChannel implements LongPollableResource {
@Override @Override
public void visitTournament(String tournamentKey, String collectionName, String formatName, String tournamentName, String type, String pairingDescription, public void visitTournament(String tournamentKey, String collectionName, String formatName, String tournamentName, String type, String pairingDescription,
String tournamentStage, int round, int playerCount, String playerList, boolean playerInCompetition, boolean abandoned) { String tournamentStage, int round, int playerCount, String playerList, boolean playerInCompetition, boolean abandoned, boolean joinable) {
Map<String, String> props = new HashMap<>(); Map<String, String> props = new HashMap<>();
props.put("collection", collectionName); props.put("collection", collectionName);
props.put("format", formatName); props.put("format", formatName);
@@ -141,6 +141,7 @@ public class HallCommunicationChannel implements LongPollableResource {
props.put("playerList", playerList); props.put("playerList", playerList);
props.put("signedUp", String.valueOf(playerInCompetition)); props.put("signedUp", String.valueOf(playerInCompetition));
props.put("abandoned", String.valueOf(abandoned)); props.put("abandoned", String.valueOf(abandoned));
props.put("joinable", String.valueOf(joinable));
tournamentsOnServer.put(tournamentKey, props); tournamentsOnServer.put(tournamentKey, props);
} }

View File

@@ -18,7 +18,7 @@ public interface HallInfoVisitor {
int readyCheckSecsRemaining, boolean confirmedReadyCheck); int readyCheckSecsRemaining, boolean confirmedReadyCheck);
public void visitTournament(String tournamentKey, String collectionName, String formatName, String tournamentName, String type, public void visitTournament(String tournamentKey, String collectionName, String formatName, String tournamentName, String type,
String pairingDescription, String tournamentStage, int round, int playerCount, String playerList, boolean playerInCompetition, boolean abandoned); String pairingDescription, String tournamentStage, int round, int playerCount, String playerList, boolean playerInCompetition, boolean abandoned, boolean joinable);
public void runningPlayerGame(String gameId); public void runningPlayerGame(String gameId);
} }

View File

@@ -1,6 +1,9 @@
package com.gempukku.lotro.hall; package com.gempukku.lotro.hall;
import com.gempukku.lotro.*; import com.gempukku.lotro.AbstractServer;
import com.gempukku.lotro.PrivateInformationException;
import com.gempukku.lotro.SubscriptionConflictException;
import com.gempukku.lotro.SubscriptionExpiredException;
import com.gempukku.lotro.chat.ChatCommandCallback; import com.gempukku.lotro.chat.ChatCommandCallback;
import com.gempukku.lotro.chat.ChatCommandErrorException; import com.gempukku.lotro.chat.ChatCommandErrorException;
import com.gempukku.lotro.chat.ChatRoomMediator; import com.gempukku.lotro.chat.ChatRoomMediator;
@@ -18,7 +21,10 @@ import com.gempukku.lotro.logic.GameUtils;
import com.gempukku.lotro.logic.timing.GameResultListener; import com.gempukku.lotro.logic.timing.GameResultListener;
import com.gempukku.lotro.logic.vo.LotroDeck; import com.gempukku.lotro.logic.vo.LotroDeck;
import com.gempukku.lotro.service.AdminService; import com.gempukku.lotro.service.AdminService;
import com.gempukku.lotro.tournament.*; import com.gempukku.lotro.tournament.Tournament;
import com.gempukku.lotro.tournament.TournamentCallback;
import com.gempukku.lotro.tournament.TournamentQueue;
import com.gempukku.lotro.tournament.TournamentService;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
@@ -540,24 +546,21 @@ public class HallServer extends AbstractServer {
try { try {
String result = ""; String result = "";
var tournament = _tournamentService.getTournamentById(tournamentId); var tournament = _tournamentService.getTournamentById(tournamentId);
if (tournament != null) { if (tournament == null) {
var stage = tournament.getInfo().Stage; result = "That tournament is already over.";
if(stage == Tournament.Stage.STARTING || stage == Tournament.Stage.DECK_BUILDING || } else if (!tournament.isJoinable()) {
stage == Tournament.Stage.PAUSED || stage == Tournament.Stage.AWAITING_KICKOFF) { result = "That tournament does not allow late joining.";
LotroDeck lotroDeck = null; } else {
if (tournament.getInfo().Parameters().requiresDeck) { LotroDeck lotroDeck = null;
lotroDeck = validateUserAndDeck(_formatLibrary.getFormat(tournament.getFormatCode()), player, deckName, tournament.getCollectionType()); if (tournament.getInfo().Parameters().requiresDeck) {
} lotroDeck = validateUserAndDeck(_formatLibrary.getFormat(tournament.getFormatCode()), player, deckName, tournament.getCollectionType());
_tournamentService.recordTournamentPlayer(tournamentId, player.getName(), lotroDeck);
tournament.issuePlayerMaterial(player.getName());
} }
_tournamentService.recordTournamentPlayer(tournamentId, player.getName(), lotroDeck);
tournament.issuePlayerMaterial(player.getName());
result = "Joined tournament <b>" + tournament.getTournamentName() + "</b> successfully."; result = "Joined tournament <b>" + tournament.getTournamentName() + "</b> successfully.";
hallChanged(); hallChanged();
} }
else {
result = "That tournament is already over.";
}
return result; return result;
} }

View File

@@ -127,4 +127,13 @@ public class ConstructedTournament extends BaseTournament implements Tournament
//This is for draft only //This is for draft only
} }
@Override
public boolean isJoinable() {
Set<String> activePlayers = new HashSet<>(_players);
activePlayers.removeAll(_droppedPlayers);
int maximumPlayers = _tournamentInfo._params.maximumPlayers;
return (getTournamentStage() == Tournament.Stage.STARTING || getTournamentStage() == Stage.PREPARING ||
getTournamentStage() == Tournament.Stage.PAUSED || getTournamentStage() == Tournament.Stage.AWAITING_KICKOFF)
&& (maximumPlayers > activePlayers.size() || maximumPlayers < 0);
}
} }

View File

@@ -238,4 +238,13 @@ public class SealedTournament extends BaseTournament implements Tournament {
//This is for draft only //This is for draft only
} }
@Override
public boolean isJoinable() {
Set<String> activePlayers = new HashSet<>(_players);
activePlayers.removeAll(_droppedPlayers);
int maximumPlayers = _tournamentInfo._params.maximumPlayers;
return (getTournamentStage() == Stage.STARTING || getTournamentStage() == Stage.DECK_BUILDING || getTournamentStage() == Stage.DECK_REGISTRATION ||
getTournamentStage() == Tournament.Stage.PAUSED || getTournamentStage() == Tournament.Stage.AWAITING_KICKOFF)
&& (maximumPlayers > activePlayers.size() || maximumPlayers < 0);
}
} }

View File

@@ -252,4 +252,14 @@ public class SoloDraftTournament extends BaseTournament implements Tournament {
public CollectionType getCollectionType() { public CollectionType getCollectionType() {
return _soloDraftInfo.generateCollectionInfo(); return _soloDraftInfo.generateCollectionInfo();
} }
@Override
public boolean isJoinable() {
Set<String> activePlayers = new HashSet<>(_players);
activePlayers.removeAll(_droppedPlayers);
int maximumPlayers = _tournamentInfo._params.maximumPlayers;
return (getTournamentStage() == Stage.STARTING || getTournamentStage() == Stage.DECK_BUILDING || getTournamentStage() == Stage.DECK_REGISTRATION ||
getTournamentStage() == Tournament.Stage.PAUSED || getTournamentStage() == Tournament.Stage.AWAITING_KICKOFF)
&& (maximumPlayers > activePlayers.size() || maximumPlayers < 0);
}
} }

View File

@@ -235,4 +235,14 @@ public class SoloTableDraftTournament extends BaseTournament implements Tourname
public CollectionType getCollectionType() { public CollectionType getCollectionType() {
return soloTableDraftInfo.generateCollectionInfo(); return soloTableDraftInfo.generateCollectionInfo();
} }
@Override
public boolean isJoinable() {
Set<String> activePlayers = new HashSet<>(_players);
activePlayers.removeAll(_droppedPlayers);
int maximumPlayers = _tournamentInfo._params.maximumPlayers;
return (getTournamentStage() == Stage.STARTING || getTournamentStage() == Stage.DECK_BUILDING || getTournamentStage() == Stage.DECK_REGISTRATION ||
getTournamentStage() == Tournament.Stage.PAUSED || getTournamentStage() == Tournament.Stage.AWAITING_KICKOFF)
&& (maximumPlayers > activePlayers.size() || maximumPlayers < 0);
}
} }

View File

@@ -257,4 +257,9 @@ public class TableDraftTournament extends BaseTournament implements Tournament {
public CollectionType getCollectionType() { public CollectionType getCollectionType() {
return tableDraftInfo.generateCollectionInfo(); return tableDraftInfo.generateCollectionInfo();
} }
@Override
public boolean isJoinable() {
return false; // cannot join draft in progress
}
} }

View File

@@ -204,4 +204,6 @@ public interface Tournament {
String produceReport(DeckRenderer renderer) throws CardNotFoundException; String produceReport(DeckRenderer renderer) throws CardNotFoundException;
TournamentInfo getInfo(); TournamentInfo getInfo();
boolean isJoinable();
} }

View File

@@ -101,6 +101,7 @@ public class TournamentService {
sealedParams.name = queueName; sealedParams.name = queueName;
sealedParams.cost = 0; sealedParams.cost = 0;
sealedParams.minimumPlayers = 2; sealedParams.minimumPlayers = 2;
sealedParams.maximumPlayers = 2;
sealedParams.playoff = Tournament.PairingType.SINGLE_ELIMINATION; sealedParams.playoff = Tournament.PairingType.SINGLE_ELIMINATION;
sealedParams.prizes = Tournament.PrizeType.NONE; sealedParams.prizes = Tournament.PrizeType.NONE;
@@ -128,6 +129,7 @@ public class TournamentService {
soloDraftParams.name = queueName; soloDraftParams.name = queueName;
soloDraftParams.cost = 0; soloDraftParams.cost = 0;
soloDraftParams.minimumPlayers = 2; soloDraftParams.minimumPlayers = 2;
soloDraftParams.maximumPlayers = 2;
soloDraftParams.playoff = Tournament.PairingType.SINGLE_ELIMINATION; soloDraftParams.playoff = Tournament.PairingType.SINGLE_ELIMINATION;
soloDraftParams.prizes = Tournament.PrizeType.NONE; soloDraftParams.prizes = Tournament.PrizeType.NONE;
@@ -265,7 +267,8 @@ public class TournamentService {
visitor.visitTournament(tourneyID, tournament.getCollectionType().getFullName(), visitor.visitTournament(tourneyID, tournament.getCollectionType().getFullName(),
formatLibrary.getFormat(tournament.getFormatCode()).getName(), tournament.getTournamentName(), tournament.getInfo().Parameters().type.toString(), tournament.getPlayOffSystem(), formatLibrary.getFormat(tournament.getFormatCode()).getName(), tournament.getTournamentName(), tournament.getInfo().Parameters().type.toString(), tournament.getPlayOffSystem(),
tournament.getTournamentStage().getHumanReadable(), tournament.getTournamentStage().getHumanReadable(),
tournament.getCurrentRound(), tournament.getPlayersInCompetitionCount(), tournament.getPlayerList(), tournament.isPlayerInCompetition(player.getName()), tournament.isPlayerAbandoned(player.getName())); tournament.getCurrentRound(), tournament.getPlayersInCompetitionCount(), tournament.getPlayerList(), tournament.isPlayerInCompetition(player.getName()), tournament.isPlayerAbandoned(player.getName()),
tournament.isJoinable());
} }
} }