Create a button's icon with a part of a big image? - Beleaguered Castle

Got a LiveCode personal license? Are you a beginner, hobbyist or educator that's new to LiveCode? This forum is the place to go for help getting started. Welcome!

Moderators: FourthWorld, heatherlaine, Klaus, kevinmiller

stam
Posts: 2682
Joined: Sun Jun 04, 2006 9:39 pm
Location: London, UK

Re: Create a button's icon with a part of a big image? - Beleaguered Castle

Post by stam » Mon Sep 05, 2022 2:17 pm

Zax wrote:
Mon Sep 05, 2022 11:28 am
The problem actually comes from the speed.
I am unable to manage actions that follow one another too quickly - and this is even more true if, for example, an action in the history triggers a resizing. I tried several things to manage this delay but without success. It's beyond my LC skills.

I don't think the card movement animation is the main cause of the problem. Besides, I find it very useful to know which card is moved during a history movement.

So I don't know what to say except to repeat not to click too quickly on cards, or to navigate in the history too quickly.
It should perhaps be kept in mind that a solitaire card game is mostly for old people, who slowly click with their gnarled fingers on cards they don't see well, while drinking herbal tea ;)
Not sure you can tell your users not to press buttons too quickly in a game - that's destined for trouble ;)

Card animation has to be an issue as doing 5 undoes will take at least a couple of seconds in animation. Perhaps have a different handler for positioning cards that doesn't animate on history changes? Instead of animating card movement in history, just have them hilite like when you press a key for a number?

Hard to know what to suggest without seeing the code - on many occasions people have posted their code here and it's been refactored tremendously leading to orders of magnitude increase in speed. Just a thought...

S.

jacque
VIP Livecode Opensource Backer
VIP Livecode Opensource Backer
Posts: 7237
Joined: Sat Apr 08, 2006 8:31 pm
Location: Minneapolis MN
Contact:

Re: Create a button's icon with a part of a big image? - Beleaguered Castle

Post by jacque » Mon Sep 05, 2022 5:41 pm

richmond62 wrote:
Mon Sep 05, 2022 12:31 pm
Try putting a wait after every resize and every move.
That will block all the handlers that are managing the backend calculations and slow down the scripts even more. But flushEvents might work. Flush all mouseups and mousedowns after the calculations complete.

Another thought might be to lock messages after a move and unlock after the calculations are done. Either method may frustrate users though because they may think the app is unresponsive. I agree with Stam that if we see the handler we may be able to speed it up.
Jacqueline Landman Gay | jacque at hyperactivesw dot com
HyperActive Software | http://www.hyperactivesw.com

Zax
Posts: 469
Joined: Mon May 28, 2007 10:12 am
Location: France
Contact:

Re: Create a button's icon with a part of a big image? - Beleaguered Castle

Post by Zax » Tue Sep 06, 2022 9:22 am

stam wrote:
Mon Sep 05, 2022 2:17 pm
Not sure you can tell your users not to press buttons too quickly in a game - that's destined for trouble ;)
Hmm, yes, I have to agree, of course :|
Let's say: "wait ten or fifty years, and play again when you will be old enough because it's not a game for young people!" :twisted:

Or...
I'll try jacque's advice ASAP.

Animation is not the only problem: an Undo command can also trigger a resize.
Concerning the code, I could post it here - I'm really don't bother abour any kind of "property" problem - but it's rather complicated. Besides, it contains lots of french names (I always try to user english names but, at some point, when I'm immersed in code problems, I forget my good intentions.

stam
Posts: 2682
Joined: Sun Jun 04, 2006 9:39 pm
Location: London, UK

Re: Create a button's icon with a part of a big image? - Beleaguered Castle

Post by stam » Tue Sep 06, 2022 9:30 am

I’m not so sure the animation is the direct issue, although may be contributing.

I suspect this issue has more to do with the data model as the error messages suggest errors are creeping in on history changes and if time-dependent, will be made worse by many animations. And with errors creeping in, eventually card objects become “disconnected” as there appears to be no connection between some cards and the data model. But just guessing here…

Perhaps it’s worth refactoring (or posting) the the code run on undo?

Or alternatively, have some code to restructure the data model with the card positions as is on screen?

S.

SWEdeAndy
VIP Livecode Opensource Backer
VIP Livecode Opensource Backer
Posts: 261
Joined: Sat Aug 16, 2008 9:48 am
Location: Stockholm, Sweden
Contact:

Re: Create a button's icon with a part of a big image? - Beleaguered Castle

Post by SWEdeAndy » Tue Sep 06, 2022 8:12 pm

Winning in 84 moves - possibly my personal best at the moment.
84.png
84.png (18.41 KiB) Viewed 8377 times
Can't remember though, so my gnarled fingers are clawing for the top list that my misty eyes can't see...
It would be a great (and simple) feature though! :wink:
Andreas Bergendal
Independent app and system developer
WhenInSpace: https://wheninspace.se

Zax
Posts: 469
Joined: Mon May 28, 2007 10:12 am
Location: France
Contact:

Re: Create a button's icon with a part of a big image? - Beleaguered Castle

Post by Zax » Wed Sep 07, 2022 6:12 am

Gratz Andreas :)
As the savedgame files contain all data, it could be nice to share these files.
A load/save game file could be added in future version.

Concerning the current annoying bug, I'll try to post the relevant code soon.

stam
Posts: 2682
Joined: Sun Jun 04, 2006 9:39 pm
Location: London, UK

Re: Create a button's icon with a part of a big image? - Beleaguered Castle

Post by stam » Wed Sep 07, 2022 8:34 am

