@@ -499,6 +499,9 @@ export class UrbinoGame extends GameBase {
499499 } else { // from *has* to be defined if move itself has content
500500 if ( smallest === undefined ) {
501501 newmove = "pass" ;
502+ // if you click on a different architect, switch to that one
503+ } else if ( ( this . board . has ( cell ) ) && ( this . board . get ( cell ) ! [ 0 ] === 0 ) && ( cell !== from ) ) {
504+ newmove = cell ;
502505 // if you click on an empty cell, assume movement
503506 } else if ( ( this . board . has ( from ) ) && ( ! this . board . has ( cell ) ) ) {
504507 newmove = `${ from } -${ cell } ` ;
@@ -703,6 +706,22 @@ export class UrbinoGame extends GameBase {
703706 }
704707 return result ;
705708 }
709+ // Check if player has this piece in their stash
710+ if ( this . pieces [ this . currplayer - 1 ] [ pSize - 1 ] < 1 ) {
711+ result . valid = false ;
712+ switch ( pSize ) {
713+ case 1 :
714+ result . message = i18next . t ( "apgames:validation.urbino.INVALID_PIECE" , { piece : "house" } ) ;
715+ break ;
716+ case 2 :
717+ result . message = i18next . t ( "apgames:validation.urbino.INVALID_PIECE" , { piece : "tower" } ) ;
718+ break ;
719+ case 3 :
720+ result . message = i18next . t ( "apgames:validation.urbino.INVALID_PIECE" , { piece : "palace" } ) ;
721+ break ;
722+ }
723+ return result ;
724+ }
706725
707726 // we're good
708727 result . valid = true ;
@@ -952,6 +971,7 @@ export class UrbinoGame extends GameBase {
952971 public findPoints ( ) : string [ ] {
953972 const points : string [ ] = [ ] ;
954973 if ( this . board . size >= 2 ) {
974+ // First, find all architect line-of-sight intersections (original behavior)
955975 for ( let i = 0 ; i < 9 ; i ++ ) {
956976 for ( let j = 0 ; j < 9 ; j ++ ) {
957977 this . scratchboard [ i ] [ j ] = 0 ;
@@ -996,6 +1016,35 @@ export class UrbinoGame extends GameBase {
9961016 return points ;
9971017 }
9981018
1019+ /**
1020+ * Enhanced version of findPoints that filters by all placement restrictions.
1021+ * Returns only cells where the current player can actually place a building.
1022+ */
1023+ public findValidPlacementPoints ( ) : string [ ] {
1024+ const intersectionPoints = this . findPoints ( ) ;
1025+ const validPoints : string [ ] = [ ] ;
1026+
1027+ for ( const cell of intersectionPoints ) {
1028+ // Check if any piece can be placed here
1029+ let canPlaceAny = false ;
1030+ for ( let size = 1 ; size <= 3 ; size ++ ) {
1031+ // Check if player has this piece available
1032+ if ( this . pieces [ this . currplayer - 1 ] [ size - 1 ] > 0 ) {
1033+ // Check if placement is valid (adjacency + district rules)
1034+ if ( this . validPlacement ( cell , size as Size , this . currplayer ) ) {
1035+ canPlaceAny = true ;
1036+ break ;
1037+ }
1038+ }
1039+ }
1040+ if ( canPlaceAny ) {
1041+ validPoints . push ( cell ) ;
1042+ }
1043+ }
1044+
1045+ return validPoints ;
1046+ }
1047+
9991048 public state ( ) : IUrbinoState {
10001049 return {
10011050 game : UrbinoGame . gameinfo . uid ,
@@ -1101,7 +1150,7 @@ export class UrbinoGame extends GameBase {
11011150 } ,
11021151 pieces : pstr
11031152 } ;
1104- const cells = this . findPoints ( ) . map ( p => UrbinoGame . algebraic2coords ( p ) ) ;
1153+ const cells = this . findValidPlacementPoints ( ) . map ( p => UrbinoGame . algebraic2coords ( p ) ) ;
11051154 if ( cells . length > 0 ) {
11061155 const points : RowCol [ ] = [ ] ;
11071156 for ( const cell of cells ) {
0 commit comments