Skip to content

Commit

Permalink
feat: spectator mode + fix selected cards not refreshed in player han…
Browse files Browse the repository at this point in the history
…d after adding/removing cards
  • Loading branch information
Oliboy50 committed Jul 20, 2022
1 parent 9a906ae commit 2c68119
Show file tree
Hide file tree
Showing 3 changed files with 88 additions and 56 deletions.
9 changes: 4 additions & 5 deletions velonimo.css
Original file line number Diff line number Diff line change
Expand Up @@ -86,10 +86,6 @@ Board
box-shadow: 2px 2px 5px black;
border: 1px solid #3b3119;
}
/* @TODO: remove if unused */
#board-carpet.yellow {
background-color: #e9c646;
}

.player-table {
position: absolute; /* position is dynamically computed */
Expand All @@ -101,7 +97,7 @@ Board
box-sizing: border-box;
background-color: rgba(255,255,255,0.7);
padding: 5px;
z-index: 2;
z-index: 0;
}
.player-table.active {
border: 2px solid #ff0000;
Expand Down Expand Up @@ -348,6 +344,9 @@ END Cards
/**
Animations
*/
.moving-card {
z-index: 100;
}
.moving-jersey {
position: absolute;
width: 65px;
Expand Down
49 changes: 26 additions & 23 deletions velonimo.game.php
Original file line number Diff line number Diff line change
Expand Up @@ -385,19 +385,18 @@ function playCards(array $playedCardIds, bool $cardsPlayedWithJersey) {
);
$numberOfCurrentPlayerCards = $numberOfCurrentPlayerCards + $numberOfCardsToPickFromDeck;
$translatedMessage = clienttranslate('${player_name} picks ${numberOfCards} card(s) from the top of the deck');
self::notifyAllPlayers('cardsMovedFromDeckToAnotherPlayer', $translatedMessage, [
'receiverPlayerId' => $currentPlayer->getId(),
'numberOfCards' => $numberOfCardsToPickFromDeck,
'player_name' => $currentPlayer->getName(),
]);
foreach ($players as $player) {
if ($player->getId() === $currentPlayer->getId()) {
self::notifyPlayer($currentPlayer->getId(), 'cardsReceivedFromDeck', $translatedMessage, [
'cards' => $this->formatCardsForClient($cardsPickedFromDeck),
'numberOfCards' => $numberOfCardsToPickFromDeck,
'player_name' => $currentPlayer->getName(),
]);
} else {
self::notifyPlayer($player->getId(), 'cardsMovedFromDeckToAnotherPlayer', $translatedMessage, [
'receiverPlayerId' => $currentPlayer->getId(),
'numberOfCards' => $numberOfCardsToPickFromDeck,
'player_name' => $currentPlayer->getName(),
]);
}
}
}
Expand Down Expand Up @@ -592,6 +591,13 @@ function selectPlayerToPickCards(int $selectedPlayerId) {
// notify players
$formattedPickedCards = $this->formatCardsForClient($pickedCards);
$translatedMessage = clienttranslate('${player_name} picks ${numberOfCards} card(s) from ${player_name2} hand');
self::notifyAllPlayers('cardsMovedBetweenTwoOtherPlayers', $translatedMessage, [
'receiverPlayerId' => $currentPlayer->getId(),
'senderPlayerId' => $selectedPlayer->getId(),
'numberOfCards' => $numberOfCardsToPick,
'player_name' => $currentPlayer->getName(),
'player_name2' => $selectedPlayer->getName(),
]);
foreach ($players as $player) {
if ($player->getId() === $currentPlayer->getId()) {
self::notifyPlayer($currentPlayer->getId(), 'cardsReceivedFromAnotherPlayer', $translatedMessage, [
Expand All @@ -609,14 +615,6 @@ function selectPlayerToPickCards(int $selectedPlayerId) {
'player_name' => $currentPlayer->getName(),
'player_name2' => $selectedPlayer->getName(),
]);
} else {
self::notifyPlayer($player->getId(), 'cardsMovedBetweenTwoOtherPlayers', $translatedMessage, [
'receiverPlayerId' => $currentPlayer->getId(),
'senderPlayerId' => $selectedPlayer->getId(),
'numberOfCards' => $numberOfCardsToPick,
'player_name' => $currentPlayer->getName(),
'player_name2' => $selectedPlayer->getName(),
]);
}
}

Expand Down Expand Up @@ -677,6 +675,13 @@ function selectCardsToGiveBack(array $selectedCardIds) {
// notify players
$formattedSelectedCards = $this->formatCardsForClient($selectedCards);
$translatedMessage = clienttranslate('${player_name} gives back ${numberOfCards} card(s) to ${player_name2}');
self::notifyAllPlayers('cardsMovedBetweenTwoOtherPlayers', $translatedMessage, [
'receiverPlayerId' => $receiverPlayer->getId(),
'senderPlayerId' => $currentPlayer->getId(),
'numberOfCards' => $numberOfCardsToGiveBack,
'player_name2' => $receiverPlayer->getName(),
'player_name' => $currentPlayer->getName(),
]);
foreach ($players as $player) {
if ($player->getId() === $currentPlayer->getId()) {
self::notifyPlayer($currentPlayer->getId(), 'cardsSentToAnotherPlayer', $translatedMessage, [
Expand All @@ -694,14 +699,6 @@ function selectCardsToGiveBack(array $selectedCardIds) {
'player_name2' => $receiverPlayer->getName(),
'player_name' => $currentPlayer->getName(),
]);
} else {
self::notifyPlayer($player->getId(), 'cardsMovedBetweenTwoOtherPlayers', $translatedMessage, [
'receiverPlayerId' => $receiverPlayer->getId(),
'senderPlayerId' => $currentPlayer->getId(),
'numberOfCards' => $numberOfCardsToGiveBack,
'player_name2' => $receiverPlayer->getName(),
'player_name' => $currentPlayer->getName(),
]);
}
}

Expand Down Expand Up @@ -791,6 +788,7 @@ function argPlayerGiveCardsBackAfterPicking() {

function stStartRound() {
$this->discardPlayedCards();
$this->discardAttackRewardCards();
// take back all cards and shuffle them
$this->deck->moveAllCardsInLocation(null, self::CARD_LOCATION_DECK);
$this->deck->shuffle(self::CARD_LOCATION_DECK);
Expand Down Expand Up @@ -1317,7 +1315,12 @@ private function discardPlayedCards(): void {
self::setGameStateValue(self::GAME_STATE_PREVIOUS_PLAYED_CARDS_VALUE, 0);
self::setGameStateValue(self::GAME_STATE_LAST_PLAYED_CARDS_VALUE, 0);
self::setGameStateValue(self::GAME_STATE_LAST_PLAYED_CARDS_PLAYER_ID, 0);
self::notifyAllPlayers('cardsDiscarded', '', []);
self::notifyAllPlayers('playedCardsDiscarded', '', []);
}

private function discardAttackRewardCards(): void {
$this->deck->moveAllCardsInLocation(self::CARD_LOCATION_ATTACK_REWARD, self::CARD_LOCATION_DISCARD);
self::notifyAllPlayers('attackRewardCardsDiscarded', '', []);
}

private function updatePlayerRoundsRanking(VelonimoPlayer $player): void {
Expand Down
86 changes: 58 additions & 28 deletions velonimo.js
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,6 @@ const PLAYERS_PLACES_BY_NUMBER_OF_PLAYERS = {
},
};

// @TODO: support "spectators"
define([
'dojo','dojo/_base/declare',
'ebg/core/gamegui',
Expand Down Expand Up @@ -271,7 +270,6 @@ function (dojo, declare) {
this.setupAttackRewardCards(gamedatas.attackRewardCards);
}

// @TODO: support spectators (do not show "my hand" in this case)
// Init playerHand "ebg.stock" component
this.playerHand = new ebg.stock();
this.playerHand.create(this, $(DOM_ID_PLAYER_HAND), CARD_WIDTH, CARD_HEIGHT);
Expand Down Expand Up @@ -622,10 +620,7 @@ function (dojo, declare) {
}
},
setupGiveCardsBackAfterPickingActionButton: function () {
if (this.playerHand.isSelected(CARD_ID_JERSEY)) {
this.playerHand.unselectItem(CARD_ID_JERSEY);
}
this.displayCardsAsNonSelectable(this.addJerseyToCards([]));
this.refreshPlayerHandSelectableCards();

const selectedCards = this.getSelectedPlayerCards();
if (!$(DOM_ID_ACTION_BUTTON_GIVE_CARDS)) {
Expand Down Expand Up @@ -1201,23 +1196,33 @@ function (dojo, declare) {
}
});

// display non-selectable cards as non-selectable
this.displayCardsAsNonSelectable(
this.getSelectedPlayerCards()
.reduce(this.getPlayerCardsThatCannotBePlayedWithCardsReducer(playerCards), [])
);
this.refreshPlayerHandSelectableCards();
},
/**
* @param {number} cardId
*/
onPlayerCardUnselected: function (cardId) {
this.refreshPlayerHandSelectableCards();
},
refreshPlayerHandSelectableCards: function () {
const playerCards = this.getAllPlayerCards();
const selectedCards = this.getSelectedPlayerCards();

// display non-selectable cards as non-selectable
this.displayCardsAsNonSelectable(
this.getSelectedPlayerCards()
.reduce(this.getPlayerCardsThatCannotBePlayedWithCardsReducer(playerCards), [])
);
if (
this.isCurrentPlayerActive()
&& this.currentState === 'playerGiveCardsBackAfterPicking'
) {
if (this.playerHand.isSelected(CARD_ID_JERSEY)) {
this.playerHand.unselectItem(CARD_ID_JERSEY);
}
this.displayCardsAsNonSelectable(this.addJerseyToCards([]));
} else if (selectedCards.length === 0) {
this.displayCardsAsNonSelectable([]);
} else {
this.displayCardsAsNonSelectable(
selectedCards.reduce(this.getPlayerCardsThatCannotBePlayedWithCardsReducer(playerCards), [])
);
}
},
/**
* @param {Object[]} cards
Expand All @@ -1233,7 +1238,7 @@ function (dojo, declare) {
},
unselectAllCards: function () {
this.playerHand.unselectAll();
this.displayCardsAsNonSelectable([]);
this.refreshPlayerHandSelectableCards();
},
/**
* @param {Object[]} cards
Expand Down Expand Up @@ -1311,7 +1316,7 @@ function (dojo, declare) {
const backgroundPositionX = this.getAbsoluteCardBackgroundPositionXFromCardPosition(position);
const backgroundPositionY = this.getAbsoluteCardBackgroundPositionYFromCardPosition(position);
animations[i] = this.slideTemporaryObject(
`<div class="velonimo-card front-side" style="position: absolute; background-position: -${backgroundPositionX}px -${backgroundPositionY}px; z-index: ${100 - i};"></div>`,
`<div class="velonimo-card front-side moving-card" style="position: absolute; background-position: -${backgroundPositionX}px -${backgroundPositionY}px; z-index: ${100 - i};"></div>`,
domId,
domId,
`player-table-${this.player_id}-hand`,
Expand All @@ -1320,6 +1325,7 @@ function (dojo, declare) {
);
dojo.connect(animations[i], 'onEnd', () => {
this.playerHand.addToStockWithId(position, cards[i].id);
this.refreshPlayerHandSelectableCards();
});
animations[i].play();
}
Expand All @@ -1332,7 +1338,7 @@ function (dojo, declare) {
moveHiddenTemporaryCardsFromDomIdToDomId: function (fromDomId, toDomId, numberOfCards) {
for (let i = 0; i < numberOfCards; i++) {
this.slideTemporaryObject(
`<div class="velonimo-card back-side" style="position: absolute; z-index: ${100 - i};"></div>`,
`<div class="velonimo-card back-side moving-card" style="position: absolute; z-index: ${100 - i};"></div>`,
fromDomId,
fromDomId,
toDomId,
Expand Down Expand Up @@ -1427,6 +1433,7 @@ function (dojo, declare) {
dojo.connect(animation, 'onEnd', () => {
if (receiverPlayerId === this.player_id) {
this.addCardsToPlayerHand(cards);
this.refreshPlayerHandSelectableCards();
}
this.fadeOutAndDestroy(rewardCardDomId);
});
Expand Down Expand Up @@ -1467,6 +1474,7 @@ function (dojo, declare) {
this.placeOnObject(`cards-stack-${topOfStackCardId}`, `${DOM_ID_PLAYER_HAND}_item_${topOfStackCardId}`);
cards.forEach((card) => {
this.playerHand.removeFromStockById(card.id);
this.refreshPlayerHandSelectableCards();
});
}

Expand Down Expand Up @@ -1513,7 +1521,7 @@ function (dojo, declare) {
const backgroundPositionY = this.getAbsoluteCardBackgroundPositionYFromCardPosition(position);
const animationStartDomId = $(`${DOM_ID_PLAYER_HAND}_item_${sortedCards[i].id}`) ? `${DOM_ID_PLAYER_HAND}_item_${sortedCards[i].id}` : `player-table-${this.player_id}-hand`;
animations[i] = this.slideTemporaryObject(
`<div class="velonimo-card front-side" style="position: absolute; background-position: -${backgroundPositionX}px -${backgroundPositionY}px; z-index: ${100 - i};"></div>`,
`<div class="velonimo-card front-side moving-card" style="position: absolute; background-position: -${backgroundPositionX}px -${backgroundPositionY}px; z-index: ${100 - i};"></div>`,
`player-table-${this.player_id}-hand`,
animationStartDomId,
`player-table-${receiverId}-hand`,
Expand All @@ -1523,11 +1531,13 @@ function (dojo, declare) {
dojo.connect(animations[i], 'onEnd', () => {
if (sortedCards[i + 1]) {
this.playerHand.removeFromStockById(sortedCards[i + 1].id);
this.refreshPlayerHandSelectableCards();
}
});
animations[i].play();
}
this.playerHand.removeFromStockById(sortedCards[0].id);
this.refreshPlayerHandSelectableCards();
},
/**
* @param {number} senderId
Expand Down Expand Up @@ -1589,19 +1599,23 @@ function (dojo, declare) {
}

this.playerHand.removeFromStockById(CARD_ID_JERSEY);
this.refreshPlayerHandSelectableCards();
},
movePlayedCardsToPreviousPlayedCards: function () {
dojo.query(`.${DOM_CLASS_CARDS_STACK_PREVIOUS_PLAYED}`).forEach(dojo.destroy);
dojo.query(`.${DOM_CLASS_CARDS_STACK_PREVIOUS_PLAYED}`).forEach(this.fadeOutAndDestroy);
dojo.query(`#${DOM_ID_LAST_PLAYED_CARDS} .${DOM_CLASS_CARDS_STACK}`).forEach((elementDomId) => {
dojo.addClass(elementDomId, DOM_CLASS_CARDS_STACK_PREVIOUS_PLAYED);
const animation = this.slideToObject(elementDomId, DOM_ID_PREVIOUS_LAST_PLAYED_CARDS);
dojo.connect(animation, 'onEnd', () => this.attachToNewParent(elementDomId, DOM_ID_PREVIOUS_LAST_PLAYED_CARDS));
animation.play();
});
},
discardAttackRewardCards: function () {
dojo.query(`#${DOM_ID_ATTACK_REWARD_CARD} .${DOM_CLASS_CARDS_STACK}`).forEach(this.fadeOutAndDestroy);
},
discardPlayedCards: function () {
this.playedCardsValue = 0;
dojo.query(`#${DOM_ID_PLAYED_CARDS_WRAPPER} .${DOM_CLASS_CARDS_STACK}`).forEach(dojo.destroy);
dojo.query(`#${DOM_ID_PLAYED_CARDS_WRAPPER} .${DOM_CLASS_CARDS_STACK}`).forEach(this.fadeOutAndDestroy);
},
discardPlayerSpeechBubbles: function () {
dojo.query(`.${DOM_CLASS_PLAYER_SPEECH_BUBBLE_SHOW}`).forEach((elementDomId) => {
Expand Down Expand Up @@ -1719,23 +1733,32 @@ function (dojo, declare) {
['cardsDealt', 1],
['roundStarted', 1],
['cardsPlayed', 1000],
['cardsDiscarded', 1],
['playedCardsDiscarded', 1],
['cardsReceivedFromAnotherPlayer', 1000],
['cardsSentToAnotherPlayer', 1000],
['cardsMovedBetweenTwoOtherPlayers', 1000],
['cardsMovedBetweenTwoOtherPlayers', 1000, (notif) => (notif.args.receiverPlayerId === this.player_id || notif.args.senderPlayerId === this.player_id)],
['roundEnded', 1],
/* START 2P */
// /!\ 2P mode only
['attackRewardCardsDiscarded', 1],
// /!\ 2P mode only
['attackRewardCardsMovedToPlayer', 1000],
// /!\ 2P mode only
['attackRewardCardsRevealed', 1000],
// /!\ 2P mode only
['cardsReceivedFromDeck', 1000],
['cardsMovedFromDeckToAnotherPlayer', 1000],
/* END 2P */
// /!\ 2P mode only
['cardsMovedFromDeckToAnotherPlayer', 1000, (notif) => notif.args.receiverPlayerId === this.player_id],
].forEach((notif) => {
const name = notif[0];
const lockDurationInMs = notif[1];
const ignoreNotifIfTrue = notif[2];

dojo.subscribe(name, this, `notif_${name}`);
this.notifqueue.setSynchronous(name, lockDurationInMs);

if (ignoreNotifIfTrue) {
this.notifqueue.setIgnoreNotificationCheck(name, ignoreNotifIfTrue);
}
});
},
notif_cardsDealt: function (data) {
Expand All @@ -1747,6 +1770,7 @@ function (dojo, declare) {
) {
this.addJerseyToPlayerHand();
}
this.refreshPlayerHandSelectableCards();
},
notif_roundStarted: function (data) {
this.currentRound = data.args.currentRound;
Expand Down Expand Up @@ -1777,7 +1801,7 @@ function (dojo, declare) {
this.useJerseyForCurrentRound();
}
},
notif_cardsDiscarded: function (data) {
notif_playedCardsDiscarded: function (data) {
this.discardPlayerSpeechBubbles();
this.discardPlayedCards();
},
Expand Down Expand Up @@ -1813,6 +1837,12 @@ function (dojo, declare) {
this.restoreJerseyForCurrentRound();
this.moveJerseyToCurrentWinner(currentJerseyWearerId);
},
/**
* /!\ 2P mode only
*/
notif_attackRewardCardsDiscarded: function (data) {
this.discardAttackRewardCards();
},
/**
* /!\ 2P mode only
*/
Expand Down

0 comments on commit 2c68119

Please sign in to comment.