Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New beta release - v2 #32

Merged
merged 19 commits into from
Jul 30, 2023
Merged
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
8 changes: 2 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# Calypso for BGA

Calypso is in alpha testing on Board Game Arena:
Calypso is available to play on Board Game Arena (as a beta version):

[<img src="./misc/Bga_button.png">](https://boardgamearena.com/reviewer?game=calypso)
[<img src="./misc/Bga_button.png">](https://boardgamearena.com/gamepanel?game=calypso)

[Credits](./misc/credits.md)

Expand All @@ -14,10 +14,6 @@ For devvy stuff check out [dev notes](./misc/dev.md).

Archived items in [an archive](./misc/archive.md), and [possible things to add](./misc/future_possibilities.md).

### Dev

* make repo public

## Browser compatibility

Checked:
Expand Down
9 changes: 8 additions & 1 deletion calypso.css

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

88 changes: 56 additions & 32 deletions calypso.game.php
Original file line number Diff line number Diff line change
Expand Up @@ -272,20 +272,32 @@ protected function getAllDatas()
}

$result['hand'] = $this->cards->getCardsInLocation( 'hand', $current_player_id );
$player_suit = self::getPlayerSuit($current_player_id);
$partner_suit = self::getPartnerSuit($player_suit);
// give suits in order: player suit, partner suit,
// same colour as player, same colour as partner
$result['suits_by_status'] = array(
+$player_suit,
$partner_suit,
self::getSameColourSuit($player_suit),
self::getSameColourSuit($partner_suit),
);
if (!self::isSpectator()){
$player_suit = self::getPlayerSuit($current_player_id);
$partner_suit = self::getPartnerSuit($player_suit);
// give suits in order: player suit, partner suit,
// same colour as player, same colour as partner
$result['suits_by_status'] = array(
+$player_suit,
$partner_suit,
self::getSameColourSuit($player_suit),
self::getSameColourSuit($partner_suit),
);
} else {
// dummy ranking to keep nice and smooth
$result['suits_by_status'] = array(
self::CLUBS,
self::DIAMONDS,
self::HEARTS,
self::SPADES,
);
}

$result['cardsontable'] = $this->cards->getCardsInLocation( 'cardsontable' );
$result['cardsincalypsos'] = $this->cards->getCardsInLocation( 'calypso' );

$result["playable_cards"] = self::getValidCards($current_player_id);

$result['dealer'] = self::getGameStateValue('currentDealer');

$result['handnumber'] = self::getGameStateValue('handNumber');
Expand Down Expand Up @@ -352,7 +364,7 @@ function getPartnerSuit($player_suit) {
self::CLUBS => self::DIAMONDS,
self::DIAMONDS => self::CLUBS,
self::HEARTS => self::SPADES,
self::SPADES => self::HEARTS
self::SPADES => self::HEARTS,
)[$player_suit];
}
// get suit the same colour as a given suit - feeds through to UI
Expand All @@ -361,7 +373,7 @@ function getSameColourSuit($player_suit) {
self::CLUBS => self::SPADES,
self::DIAMONDS => self::HEARTS,
self::HEARTS => self::DIAMONDS,
self::SPADES => self::CLUBS
self::SPADES => self::CLUBS,
)[$player_suit];
}

Expand Down Expand Up @@ -704,24 +716,41 @@ function setRoundScore( $player_id, $num_calypsos, $calypso_cards, $won_cards ){
}

function validPlay( $player_id, $card ){
// check that player leads or follows suit OR has no cards of lead suit
$valid_cards = self::getValidCards($player_id);
// this also ensures that $card is in hand, and there has been no funny business
return in_array($card, $valid_cards);
}

function getValidCards( $player_id ) {
// return array of valid cards
// all cards of led suit if available, otherwise anything
$trick_suit = self::getGameStateValue( 'trickSuit' );
$hand = $this->cards->getCardsInLocation( 'hand', $player_id );
if( $trick_suit == 0){
// i.e. first card of trick
return true;
// any card is fine
return $hand;
}
if( $card['type'] == $trick_suit ){
return true;
}
$hand = $this->cards->getCardsInLocation( 'hand', $player_id );

// otherwise, get all cards of led suit
$suit_cards = array_filter( $hand, function($hand_card) use ($trick_suit) {
return $hand_card['type'] == $trick_suit;
});
if( empty($suit_cards) ){
return true;
// if we have no cards of suit, again any card is fine
return $hand;
}
return false;
return $suit_cards;
}

function setPlayerHandActive($player_id) {
self::notifyPlayer(
$player_id,
'playableCards',
'',
array(
'playable_cards' => self::getValidCards($player_id),
)
);
}

