I'm a little late to this but I really enjoy Lua and noticed that at ~17:11 in your video there is a syntax error. TTS didn't throw an error, maybe because onChat() hadn't been called yet. The conditional not operator is ~= where as in your video you employ != which is used basically by every other language. Kinda like how Lua indexs start at 1 and not at 0. Great series btw.. I've wanted to get TTS for a while now but haven't pulled the trigger until... "I can script my games in Lua!! :O " -- thx for readin'
@LudoLodge3 жыл бұрын
You're right! I guess it didn't break this example, but I'll have to remember that in the future since 99% of my programming isn't in Lua haha.
@petrvavrinec94812 жыл бұрын
@@LudoLodge But in Python, how I am thinking and observe :-)
@MandyFilet3 жыл бұрын
Helpful tutorial, great work! :) Quick tip for anyone reading this: it's good practice to store the deck in a variable when checking if it's nil, so that if it in fact isn't nil, you can then call that variable for your game logic, rather than having to call getDeck again. :)
@Wisdomseyes14 жыл бұрын
Yay another scripting tutorial. I was worried these were over. These have been by far the most useful tutorials for me to figure out scripting in TTS
@edwardowen86682 жыл бұрын
Another great one. The one thing I’m looking for and have not been able to find is scripting to gather all the cards together and put them back in the deck for another hand. I have a scripting zone on top of my deck so all of my cards are tagged the moment the game starts. If you have a video that shows this or are inclined to make one, that would be completely awesome. It seems like it’s the last missing piece of the puzzle. Great job as always, thank you for your great videos.
@jazzthepirate Жыл бұрын
I need this too!
@BadgerRobot4 жыл бұрын
Excellent topic... I literally spent days trying to figure this out when I ran into it the first time.
@GrandElemental4 жыл бұрын
Yeah me too! Coming from C languages background, I originally expected to be able to create an empty deck container and the utilize that to store cards, but that is clearly not how any of this works. I am aware of the solution (or rather, a workaround), but it's good to get the confirmation that it is a valid one and I'm not missing an obvious better solution!
@aaro12682 жыл бұрын
Love that there's someone providing excellent scripting tips for TTS. It's... not an ideal platform, but it's one of the best we've got for boardgaming. Glad to hear some sage tips!
@kaitlynmadymy75564 жыл бұрын
Hi there! I literally just got into scripting so my knowledge base is very limited. I followed the video on how to make this function, but I'm not sure how to integrate it into other object's functions (i.e. the refill cards button function example in a previous video in the series). How exactly do I end up replacing using the deck GUID with using the deck zone GUID and associated getDeck function we just added in this video. Thank you again for all the time you put into this because it has helped me out sooo much!
@LudoLodge4 жыл бұрын
Great question! I haven't really talked about how to call functions from other scripts (e.g. calling "getDeck()" from the button's Lua script). I think what you want, is instead of having the button find the deck by GUID like this: "deck = getObjectFromGUID(DECK_GUID)" You can do it like this: "deck = Global.call("getDeck")" "Global.call()" should allow you to call functions in the Global Lua file from the Lua files for other components. Let me know if that doesn't work for you or if you have any other questions!
@kaitlynmadymy75564 жыл бұрын
@@LudoLodge I tried it out and I got it to work using the "deck = Global.call("getDeck")" within the refillCards() function rather than the onLoad() function. But, I seem to have run into another problem that I've been trying to find the solution to. In the refillCards() function, there is the line "deck.takeObject({flip=true, position=zone.getPosition()}) and I believe that is only allowing a card to be flipped and moved if the object is a deck and not a single remaining card. Is there a way to fix this? Thank you again for taking the time to reply!!!
@LudoLodge4 жыл бұрын
Ah that is unfortunate that cards don't have the takeObject() function! You would probably need to check if the tag is a "Deck" or a "Card", and then call either takeObject() or something like setPositionSmooth() to handle each case. You could get fancy and define a dealCard() function that handles that Deck/Card logic, and then just use the function anywhere that you need it. I wonder if you were running into a race condition with onLoad() where certain things weren't ready yet for getDeck() to work? Hard to say for sure, but you are right that you can just call getDeck() inside of whatever functions need it. Let me know if that doesn't help!
@ProfessorAnthrax3 жыл бұрын
Thanks so much for all of your help Ryan! I am brand new to scripting but with your guides I have been able to get a pretty decent first mod up and running with a lot of QOL scripting enhancements. Your comment here about cards not having the takeObject function was the key to figuring out the issue of dealing the last card to a scripted zone, as per Kaitlyn's example above. I had to use setPositionSmooth as per your suggestion Ryan, but since I needed the card flipped I also had to use setRotationSmooth as well. I used -180 on the y axis as I prefer the direction it flips in my mod, but setting it to 180 would work the same - just flipping the opposite way. Also, I've changed the .tag checks from this video's examples to .type, as .tag has been deprecated as per an update in January (.tag will still work apparently, but TTS recommends using .type instead on new code). It's been a while so hopefully you've found the answers you needed Kaitlyn, but for you or anyone else who runs into this issue and needs an example to help them here is the code that worked for me: function replenish() if dw_deck_exists() and dw_deck().type == 'Deck' then for _, zone in ipairs(card_zones) do if #zone.getObjects() == 0 then dw_deck().takeObject({flip = true, position = zone.getPosition()}) end end elseif dw_deck_exists() and dw_deck().type == 'Card' then for _, zone in ipairs(card_zones) do if #zone.getObjects() == 0 then dw_deck().setRotationSmooth({x=0, y=-180, z=0}) dw_deck().setPositionSmooth(zone.getPosition()) end end else broadcastToAll("Please place the Deck in the green zone", {0, (255/255), 0}) return end end
@jon.p4 жыл бұрын
Definitivamente sos el héroe del 2020. Muchas gracias!
@naveedfarbakhsh8453 Жыл бұрын
I hope you make more Tabletop Simulator videos.
@FightAgainstBoredom3 жыл бұрын
Man you are literally my hero
@ralphking1174 жыл бұрын
Just ran into this problem and this helped to solve it, so thanks!
@ralphking1174 жыл бұрын
Just to add... I only got Tabletop Simulator 2 days ago. Yes, I have programming experience (but not with Lua) and yes I have developed my card game using other software (mainly to have them printed) so my assets were pretty much in place, but in a short time after following these tutorials I almost have a playable game. The set up involved a deck of 126 cards in 7 colours (suits). 6 suits had to be individually shuffled and 5 cards each dealt into a subdeck. That subdeck then had to be shuffled and all 30 cards dealt to a pattern on the table to form the outer limit of the playing space (all orientated the correct way and snapped into place. Then all the remaining cards had to be combined into a master desk and shuffled and then 6 cards given to each player. I took a lot of thought, patience, experimentation and some adapting of the code given here (and to be honest from another source ). As the game is played over 2 rounds and the outer ring of cards remain in place for both, I was pleasantly surprised that when I clicked on reset deck, and outer ring of cards stayed put and all the rest came back into the deck ... just lucky I'd guess. So a big thank you for making this easier than I originally thought.
@dalebob3714 Жыл бұрын
How to use this with a button rather than the Chat option? I tried using your button tute with this tute and the button function call just doesn't work for me. Thank you for the great vids and hope to see some up to date vids on scripting in Lua.
@holm763 жыл бұрын
Hi Ludo Lodge. Nice video series. Based on your videos I've been able to get some work done on a Pandemic helper component but have run into a little problem. So quick question. I've created card stacks containing city and epidemic cards. I know the position of these decks but I have not created scripting zones for them. The decks were created by placing city and epidemic cards on locations in a loop. That is how I know their position. Would it be possible to get a reference to those decks without creating scripting zones? I need to shuffle the decks and then add them to one giant deck afterwards.
@PhoutianPhill Жыл бұрын
do you have a video on how to search a large deck for a specific card by name? I'm playing SW: Outer Rim and want a box to type in the number of the token i need then the card pops up. and if there are multiple of a number (ex #90 for setup) it randomly selects one of them to give to me.
@nelz0r5124 жыл бұрын
Thank you so much. Your lessons are very helpful. Thanks a lot👍
@mololkins Жыл бұрын
Please tell me how to pull an object out of the bag by GUID, through a script
@nelz0r5124 жыл бұрын
Also, could you help please with player scriptings and discard script. For example, how to deal only to a clicking player, to broadcast to all about the certain player clicking the button and etc.
@LudoLodge4 жыл бұрын
Good ideas! Added to my list of potential videos. 👍🏻
@legowelt08094 жыл бұрын
Hey, great tutorials, im really just starting out but your videos are helping me a lot. With this new empty deck scripting (and no knowledge of programming on my side) im struggling to add this feature with the other card setup/autorefill/drafting scripts. Could you add this simple getDeck() function to the other scripts? Or atleast 1, so I know how it to combine this feature? Would i have to copy each function or can i use something like call()? Thanks and keep up the good work!
@LudoLodge4 жыл бұрын
Hey, glad you've found them helpful so far! You are right that the call() function is what you want. For example, you might reference the deck in another script with something like: deck = Global.call("getDeck"). If you look down in these comments, I answered a few related questions from Kaitlyn M Adymy that may help as well.
@urdaanglospey66663 жыл бұрын
Is there a way to conveniently put a card (facedown) under the deck from a specified location/scripting zone?
@LudoLodge3 жыл бұрын
From what I can tell, the easiest way might be to change the deck's position to be slightly lifted off the table, and then move the card to the deck's old position. It will then drop and merge together. A little hacky, but it sounds like that is the conclusion others came to here: www.reddit.com/r/tabletopsimulator/comments/9uhj86/scripting_is_there_a_way_to_putobject_on_the/
@urdaanglospey66663 жыл бұрын
@@LudoLodge That's a great solution! Thank you!
@Nucleomancer4 жыл бұрын
Hi Ryan, I am mucking about with your examples and I am running into an annoying problem. (A little bit off topic, but maybe of use to others as well.) I have added some functions to one of my dice. (I'm making it tell me if it is still rolling and which face came up.) However, my own functions can only be accessed when I put them in the Global script. When I add the function to the die script. My Global code says: "cannot access field of userdata..." What am I doing wrong? Is this not the "proper" way to combine my functions. I also gave a pawn some custom functions which cannot be called from outside the pawn either so I guess I'm missing something. So my core question is: How can I let one custom script activate custom functionality from another object? Kind regards!
@LudoLodge4 жыл бұрын
I think you are looking for the call() method! Some info on it at these links: api.tabletopsimulator.com/object/#call www.reddit.com/r/tabletopsimulator/comments/5l7z6e/coding_question_calling_a_function_from_an_object/
@Nucleomancer4 жыл бұрын
@@LudoLodge That! Would not have been obvious to me. Thanks very much! I got my game working this way.
@jamesvogt53394 жыл бұрын
These videos are great and have been very helpful! Can you do something on how I can "share" my entire custom game? I want to let a friend use it in his play-test group without myself needing to host it. Maybe this isn't even possible. Maybe I'm missing something. Maybe you can help. Thanks for the great content!
@LudoLodge4 жыл бұрын
Hey James, it is very possible by uploading your game as a mod to the Steam workshop! I haven't talked about it in my videos yet, but you can find some details here: kb.tabletopsimulator.com/custom-content/steam-workshop/
@nelz0r5124 жыл бұрын
What to do if there are 2 decks? How to name them?
@LudoLodge4 жыл бұрын
The main thing is you would just have a different scripting zone for each, each with their own GUID. And instead of getDeck() you could have getDeck1() and getDeck2(), for example.
@nelz0r5124 жыл бұрын
@@LudoLodge, okay, thank you!
@paullumsden60933 жыл бұрын
Hi guys, Here is my code. The last card still won't move. Not sure where I'm going wrong. -------- Initialize Parameter --------- button_offset_y = 0 -- Set number. Value greater than or equal to 0. Defaults to 0.10. button_width = 1100 -- Set number. Defaults to 450. button_height = 10 -- Set number. Defaults to 300. button_color = {0.25, 0.25, 0.25} -- Set number {Red,Green,Blue}. Value bitween 0.00 to 1.00. Defaults to {1.00,1.00,1.00] ("White"). text_color = {1.00, 1.00, 1.00} -- Set number {Red,Green,Blue}. Value bitween 0.00 to 1.00. Defaults to {0.25,0.25,0.25] ("Black"). text_size = 80 -- Set number. Defaults to 100. DECK_ZONE_GUID = 'dc0a80' function onLoad() self.createButton({ label="Refresh Discard", click_function="setupCards", function_owner=self, position={0,2,0}, color=button_color, font_color=text_color, height=button_height, width=button_width, font_size=text_size, rotation={0,0,0} }) deckZone = getObjectFromGUID(DECK_ZONE_GUID) end function getDeck() local zoneObjects = deckZone.getObjects() for _, item in ipairs(zoneObjects) do if item.tag == 'Deck' then return item end end for _, item in ipairs(zoneObjects) do if item.tag == 'Card' then return item end end return nil end function setupCards() getDeck().takeObject({ position = {4.50, 1.67, -0.94}}) end
@LudoLodge3 жыл бұрын
Hard to say without more info on what happens when you test it... but maybe try adding something like "print("TEST")" inside of the "item.tag == 'Card'" conditional. That would help you determine if it is ever making it inside that check that would return the single card (you would see "TEST" printed in the chat). In general, adding print statements to specific sections of your code is a great way to narrow down what is actually happening and give you clues on where to look for an error.