I think Andreas was hinting at a 'high score' feature rather than loading/sharing a saved game?
And in that case, maybe consider a shared 'high score' list over the internet as well?

S.

SWEdeAndy
VIP Livecode Opensource Backer
VIP Livecode Opensource Backer
Posts: 261
Joined: Sat Aug 16, 2008 9:48 am
Location: Stockholm, Sweden
Contact:

Re: Create a button's icon with a part of a big image? - Beleaguered Castle

Post by SWEdeAndy » Wed Sep 07, 2022 8:47 am

stam wrote:
Wed Sep 07, 2022 8:34 am
I think Andreas was hinting at a 'high score' feature rather than loading/sharing a saved game?
And in that case, maybe consider a shared 'high score' list over the internet as well?
Correct. Primarily just a local thing, like 'top 10 results on this computer'.
But a cloud based one to which you can submit you score, with a name, and the date, or something, could be cool too. A little more work to do, but not difficult. I did that for a game I made a few years back.
Andreas Bergendal
Independent app and system developer
WhenInSpace: https://wheninspace.se

Zax
Posts: 469
Joined: Mon May 28, 2007 10:12 am
Location: France
Contact:

Re: Create a button's icon with a part of a big image? - Beleaguered Castle

Post by Zax » Wed Sep 07, 2022 1:01 pm

I've correctly understood Andreas' wish, but I'm not convinced because all depends of the cards deal. Some deal are easy, others are difficult, and some and not winable.
That's why I would prefer to start a won saved game (at its initial state) and try to win with less card movements.
Actually, a saved game contains its initial state.

Otherwise, one thing could be done: a simple local statistic, showing the amount of won games / started games.

But first, I have to try to solve the nasty bug :evil:

SWEdeAndy
VIP Livecode Opensource Backer
VIP Livecode Opensource Backer
Posts: 261
Joined: Sat Aug 16, 2008 9:48 am
Location: Stockholm, Sweden
Contact:

Re: Create a button's icon with a part of a big image? - Beleaguered Castle

Post by SWEdeAndy » Wed Sep 07, 2022 1:24 pm

Indeed, it's not a type of game that makes that much sense comparing your result with others, unless you've played the exact same deal.

So, I'd be happy with just a local top list that simply stores and displays the 10 best results I've ever had. Adds a little spice to winning, if you also win well enough to make the list. :D
Andreas Bergendal
Independent app and system developer
WhenInSpace: https://wheninspace.se

stam
Posts: 2682
Joined: Sun Jun 04, 2006 9:39 pm
Location: London, UK

Re: Create a button's icon with a part of a big image? - Beleaguered Castle

Post by stam » Wed Sep 07, 2022 6:20 pm

Not sure that logic stands. All games have an element of luck; that’s no reason not to include high scores.

And I would point out that many solitaire-type games include this, knowing full well the effect of random draw.

Zax
Posts: 469
Joined: Mon May 28, 2007 10:12 am
Location: France
Contact:

Re: Create a button's icon with a part of a big image? - Beleaguered Castle

Post by Zax » Thu Sep 08, 2022 1:36 pm

flushEvents is interesting. It fixes some History problems in the 0.15 version.

Mac OS: https://sw.ixoft.com/files/_OLD/Beleagu ... 15_OSX.zip
Windows: https://sw.ixoft.com/files/_OLD/Beleagu ... 15_win.zip
Linux: https://sw.ixoft.com/files/_OLD/Beleagu ... inux64.zip

However, there are still problems with very fast clicks on the cards, so I'm posting parts of the code.

button "BtnCardBehavior" (behavior for cards images)

Code: Select all

global BCA_DELIM
global BCA_CARDS // array des cartes battues, rangées par colonnes
global BCA_HISTO // historique

global BCA_COLSRECTS // array des rectangles des colonnes et fondation

local gStartLoc, gIsMoving
local gMovableCards // liste des cartes draggables
local gArrAvailableCards // array des cartes-cibles possibles avec les colonnes correspondantes
local gTargetCard // carte cible (sur laquelle la carte déplacée sera droppée)
local gDraggedCard // carte bougée : short name of me
local gColStart, gColDest // numéros des colonnes de départ et de destination quand mouvement carte

on mouseDoubleUp
   //beep
end mouseDoubleUp

on mouseDown pBtn // peuplement de gDraggedCard, gStartLoc, gColStart et gMovableCards
   devPrint "", true // card : reset
   put the short name of me into gDraggedCard
   put getMovableCardsList() into gMovableCards
   if (gDraggedCard is not among the items of gMovableCards) then // carte non bougeable
      put "" into gMovableCards
      exit mouseDown // mais mouseUp sera exécuté !
   end if
   
   set the layer of me to top
   if (enTest() and the optionKey = down) then // DEV
      put false into gIsMoving // reset
      grab me // mouvement suivant souris
   else
      put getAvailableCards(gDraggedCard) into gArrAvailableCards // définition toutes cibles possible pour droppage
      if (pBtn = 3 or the controlKey = down) then
         hiliteAvailableCards true
         put false into gIsMoving
      else
         ---------------- peuplement de gStartLoc et gColStart
         put the loc of me into gStartLoc
         repeat with col = 1 to 12
            if (gStartLoc is within BCA_COLSRECTS[col]) then
               put col into gColStart
               exit repeat
            end if
         end repeat
         ---------------
         put "" into gTargetCard // reset
         put true into gIsMoving
         grab me // mouvement suivant souris
      end if
   end if
end mouseDown

on hiliteAvailableCards hiliteBoolean
   repeat for each key cardName in gArrAvailableCards
      if (hiliteBoolean) then
         cardHiliteTrue cardName // card
      else cardHiliteFalse cardName // card
   end repeat
