Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
96 changes: 96 additions & 0 deletions src/main/java/net/deckserver/dwr/DeckserverRemote.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,16 @@
import net.deckserver.dwr.creators.UpdateFactory;
import net.deckserver.dwr.model.GameModel;
import net.deckserver.dwr.model.GameView;
import net.deckserver.dwr.model.JolGame;
import net.deckserver.dwr.model.PlayerModel;
import net.deckserver.game.enums.GameFormat;
import net.deckserver.game.enums.RegionType;
import net.deckserver.services.*;
import net.deckserver.storage.json.deck.Deck;
import net.deckserver.storage.json.deck.ExtendedDeck;
import net.deckserver.storage.json.game.CardData;
import net.deckserver.storage.json.game.ChatData;
import net.deckserver.storage.json.game.RegionData;
import net.deckserver.storage.json.system.DeckInfo;
import net.deckserver.storage.json.system.GameHistory;
import net.deckserver.storage.json.system.PlayerResult;
Expand Down Expand Up @@ -411,6 +415,75 @@ public String exportPastGamesAsCsv() throws IOException {
return writer.toString();
}

/**
* Swap two cards in a given Region
* @param gameName - Name where cards should be swapped
* @param player - Player whom card shall be swapped
* @param region - Region where the cards shall be swapped
* @param oldPos - Old Position of the Card
* @param newPos - New Positon of the Card
* @return Map with View to Update
*/
public Map<String, Object> swapCardsInRegion(String gameName, String player, String region, int oldPos, int newPos) {
//get Game & Region & Cards
JolGame game = GameService.getGameByName(gameName);
RegionData playerRegion = game.data().getPlayerRegion(player, RegionType.valueOf(region));
LinkedList<CardData> cards = (LinkedList<CardData>) playerRegion.getCards();
CardData cardData = getCard(cards, String.valueOf(oldPos));
//swap pos in collection
Collections.swap(cards, oldPos-1, newPos);
sendChatMessage(game.id(), player, cardData.getName(), String.valueOf(oldPos), String.valueOf(newPos+1), region);
//reload State
return doReload(gameName);
}

/**
* Detach a Card from another card to a Region
*
* @param gameName - Name where cards should be detached
* @param player - Player whom card shall be detached
* @param region - Region where the cards shall be detached
* @param oldPos - Old Position of the Card
* @param newPos - New Positon of the Card
* @return Map with View to Update
*/
public Map<String, Object> detachRegionCard(String gameName, String player, String region, String oldPos, int newPos) {
//get Game & Region & Cards
JolGame game = GameService.getGameByName(gameName);
RegionData playerRegion = game.data().getPlayerRegion(player, RegionType.valueOf(region));
LinkedList<CardData> cards = (LinkedList<CardData>) playerRegion.getCards();
//get Card
CardData cardData = getCard(cards, oldPos);
//detach Card
playerRegion.addCard(cardData, newPos);
sendChatMessage(game.id(), player, cardData.getName(), oldPos, String.valueOf(newPos+1), region);
//reload State
return doReload(gameName);
}

/**
* Attach Card to another Card in a given Region
* @param gameName - Name where cards should be attached
* @param player - Player whom card shall be attached
* @param region - Region where the cards shall be attached
* @param oldPos - Old Position of the Card
* @param newPos - New Positon of the Card
* @return Map with View to Update
*/
public Map<String, Object> attachRegionCard(String gameName, String player, String region, String oldPos, String newPos) {
//get Game & Region & Cards
JolGame game = GameService.getGameByName(gameName);
RegionData playerRegion = game.data().getPlayerRegion(player, RegionType.valueOf(region));
LinkedList<CardData> cards = (LinkedList<CardData>) playerRegion.getCards();
//get card
CardData cardData = getCard(cards, oldPos);
//attach Card
getCard(cards, newPos).add(cardData, true);
sendChatMessage(game.id(), player, cardData.getName(), oldPos, newPos, region);
//reload State
return doReload(gameName);
}

