Skip to content

Commit

Permalink
feat(jersey): support jersey
Browse files Browse the repository at this point in the history
  • Loading branch information
Oliboy50 committed May 15, 2022
1 parent b43bb98 commit f2e4c61
Show file tree
Hide file tree
Showing 7 changed files with 259 additions and 151 deletions.
Binary file added img/jersey.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions modules/constants.inc.php
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,6 @@
define('VALUE_40', 40);
define('VALUE_45', 45);
define('VALUE_50', 50);

// Jersey value
define('JERSEY_VALUE', 10);
4 changes: 3 additions & 1 deletion velonimo.action.php
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,9 @@ public function playCards()
$cardsArg = trim(self::getArg('cards', AT_numberlist, true), ';');
$cardIds = explode(';', $cardsArg);

$this->game->playCards(array_map(fn ($id) => (int) $id, $cardIds));
$withJerseyArg = (bool) self::getArg('withJersey', AT_bool, true);

$this->game->playCards(array_map(fn ($id) => (int) $id, $cardIds), $withJerseyArg);

self::ajaxResponse();
}
Expand Down
42 changes: 40 additions & 2 deletions velonimo.css
Original file line number Diff line number Diff line change
Expand Up @@ -100,23 +100,61 @@ Board
border: 2px solid #ff0000;
transform: scale(1.02);
}
.player-table.is-wearing-jersey .player-table-jersey {
position: absolute;
bottom: 10px;
right: 0;
width: 60px;
height: 83px;
background-size: 60px 83px;
background-image: url('img/jersey.png');
background-repeat: no-repeat;
background-position: center center;
pointer-events: none;
}
.player-table.is-wearing-jersey.has-used-jersey .jersey-overlay {
display: block;
position: relative;
top: 20px;
height: 50px;
width: 10px;
margin: 0 auto;
background: black;
transform: rotate(45deg);
}
.player-table.is-wearing-jersey.has-used-jersey .jersey-overlay:after {
content: "";
position: absolute;
left: -20px;
top: 20px;
width: 50px;
height: 10px;
background: black;
}
.player-table-name {
font-weight: bold;
pointer-events: none;
}
.player-table-hand {
position: relative;
width: 90px;
width: 65px;
height: 90px;
background-size: 65px 90px;
margin: 5px auto 0;
border-radius: 5px;
background-image: url('img/remaining_cards.png');
background-repeat: no-repeat;
background-position: center center;
pointer-events: none;
transition-property: all;
transition-duration: 1s;
}
.player-table.is-wearing-jersey .player-table-hand {
margin: 5px 0 0 -5px;
}
.player-table-hand .number-of-cards {
position: absolute;
left: 20px;
left: 8px;
top: 20px;
font-size: 2em;
text-align: center;
Expand Down
48 changes: 41 additions & 7 deletions velonimo.game.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
class Velonimo extends Table
{
private const GAME_STATE_CURRENT_ROUND = 'currentRound';
private const GAME_STATE_JERSEY_HAS_BEEN_USED_IN_THE_CURRENT_ROUND = 'jerseyUsedInRound';
private const GAME_STATE_LAST_PLAYED_CARDS_VALUE = 'valueToBeat';
private const GAME_STATE_LAST_PLAYED_CARDS_PLAYER_ID = 'playerIdForValueToBeat';
private const GAME_STATE_SELECTED_NEXT_PLAYER_ID = 'selectedNextPlayerId';
Expand Down Expand Up @@ -54,6 +55,7 @@ function __construct() {
self::GAME_STATE_LAST_PLAYED_CARDS_VALUE => 11,
self::GAME_STATE_LAST_PLAYED_CARDS_PLAYER_ID => 12,
self::GAME_STATE_SELECTED_NEXT_PLAYER_ID => 13,
self::GAME_STATE_JERSEY_HAS_BEEN_USED_IN_THE_CURRENT_ROUND => 14,
self::GAME_OPTION_HOW_MANY_ROUNDS => 100,
]);

Expand Down Expand Up @@ -110,6 +112,7 @@ protected function setupNewGame($players, $options = []) {
self::setGameStateValue(self::GAME_STATE_LAST_PLAYED_CARDS_VALUE, 0);
self::setGameStateValue(self::GAME_STATE_LAST_PLAYED_CARDS_PLAYER_ID, 0);
self::setGameStateValue(self::GAME_STATE_SELECTED_NEXT_PLAYER_ID, 0);
self::setGameStateValue(self::GAME_STATE_JERSEY_HAS_BEEN_USED_IN_THE_CURRENT_ROUND, 0);

// Init game statistics
// (note: statistics used in this file must be defined in your stats.inc.php file)
Expand Down Expand Up @@ -181,6 +184,7 @@ protected function getAllDatas() {

// Rounds
$result['currentRound'] = (int) self::getGameStateValue(self::GAME_STATE_CURRENT_ROUND);
$result['jerseyHasBeenUsedInTheCurrentRound'] = $this->isJerseyUsedInCurrentRound();
$result['howManyRounds'] = (int) self::getGameStateValue(self::GAME_OPTION_HOW_MANY_ROUNDS);

// Players
Expand Down Expand Up @@ -231,7 +235,7 @@ function getGameProgression() {
/**
* @param int[] $playedCardIds
*/
function playCards(array $playedCardIds) {
function playCards(array $playedCardIds, bool $cardsPlayedWithJersey) {
self::checkAction('playCards');

// validate $playedCardIds
Expand Down Expand Up @@ -290,9 +294,21 @@ function playCards(array $playedCardIds) {
$lastCheckedCard = $card;
}

// check that player is allowed to use jersey
$players = $this->getPlayersFromDatabase();
$currentPlayer = $this->getPlayerById($currentPlayerId, $players);
if ($cardsPlayedWithJersey) {
if ($this->isJerseyUsedInCurrentRound()) {
throw new BgaUserException(self::_('The jersey can be used only once by turn.'));
}
if (!$currentPlayer->isWearingJersey()) {
throw new BgaUserException(self::_('You cannot play the jersey if you are not wearing it.'));
}
}

// check that played cards value is higher than the previous played cards value
$lastPlayedCardsValue = (int) self::getGameStateValue(self::GAME_STATE_LAST_PLAYED_CARDS_VALUE);
$playedCardsValue = $this->getCardsValue($playedCards);
$playedCardsValue = $this->getCardsValue($playedCards, $cardsPlayedWithJersey);
if ($playedCardsValue <= $lastPlayedCardsValue) {
throw new BgaUserException(sprintf(
self::_('The value of the cards you play must be higher than %s.'),
Expand All @@ -303,6 +319,9 @@ function playCards(array $playedCardIds) {
// discard table cards and play cards
$this->deck->moveAllCardsInLocation(self::CARD_LOCATION_PLAYED, self::CARD_LOCATION_DISCARD);
$this->deck->moveCards($playedCardIds, self::CARD_LOCATION_PLAYED, $currentPlayerId);
if ($cardsPlayedWithJersey) {
self::setGameStateValue(self::GAME_STATE_JERSEY_HAS_BEEN_USED_IN_THE_CURRENT_ROUND, 1);
}
self::setGameStateValue(self::GAME_STATE_LAST_PLAYED_CARDS_PLAYER_ID, $currentPlayerId);
self::setGameStateValue(self::GAME_STATE_LAST_PLAYED_CARDS_VALUE, $playedCardsValue);
self::incStat(1, 'playCardsAction');
Expand All @@ -313,6 +332,7 @@ function playCards(array $playedCardIds) {
'remainingNumberOfCards' => count($currentPlayerCards) - count($playedCards),
'playerName' => self::getCurrentPlayerName(),
'playedCardsValue' => $playedCardsValue,
'withJersey' => $cardsPlayedWithJersey,
]);

// if the player did not play his last card, it's next player turn
Expand All @@ -322,10 +342,8 @@ function playCards(array $playedCardIds) {
}

// the player played his last card, set its rank for this round
$players = $this->getPlayersFromDatabase();
$currentRound = (int) self::getGameStateValue(self::GAME_STATE_CURRENT_ROUND);
$nextRankForRound = $this->getNextRankForRound($players, $currentRound);
$currentPlayer = $this->getPlayerById($currentPlayerId, $players);
$currentPlayer->addRoundRanking($currentRound, $nextRankForRound);
$this->updatePlayerRoundsRanking($currentPlayer);

Expand Down Expand Up @@ -519,6 +537,9 @@ function stEndRound() {
));
}

// re-allow the jersey to be used
self::setGameStateValue(self::GAME_STATE_JERSEY_HAS_BEEN_USED_IN_THE_CURRENT_ROUND, 0);

self::notifyAllPlayers('roundEnded', '', [
'players' => $this->formatPlayersForClient($players),
]);
Expand Down Expand Up @@ -639,13 +660,21 @@ private function formatCardsForClient(array $cards): array {
/**
* @param VelonimoCard[] $cards
*/
private function getCardsValue(array $cards): int {
private function getCardsValue(array $cards, bool $withJersey): int {
if (count($cards) <= 0) {
return 0;
}

// the jersey cannot be played with an adventurer
if ($withJersey && in_array(COLOR_ADVENTURER, array_map(fn (VelonimoCard $c) => $c->getColor(), $cards), true)) {
return 0;
}

$addJerseyValueIfUsed = fn (int $value) => $value + ($withJersey ? JERSEY_VALUE : 0);


if (count($cards) === 1) {
return $cards[0]->getValue();
return $addJerseyValueIfUsed($cards[0]->getValue());
}

$minCardValue = 1000;
Expand All @@ -655,7 +684,7 @@ private function getCardsValue(array $cards): int {
}
}

return (count($cards) * 10) + $minCardValue;
return $addJerseyValueIfUsed((count($cards) * 10) + $minCardValue);
}

/**
Expand Down Expand Up @@ -727,6 +756,7 @@ private function formatPlayersForClient(array $players): array {
'name' => $player->getName(),
'color' => $player->getColor(),
'score' => $player->getScore(),
'isWearingJersey' => $player->isWearingJersey(),
'howManyCards' => count($this->deck->getCardsInLocation(self::CARD_LOCATION_PLAYER_HAND, $player->getId())),
];
}
Expand Down Expand Up @@ -849,4 +879,8 @@ private function updatePlayerRoundsRanking(VelonimoPlayer $player): void {
$player->getId()
));
}

private function isJerseyUsedInCurrentRound(): bool {
return 1 === (int) self::getGameStateValue(self::GAME_STATE_JERSEY_HAS_BEEN_USED_IN_THE_CURRENT_ROUND);
}
}
Loading

0 comments on commit f2e4c61

Please sign in to comment.