end hiliteAvailableCards

on mouseMove // peuplement gTargetCard
   if (gIsMoving) then
      ------------------------------------ définition carte-cible potentielle (gTargetCard) ET hilite
      try
         repeat for each key thisCard in gArrAvailableCards
            put gArrAvailableCards[thisCard] into thisCol
            if (the mouseLoc is within BCA_COLSRECTS[thisCol]) then
               put thisCard into gTargetCard // définition cible possible pour droppage
               put thisCol into gColDest
               cardHiliteTrue gTargetCard // card
               exit repeat
            else
               set the colorOverlay["color"] of img thisCard to white
               set the colorOverlay["opacity"] of img thisCard to 0
            end if
         end repeat
      catch errMsg
         //devPrint "- mouseMove() : ERROR:" && error_getStr(errMsg) // card
         put false into gIsMoving
         put "" into gTargetCard // reset
         put "" into gColStart // reset
         put "" into gColDest // reset
         moveBack
      end try
      ------------------------------------ 
   end if
end mouseMove

on mouseUp pBtn
   put false into gIsMoving
   if (pBtn = 3 or the controlKey = down) then
      ------------------------------- extinction all hilites
      hiliteAvailableCards false
   else
      ------------------------------- mvt
      if (gMovableCards = "") then exit mouseUp
      ------------------ drag ou click ?
      put the loc of me into locMe
      put 2 into ecart
      put (item 1 of locMe) - ecart & comma & (item 2 of locMe) - ecart & comma & (item 1 of locMe) + ecart & \
            comma & (item 2 of locMe) + ecart into tmpRect
      ------------------ 
      if (gStartLoc is within tmpRect) then // pas de mouvement significatif : click
         set the loc of me to gStartLoc // re-placement si décalage
         clickCard
      else dropCard // mouvement significatif
      ------------------ 
   end if
   put "" into gTargetCard // reset
   put "" into gColStart // reset
   put "" into gColDest // reset
end mouseUp

on dropCard // droppage sur la colonne de la targetCard
   try
      if (the mouseLoc is within BCA_COLSRECTS[gColDest]) then // area colonne
         put last item of BCA_CARDS[gColDest] into targetCard
         moveCard targetCard, gColStart, gColDest, false // no histo
      else moveBack
   catch errMsg
      //devPrint "- dropCard() : ERROR:" && error_getStr(errMsg) && "  gTargetCard=" & gTargetCard // card
      moveBack
   end try
   cardHiliteFalse gTargetCard // card
end dropCard

on clickCard // placement auto si possible de la carte cliquée
   if (enTest() and the optionKey = down) then exit clickCard // pour DEV
   if (gArrAvailableCards = "") then exit clickCard
   put "" into gTargetCard
   put the keys of gArrAvailableCards into theKeys
   -------------------------------------- recherche cible : check fondation
   repeat for each key thisKey in gArrAvailableCards
      if (gArrAvailableCards[thisKey] <= 4) then
         put thisKey into gTargetCard
         exit repeat
      end if
   end repeat
   ------------------------------------- recherche cible : check colonnes (avec les vides en dernier)
   ---------------------- recherche colonnes proches
   if (gTargetCard = "") then
      local arrBest
      put "6,9,10,7,11" into arrBest[5] // du meilleur au moins bien
      put "5,7,10,9,11" into arrBest[6]
      put "6,8,10,11,12" into arrBest[7]
      put "7,12,11,6,10" into arrBest[8]
      put "5,10,6,11,7" into arrBest[9]
      put "9,11,6,5,7" into arrBest[10]
      put "10,12,7,6,8" into arrBest[11]
      put "11,8,7,10,6" into arrBest[12]
      put arrBest[gColStart] into bestCols
      put clickCard_getBestCol(bestCols) into gTargetCard // peut renvoyer ""
   end if
   ---------------------- recherche autres colonnes
   if (gTargetCard = "") then
      replace BCA_DELIM with "." in theKeys
      sort lines of theKeys ascending numeric
      replace "." with BCA_DELIM in theKeys
      repeat for each line thisCard in theKeys
         if (the number of items of BCA_CARDS[thisCol] = 1) then next repeat
         if (("20" & BCA_DELIM) is not thisCard) then
            put thisCard into gTargetCard
            exit repeat
         end if
      end repeat
   end if
   ---------------------- recherche colonnes vides en commençant par le bas
   if (gTargetCard = "") then
      replace BCA_DELIM with "." in theKeys
      sort lines of theKeys descending numeric
      replace "." with BCA_DELIM in theKeys
      put line 1 of theKeys into gTargetCard
   end if
   put gArrAvailableCards[gTargetCard] into colDest
   ------------------------------------- mouvement auto
   //devPrint "- clickCard() : gTargetCard=" & gTargetCard && " gColStart=" & gColStart && " colDest=" & colDest
   if (gTargetCard <> "") then moveCard gTargetCard, gColStart, colDest, false // no histo
   flushBoardEvents
end clickCard

function clickCard_getBestCol bestCols // peut renvoyer ""
   repeat for each item thisCol in bestCols // respecte l'ordre
      if (the number of items of BCA_CARDS[thisCol] = 1) then next repeat // colonne vide
      repeat for each key thisCard in gArrAvailableCards
         if (gArrAvailableCards[thisCard] = thisCol) then return thisCard
      end repeat
   end repeat
   return ""
end clickCard_getBestCol

on moveCard targetCard, colFrom, colDest, isHistoMoveBoolean
   if (isHistoMoveBoolean) then
      ---------------------------------- appel depuis historique (undo ou redo)
      put the short name of me into gDraggedCard
      set the layer of me to top
      put appSettingsGet("special", "moveSpeedFast") into mvtSpeed
      put false into fondationEffect
   else
      ---------------------------------- mvt manuel
      ---------- effacement éventuel de la partie récente de l'historique
      put the number of lines of the keys of BCA_HISTO into numLignesHisto
      if (numLignesHisto > fld "Steps") then
         repeat with i = numLignesHisto down to (fld "Steps" + 1)
            delete variable BCA_HISTO[i]
         end repeat
         histo_updateFld the number of lines of the keys of BCA_HISTO
      end if
      ----------
      put appSettingsGet("special", "moveSpeedSlow") into mvtSpeed
      put true into fondationEffect
   end if
   
   if (there is a img targetCard) then
      put the loc of img targetCard into locDest
      put getNeededOffset(targetCard, colDest) into offsetPx // offset nécessaire ?
      add offsetPx to item 1 of locDest
      set the moveSpeed to mvtSpeed
      move me to locDest
      updateCardsList gDraggedCard, targetCard, colFrom, colDest, isHistoMoveBoolean // MAJ de BCA_CARDS
      /*
      devPrint "- moveCard() :  gDraggedCard="& gDraggedCard & "  targetCard=" & targetCard && "  colFrom=" & colFrom & \
            "  colDest=" & colDest
      */
      updateColsArea colFrom
      updateColsArea colDest
      
      -- cause bug si double-click trop rapide !!!
      --if (fondationEffect and colDest <= 4) then send "effectFondation targetCard" to this card in 10 milliseconds
      ---------------------------- check si jeu bloqué
      /* algo faux !
      put getMovableCardsList() into movableCards // cartes bougeables seulement
      put false into gameStuck
      repeat for each item thisCard in movableCards
         if (getAvailableCards(thisCard) <> "") then put true into gameStuck
      end repeat
      devPrint "- moveCard() : movableCards=" & movableCards & "  gameStuck=" & gameStuck
      if (gameBlocked) then game_stuck // card
      */
      ---------------------------- log éventuel
      populateLogStack
      ---------------------------- check si jeu gagné
      get isGameWon()
      if (it > 0) then
         game_won (it > 1) // card
         exit moveCard
      end if
      ---------------------------- check si resize needed pour colonne trop longue ou trop courte
      checkFreeSpace // card
      flushBoardEvents
   else
      if ("standalone" is not in the environment) then
         get cr & cr & "- moveCard() : ERROR:" && error_getStr(errMsg) && "  targetCard=" & targetCard && \
               "  locDest=" & locDest && "  isHistoMoveBoolean=" & isHistoMoveBoolean
      else get ""
      histo_error 6085, "Error in card movement." & it
   end if
end moveCard
   
function getNeededOffset targetedCard, colDest // renvoit l'offset (px) nécessaire au placement de la carte bougée
   if (("20" & BCA_DELIM) is in targetedCard) then return 0 // colonne vide
   if (colDest <= 4) then return 0 // fondation (pas d'offset)
   
   put floor((the width of me) * appSettingsGet("special", "cardOffset")) into cardOffset
   if (colDest <= 8) then
      return 0 - cardOffset
   else return cardOffset
end getNeededOffset

function isGameWon // renvoit 0, 1 (win assuré) ou 2 (win effective)
   put 0 into numColsVides
   put 0 into numCardsLeft
   repeat with col = 5 to 12
      get the number of items in BCA_CARDS[col]
      if (it = 1) then
         add 1 to numColsVides
      else add (it - 2) to numCardsLeft // ne pas compter les bases des colonnes et les cartes en haut des colonnes
   end repeat
   //devPrint "- isGameWon() : numColsVides=" & numColsVides & "  numCardsLeft=" & numCardsLeft
   if (numColsVides = 8) then
      return 2
   else if (numColsVides >= max(numCardsLeft)) then
      return 1
   else return 0
end isGameWon

on moveBack
   set the moveSpeed to appSettingsGet("special", "moveSpeedFast")
   move me to gStartLoc
end moveBack

function getMovableCardsList // liste des cartes déplaçables (dernier item de chaque colonne non vide)
   local basColonnesListe
   repeat with col = 1 to 4
      get last item of BCA_CARDS[col]
      if (char 1 of it > 2) then put it & comma after basColonnesListe
   end repeat
   repeat with col = 5 to 12
      get last item of BCA_CARDS[col]
      if (char 1 to 2 of it <> 20) then put it & comma after basColonnesListe
   end repeat
   delete last char of basColonnesListe
   return basColonnesListe
end getMovableCardsList

function getAvailableCards draggedCard // ARRAY des noms des cartes targettables (img) et des colonnes
   put draggedCard into devComm
   split draggedCard using BCA_DELIM // array
   local arrResu
   if (draggedCard[1] = 2) then
      ------------------------------ cas spécial des 2
      put draggedCard[2] into arrResu["1" & BCA_DELIM & draggedCard[2]] // As de la même couleur
   else
      ------------------------------ autre carte
      ---------------- fondation ?
      if (last item of BCA_CARDS[draggedCard[2]] = (draggedCard[1] - 1 & BCA_DELIM & draggedCard[2]))
      then put draggedCard[2] into arrResu[last item of BCA_CARDS[draggedCard[2]]]
      ---------------- colonnes ?
      repeat with col = 5 to 12
         if (("20" & BCA_DELIM) is in last item of BCA_CARDS[col]) then // colonne vide
            put col into arrResu[last item of BCA_CARDS[col]]
         else if ((draggedCard[1] + 1 & BCA_DELIM) is in last item of BCA_CARDS[col]) then
            put col into arrResu[last item of BCA_CARDS[col]]
         end if
      end repeat
   end if
   -------------------------------- 
   return arrResu
end getAvailableCards

on updateCardsList droppedCard, targetCard, colFrom, colDest, isHistoMoveBoolean // MAJ de BCA_CARDS après un mvt de carte
   put not isHistoMoveBoolean into histoUpdate
   if (droppedCard <> "" and colFrom <> "" and gDestCol <> "") then
      ----------------------------- suppression de la carte droppée dans la colonne de départ
      delete last item of BCA_CARDS[colFrom]
      if (last char of BCA_CARDS[colFrom] = comma) then delete last char of BCA_CARDS[colFrom] // secu
      ----------------------------- ajout de la carte droppée dans la colonne de destination
      put comma & droppedCard after BCA_CARDS[colDest] // BCA_CARDS[col] n'est jamais vide
      
      //devPrint "- updateCardsList() : droppedCard=" & droppedCard & "  colFrom=" & colFrom & "  colDest=" & colDest
      if (histoUpdate) then
         histo_add (droppedCard & comma & colFrom & comma & colDest) // card
      end if
   else
      beep
      --histo_error 1022, "Card mouvement." // card
   end if
end updateCardsList
card "Main" (extracts)

Code: Select all

local gArrDimsCard // taille des cartes en px : array ["height"] et ["width"]
local gRapportCard // rapport largeur/hauteur d'un carte
local gLargeurBoard, gHauteurBoard // largeur et hauteur en px du "tapis"
local gHiliteColor, gHiliteBorder
local gHilitedCards, gFoundHiliteColor // pour recherche cartes
local gHistoLastState // pour revenir à la dernière étape de l'historique
local gImgList // pour check board
local gSettingsApp // copie de appSettingsGet("special") (pour vitesse exécution)

global BCA_CARDS // array des cartes battues, rangées par colonnes
global BCA_CARDS_INIT // array : initial state of BCA_CARDS
global BCA_HISTO // array des mouvements de cartes
global BCA_COLSRECTS // array des rectangles des colonnes et fondation

global BCA_DELIM // "_" (defined on openStack)

on cards_initDims maxNumCardsInColumn, initDimBoolean // calcul des dimensions d'une carte (gArrDimsCard)
   put the width of graphic "Board" into gLargeurBoard
   put the height of graphic "Board" into gHauteurBoard
   if (visible of fld "DevLog") then subtract (the height of fld "DevLog" + 25) from gHauteurBoard
   cardsGetDim maxNumCardsInColumn, initDimBoolean // peuplement gArrDimsCard
end cards_initDims

on cardsGetDim optionalCardsNum, initDimBoolean // paramètre optionnel lors d'un resize (quand board déjà construit)
   // dimension d'une carte suivant taille "Board" : renvoit 1 array de 2 éléments : height, width (px)
   // peuplement de gArrDimsCard
   ----------------- largeur potentielle
   if (initDimBoolean) then // début partie
      put gLargeurBoard * gSettingsApp["sideInitMargins"] into margeCotes
   else put gLargeurBoard * gSettingsApp["sideMargins"] into margeCotes
   put gLargeurBoard * gSettingsApp["foundationMargin"] into margeFondation
   put 3 into numCartesVisibles // 1 pour chaque colonne + 1 pour fondation
   put 6 into nbreCartesColonne // colonne nominale de 6 cartes
   if (optionalCardsNum <> "" and optionalCardsNum > nbreCartesColonne) then put optionalCardsNum into nbreCartesColonne
   put (nbreCartesColonne - 1) * 2 into nbreCartesTronquees
   put floor((gLargeurBoard - (margeFondation * 2) - (margeCotes * 2)) / \
         (numCartesVisibles + (nbreCartesTronquees * gSettingsApp["cardOffset"]))) into largeurCard
   /*
   get "gLargeurBoard=" & gLargeurBoard & "  margeCotes=" & margeCotes & "  margeFondation=" & margeFondation & \
         "  cardOffset=" & gSettingsApp["cardOffset"] & "  >>>> largeurCard=" & largeurCard
   devPrint "- cardsGetDim(LARGEUR_CARD) :" && it /////
   */
   ----------------- hauteur potentielle
   put gHauteurBoard * gSettingsApp["topMargin"] into margeHaut
   put gHauteurBoard * gSettingsApp["bottomMargin"] into margeBas
   put gHauteurBoard * gSettingsApp["intervalMargin"] into margeInterval // %
   put gHauteurBoard - margeHaut - margeBas - (margeInterval * 3) into espaceRestant
   put floor(espaceRestant / 4) into hauteurCard
   ----------------- hauteur ou largeur ?
   put floor(largeurCard / gRapportCard) into tmpHauteurCard
   put floor(hauteurCard * gRapportCard) into tmpLargeurCard
   
   if (tmpHauteurCard < hauteurCard) then // prendre la plus petite dimension
      --------- dims d'après largeur
      put tmpHauteurCard into gArrDimsCard["height"]
      put largeurCard into gArrDimsCard["width"]
      put "*LARGEUR*" into devNote
   else
      --------- dims d'après hauteur
      put hauteurCard into gArrDimsCard["height"]
      put tmpLargeurCard into gArrDimsCard["width"]
      put "*HAUTEUR*" into devNote
   end if
   -----------------
   /*
   get "hauteurCard=" & hauteurCard & "  largeurCard=" & largeurCard & " --- " & \
         "tmpHauteurCard=" & tmpHauteurCard & "  tmpLargeurCard=" & tmpLargeurCard && \
         " >>>> mode=" & devNote & "  L=" & gArrDimsCard["width"] & "  H=" & gArrDimsCard["height"]
   */
   //devPrint "- cardsGetDim() : mode=" & devNote && "  L=" & gArrDimsCard["width"] & "  H=" & gArrDimsCard["height"]
end cardsGetDim

on hiliteAvailableFondationCards hiliteBoolean // allumage des cartes dispos pour Fondations
   if (hiliteBoolean) then
      if (BCA_CARDS <> "") then
         put "" into gHilitedCards
         repeat with col = 5 to 12
            put last item of BCA_CARDS[col] into cardName
            if (("20_" & BCA_DELIM) is not in cardName) then
               get cardName
               split it using BCA_DELIM // array
               if (last item of BCA_CARDS[it[2]] = (it[1] - 1 & BCA_DELIM & it[2])) then put cardName & comma after gHilitedCards
            end if
         end repeat
         delete last char of gHilitedCards
         cardsFoundHilite gHilitedCards, true, gHiliteColor
      end if
   else cardsFoundHilite gHilitedCards, false
end hiliteAvailableFondationCards

on keyDown tKey // recherche de cartes par valeur
   if ("pointer" is in the tool) then pass keyDown
   
   if (BCA_CARDS = "") then pass keyDown
   ---------------------------- conversion : touche --> carte
   put itemOffset(tKey, "2,3,4,5,6,7,8,9,0,J,Q,K") into numKey
   if (numKey > 0) then
      put item numKey of "2,3,4,5,6,7,8,9,10,11,12,13" & BCA_DELIM into refCard
      put refCard & "1" & comma & refCard & "2" & comma & refCard & "3" & comma & refCard & "4" into gHilitedCards
      cardsFoundHilite gHilitedCards, true
   else pass keyDown
end keyDown

on keyUp
   cardsFoundHilite gHilitedCards, false
end keyUp

on cardsFoundHilite cardsList, hiliteBoolean, colorHilited
   if (colorHilited = "") then put gFoundHiliteColor into colorHilited
   repeat for each item cardName in cardsList
      try
         if (hiliteBoolean) then
            set the colorOverlay["color"] of img cardName to colorHilited
            set the colorOverlay["opacity"] of img cardName to 70
         else
            set the colorOverlay["color"] of img cardName to white
            set the colorOverlay["opacity"] of img cardName to 0
         end if
      catch errMsg
         devPrint "- cardsFoundHilite() : ERROR. cardName=" & cardName && " colorHilited=" & colorHilited
      end try
   end repeat
end cardsFoundHilite

on cardHiliteTrue cardName // hilite d'une carte (divisé en 2 parties pour rapidité)
   try
      set the colorOverlay["color"] of img cardName to gHiliteColor
      set the colorOverlay["opacity"] of img cardName to 75
   catch errMsg
      //devPrint "- cardHilite() : ERROR. cardName=" & cardName
   end try
end cardHiliteTrue

on cardHiliteFalse cardName // des-hilite une carte
   try
      set the colorOverlay["color"] of img cardName to white
      set the colorOverlay["opacity"] of img cardName to 0
   catch errMsg
      //devPrint "- cardHilite() : ERROR. cardName=" & cardName
   end try
end cardHiliteFalse

on flushBoardEvents // pour ne pas tenir compte des events en attente lors d'un process long
   get flushEvents("mouseDown")
   get flushEvents("keyDown")
   get flushEvents("autoKey") // répétition touches
end flushBoardEvents

on checkFreeSpace // test si colonne trop grande ou trop petite --> besoin resize cards
   put getNumCardsLargerColumn() into maxNumCardsInColumn // nbre de cartes dans la plus grande colonne
   put (the right of img ("20" & BCA_DELIM & "5")) - (the left of graphic "Board") into availableWidth //largeur dispo pour 1 col
   put floor(gArrDimsCard["width"] * gSettingsApp["cardOffset"]) into offsetPx
   put gArrDimsCard["width"] + ((maxNumCardsInColumn - 1) * offsetPx) into largeurMaxCol // largeur de la plus grande colonne
   put availableWidth - largeurMaxCol into freeSpace // espace restant (px)
   //devPrint "- checkFreeSpace() : availWidth=" & availableWidth && " largMaxCol=" & largeurMaxCol && " space=" & freeSpace
   if (freeSpace < gLargeurBoard * gSettingsApp["sideMargins"]) then // réduire + 2 cartes pour pas resize à chaque mvt
      cardsResize maxNumCardsInColumn + 2, false, false // no forcage
   else if (freeSpace > gLargeurBoard * gSettingsApp["sideMaxMargins"]) then// augmenter + 4 cartes pour pas resize à chaque mvt
      cardsResize maxNumCardsInColumn + 4, false, false // no forcage
   end if
end checkFreeSpace

on cardsResize maxNumCardsInColumn, forceRedimBoolean, initDimBoolean
   // retaille et placement des cartes demandé (avec ou sans forcage de redimensionnement)
   if (maxNumCardsInColumn = "") then put getNumCardsLargerColumn() into maxNumCardsInColumn
   cards_initDims maxNumCardsInColumn, initDimBoolean // re-calcul des dimensions d'une carte
   if ((forceRedimBoolean) or (gArrDimsCard["width"] <> the width of img ("1" & BCA_DELIM & "1")) or \
         (item 1 of the loc of img ("1" & BCA_DELIM & "1") <> item 1 of the loc of graphic "board")) then
      cards_placeFondation false // no reset hilite (faster)
      cards_placeBaseCols false // no reset hilite (faster)
      if (visible of btn "MenuDev") then cards_placeDevNumCols // DEV
      cardsResize_suite initDimBoolean // retaille effective des cartes
      /*
      devPrint "- cardsResize() : maxNumCardsInColumn=" & maxNumCardsInColumn & "  gLargeurBoard=" & gLargeurBoard & \
            "  widthCard=" & gArrDimsCard["width"] & "  heightCard=" & gArrDimsCard["height"]
      */
   end if
end cardsResize

on cardsResize_suite initDimBoolean // retaille et placement effectif des cartes (d'après BCA_CARDS)
   lock screen // pour accélerer l'affichage
   --------------------------------------- cartes sur fondation
   repeat with col = 1 to 4
      put the rect of img ("1" & BCA_DELIM & col) into cardRect
      put cardRect into BCA_COLSRECTS[col]
      repeat with itm = 2 to (the number of items in BCA_CARDS[col]) // base fondation déjà placée
         set the rect of img (item itm of BCA_CARDS[col]) to cardRect
         set the layer of img (item itm of BCA_CARDS[col]) to top
      end repeat
   end repeat
   --------------------------------------- cartes dans colonnes
   put floor(gArrDimsCard["width"] * gSettingsApp["cardOffset"]) into offsetPx
   try
      repeat with col = 5 to 8 // gauche
         put the rect of img ("20" & BCA_DELIM & col) into cardRect // base col
         put 0 into delta
         repeat with itm = 2 to (the number of items in BCA_CARDS[col]) // base colonne déjà placée
            put item itm of BCA_CARDS[col] into thisCard
            set rect of img thisCard to ((item 1 of cardRect) - delta & comma & item 2 of cardRect & \
                  comma & (item 3 of cardRect) - delta & comma & item 4 of cardRect)
            add offsetPx to delta
            set the layer of img thisCard to top
         end repeat
         updateColsArea col
      end repeat
      repeat with col = 9 to 12 // droite
         put the rect of img ("20" & BCA_DELIM & col) into cardRect // base col
         put 0 into delta
         repeat with itm = 2 to (the number of items in BCA_CARDS[col]) // base colonne déjà placée
            put item itm of BCA_CARDS[col] into thisCard
            set rect of img thisCard to ((item 1 of cardRect) + delta & comma & item 2 of cardRect & \
                  comma & (item 3 of cardRect) + delta & comma & item 4 of cardRect)
            add offsetPx to delta
            set the layer of img thisCard to top
         end repeat
         updateColsArea col
      end repeat
   catch errMsg
      if ("standalone" is not in the environment) then get errorCatch(errMsg) else get "Cards resizing"
      histo_error 6050, it
   end try
   if (initDimBoolean) then unlock screen with dissolve very fast
end cardsResize_suite

function getNumCardsLargerColumn // renvoit le nombre de cartes dans la plus grande colonne
   local liste
   repeat with col = 5 to 12
      put the number of items in BCA_CARDS[col] & comma after liste
   end repeat
   return max(liste)
end getNumCardsLargerColumn

on updateColsArea col // MAJ rectangles des colonnes et fondation
   try // pour bug PC au lancement si pas de savedgame
      if (col > 4) then
         get "20" & BCA_DELIM & col
         if (col <= 8) then // left
            put the topLeft of img (last item of BCA_CARDS[col]) & comma & the bottomRight of img it into BCA_COLSRECTS[col]
         else put the topLeft of img it & comma & the bottomRight of img (last item of BCA_CARDS[col]) into BCA_COLSRECTS[col]
      end if
   catch errMsg
      // ne rien faire : ça passe quand même
   end try
end updateColsArea
on histo_init // new game
   put "" into BCA_HISTO
   put BCA_CARDS into gHistoLastState
   histo_updateFld 0
end histo_init

on histo_add mvt // incrementation (card movement)
   get (the number of lines of the keys of BCA_HISTO) + 1
   put mvt into BCA_HISTO[it] // push mvt definition
   put BCA_CARDS into gHistoLastState
   histo_updateFld it
end histo_add

on histo_undo
   get (the number of lines of the keys of BCA_HISTO)
   if (it > 0) then
      histo_loadStep fld "Steps", -1
   else histo_error
end histo_undo

on histo_redo
   get (the number of lines of the keys of BCA_HISTO)
   if (fld "Steps" <= it) then
      histo_loadStep fld "Steps" + 1, 0
   else histo_error
end histo_redo

on histo_loadStep stepVal, increment
   if (BCA_HISTO[stepVal] <> "") then
      put BCA_HISTO[stepVal] into currMvt
      put item 1 of currMvt into draggedCard
      if (increment < 0) then
         put item 2 of currMvt into colDest
         put item 3 of currMvt into colRetrait
      else
         put item 3 of currMvt into colDest
         put item 2 of currMvt into colRetrait
      end if
      put last item of BCA_CARDS[colDest] into targetCard
      /*
      devPrint "- histo_loadStep() : increment=" & increment & "  stepVal=" & stepVal & "  draggedCard=" & draggedCard & \
            "  targetCard=" & targetCard & "  colRetrait=" & colRetrait & "  colDest=" & colDest
      */
      try
         dispatch "moveCard" to img draggedCard with targetCard,colRetrait,colDest,true // histo
         histo_updateFld stepVal + increment
         populateLogStack
         flushBoardEvents--***
      catch errMsg
         histo_error 1023
      end try
   else histo_error
end histo_loadStep

on histo_updateFld stepVal
   put the number of lines of the keys of BCA_HISTO into numSteps
   if (stepVal = "") then put numSteps into stepVal // pour load game
   put stepVal into fld "Steps"
   set the enabled of btn "BtnUndo" to (fld "Steps" > 0)
   set the enabled of btn "BtnRedo" to (fld "Steps" < numSteps)
end histo_updateFld

on histo_error errNum, comm
   beep
   set the foregroundColor of fld "Steps" to red
   wait 400 milliseconds
   set the foregroundColor of fld "Steps" to "#3F3F3F"
   if (errNum <> "") then answer error "History error." & cr & "    [#" & errNum & "]" & cr & "Check board data?" with \
         "Cancel" or "Check"
   if (it = "Check") then game_checkBoardData // card
end histo_error

Zax
Posts: 469
Joined: Mon May 28, 2007 10:12 am
Location: France
Contact:

Re: Create a button's icon with a part of a big image? - Beleaguered Castle

Post by Zax » Thu Sep 08, 2022 2:50 pm

I forgot to explain the encoded board:
Array BCA_CARDS

[1] - 1_1
[2] - 1_2
[3] - 1_3
[4] - 1_4
[5] - 20_5,13_1,12_1,11_1,10_1,9_1,8_1
[6] - 20_6,13_2,12_2,11_2,10_2,9_2,8_2
[7] - 20_7,13_3,12_3,11_3,10_3,9_3,8_3
[8] - 20_8,13_4,12_4,11_4,10_4,9_4,8_4
[9] - 20_9,7_1,6_1,5_1,4_1,3_1,2_1
[10] - 20_10,7_2,6_2,5_2,4_2,3_2,2_2
[11] - 20_11,7_3,6_3,5_3,4_3,3_3,2_3
[12] - 20_12,7_4,6_4,5_4,4_4,3_4,2_4
Each element is a row. Elements 1 from 4 are the foundation, pre-filled with aces.
Cards name is coded like this: cardValue_cardSuit
Cards value is from 1 to 13 (King)

jacque
VIP Livecode Opensource Backer
VIP Livecode Opensource Backer
Posts: 7237
Joined: Sat Apr 08, 2006 8:31 pm
Location: Minneapolis MN
Contact:

Re: Create a button's icon with a part of a big image? - Beleaguered Castle

Post by jacque » Fri Sep 09, 2022 7:40 pm

Here are three extra background images for the game, if you like them.
Attachments
ThreeBackgrounds.zip
(190.57 KiB) Downloaded 84 times
Jacqueline Landman Gay | jacque at hyperactivesw dot com
HyperActive Software | http://www.hyperactivesw.com

Zax
Posts: 469
Joined: Mon May 28, 2007 10:12 am
Location: France
Contact:

Re: Create a button's icon with a part of a big image? - Beleaguered Castle

Post by Zax » Mon Sep 12, 2022 9:00 am

Thank you jacque for the backgrounds.

As my code is rather complex, this is its simplified structure:

Code: Select all

on mouseDoubleUp
   //beep
end mouseDoubleUp

on mouseDown pBtn
   search for movable cards
   if me is not in movable cards then exit (but mouseUp will be executed!)	
   
   get the list of possible target cards
   if pBtn = 3 or the controlKey = down then
      hilite possible target cards
      set flag "isMoving" to false
   else
      populate "startLoc" and "colStart"
      set flag "isMoving" to true
      grab me
   end if
end mouseDown

on mouseMove // 
   if flag "isMoving" to true then
      repeat with all cards
         if the mouseLoc is within an available row then
            populate "targetCard"
            hilite target card
            exit repeat
         else
            des-hilite card
         end if
      end repeat
   end if
end mouseMove

on mouseUp pBtn
   set flag "isMoving" to false
   if pBtn = 3 or the controlKey = down then
      des-hilite all cards
   else
      if there is no available target then exit mouseUp
      if me has not been moved then // drag or click ?
         clickCard
      else moveCard
   end if
end mouseUp

on clickCard // auto movement
   if available target cards is empty then exit clickCard
   search for the best target card --> populate "targetCard"
   moveCard
   flushBoardEvents
end clickCard
   
on moveCard
   updateCardsList
   dest location calculation
   move me to locDest
   
   update rows areas (for drag card hilite effect)
   check if game won
   check if enough free space on the board for next card movement : if not, resize cards
   flushBoardEvents
end moveCard

on updateCardsList
   delete last item of BCA_CARDS[CARD_BEHAVIOR["colStart"]]
   put comma & CARD_BEHAVIOR["draggedCard"] after BCA_CARDS[CARD_BEHAVIOR["colDest"]]
end updateCardsList
BCA_CARDS Array

[1] - 1_1
[2] - 1_2
[3] - 1_3
[4] - 1_4
[5] - 20_5,13_1,12_1,11_1,10_1,9_1,8_1
[6] - 20_6,13_2,12_2,11_2,10_2,9_2,8_2
[7] - 20_7,13_3,12_3,11_3,10_3,9_3,8_3
[8] - 20_8,13_4,12_4,11_4,10_4,9_4,8_4
[9] - 20_9,7_1,6_1,5_1,4_1,3_1,2_1
[10] - 20_10,7_2,6_2,5_2,4_2,3_2,2_2
[11] - 20_11,7_3,6_3,5_3,4_3,3_3,2_3
[12] - 20_12,7_4,6_4,5_4,4_4,3_4,2_4

Each element is a row. Elements 1 from 4 are the foundation, pre-filled with aces.
Cards name is coded like this: cardValue_cardSuit
Cards value is from 1 (Ace) to 13 (King). So for example Jack of Hearts is coded 11_1, and seven of Diamonds 7_3.
I recently optimized the code but I did not find any error that could cause the bug encountered. However, this bug still occurs sometimes and corrupts the array BCA_CARDS. All i can do and improve the error recovery and improve the repair of the board in order to be able to continue the game in progress.

Post Reply

Return to “Getting Started with LiveCode - Complete Beginners”