private GameView getView(String name) {
String player = getPlayer(request);
return getModel(name).getView(player);
Expand All @@ -420,4 +493,27 @@ private GameModel getModel(String name) {
return JolAdmin.getGameModel(name);
}

public Map<String, Object> doReload(String name) {
//reload State
getModel(name).doReload(true,false,false);
return UpdateFactory.getUpdate();
}

private CardData getCard(LinkedList<CardData> cards, String pos) {
LinkedList<CardData> targetCards = cards;
if(pos.contains(".")){
String[] split = pos.split("\\.");
int lastCard = Integer.valueOf(split[split.length-1]);
for(int i = 0; i < split.length-1; i++) {
targetCards = targetCards.get(Integer.valueOf(split[i])-1).getCards();
}
return targetCards.get(lastCard-1);
} else {
return cards.get(Integer.valueOf(pos)-1);
}
}

private void sendChatMessage(String id, String playerName, String cardName, String oldPos, String newPos, String region) {
ChatService.sendMessage(id, playerName, playerName + " moves "+cardName+" from "+oldPos+" to "+newPos+" of their "+region+" region.");
}
}
25 changes: 25 additions & 0 deletions src/main/java/net/deckserver/storage/json/game/RegionData.java
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,31 @@ public void addCard(CardData card, boolean top) {
card.setParent(null);
card.setRegion(this);
}
public void addCard(CardData card, int pos) {
// Remove from parent first, if it exists
if (card.getParent() != null) {
card.getParent().remove(card);
}
// Remove from region if it exists
if (card.getRegion() != null) {
card.getRegion().removeCard(card);
}
// Add new Card to correct position
LinkedList<CardData> newCardsOrder = new LinkedList<>();
for(int i = 0; i<cards.size();i++){
if(i == pos) {
newCardsOrder.add(card);
}
newCardsOrder.add(cards.get(i));
}
//add card to last position if currently missing
if(this.cards.size()==newCardsOrder.size()) {
newCardsOrder.add(card);
}
this.cards = newCardsOrder;
card.setParent(null);
card.setRegion(this);
}

