diff --git a/gemp-lotr/gemp-lotr-async/src/main/web/js/gemp-022/hallUi.js b/gemp-lotr/gemp-lotr-async/src/main/web/js/gemp-022/hallUi.js
index bd34f4ae6..d7c9ceec5 100644
--- a/gemp-lotr/gemp-lotr-async/src/main/web/js/gemp-022/hallUi.js
+++ b/gemp-lotr/gemp-lotr-async/src/main/web/js/gemp-022/hallUi.js
@@ -666,6 +666,7 @@ var GempLotrHallUI = Class.extend({
var stage = tournament.getAttribute("stage");
if(stage !== null)
stage = stage.toLowerCase();
+ var joinable = tournament.getAttribute("joinable") === "true";
var abandoned = tournament.getAttribute("abandoned") === "true";
if (action == "add" || action == "update") {
var actionsField = $("
| ");
@@ -763,8 +764,7 @@ var GempLotrHallUI = Class.extend({
actionsField.append(but);
}
else if(!abandoned){
- if(!(type === "table_draft") && (stage === "deck-building" || stage === "drafting" || stage === "awaiting kickoff"
- || stage === "preparing" || stage === "paused between rounds")) {
+ if(joinable) {
var but = $("");
$(but).button().click((
function(tourneyInfo) {
diff --git a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/hall/HallCommunicationChannel.java b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/hall/HallCommunicationChannel.java
index 08534db31..2a6d7898c 100644
--- a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/hall/HallCommunicationChannel.java
+++ b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/hall/HallCommunicationChannel.java
@@ -128,7 +128,7 @@ public class HallCommunicationChannel implements LongPollableResource {
@Override
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 props = new HashMap<>();
props.put("collection", collectionName);
props.put("format", formatName);
@@ -141,6 +141,7 @@ public class HallCommunicationChannel implements LongPollableResource {
props.put("playerList", playerList);
props.put("signedUp", String.valueOf(playerInCompetition));
props.put("abandoned", String.valueOf(abandoned));
+ props.put("joinable", String.valueOf(joinable));
tournamentsOnServer.put(tournamentKey, props);
}
diff --git a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/hall/HallInfoVisitor.java b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/hall/HallInfoVisitor.java
index 65f845dbc..6e49cbe33 100644
--- a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/hall/HallInfoVisitor.java
+++ b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/hall/HallInfoVisitor.java
@@ -18,7 +18,7 @@ public interface HallInfoVisitor {
int readyCheckSecsRemaining, boolean confirmedReadyCheck);
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);
}
diff --git a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/hall/HallServer.java b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/hall/HallServer.java
index 2bedd4f32..fb26fb66f 100644
--- a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/hall/HallServer.java
+++ b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/hall/HallServer.java
@@ -1,6 +1,9 @@
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.ChatCommandErrorException;
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.vo.LotroDeck;
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.Logger;
@@ -540,24 +546,21 @@ public class HallServer extends AbstractServer {
try {
String result = "";
var tournament = _tournamentService.getTournamentById(tournamentId);
- if (tournament != null) {
- var stage = tournament.getInfo().Stage;
- if(stage == Tournament.Stage.STARTING || stage == Tournament.Stage.DECK_BUILDING ||
- stage == Tournament.Stage.PAUSED || stage == Tournament.Stage.AWAITING_KICKOFF) {
- LotroDeck lotroDeck = null;
- 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());
+ if (tournament == null) {
+ result = "That tournament is already over.";
+ } else if (!tournament.isJoinable()) {
+ result = "That tournament does not allow late joining.";
+ } else {
+ LotroDeck lotroDeck = null;
+ 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());
result = "Joined tournament " + tournament.getTournamentName() + " successfully.";
hallChanged();
}
- else {
- result = "That tournament is already over.";
- }
return result;
}
diff --git a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/tournament/ConstructedTournament.java b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/tournament/ConstructedTournament.java
index 6c34f347f..cd3f1e69d 100644
--- a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/tournament/ConstructedTournament.java
+++ b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/tournament/ConstructedTournament.java
@@ -127,4 +127,13 @@ public class ConstructedTournament extends BaseTournament implements Tournament
//This is for draft only
}
+ @Override
+ public boolean isJoinable() {
+ Set 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);
+ }
}
diff --git a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/tournament/SealedTournament.java b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/tournament/SealedTournament.java
index ee8ff9cd1..29f827c12 100644
--- a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/tournament/SealedTournament.java
+++ b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/tournament/SealedTournament.java
@@ -238,4 +238,13 @@ public class SealedTournament extends BaseTournament implements Tournament {
//This is for draft only
}
+ @Override
+ public boolean isJoinable() {
+ Set 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);
+ }
}
diff --git a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/tournament/SoloDraftTournament.java b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/tournament/SoloDraftTournament.java
index 0998cd7de..438e70a77 100644
--- a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/tournament/SoloDraftTournament.java
+++ b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/tournament/SoloDraftTournament.java
@@ -252,4 +252,14 @@ public class SoloDraftTournament extends BaseTournament implements Tournament {
public CollectionType getCollectionType() {
return _soloDraftInfo.generateCollectionInfo();
}
+
+ @Override
+ public boolean isJoinable() {
+ Set 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);
+ }
}
diff --git a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/tournament/SoloTableDraftTournament.java b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/tournament/SoloTableDraftTournament.java
index 51a5d13f1..01a77415e 100644
--- a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/tournament/SoloTableDraftTournament.java
+++ b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/tournament/SoloTableDraftTournament.java
@@ -235,4 +235,14 @@ public class SoloTableDraftTournament extends BaseTournament implements Tourname
public CollectionType getCollectionType() {
return soloTableDraftInfo.generateCollectionInfo();
}
+
+ @Override
+ public boolean isJoinable() {
+ Set 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);
+ }
}
diff --git a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/tournament/TableDraftTournament.java b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/tournament/TableDraftTournament.java
index 04f847c10..281eea745 100644
--- a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/tournament/TableDraftTournament.java
+++ b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/tournament/TableDraftTournament.java
@@ -257,4 +257,9 @@ public class TableDraftTournament extends BaseTournament implements Tournament {
public CollectionType getCollectionType() {
return tableDraftInfo.generateCollectionInfo();
}
+
+ @Override
+ public boolean isJoinable() {
+ return false; // cannot join draft in progress
+ }
}
diff --git a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/tournament/Tournament.java b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/tournament/Tournament.java
index ccf878962..3ed4b703f 100644
--- a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/tournament/Tournament.java
+++ b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/tournament/Tournament.java
@@ -204,4 +204,6 @@ public interface Tournament {
String produceReport(DeckRenderer renderer) throws CardNotFoundException;
TournamentInfo getInfo();
+
+ boolean isJoinable();
}
diff --git a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/tournament/TournamentService.java b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/tournament/TournamentService.java
index 07955a59b..732f12b46 100644
--- a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/tournament/TournamentService.java
+++ b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/tournament/TournamentService.java
@@ -101,6 +101,7 @@ public class TournamentService {
sealedParams.name = queueName;
sealedParams.cost = 0;
sealedParams.minimumPlayers = 2;
+ sealedParams.maximumPlayers = 2;
sealedParams.playoff = Tournament.PairingType.SINGLE_ELIMINATION;
sealedParams.prizes = Tournament.PrizeType.NONE;
@@ -128,6 +129,7 @@ public class TournamentService {
soloDraftParams.name = queueName;
soloDraftParams.cost = 0;
soloDraftParams.minimumPlayers = 2;
+ soloDraftParams.maximumPlayers = 2;
soloDraftParams.playoff = Tournament.PairingType.SINGLE_ELIMINATION;
soloDraftParams.prizes = Tournament.PrizeType.NONE;
@@ -265,7 +267,8 @@ public class TournamentService {
visitor.visitTournament(tourneyID, tournament.getCollectionType().getFullName(),
formatLibrary.getFormat(tournament.getFormatCode()).getName(), tournament.getTournamentName(), tournament.getInfo().Parameters().type.toString(), tournament.getPlayOffSystem(),
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());
}
}