function getCurrentRanks($player_id){
Expand Down Expand Up @@ -1560,6 +1589,8 @@ function stNewHand() {

function stNewTrick() {
self::initialiseTrick();
$player_id = self::getActivePlayerId();
self::setPlayerHandActive($player_id);
$this->gamestate->nextState();
}

Expand All @@ -1584,6 +1615,7 @@ function stNextPlayer() {
// Standard case (not the end of the trick)
$player_id = self::activeNextPlayer();
self::giveExtraTime($player_id);
self::setPlayerHandActive($player_id);
$this->gamestate->nextState('nextPlayer');
}
}
Expand Down Expand Up @@ -1643,17 +1675,9 @@ function zombieTurn( $state, $active_player )
if ($state['type'] === "activeplayer") {
switch ($statename) {
case "playerTurn":
$cards_in_hand = $this->cards->getCardsInLocation(
"hand", $active_player
);
// go through cards in hand and play the first one that's legal
foreach ($cards_in_hand as $card) {
if ( self::validPlay($active_player, $card) ){
$card_to_play = $card;
break;
}
}
$this->playCard($card_to_play['id'], $active_player);
$valid_cards = self::getValidCards($active_player);
$card_to_play = array_rand($valid_cards, 1);
$this->playCard($card_to_play, $active_player);
break;
}

Expand Down
50 changes: 44 additions & 6 deletions calypso.js
Original file line number Diff line number Diff line change
Expand Up @@ -122,10 +122,9 @@ function (dojo, declare) {
let card = gamedatas.hand[i];
let suit = card.type;
let rank = card.type_arg;
let unique_type = this.getCardUniqueType(suit, rank);
this.playerHand.addToStockWithId(unique_type, card.id);
this.addCardToPlayerHand(suit, rank, card.id);
}
this.setHandActiveness(this.isCurrentPlayerActive());
this.setHandActiveness(this.isCurrentPlayerActive(), gamedatas.playable_cards);

// Cards played on table
for (i in gamedatas.cardsontable) {
Expand Down Expand Up @@ -236,7 +235,6 @@ function (dojo, declare) {
switch( stateName )
{
case 'playerTurn':
this.setHandActiveness(this.isCurrentPlayerActive());
break;
}
},
Expand Down Expand Up @@ -302,17 +300,52 @@ function (dojo, declare) {
}
},

setHandActiveness(active){
addCardToPlayerHand(suit, rank, card_id){
const unique_type = this.getCardUniqueType(suit, rank);
this.playerHand.addToStockWithId(unique_type, card_id);
},

setHandActiveness(active, playable_cards=[]){
const hand_div_id = "clp-myhand";
if(active){
dojo.addClass(hand_div_id, "clp-active-hand");
dojo.removeClass(hand_div_id, "clp-inactive-hand");
this.highlightPlayable(hand_div_id, true, playable_cards);
} else{
dojo.removeClass(hand_div_id, "clp-active-hand");
dojo.addClass(hand_div_id, "clp-inactive-hand");
this.highlightPlayable(hand_div_id, false);
}
},

highlightPlayable(hand_div_id, make_playable, playable_cards=[]){
// add css class to playable / not playable cards if make_playable is true
// else remove all classes
// actual behaviour covered by css, as it is a user pref
const card_els = $(hand_div_id).children;
const regex_card_id = /clp-myhand_item_(?<card_id>\d+)/m;
const playable_card_ids = Object.values(playable_cards).map(
(card) => card.id
);
[...card_els].forEach(
(card_el) => {
let card_el_id = card_el.id;
let r_match = card_el_id.match(regex_card_id)
let card_id = r_match.groups.card_id;
if (make_playable) {
if (playable_card_ids.includes(card_id)) {
dojo.addClass(card_el_id, "clp-hand-card-playable");
} else {
dojo.addClass(card_el_id, "clp-hand-card-unplayable");
}
} else {
dojo.removeClass(card_el_id, "clp-hand-card-playable");
dojo.removeClass(card_el_id, "clp-hand-card-unplayable");
}
}
);
},

playCardOnTable : function(player_id, suit, rank, card_id) {
dojo.place(this.format_block('jstpl_cardontable', {
x : this.cardwidth * (rank - 2),
Expand Down Expand Up @@ -729,6 +762,7 @@ function (dojo, declare) {
dojo.subscribe('newCards', this, "notif_newCards");
// admin around hand/dealer changing
dojo.subscribe('dealHand', this, "notif_dealHand");
dojo.subscribe('playableCards', this, "notif_playableCards");
// playing a card - the main game action occurring
dojo.subscribe('playCard', this, "notif_playCard");
// handles setting renounce flags when a player renounces
Expand Down Expand Up @@ -781,7 +815,7 @@ function (dojo, declare) {
let card = notif.args.cards[i];
let suit = card.type;
let rank = card.type_arg;
this.playerHand.addToStockWithId(this.getCardUniqueType(suit, rank), card.id);
this.addCardToPlayerHand(suit, rank, card.id);
}
this.playerHand.updateDisplay();
},
Expand All @@ -794,6 +828,10 @@ function (dojo, declare) {
}
},

notif_playableCards: function(notif) {
this.setHandActiveness(true, notif.args.playable_cards);
},

notif_playCard : function(notif) {
this.playCardOnTable(notif.args.player_id, notif.args.suit, notif.args.rank, notif.args.card_id);
},
Expand Down
14 changes: 13 additions & 1 deletion calypso_style.scss
Original file line number Diff line number Diff line change
Expand Up @@ -209,9 +209,21 @@ $top_bottom_offset: $card_area_height + 20px;
margin-top: 10px;
margin-bottom: 10px;
}
.clp-active-hand .clp-hand-card:hover, .clp-selected-card {

// active cards - ones I can try and click
// if user pref is highlight playable, these will only be legal, otherwise all cards
.clp-cards-dont-highlight-playable .clp-active-hand .clp-hand-card:hover,
.clp-cards-highlight-playable .clp-active-hand .clp-hand-card-playable.clp-hand-card:hover {
transform: translate(0, -10px);
}
// if user pref is highlight playable, grey out unplayable cards
// if not then these are not distinguished
.clp-cards-highlight-playable .clp-active-hand .clp-hand-card-unplayable {
background-color: #aaa;
background-blend-mode: multiply;
cursor: default !important;
}
// not my turn
.clp-inactive-hand .clp-hand-card {
cursor: default !important;
}
Expand Down
13 changes: 12 additions & 1 deletion changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,16 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)

## [Unreleased]

## [beta-v02] - 2023-07-30

### Added

- User preference to highlight playable cards (vs non-playable). Default is on

### Fixed

- Fixed spectator (silent) server errors by skipping problematic functions

## [beta-v01] - 2023-07-15

Entered beta on 15/7 - no changes
Expand Down Expand Up @@ -55,7 +65,8 @@ Online version working 2021-02-24.

- Working version of Calypso. Sorry this is as detailed as it will go up this point! Have a shufti at previous PRs and commit history if you really need more.

[unreleased]: https://github.com/ADBond/bga-calypso/compare/beta-v01...HEAD
[unreleased]: https://github.com/ADBond/bga-calypso/compare/beta-v02...HEAD
[beta-v02]: https://github.com/ADBond/bga-calypso/compare/beta-v01...beta-v02
[beta-v01]: https://github.com/ADBond/bga-calypso/compare/alpha-v06...beta-v01
[alpha-v06]: https://github.com/ADBond/bga-calypso/compare/alpha-v05...alpha-v06
[alpha-v05]: https://github.com/ADBond/bga-calypso/compare/alpha-v04...alpha-v05
Expand Down
10 changes: 10 additions & 0 deletions gameoptions.inc.php
Original file line number Diff line number Diff line change
Expand Up @@ -124,4 +124,14 @@
),
'default' => 1
),
102 => array(
'name' => totranslate('Highlight playable cards'),
'needReload' => true,
'values' => array(
1 => array( 'name' => totranslate('Yes'), 'cssPref' => 'clp-cards-highlight-playable' ),
2 => array( 'name' => totranslate('No'), 'cssPref' => 'clp-cards-dont-highlight-playable' ),
),
'default' => 1

)
);
2 changes: 2 additions & 0 deletions misc/credits.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,5 @@
Thanks to the BGA dev community for all the resources and for answering my questions when I was doing something stupid. I also owe credit in particular to the code of W. Michael Shirk's [Grosstarock implementation](https://github.com/wmichaelshirk/grosstarock) and Drasill's [Coinche](https://github.com/drasill/bga-coinche) which were both very useful to stare at when I was trying to understand the framework.

Additionally I have taken inspiration from the implementation of several great games available on BGA - in particular in addition to the above, [Hungarian Tarokk](https://boardgamearena.com/gamepanel?game=hungariantarokk), [Solo Whist](https://boardgamearena.com/gamepanel?game=solowhist), and [Phat](https://boardgamearena.com/gamepanel?game=phat). Go play them, they are excellent!

The banner image is a modified version of [this Harris and Ewing photograph of card players from the USA Library of Congress](https://www.loc.gov/resource/hec.41092/). The game they are playing is certainly _not_ Calypso (being seemingly three players, and dating from 1936, nearly twenty years before Calypso's conception), but might pass for it if you squint pretty heavily.