public void removeCard(CardData card) {
cards.remove(card);
Expand Down
6 changes: 4 additions & 2 deletions src/main/webapp/WEB-INF/jsps/game/card.jsp
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
// Red: hasBlood || hasCapacity
String counterStyle = (cardSummary.hasLife() && RegionType.OTHER_VISIBLE_REGIONS.contains(region)) ? "text-bg-success" : ((cardSummary.hasBlood() || hasCapacity) ? "text-bg-danger" : "text-bg-secondary");
String regionStyle = region == RegionType.TORPOR ? "opacity-75" : "";
boolean regionDragDrop = region == RegionType.READY ? true : false;
String contestedStyle = contested ? "bg-warning-subtle" : "";
String counterText = counters + (capacity > 0 ? " / " + capacity : "");
String attributes = cardDetail.buildAttributes(region, index, true);
Expand All @@ -56,7 +57,7 @@
request.setAttribute("cards", cards);
%>
<li <%= attributes %> onclick="<%= showAction %>"
class="list-group-item d-flex justify-content-between align-items-baseline px-2 pt-2 pb-1 <%= regionStyle%> <%= shadowStyle %> <%= contestedStyle %>">
class="list-group-item d-flex justify-content-between align-items-baseline px-2 pt-2 pb-1 dropable-item <%= regionStyle%> <%= shadowStyle %> <%= contestedStyle %>">
<div class="mx-1 me-auto w-100">
<div class="d-flex justify-content-between">
<div class="d-flex flex-column">
Expand Down Expand Up @@ -102,7 +103,7 @@
</div>
</div>
</div>
<ol class="list-group list-group-numbered ms-n3">
<ol class="list-group list-group-numbered ms-n3 sortable2 drop-zone" style="min-height: 10px">
<c:forEach items="<%= cards %>" var="card" varStatus="counter">
<c:if test="${!player.equals(card.owner)}">
<c:set var="visible" value="true"/>
Expand Down Expand Up @@ -130,4 +131,5 @@
</c:forEach>
</ol>
</div>
<c:if test="<%= regionDragDrop %>"><i class="bi bi-grip-vertical" draggable="true"></i></c:if>
</li>
2 changes: 1 addition & 1 deletion src/main/webapp/WEB-INF/jsps/game/region.jsp
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
</span>
</div>
<ol id="<%= regionId %>"
class="region list-group list-group-flush list-group-numbered <%= regionStyle %> collapse <%= show %>">
class="region sortable1 list-group list-group-flush list-group-numbered drop-zone<%= regionStyle %> collapse <%= show %>">
<c:forEach items="<%= cards %>" var="card" varStatus="counter">
<c:if test="${!player.equals(card.ownerName)}">
<c:set var="visible" value="true"/>
Expand Down
1 change: 1 addition & 0 deletions src/main/webapp/WEB-INF/main.jsp
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@
<script src='${pageContext.request.contextPath}/dwr/util.js'></script>
<script src='${pageContext.request.contextPath}/js/ds.js?version=<%= VersionService.getVersion() %>'></script>
<script src="${pageContext.request.contextPath}/js/card-modal.js?version=<%= VersionService.getVersion() %>"></script>
<script src="${pageContext.request.contextPath}/js/jquery.ui.touch-punch.min.js"></script>
<script>
<jsp:include page="notification.jsp"/>
</script>
Expand Down
74 changes: 74 additions & 0 deletions src/main/webapp/js/ds.js
Original file line number Diff line number Diff line change
Expand Up @@ -1301,6 +1301,80 @@ function loadGame(data) {
addCardTooltips("#hand");
}

// drag and drop
//add sortable to highest order list and connect to sublists
let startPlayer;
$(".sortable1").each(function (index, region) {
let regionName = region.id.substring(2);
if(region.id.indexOf("READY")>-1) {
$(region).sortable({
connectWith: ".sortable1, .sortable2, .drop-zone",
handle: ".bi-grip-vertical",
dropOnEmpty: true,
start: function (event, ui) {
startPlayer = ui.item.closest(".player").attr("data-player");
},
stop: function (event, ui) {
let playerName = ui.item.closest(".player").attr("data-player");
if(playerName==startPlayer) {
let newPos;
if(ui.item.parent("ol").hasClass("region")) {
ui.item.parent("ol").children("li").each(function (index, li) {
if(li===ui.item[0]) {
newPos = index;
}
});
DS.swapCardsInRegion(data.name, playerName, regionName, ui.item.attr("data-coordinates"), newPos, {callback: processData, errorHandler: errorhandler});
} else {
DS.attachRegionCard(data.name, playerName, regionName, ui.item.attr("data-coordinates"), ui.item.parents("li").attr("data-coordinates"), {callback: processData, errorHandler: errorhandler});
}
} else {
DS.doReload(data.name, {callback: processData, errorHandler: errorhandler});
}
}
});
$(region).disableSelection();
}
//add drag and drop to all sub lists and connect to parent list
$(".sortable2").sortable({
handle: ".bi-grip-vertical",
dropOnEmpty: true,
connectWith: ".sortable1, .drop-zone, .sortable2 ",
start: function (event, ui) {
startPlayer = ui.item.closest(".player").attr("data-player");
},
stop: function (event, ui) {
let playerName = ui.item.closest(".player").attr("data-player");
if(playerName==startPlayer) {
let newPos;
if(ui.item.parent("ol").hasClass("region")) {
ui.item.parent("ol").children("li").each(function (index, li) {
if(li===ui.item[0]) {
newPos = index;
}
});
DS.detachRegionCard(data.name, playerName, "READY", ui.item.attr("data-coordinates"), newPos, {callback: processData, errorHandler: errorhandler});
} else {
DS.attachRegionCard(data.name, playerName, "READY", ui.item.attr("data-coordinates"), ui.item.parents("li").attr("data-coordinates"), {callback: processData, errorHandler: errorhandler});
}
} else {
DS.doReload(data.name, {callback: processData, errorHandler: errorhandler});
}
}
});
$(".sortable2").disableSelection();
//create a drop zone
$(".drop-zone").droppable({
accept: ".dropable-item",
});
$(".drop-zone").sortable({
handle: ".bi-grip-vertical",
connectWith: '.drop-zone, .sortable1, .sortable2',
});
$(".drop-zone").disableSelection();

});

// Setup polling
if (refresher) clearTimeout(refresher);
if (data.refresh > 0 || fetchFullLog) {
Expand Down
11 changes: 11 additions & 0 deletions src/main/webapp/js/jquery.ui.touch-punch.min.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.