#Answering stupid questions

1 messages ยท Page 1 of 1 (latest)

alpine vapor
#

The api is frustrating to navigate, I'm doing very few tasks, I (thought I was) a strong programmer, and there's not really a lot I'll be scripting in tabletop for; I don't write in lua outside of it.

So reading the guides or watching the walkthroughs is just... huge mind numbing portions of stuff I don't need or already know until I finally hit that one critical piece of information I'm needing to continue.

Yesterday it was how to read error codes and seeing an example in action. Frickin. Took off like a rocket after that (thanks Chr1Z, btw).

So I know what I'm gonna ask is gonna sound basic or stupid- but what I'm doing will go a million times easier and faster if I can just ask a few stupid questions and get what may seem to be an obvious answer.

Because I've spent the last 4 hours trying and failing to get the fucking global script to spawn a scripted zone and failing- WITH the help of chatGPT and the api. I finally broke down and came here when I couldn't get it to summon a cube for debugging

sturdy shell
#

show what you've tried, we'll work from there

alpine vapor
#

Alright, we'll start at the easiest

    local position = { -34.848167, 1.771517, 46.017006 }  -- Position
    local size = { 1.4, 1, 1.4 }  -- Width, Height, Depth

    local zoneParams = {
        type = "zone",
        position = position,
        scale = size,
        color = {1, 1, 1, 0.5},  -- White with transparency
        isInteractive = false      -- Non-interactive
    }

    -- Creating the zone
    createZone(zoneParams)
end

function onLoad()
    createRectangleZone()  -- Call the function when the script loads
end ```

The error I'm getting is:

Error in Script (Global) function <onLoad>: chunk_4:(14,14-26): attempt to call a nil value
#

So I it seems to be wigging out on createZone. Dunno why.

sturdy shell
#

do you know what the error means?
do you know what the numbers mean?

alpine vapor
#

Yeah, line 14, 14-26. It's pulling nil. The problem is it defined what they were in the same block.

sturdy shell
#

let's be specific here

#

"It's pulling nil"
clarify what you said

alpine vapor
#

It's pulling a value that's undefined or purposefully defined as... well undefined.

#

Usually when you try and pull something that doesn't belong there, or is out of scope

sturdy shell
#

I don't really know what you mean by "pulling", and I certainly don't know what you mean by "it"

alpine vapor
#

er- sorry. The function argument in createZone- it checks zoneParams.
Colloquially, pulling the data

but the data it's receiving is defined as nil, meaning the data contained in zoneParams either doesn't belong/isn't what the argument is expecting (so it defaults to nil), is undefined, or was purposefully defined as nil- at least how I understand it.

but it looks pretty fine to me, and I had it checked over by the chatbot who also greenlit it.

sturdy shell
#

you're wrong, so i'll correct you

alpine vapor
#

Please do, man.

sturdy shell
#

attempt to call a nil value
means you are (effectively) doing this:

local someValueThatIsNil = nil -- or never defining it as a non-nil value
someValueThatIsNil()
#

you are attempting to call () a value that is nil

alpine vapor
#

wait....

sturdy shell
#

it would resolve to nil() which causes the error

alpine vapor
#

....so it's not the argument

#

it's createZone().

#

I was assuming that was built into tabletop- that's one of the things gpt recommended

sturdy shell
#

yes, as you are calling only once on that line, either the error message is wrong (which can happen in TTSLua), or createZone == nil

#

If you want my advice, take machine learned programs and avoid them

#

they don't know TTSLua because of the poor documentation and lack of usage that doesn't contain user-defined functions. Using code from it that isn't pure Lua will actively cause you problems

alpine vapor
#

Alright, well that makes perfect sense. So how should I be doing this?

sturdy shell
#

I'll take step back first before I waste an answer on a bad solution

#

What do you want to achieve?

#

no programming terms allowed, use sentences

alpine vapor
#

Well, right now I'm just trying to achieve a scripted zone at a specific place on a board, for a deck slot. Witha specific card size. The card game I'm working with has a couple different ones, so it's worth specifying.

sturdy shell
#

take a further step back - why?

alpine vapor
#

Once I got that down I was gonna practice bouncing cards around the zones-

sturdy shell
#

an example of an answer I'm looking for would be:
I have places on my table I want to place cards, but I also need to know whether a card is there so I don't place another when it is occupied

alpine vapor
#

Well originally I was scripting a score counter for a card game- which I did. It's... finished.

But with all the stuff I learned I figured I'd try a few more things- and if they go well I might be able to do some more complex stuff.

#

Ah, worded like that... well it's a deck slot.

#

It's just there for the deck to sit in. Ideally I'd like it to line itself up and sit straight. That's why the size matters.

#

Once I get the hang of tossing down scripted zones I can do other stuff though too, like having a scripted spot for a card to lay on

#

Bounce around cards between guids, so potentially pass cards with a button- that kind of thing.

#

I mean once I learn how to spawn in a scripted zone- with script, it'll be a breeze to simply, spawn the other ones for say a line up. Once I know how to pass cards- it's only a hop skip and a step away from automating a game really.

#

I already learned how to harvest and manipulate data yesterday. I just can't get the things to spawn for some reason

sturdy shell
#

normally I advise people to use what I call a "plinth". a scaled, locked, uninteractable (eventually) TTS cube

#

it has a rotaitonal snap point locally at 0,0,0, and is used to generate casts using Physics.cast() to find objects above it

#

you can do without the "plinth" but it makes it much easier to scale (this solution) to multiple plinths for those less experienced

alpine vapor
#

sounds like it's basically a card slot

#

Can you pass things to it via guid?

#

And is it any easier to spawn via scripting?

sturdy shell
#

these are very emergent questions

alpine vapor
#

Oh, sorry is... that a problem?

sturdy shell
#

no, it means slow down :)

#

can you pass things to it (again, what is it?) via guid (I can't answer without knowing what you mean by "it", you also don't things "via" guid, you do things "with" guids, they're just a string)

alpine vapor
#

You're a literal one. I respect that. I am... less so. Kinda talk loose. Bare with me if I'm unclear.

#

So what I'm asking is if I have a deck on one of these plinths, and I wanted to call a global function that moves a the top card of the deck on top of that plinth (referenced by guid), to another plinth (also referenced by guid)- can it be done?*

#

Honestly, though, I don't know man.

I've gotten pretty comfortable at getting things with guids to do what I want them to do, and referencing them.

I feel like if I can just figure out how to get a zone to spawn at a specified spot and size, it'd open a lot of doors.

sturdy shell
#

yup, can be done

#

that's for further information, and not necessary to answering your question

#

you could make, for example

takeCardFromDrawPileAndPlaceAbovePlintWithGUID("abc123") -- long name but describes what it does
#

or

takeCardAbovePlinth1AndPlaceAbovePlinth2("abc123", "def456")
#

functions only really exist to make things more convenient for the programmer/scripter

alpine vapor
#

Yeah that all makes sense. I mean the guid is done so that every object has a unique 'tag' so to speak. It makes sense that copies and stuff like that would need a new one if it's taken

sturdy shell
#

except that when a deck becomes a card the Object reference will break, and when cards become a deck again, the guid will be different

alpine vapor
#

Like if I wanted card all the copies of reference every copy of card A I'd just give em some data or a tag or something

sturdy shell
#

which is why you ideally want a method like I explained

alpine vapor
#

Yeah, that all totally makes sense.

#

guids are super dynamic. When I reference 3f3wrewe or whatever, I want to reference 1 specific instance of that card, or a specific deck, not every instance of it.

#

I am considering moving over to GM notes for identifying names of stuff... I feel like a player is gonna rename their card (by accident) and my name search engine's gonna get confused.

#

I am interested in the stuff for plinths though, I'm pretty sure I could do some cool stuff with that too

sturdy shell
#

at the point you're giving people your mod, they can break it if they want

#

it's just a question of how much (and you can't completely) you want to dissuade from that

alpine vapor
#

Yeah I kinda realized that 3am this morning when I was thinking lol.

sturdy shell
#

GM Notes is a nice compromise of easy to access via ui and hidden to players in most games

alpine vapor
#

That's what I was thinking, cuz the whole point of what I'm doing is for the public, so I don't care, but I don't want a misclick to break the score script either, ya know?

sturdy shell
#

if you want a fiend that isn't accessible by ui, without having to worry about updating the script state on save/load, you can use .memo

#

anyone who is sat in the Black seat has already "misclicked"

alpine vapor
#

(jotting that down in my notes)

#

.memo? is that built in? I mean I can just... assign it if not, but yeah?

sturdy shell
#

go look it up on the api and find no example ๐Ÿ˜‰

alpine vapor
#

Will do

#

Here, gimme like 2 minutes and I'll summarize real quick

sturdy shell
#

It's a string Object property that can be read/set the same as other properties, and is persistent (meaning it saves with the game state)

alpine vapor
#

So like- I used to program video games back in the day. Been a long time.

So it's really a battle with learning lua's quirks and remembering things.

Yesterday, Chr1Z taught me... well almost everything I need.

Most of what I know is applicable, and the Lua's honestly not a horrible language imo.

Here's what I have left to learn:
Stuff I need answers to:

Spawn a zone at a specified place, with a specified size from global script
despawn zones by guid from global script
move stuff between zones by referencing guid.
call global functions from within an objects code.

Stuff I'm pretty sure I've got, but might need help with:
giving click functionality to a card while it's in a zone, and only in a zone
Having a card go back to the zone it started in when the mouse was released.
having a function on an object that fires off when upon entering a zone.

If I can learn those like... 7 things I should be good to do some really interesting things.

I hesitate to say what, because I don't know how much I'm gonna feel like doing or have time to do (I take care of children), but I know if I can just learn those skills in addition to what I already know and learned yesterday- I should be able to do... pretty much whatever I want.

Google, the api, and GPT are pretty useful, but they're just... no match for just being able to ask a veteran how to do something. Especially when you get stuck. I... no joke have been trying to spawn a rectangle algorythmically all day.

#

Anything else is just surprise debugging

#

I'm also open to a guide if you know one that... has the meat and potatoes of what I'm looking for

sturdy shell
#

I do not, what you want is specific to what you want

alpine vapor
#

Well. That's comforting. At least it makes sense why I had trouble finding it.

sturdy shell
#

just solve each smallest thing one at a time

alpine vapor
#

Yeah I figured... spawning a rectangle... was the easiest.

sturdy shell
#

just "create a button" isn't even the smallest thing, that itself can be exploded out into smaller problems

alpine vapor
#

meh, figured that out yesterday

#

Once I had a prototype to work with, it wasn't horribly difficult to figure out how it worked.

sturdy shell
#

if you want the scripts in Global, then you want to look at Global and Universal events

alpine vapor
#

tbf, chr1z code is also very clean and well notated though.

sturdy shell
#

that's because they're writing it for you ๐Ÿ˜‰

#

onObjectEnterScriptingZone() onObjectLeaveScriptingZone() onObjectDrop() onObjectPickUp()

alpine vapor
#

Yoink, that solves that.

#

Well with those- and the ability to move things from zone to zone, that solves... literally all the maybes

#

Cuz I can just arm the "onClick" function on entering, and disarm it on leaving it

#

And. Send it back on object drop

sturdy shell
#

you'll want to create and remove it, as if a card is put into a deck and then re-enters you won't have something to "un-hide"

alpine vapor
#

That's a pretty crucial note

#

So calling global functions from within an objects code

#

Experience says that should be easy.

sturdy shell
#

don't do it that way if you want to remain sane

alpine vapor
#

Well... I kinda need to.

sturdy shell
#

no, you don't

#

you just don't know how to do it another way

alpine vapor
#

Well... I do though.

#

See I could just code the whole thing globally

sturdy shell
#

there's only one reason why you do, and even if you do you don't need to

#

and that reason is moot as soon as you started asking about Global functions to do the work for you

alpine vapor
#

and run it through one big 'brain' but that seems like it'll be non modular at best, and laggy at worst

#

But my plan (feel free to poke holes)

sturdy shell
#

i already have

alpine vapor
#

er... more holes

sturdy shell
#

hard to poke holes in a big hole but sure ๐Ÿ˜

alpine vapor
#

but the plan is have a list of basic functions defined globally, and have the card call them out in a certain order when it hits- say the board. That way I don't have to run every single card effect through one engine at once, it just pops off a couple commands- should really help with lag.

#

and I can still get some pretty neat automation.

#

That method is also very modular

#

as I add cards to the game, it'll allow me to do more complex effects with less code, and if I need a new effect I can define it globally and just call on it on multiple cards

#

It sounds like it'd be pretty easy... it's just calling on a function that's defined elsewhere right?

#

I thought about running the full effect through each card and nixing globally, but scope becomes a problem.

#

and I thought about running it all globally, but I figured lag would become an issue

#

.....although........

#

hm.

#

Why do I need to call the function from on the card in the first place...

#

If it's just a set of instructions I could just... assign a string or table containing the commands and their order and simply assign them to each card.

#

Then the functions would all be firing from global....

sturdy shell
#

no need to, see big hole above

alpine vapor
#

hm...

"and that reason is moot as soon as you started asking about Global functions to do the work for you"

I don't understand.

#

Is this the hole you mean?

sturdy shell
#

I'll explain shortly

alpine vapor
#

Not a problem.

sturdy shell
#

create your buttons in your Global script, but those buttons are made on objects
when the buttons on the objects are clicked, they run a function in Global
absolutely nothing is required on your objects with buttons other than a means of identification e.g. GM Notes

alpine vapor
#

Oh right, yeah that makes sense, but that's not quite how I was going to use them-

So- again- this is kind of rough because I wanted to get the hang of being able to spawn things before I went into smoothing it out (which is another reason I have been hesitant to talk on the subject- there's gonna be holes on the subject. I've been kind of trying to do things one piece at a time)

#

but the idea was to have a card just... well be a card.

#

but it would have scripts that activate when it enters certain zones. Those would just call the functions in the proper order- the reason they need to be global is because some of the functions will need to reach scope the cards won't be able to, but global will easily.

#

so once it enters the hand, the player will be able to pick it up and rearrange it as they please, but if they try to set it down outside the zone- it just warps back.

#

when the player has the ability to play cards, the zone it's able to go in will be 'greenlit' so to speak (I already know how I'll do all that), and so it'll be able to be passed to the appropriate zone (the play zone) where it's onenter() will fire off and it's effect will activate. It'll be like... when you play the card down, it'll just do the thing, only stopping to ask you input/tell you what to do next

#

the click feature was gonna be for cards on the line up. While on the line up, on click, it'll check if you can afford that card and if you can, it'll buy it and put it in your pile.

#

again the reason it needed to be global, was purely for scope. I would love to have it more centralized...

#

and the reason it was gonna be on the cards themselves is two fold.

#

One it's modular- like I said. but number 2 if a card is breaking things, it will enable me to troubleshoot only the card itself and it's functions

#

I won't have to search through the entire engine to troubleshoot

sturdy shell
#

having it in Global is modular, why do you think it isn't?

alpine vapor
#

So... say I ran everything through global, and I'm playing the card game, and something breaks when a card enters the field.

#

I'll have to dig through all that code to troubleshoot.

If the only functions that were run are all listed on the card, I have a much shorter list of culprits, and very likely easier to figure out... although talking about it now... if something breaks when I play a certain card I could still just ctrl+F... like I said, I haven't thought this all the way through, these are just things I was hoping to maybe, if I feel like it, accomplish later.

Right now I was just trying to figure out how to do the things, so I'd know what was and wasn't possible- and how hard it is to do each thing.

#

Honestly I already did what I had originally set out to do yesterday, I just wanted to script a scorer that could handle some pretty complex stuff.

#

So I gutted his tagger and have been updating it successfully since.

#

Which brings us back to the present... globally calling in a zone.

#

It shouldn't take all day to spawn a rectangle... how do I do this.

fast heart
sturdy shell
#

creating/spawning a zone?

alpine vapor
#

Yeah, the list of stuff I asked earlier- which you've answered... almost all of lol

fast heart
alpine vapor
#

I just need to know how to spawn a zone at a place I specify, with a size I specify

sturdy shell
#

personally, I spawn one manually, check .getData() and use that to spawnObjectData()

alpine vapor
#

Oh shit, yeah you're not the same guy

#

lol

sturdy shell
#

you can use .getJSON() and spawnObjectJSON() if you prefer

#

I avoid the method Eldin is recommending simply due to the lack of documentation for some objects on the api

alpine vapor
#

Jesus christ it's so easy... I knew it was something stupid.

sturdy shell
#

I don't even try any more, I go straight to a method that works.

fast heart
#

you almost had the parameters right in the first post in #scripting , but used GPT to suggest something that did not exist

alpine vapor
#

of course I did.

#

So I can use destroyobject to kill it, right?

sturdy shell
#

not quite (spelling), destroyObject() or .destruct()

fast heart
sturdy shell
#

oh it's efficient in filesize but not in my time ๐Ÿ˜…

fast heart
fast heart
alpine vapor
#

Fair, so let's see...

    local position = { -34.848167, 1.771517, 46.017006 }  -- Position
    local size = { 1.4, 1, 1.4 }  -- Width, Height, Depth

    local zoneParams = {
        type = "zone",
        position = position,
        scale = size,
        color = {1, 1, 1, 0.5},  -- White with transparency
        isInteractive = false      -- Non-interactive
    }

    -- Creating the zone
    spawnObject(zoneParams)
end

function onLoad()
    createRectangleZone()  -- Call the function when the script loads
end```

I tried running this and it says "Error in Script (Global) function <onLoad>: Object reference not set to an instance of an object"
sturdy shell
#

"type = "zone" is not correct check the api

fast heart
alpine vapor
#

Nah, was copy/pasted.

#

LayoutZone

alpine vapor
#

lemme try LayoutZone

fast heart
sturdy shell
#

hint: onObjectEnterScriptingZone()

alpine vapor
#

er no, I was just on the wrong api page. I was looking at types on the spawnObject

alpine vapor
#

...wait.

#

it's ScriptingTrigger

sturdy shell
#

type = "ScriptingTrigger" in your spawnObject() parameters

alpine vapor
#

it took all day for this.

#

alright... well at least it is straight forward.

#

While I have you, that just leaves one thing left to figure out.

#

lemme see if I can figure it out myself.

fast heart
#

with me (and as far as I know with Bone too) you will have to, because I'm not going to straight up tell you ๐Ÿ˜„

#

what is the "one thing"?

sturdy shell
#

we're more incentivised in helping you to help yourself, rather than just handing out answers

alpine vapor
#

Yeah I've been at it for several hours before posting here man... I prefaced that.

alpine vapor
sturdy shell
#

do you know how to turn a guid into an Object reference?

fast heart
#

I'm off for tonight, but good luck

fast heart
alpine vapor
#

just... a function

#

built in

#

I'm digging through the api now

#

but if you know of one... I'm ears.

sturdy shell
#

there is not, hence why I'm asking

#

as there isn't let's break down the problem into parts

alpine vapor
#

wait... seriously

#

... that's.

#

Seriously?

sturdy shell
#

why would there be?

alpine vapor
#

Well... for passing cards between peoples hands

sturdy shell
#

ok, but that's not what you're asking about, so don't confuse things ๐Ÿ˜‰

alpine vapor
#

aren't hands just zones?

sturdy shell
#

no, they're a special type of Zone known as a Hand Zone

#

all Hand Zones are Zones but not all Zones are Hand Zones

alpine vapor
#

Yeah, I mean... yeah? same logic as what's it called... layout zone innit?

#

Looks like takeObject is what I'm looking for

fast heart
sturdy shell
#

not necessarily

alpine vapor
#

Yeah the api?

#

Yeah I've been traversing it the last couple days.

#

Or do you mean that particular page?

sturdy shell
#

I'll summarise the steps you'll want to consider:

  1. get a reference to the scripting zone Object you want to search
  2. loop through all objects within the scripting zone to get the card or deck that you require
  3. repeat step 1) for your target scripting zone
  4. if 2. was a Deck, take a card out of the deck and use the referene to it in step 5
  5. use your card reference to set it sposition to the position of the scripting zone in 3.
#

for those of us experiencd in modding in TTS this is trivial

#

I don't expect you to consider it to be trivial, just solve each part in turn

alpine vapor
#

So you have to use positions?

#

You can't just use the reference id? (Guid if you will)

sturdy shell
#

correct

alpine vapor
#

I can't tell if you're messing with me.

sturdy shell
#

all a guid does is helps you identify a specific object

#

When someone is taking the time to help you and answer your questions, apply a modicum of faith

alpine vapor
#

Yeah, I suppose you're right.

sturdy shell
#

it feels like you have experience of other languages/implementations, in which case yes, a lot of them allow you to use a function and supply an identifier, rather than using the identifier to get the Object, and then running the function on that Object

#

there's arguments for and against each method, TTS uses the latter

#

so again I ask:

do you know how to turn a guid into an Object reference?

alpine vapor
#

No... I don't. Hm. Maybe this is why I was having trouble with collision

sturdy shell
#

it's the one function in TTS that causes the most problems for newcomers because guids are volatile and this is used in almost all examples

alpine vapor
#

wait I actually do

#

I remember this a while ago...

sturdy shell
#
someObject = getObjectFromGUID("abc123")
alpine vapor
#

getO- that yeah

#

It's so odd to me that noone once considered that function

sturdy shell
alpine vapor
#

I'll just write one myself to call on

sturdy shell
alpine vapor
#

eh it's not important, but I don't like referencing position often- I'm much better with the parts that run in the back than the actual... objects on the screen

#

I'll just write my own function with guid arguments and positions and shit to pass them around by id

#

that way I only have to worry about WHAT point A and Point B are, not WHERE they are.

sturdy shell
#

sure, that's exactly what functions are for

alpine vapor
#

So it's quick and dirty, but here's what I got

#
function transferFirstCard(sourceGUID, targetGUID)
    local sourceHand = getObjectFromGUID(sourceGUID)
    local targetHand = getObjectFromGUID(targetGUID)

    if sourceHand and targetHand then
        local cards = sourceHand.getObjects()
        
        if #cards > 0 then
            local firstCard = cards[1]
            
            firstCard.setPosition(targetHand.getPosition())
            firstCard.setRotation(targetHand.getRotation())
            targetHand.takeObject(firstCard)
        end
    end
end

transferFirstCard("b33e7e", "594448")

Upside? It runs without error.

#

Downside, it doesn't do the thing.

sturdy shell
#

why are you naming them hands?

alpine vapor
#

they are hands, I just tossed up 2 quick hands to test it on because they're easy to see.

sturdy shell
#

ok, you're doing a lot of things here you don't really understand

alpine vapor
#

the same logic should apply for other zones though, right?

#

just need to tweak it

sturdy shell
#
1) get a reference to the scripting zone Object you want to search
2) loop through all objects within the scripting zone to get the card or deck that you require
3) repeat step 1) for your target scripting zone
4) if 2. was a Deck, take a card out of the deck and use the referene to it in step 5
5) use your card reference to set it sposition to the position of the scripting zone in 3.

use this as a reference and worry about your custom function afterwards

alpine vapor
#

Yeah?

#

It was in a hurry though, I'm trying to figure this out before the kids get off school.

#

(hence no notations)

#

Honestly, I'm pretty bad about notations anyway

#

that's why I even use GPT for the most part. It answers dumb questions (usually) and helps me remember the crap I wrote.

#

yeah gimme a sec, I'm gonna try and tinker with bone's solution

fast heart
alpine vapor
#

Ahhh... I forgot onLoad.

#

Derp.

sturdy shell
#

how many of the five outlined steps do you think you've achieved?

alpine vapor
#

None, I just slapped onLoad on and tested it and it works as intended.

#

But this won't go to waste

#

the script I just wrote only works for singular stuff really- passing and drawing and stuff. I'm gonna need the steps you sent me when I start doing more complex shit with decks.

#

Thank you both for your help

alpine vapor
alpine vapor
#

I'm very grateful to both of you.

alpine vapor
fast heart
alpine vapor
#

Well there was nothing to actually call the function

fast heart
#

The function idea is not bad at all, but it really helps to pause along the steps a bit

alpine vapor
#

I left the function call out because I was stressing cuz I have to go in like 3 minutes and wanted to solve it

sturdy shell
#

let's re-visit this when you have more time

#

feel free to @ me if this thread isn't dead

alpine vapor
#

Oh thank you, I appreciate that ^ ^. I definitely will. but seriously, I'm... really rushed AND my patience is thin from... honestly not coming here in the first place (lesson learned)

#

but you guys have been very helpful and my notes are loaded with gems.

#

See you next time.

alpine vapor
#

@sturdy shell Hey I've more time to talk today. Sorry if I was short last time.

#

I also fully read instead of skimming the guid guide you sent, including the second optional page.

#

Honestly, I don't think it applies to the project I have in mind- I'm only tracking things by guid while they're in certain places, and I'll be stop tracking them when they leave said place- there's never a time when I'll be referencing an object by a specific guid (I have been in testing, but that's because I'm testing the functions).

#

I also think I'm gonna go ahead and run my plans start to finish as it seems like everything I was hoping I could do, lua and tabletop support, and honestly apart from getting hung up on something silly now and then, dev is actually going very smoothly.

#

So if you're still interested, I can write up a full plan for what I'm wanting to accomplish.

sturdy shell
#

getting a reference to an Object by checking a Zone is one of the much more reliable ways than getting an Object reference directly via GUID
it was more for your education and explaining why and when GUIDs are volatile, rather than a direct "this is important for you use case"

alpine vapor
#

Yeah basically if I Can handle it dynamically, I'm gonna.

sturdy shell
#

you can write a plan, I should be able to tell if it's possible or not. just bear in mind that TTS has lots of nuances and a lot of the answers may be "yes but with compromises" or "kind of"

alpine vapor
#

so far everything seems real doable- but your warning against running global functions from objects had me rethinking a lot of things.

sturdy shell
#

let me be very specific here

#

I am not warning you against running Global (note the upper-case G) functions from objects

#

I am saying that it makes more sense (unless a very specific use-case of being able to have a sandalone object that is dragged into other mods ad-hoc) I believe it makes more sense to create buttons from Global (on objects), and have those buttons call functions in Global's script when clicked; as opposed to having any scripting on the objects in question

#

Global is a Unity gameobject which is only used (as far as scripting is concerned) for its script
global is the top-most scope type in a script

alpine vapor
#

Ah... I see.

#

I thought it being in caps was just a lua thing.

#

hm.... I was hoping to use the top-most scope type

#

but I've actually redesigned things in- what I think- is a simpler way

#

I was actually looking forward to your input on this

sturdy shell
#

Global makes the buttons
Global receives the click function calls
ezpz

alpine vapor
#

I was reading assigning buttons to an object, from not within said object is a pain in the ass

sturdy shell
#
-- in Global
function onLoad()
  local myObj = getObjectFromGUID("abc123")
  myObj.createButon({
    function_owner = Global,
    click_function = "myClickFunc",
    -- other params here
  })
end

function myClickFunc(obj, playerColor, altClick)
  log(playerColor) -- works!
end

that's the basic idea. Nothing in myObj's script at all

alpine vapor
#

really I only need 2 things on these friggin cards, a button to click that sends a signal to global, and a toggle for the button that global can switch on and off.

sturdy shell
#

ok so let's pair this up with another idea you would've seen in the guides you read before

alpine vapor
#

sigh I need to spend less time on google and the api and more time here.

#

or Global. whichever. Whatever it is I'm running the main script from

sturdy shell
#
function onLoad()
  for _,obj in ipairs(getObjects()) do
     onObjectSpawn(obj) -- objects loaded before scripts run will not call this _unless_ you run this code here
  end
end

function onObjectSpawn(obj)
  if someCondition then -- to know whether obj needs a button or not e.g. it has a certain tag e.g. if obj.hasTag("button") then
    createMyButton(obj)
  end
end

function createMyButton(obj)
  obj.clearButtons() -- removes all buttons from the obj to avoid duplicates
  obj.createButon({
    function_owner = Global,
    click_function = "myClickFunc",
    -- other params here
  })
end

function myClickFunc(obj, playerColor, altClick)
  log(playerColor) -- works!
end

-- and finally you want a way of hiding your button, so we can do this two ways:
-- this code belongs in another function somewhere but that requires a greater conversation
  obj.editButton({
    index = 0, -- editButton is 0-indexed (first button is at index == 0)
    scale = {0,0,0}, -- the button remains, and can be edited in future, but as it now has no scale it cannot be seen or clicked
  })
-- or
  obj.clearButtons()
  -- and then re-make when you want the buttons to work again using createMyButton() above
alpine vapor
#

it can handle the bulk

sturdy shell
#

the above is a good template to start from

#

buttons and xml in TTS isn't very efficient (what is?) so if you are dealing with hundreds of buttons I recommend removing them rather than setting their scale to 0,0,0

alpine vapor
#

I was actually just thinking of disabling it through a function

#

I also have a question about that template- Say a player gets lazy and copy/pastes a card during setup, will it still have the scripting passed to it?

#

Like will the copies have the button global gave it, on them?

sturdy shell
#
myButtonsDisabled = false
function myClickFunc(obj, playerColor, altClick)
  if myButtonsDisabled then return end
  log(playerColor) -- works!
end

you can use a Global var for this

sturdy shell
alpine vapor
#

Yes, this is exactly what I was thinking! Yeah I didn't think it would... hm.

sturdy shell
#

you can use obj.getButtons() and loop through that, but I find it much easier to do this in my own table

#

you cannot store extra information in the above, and while it is stateless (a programming concept) I polytheize a different method.

alpine vapor
#

I find it odd I understood stateless, but not prolythesise.

#

or polytheize for that matter lol

#

Alright, what you have in mind?

sturdy shell
#

basically "preach religiously"

#

#scripting message
this adds all your button parameters to a table, then loops through that table to create the buttons. it programmatically handles the names of your functions and allows you to pass the table that created the button back into the click itself (which is where the power is)

alpine vapor
#

Actually wait- so if I- inbound

#

Alright copied that, will look it over in a second-

#

but wait, if you copy paste an object that has scripting it typically keeps it

sturdy shell
#

yes

alpine vapor
#

If I just put a uniform " button definition- on click toggle variable in global/Global" and "toggle button functionality" functions on every card- so that none of them have any differences- what kind of issues can I expect?

sturdy shell
#

updating your code later and filesize

#

100 buttons with 100 duplicate scripts with the same error means 100 edits

alpine vapor
#

Ah ha. So it'll be harder to debug

sturdy shell
#

or, you can use require() to modularly import .lua or .ttslua files on your PC into your script en-masse

sturdy shell
#

as for the second issue filesize, require() can't fix that

#

as in the save file that required file has been expanded out and will be literal duplucaes

alpine vapor
#

Yeah I thought I could duck it by making the code idiotproof and uniform

sturdy shell
#

I've seen mods over 100MB because scripts are duplicated on objects for no reason other than creator's lack of experience/knowledge

alpine vapor
#

hm.... filesize bloat does concern me.

#

Alright, I kinda wanted to do it dynamically anyway.

#

Let's see... wait I know what to do

#

I can assign the button functionality on the zone it's expected in....

#

That way it doesn't have to load in at all.

#

If I did it that way, I could use your recommendation of just killing the button altogether, rather than toggling it, too.

#

Should be less data to worry about sifting through, too.

sturdy shell
#

I don't get what you're saying:

I can assign the button functionality on the zone it's expected in....

alpine vapor
#

So the scripting applying the buttons to the stuff is the same scripting handling the 'onenterzone' commands. I could assign the button functionality to the cards as they enter the zones that expect them to have it.

#

Then just get rid of them when they leave it.

sturdy shell
#

ok, so the "trigger" to create/remove the buttons is "zone related"

#

nothing is going "on" the zone itself

#

still put everything in Global

#

onObjectEnterScriptingZone() onObjectLeaveScriptingZone()

#

just bear in mind this will not run for objects in the scripting zone when scripts are loaded as it is neither entering nor leaving but already there

#

so you'll have to handle that in onLoad() again another simple yet effective solution

alpine vapor
#

Yeah. I'm running almost everything through it, so I can minimize scope issues- I thought I would need to slap some stuff on the cards themselves, but after talking it through with you the last couple days I now realize I don't need anything on them.

sturdy shell
#
function onLoad()
  for _,obj in ipairs(getObjects()) do
     onObjectSpawn(obj) -- objects loaded before scripts run will not call this _unless_ you run this code here
    for _,zone in ipairs(obj.getZones()) do
      if zone.type == "Scripting" then
        onObjectEnterScriptingZone(zone, obj)
      end
    end
  end
end
alpine vapor
#

Oh man that is some gold.

#

I would have not thought of that contingency.

sturdy shell
#

this is the same reasoning as the comment above, scripts run only after all objects are loaded

#

the guide you read before this covers this in more detail

alpine vapor
#

Wait- yeah that does ring a bell

#

when you were explaining the load in function

#

Okay, so I've taken note of all this- when it's time to dick with buttons I'll look over your code examples and see if I can't kajigger it to get it working

#

at the moment though, I've got the hang of spawning in zones and getting them the size and shape I want, and I was playing with the onEnterScriptingZone functionality.

#

and I've got a script working as intended- but it's throwing an error. I checked the api, and it looks like I'm using the correct syntax.

sturdy shell
#

post it up then, my replies will be fragmented as I'm making foods

alpine vapor
#

No problem, hoss.

wait(2, function() cooldownTimers[object.getGUID()] = nil end)

#

That's not the whole script, but it's what's throwing the error

#

Error in Script (Global) function <onObjectEnterScriptingZone>: chunk_4:(51, 12-70): attempt to call a nil value <2>

#

So I know attempt to 'call' a nil value means a function it's running is nil- but it isn't. In fact it's working fine, it does what I'm telling it to, the script doesn't break, it's still reusable.

#

Another interesting thing, is it only throws the error when it triggers- it loads up fine.

sturdy shell
#

means a function it's running is nil- but it isn't
prove it, both to me and to yourself

alpine vapor
#

hm... wait I have an update.

#

it is reusable- just not to the same card I put in it

#

so that means it is attempting to pause the effect of the guid- but the script IS breaking, as instead of putting it on a cooldown, it's ineligble to be run on agian.

sturdy shell
#

I'm going to warn you now this is a really good method to stop me helping you

alpine vapor
#

so it's stopping- wait what?

sturdy shell
alpine vapor
#

Oh sorry I was trying to close in on where the function was wrong- I didn't mean to do that.

sturdy shell
#

I would call you a "flitterling", someone who flitters from place to place in quick succession without pausing, and not only is it (already) causing you problems, it's going to frustrate anyone who is trying to help you

alpine vapor
#

Uhh... sorry. Well... I checked the api, and my code looks very similar- I mean obviously it's not going to match the example text exactly but yeah

#

So that tells me something's wrong with the syntax... I've typed something wrong in this function

sturdy shell
#

none of that is proving what you said

alpine vapor
#

that's where the testing came in- See, it does in fact stop it from doing what I'm trying to pause it from doing, so I thought it was running fine, so the function can't be nil

sturdy shell
#

I'll assume you don't know how to prove it at this point, so I'll show you

alpine vapor
#

uh... I guess not.

sturdy shell
#
  log(type(wait)) --> should be nil, considering the error
  wait(2, function() cooldownTimers[object.getGUID()] = nil end) 
alpine vapor
#

Oh you wanted me to run a log to ensure it wasn't- ah.

#

Sorry, I didn't think of that.

sturdy shell
#

I wanted you to prove to the both of us that what you said is true:

means a function it's running is nil- but it isn't

#

I'll believe an error over you ๐Ÿ˜‰

#

(and you should believe errors over your own assumptions too)

alpine vapor
#

I mean- yes. clearly, hence why I didn't just call it a day and accept that it's throwing one- I just couldn't figure out where the error in the function was... what was causing it throw nil... or how it was working if it was nil.

#

but that's when I noticed that the function doesn't toggle it off- it toggles it on after it's done, so I did that test

#

Which would explain how it's 'working' but throwing nil- it's not... actually working.

sturdy shell
#

flitter flitter flitter...
what's the output of the log?

alpine vapor
#

attempt to call a nil value, and it's between 21 and 70

sturdy shell
#

... and the output of the log?

alpine vapor
#

Ah, right, I forgot to run that

sturdy shell
#

๐Ÿ˜‘

alpine vapor
#

Hm... it's coming back 'true'

sturdy shell
#

ok, so that means it isn't a function

#

which means you need to fix that, why isn't wait a function?

#

the error might've been wrong (or you're reading the wrong part of the log, i am unsure of this), but now you have proven that wait is not a function

#

there is no point worrying about anything else you were flittering to until you solve this

alpine vapor
#

Okay. It's not a function.

And the changing that log to the "Wait" with a cap returns true too. Which means it is also not a function.

#

So that brings me back to the page where it shows it's a class.