Results 1 to 4 of 4

Thread: Handling decks with scripts attached that get destroyed when all cards are removed

  1. #1

    Handling decks with scripts attached that get destroyed when all cards are removed

    Hi!

    I'm trying write a script for a card game, from which I've taken inspiration from the Blackjack example.

    In the blackjack example the deck of cards has a script attached to it, and I am doing something similar in my game. The problem is in my game the deck is dealt out completely, destroying the deck. Then when a new one is created by putting the cards back together the script has gone.

    I'm wondering what might be the best way to handle this problem.. I've been looking at the onObjectDestroyed function, but I think and "onObjectCreated" function would be more useful in this case, so I could re-attach the script to it if the primary deck no longer existed.

    Does anyone have any advice on how I might solve this problem?

    Cheers!

  2. #2
    So how I "solved" this problem in the end feels a bit hacky but it worked. Basically the steps I did was

    1. Record the position, rotation and lua script of the deck in onload()
    2. Created a button called "Next Round"
    3. When the button is clicked it finds all cards on the table and moves them to the original position
    4. Set a 1 second timer to run a reinitDeck function, this is to allow time for all the cards to "settle" into a single deck
    5. loop through all objects and find the deck
    6. set the new deck to my global deck variable

    I'll put the relevant bits of code here for anyone interested.
    Code:
    --[[ Global Variables --]]
    deck = {}
    deck_guid = '7be2a3'
    deck_script = nil
    deck_orig_pos = {}
    deck_orig_rot = {}
    deal_button = {}
    deal_button_guid = 'faf352'
    next_round_button = {}
    next_round_button_guid = '13f56a';
    
    --[[ The OnLoad function. This is called after everything in the game save finishes loading.
    Most of your script code goes here. --]]
    function onload()
        deal_button = getObjectFromGUID(deal_button_guid)
        next_round_button = getObjectFromGUID(next_round_button_guid)
        deck = getObjectFromGUID(deck_guid)
        deck_script = deck.script_code
        deck_orig_pos = deck.getPosition()
        deck_orig_rot = deck.getRotation()
        turn_text = getObjectFromGUID(turn_text_gui)
    
        local button = {}
        button.click_function = 'nextRound'
        button.label = 'Next\nRound'
        button.function_owner = Global
        button.font_size = 100
        button.flip = true
        button.width = 350
        button.height = 350
        button.position = {0, 0.2, 0}
        button.rotation = {0, 0, 0}
    
        next_round_button.createButton(button)
    end
    
    
    function nextRound ()
        if deck == nil then
            local tableObjects = getAllObjects()
    
            for i, v in pairs(tableObjects) do
                if (v.name == 'Card' or v.name == 'Deck') then
                    v.setPosition(deck_orig_pos)
                    v.setRotation(deck_orig_rot)
                end
            end
        end
    
        local params = {}
        params.identifier = 'reinitDeckTimer'
        params.function_name = 'reinitDeck'
        params.delay = 1
        Timer.create(params)
    end
    
    function reinitDeck ()
        local tableObjects = getAllObjects()
        for i, v in pairs(tableObjects) do
            if (v.name == 'Deck') then
                deck = v
                deck.setLuaScript(deck_script)
            end
        end
    
        if deck == nil then
            print('Still no deck!')
        else
            deck.reset()
        end
        return 1;
    end

    If there's a better solution to this problem though I'd be very happy to hear it!

  3. #3
    There was a suggestion at one point to put a couple filler cards at the bottom of the deck. Basically 2 dummy cards which can even say something like "please reshuffle the deck". Then, in the onObjectDropped event you can check to see the deck count (getQuantity). If the deck contains only 2 cards, place a transparent, locked, object over the deck which will capture all mouse click and thus make it impossible to remove a card from the deck. Once more cards are added to the deck, the blocker object can be removed.

    I think you might be able to also do this with the interactable property. When the deck is down to the two dummy cards then set interactable to false. However, this may not work depending on how cards are re-added to the deck. If it is done through a script then the script can easily set the interactable back to true. However, if done manually the added cards, probably (I have not tried), will not merge with the deck because the deck is still not interactable.

    EDIT: The reason why you need 2 dummy object is that if you only have one when the second last card is drawn the deck only contains one card in which case the card is automatically removed from the deck container and the deck is destroyed. To avoid this a second dummy card need to be introduced. The downside of this is that the deck count will always be off by 2 objects.
    Last edited by LordAshes; 07-23-2016 at 07:51 AM. Reason: Added reason why 2 dummy cards are needed

  4. #4
    Similar to oxide246, I've used a rather messy workaround.

    Mine is probably worse than his.

    The short version:
    There's a script zone where every deck is. A draw/shuffle/whatever function will in the process always call a function I call checkDeck. This function determines whether the deck exists or if it is one lone card left, or none at all. Updates a global table that tracks this status for each deck. And returns the object back to the draw/shuffle/reset function that called as a variable "deck", which is then manipulated further by that function based on the status of the variables in the global table.

    In this way, the deck itself is never referenced by GUID, since the GUID will change everytime the deck runs out.

    The long version:


    A script zone exists where every deck is -- optionally you can spawn this script zone where this deck is during the onLoad and store it in a table so you don't have to update the script zone if you decide to move around the decks.

    When any function is doing something with the decks, it executes a checkDeck function.
    warning: this function is messy and needs to be cleaned up -- cobbled together from examples and my circumstances, could definitely be streamlined for your circumstance probably.

    Code:
    function checkDeck(zone, drawDeck)
    	--Checks card zones for deck status
    	local zoneObject = {}
    	local objects = {}
            zoneObject = zone
    	objects = zoneObject.getObjects()
    	local isDeck = false
    	local deck = nil
    	local deckPossible = {}
    	local oneCard = false
    	for index, object in pairs(objects) do
    		local type = object.tag
    		if string.find(type, 'Deck') then
    			deck = object
    			isDeck = true
    		elseif string.find(type, 'Card') then
    			deckLastCard = object
    			oneCard = true
    		end
    	end
    	if isDeck == true then
    		cardDeckTable[drawDeck].lastCard = false
    		return deck
    	elseif oneCard == true then
    		if drawDeck ~= nil then
    			cardDeckTable[drawDeck].lastCard = oneCard
    		end
    		deck = deckLastCard
    		return deck
    	else
    		return nil
    	end
    end

    this function is called using params: zone -- the script zone the deck is in and drawDeck -- a index in a global table "cardDeckTable" that has all information about each different deck (guids,lastCard status, position, where it gets drawn to, etc) as different keys.

    looks at the objects in the script zone

    if an object is a Deck, assigns the Deck object as the returned variable "deck", updates the global deck table that this deck is not in 'last card' status, so can still be drawn from.

    if the object is a card and there is no Deck type object in the zone, assigns the card as the "deck" variable, and updates the global deck table that the deck is in last card status.

    then finally it returns the variable "deck" back to the function that called this one. That other function will continue the process and either use takeObject() or setPosition() for the deck object based on whether lastCard status is true or false for that particular Deck according to the global cardDeckTable --- or if there's no cards left, will call into a resetDeck function that references any discard piles in the same way and shuffles, resets their position to create a new deck.


Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •