coincoin
This commit is contained in:
parent
a10266f301
commit
11dc04b5b0
2 changed files with 85 additions and 16 deletions
|
|
@ -72,21 +72,22 @@
|
||||||
function cardRequiresTarget(cardId){
|
function cardRequiresTarget(cardId){
|
||||||
if(!cardId) return null;
|
if(!cardId) return null;
|
||||||
const id = String(cardId).toLowerCase();
|
const id = String(cardId).toLowerCase();
|
||||||
if(id.indexOf('mine') !== -1) return 'empty';
|
if(id.indexOf('mine') !== -1) return 'empty';
|
||||||
// kamikaz targets one of your pieces (play card, then choose a piece)
|
// kamikaz targets one of your pieces (play card, then choose a piece)
|
||||||
if(id.indexOf('kamikaz') !== -1) return 'owned';
|
if(id.indexOf('kamikaz') !== -1) return 'owned';
|
||||||
if(id.indexOf('invis') !== -1 || id.indexOf('invisible') !== -1) return 'owned';
|
if(id.indexOf('invis') !== -1 || id.indexOf('invisible') !== -1) return 'owned';
|
||||||
if(id.indexOf('rebond') !== -1) return 'owned';
|
if(id.indexOf('rebond') !== -1) return 'owned';
|
||||||
if(id.indexOf('adoub') !== -1) return 'owned';
|
if(id.indexOf('adoub') !== -1) return 'owned';
|
||||||
if(id.indexOf('folie') !== -1 || id.indexOf('fou') !== -1) return 'owned';
|
if(id.indexOf('folie') !== -1 || id.indexOf('fou') !== -1) return 'owned';
|
||||||
if(id.indexOf('fortif') !== -1 || id.indexOf('fortification') !== -1) return 'owned';
|
if(id.indexOf('fortif') !== -1 || id.indexOf('fortification') !== -1) return 'owned';
|
||||||
// promotion targets one of your pawns (special handling client-side to show promotion choice)
|
// promotion targets one of your pawns (special handling client-side to show promotion choice)
|
||||||
if(id.indexOf('promotion') !== -1 || id.indexOf('promot') !== -1 || id.indexOf('promouvoir') !== -1) return 'owned_pawn';
|
if(id.indexOf('promotion') !== -1 || id.indexOf('promot') !== -1 || id.indexOf('promouvoir') !== -1) return 'owned_pawn';
|
||||||
// steal a card (target a player) if the card mentions 'carte'/'card' — otherwise a 'vol' often targets a piece
|
// steal a card (target a player) if the card mentions 'carte'/'card' — otherwise a 'vol' often targets a piece
|
||||||
if(id.indexOf('vol') !== -1 || id.indexOf('vole') !== -1 || id.indexOf('steal') !== -1){
|
if(id.indexOf('vol') !== -1 || id.indexOf('vole') !== -1 || id.indexOf('steal') !== -1){
|
||||||
if(id.indexOf('carte') !== -1 || id.indexOf('card') !== -1) return 'player';
|
if(id.indexOf('carte') !== -1 || id.indexOf('card') !== -1) return 'player';
|
||||||
return 'enemy';
|
return 'enemy';
|
||||||
}
|
}
|
||||||
|
if(id.indexOf('coin') !== -1 || id === 'coin_coin') return 'owned';
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
70
server.js
70
server.js
|
|
@ -151,7 +151,7 @@ function buildDefaultDeck(){
|
||||||
['invisible','Une des pièces devient invisible pour l adversaire'],
|
['invisible','Une des pièces devient invisible pour l adversaire'],
|
||||||
// ['épidémie','Toutes les pièces sur le territoire enemie est est capturée'],
|
// ['épidémie','Toutes les pièces sur le territoire enemie est est capturée'],
|
||||||
// ['glue','Toutes les pièces autour de la pièce désignée ne peuvent pas bouger tant que cette dernière ne bouge pas'],
|
// ['glue','Toutes les pièces autour de la pièce désignée ne peuvent pas bouger tant que cette dernière ne bouge pas'],
|
||||||
// ['coin coin','Possibilité de se téléporter depuis un coin vers n importe quel autre coin'],
|
["coin coin","Possibilité de se téléporter depuis un coin vers n'importe quel autre coin"],
|
||||||
// ['téléportation','Téléporte n importe quelle pièce de son camp sur une case vide'],
|
// ['téléportation','Téléporte n importe quelle pièce de son camp sur une case vide'],
|
||||||
// ['changement de camp','On retourne le plateau'],
|
// ['changement de camp','On retourne le plateau'],
|
||||||
// ['ça tangue','Toutes les pièces se décale du même côté'],
|
// ['ça tangue','Toutes les pièces se décale du même côté'],
|
||||||
|
|
@ -298,6 +298,21 @@ function computeLegalMoves(room, square){
|
||||||
|
|
||||||
const x = fromCoord.x, y = fromCoord.y;
|
const x = fromCoord.x, y = fromCoord.y;
|
||||||
const type = (piece.type || '').toUpperCase();
|
const type = (piece.type || '').toUpperCase();
|
||||||
|
// If this piece has been granted corner-teleport moves by 'coincoin', include those allowed squares
|
||||||
|
try{
|
||||||
|
const coin = (room.activeCardEffects || []).find(e => e && e.type === 'coincoin' && ((e.pieceId && e.pieceId === piece.id) || e.pieceSquare === square));
|
||||||
|
if(coin && Array.isArray(coin.allowedSquares) && coin.allowedSquares.length > 0){
|
||||||
|
coin.allowedSquares.forEach(sq => {
|
||||||
|
try{
|
||||||
|
// only add empty corner squares (do not allow capture via coincoin)
|
||||||
|
if(!moves.some(m => m.to === sq)){
|
||||||
|
const occ = getPieceAt(sq);
|
||||||
|
if(!occ) moves.push({ from: square, to: sq });
|
||||||
|
}
|
||||||
|
}catch(_){ }
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}catch(_){ }
|
||||||
// detect if this specific piece has a permanent adoubement effect (grants knight moves)
|
// detect if this specific piece has a permanent adoubement effect (grants knight moves)
|
||||||
// effects may be bound either to the piece's current square or to the piece id (preferred)
|
// effects may be bound either to the piece's current square or to the piece id (preferred)
|
||||||
const hasAdoubement = (room.activeCardEffects || []).some(e => e.type === 'adoubement' && ((e.pieceId && e.pieceId === piece.id) || e.pieceSquare === square));
|
const hasAdoubement = (room.activeCardEffects || []).some(e => e.type === 'adoubement' && ((e.pieceId && e.pieceId === piece.id) || e.pieceSquare === square));
|
||||||
|
|
@ -1307,6 +1322,59 @@ io.on('connection', (socket) => {
|
||||||
}catch(_){ }
|
}catch(_){ }
|
||||||
}catch(e){ console.error('kamikaz effect error', e); }
|
}catch(e){ console.error('kamikaz effect error', e); }
|
||||||
}
|
}
|
||||||
|
// coin coin: teleport one of your pieces from a corner to another empty corner
|
||||||
|
else if((typeof cardId === 'string' && (cardId.indexOf('coin') !== -1 || cardId.indexOf('coincoin') !== -1)) || cardId === 'coin_coin'){
|
||||||
|
try{
|
||||||
|
const board = room.boardState;
|
||||||
|
let source = payload && payload.targetSquare;
|
||||||
|
if(!source){ try{ source = socket.data && socket.data.lastSelectedSquare; }catch(e){ source = null; } }
|
||||||
|
const roomPlayer = room.players.find(p => p.id === senderId);
|
||||||
|
const playerColorShort = (roomPlayer && roomPlayer.color && roomPlayer.color[0]) || null;
|
||||||
|
const piece = (board && board.pieces || []).find(p => p.square === source);
|
||||||
|
// determine corner squares for the current board
|
||||||
|
const w = (board && board.width) || 8;
|
||||||
|
const h = (board && board.height) || 8;
|
||||||
|
const left = 'a';
|
||||||
|
const right = String.fromCharCode('a'.charCodeAt(0) + (w - 1));
|
||||||
|
const corners = [ left + '1', left + String(h), right + '1', right + String(h) ];
|
||||||
|
// validate source exists, belongs to the player and is on a corner
|
||||||
|
if(!board || !source || !piece || piece.color !== playerColorShort || corners.indexOf(source) === -1){
|
||||||
|
// invalid target: restore card to hand and abort
|
||||||
|
try{
|
||||||
|
room.hands = room.hands || {};
|
||||||
|
room.hands[senderId] = room.hands[senderId] || [];
|
||||||
|
if(removed) room.hands[senderId].push(removed);
|
||||||
|
room.discard = room.discard || [];
|
||||||
|
for(let i = room.discard.length - 1; i >= 0; i--){ if(room.discard[i] && room.discard[i].id === (removed && removed.id)){ room.discard.splice(i,1); break; } }
|
||||||
|
}catch(e){ console.error('restore removed card error', e); }
|
||||||
|
return cb && cb({ error: 'no valid corner piece selected' });
|
||||||
|
}
|
||||||
|
// find available destination corners (empty)
|
||||||
|
const emptyCorners = corners.filter(c => { return !(board.pieces || []).some(p => p.square === c); });
|
||||||
|
// remove the source corner from choices
|
||||||
|
const destChoices = emptyCorners.filter(c => c !== source);
|
||||||
|
if(!destChoices || destChoices.length === 0){
|
||||||
|
// nothing to teleport to: restore card
|
||||||
|
try{
|
||||||
|
room.hands = room.hands || {};
|
||||||
|
room.hands[senderId] = room.hands[senderId] || [];
|
||||||
|
if(removed) room.hands[senderId].push(removed);
|
||||||
|
room.discard = room.discard || [];
|
||||||
|
for(let i = room.discard.length - 1; i >= 0; i--){ if(room.discard[i] && room.discard[i].id === (removed && removed.id)){ room.discard.splice(i,1); break; } }
|
||||||
|
}catch(e){ console.error('restore removed card error', e); }
|
||||||
|
return cb && cb({ error: 'no empty destination corner available' });
|
||||||
|
}
|
||||||
|
// instead of teleporting immediately, record an effect that grants this piece the ability
|
||||||
|
// to move to any of the available corner squares for one turn
|
||||||
|
const effect = { id: played.id, type: 'coincoin', playerId: senderId, pieceId: piece.id, pieceSquare: source, allowedSquares: destChoices.slice(0), remainingTurns: 1, ts: Date.now() };
|
||||||
|
room.activeCardEffects = room.activeCardEffects || [];
|
||||||
|
room.activeCardEffects.push(effect);
|
||||||
|
// bump version so clients refresh legal moves when they request them
|
||||||
|
board.version = (board.version || 0) + 1;
|
||||||
|
try{ io.to(room.id).emit('card:effect:applied', { roomId: room.id, effect }); }catch(_){ }
|
||||||
|
played.payload = Object.assign({}, payload, { applied: 'coincoin', from: source, allowed: destChoices.slice(0) });
|
||||||
|
}catch(e){ console.error('coincoin effect error', e); }
|
||||||
|
}
|
||||||
// invisible: make one of your pieces invisible to the opponent for a number of turns
|
// invisible: make one of your pieces invisible to the opponent for a number of turns
|
||||||
else if(cardId === 'invisible' || (typeof cardId === 'string' && cardId.indexOf('invis') !== -1)){
|
else if(cardId === 'invisible' || (typeof cardId === 'string' && cardId.indexOf('invis') !== -1)){
|
||||||
try{
|
try{
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue