Skip to main content

On Sale: GamesAssetsToolsTabletopComics
Indie game storeFree gamesFun gamesHorror games
Game developmentAssetsComics
SalesBundles
Jobs
TagsGame Engines

how to have interaction between cards

A topic by EHowe356 created Mar 06, 2023 Views: 667 Replies: 3
Viewing posts 1 to 4
(+2)

I am making a text based adventure game, for it to work I require a way to have an inventory. I want to be able to click a button on one card and have it update the grid on another card. How do I do that?

Developer(+5)

That's a great question! There are several ways to tackle this, so let's go through it step by step.

To begin with, let's say we have a card with a normal button "chester" and a checkbox "frobnicate":


If we wanted clicking on chester to toggle frobnicate, we'd write a script for him like so:

on click do
 frobnicate.value:!frobnicate.value
end

We're able to write code like this because, from the perspective of a script on a widget, all the widgets on the same card are available in Lil variables corresponding to their name; in this case "frobnicate".

The same is true of cards: every card in the deck is available in a variable corresponding to its name. If the card we're on is named "home", we could also write the above script like this:

on click do
 home.widgets.frobnicate.value:!home.widgets.frobnicate.value
end

Or, to be a bit less repetitive,

on click do
 f:home.widgets.frobnicate
 f.value:!f.value
end

The above script will now work even if "chester" is on a different card from "frobnicate" entirely: what matters is that "frobnicate" is a widget on the card named "home". If we wanted to be really explicit, we could look up the card in "deck" (another "magic variable"), and then look up the widget in that card:

on click do
 f:deck.cards.home.widgets.frobnicate
 f.value:!f.value
end

Side track on naming: All the names of cards and widgets we've seen so far are also valid variable names in Lil: all one word with no spaces, composed of letters, digits, and underscores, and they don't start with a digit. If names aren't valid Lil variable names, like if our card was named "My Fantastic Card", we would have to use bracket-indexing with a string into deck.cards any time we wanted to reference it:

on click do
 f:deck.cards["My Fantastic Card"].widgets.frobnicate
 f.value:!f.value
end

Prefer Lil-compatible names for things you expect to interact with in scripts!

We now know how to reference widgets on a distant card, so we have the building blocks necessary for an inventory system. For a simple game that only has a handful of possible inventory items, it might be easiest to represent each possible item with an individual widget on an "inventory" card. Perhaps they're locked checkbox widgets, toggled with the .value attribute as in our previous examples, or perhaps they're canvas widgets with a default .show property of "none" that appear when you've picked up the item:

inventory.widgets.sworde.show:"solid"
alert["ye have acquired ye sworde!"]
...
if inventory.widgets.sworde.show="solid"
 alert["ye slaye yon wickede beaste withe ye sworde!"]
 alert["forsooth, ye sworde is all gross and sticky, so we shall discarde it."]
 inventory.widgets.sworde.show:"none"
 go["slayed beaste"]
else
 alert["alas, without ye sworde, yon wickede beaste hast devoured thou!"]
 go["game over"]
end

If you have a lot of items, using a grid might be desirable instead. Let's say the grid on our inventory card is named "items" and it initially contains an empty table with a single column, "name":


Now we'll need to manipulate the table inside our grid to pick up items or test for their presence. Our script above might now look something like:

i:inventory.widgets.items
i.value:insert name:"sworde" into i.value
alert["ye have acquired ye sworde!"]
...
i:inventory.widgets.items
if "sworde" in i.value.name
 alert["ye slaye yon wickede beaste withe ye sworde!"]
 alert["forsooth, ye sworde is all gross and sticky, so we shall discarde it."]
 i.value:select where !name="sworde" from i.value
 go["slayed beaste"]
else
 alert["alas, without ye sworde, yon wickede beaste hast devoured thou!"]
 go["game over"]
end

If we're manipulating an inventory frequently throughout our deck, it might be a good idea to factor some of this logic out into "Deck-level" functions. Functions you define in a Deck script can be called from any other script. While we're at it, we can define a function for resetting the game to its initial state. You can set Deck scripts via "File -> Properties... -> Script...":

on get_items do
 inventory.widgets.items
end
on add_item n do
 i:get_items[]
 i.value:insert name:n into i.value
end
on remove_item n do
 i:get_items[]
 i.value:select where !name=n from i.value
end
on has_item n do
 n in get_items[].value.name
end
on reset_game do
 i:get_items[]
 i.value:0 take i.value
end

With these new utility functions we could rewrite our game scripts once again to be more concise and easier to understand:

add_item["sworde"]
alert["ye have acquired ye sworde!"]
...
if has_item["sworde"]
 alert["ye slaye yon wickede beaste withe ye sworde!"]
 alert["forsooth, ye sworde is all gross and sticky, so we shall discarde it."]
 remove_item["sworde"]
 go["slayed beaste"]
else
 alert["alas, without ye sworde, yon wickede beaste hast devoured thou!"]
 go["game over"]
end

And we can also test and manipulate the inventory using these functions in the Listener:


Does that point you in the right direction?

(+3)(-1)

Well, it's "...yon wickede beaste hast devoured THEE!", but only a fool would point out such a nerdy and pedantic mistake. Other than that, thanks for the inventory code snippets!

(+3)

yes this was extremely helpful thank you so much