Accessing gameobject or datamap entry based on variable

Please specify version and format if asking for help, or apply optional tags above:
Twine Version: 2.3.9
Story Format: Sugarcube 2.31.11

Hi, I’m having a little bit of trouble converting some scripting from Harlowe to Sugarcube. Essentially, I had it set up so that I had hover text, with the contents of that being pulled from a datamap based on a variable. So essentially in the text:

The green (set: $lore to "moss")(display: "lore") carpets

Which would call to a passage where something like this was set up:

(set: $_lore to (dm:
"moss",
"You've not seen anything like it before. Nothing in the guide matches it."
))

(set: $_description to $_lore's $lore)

(print:'<span class="lore" lore="'+$_description+'")>'+$lore+'</span>')

I’ve managed to replicate it in Sugarcube for the most part. In the passage it’s this:

<<set $lore to "power">><<display "lore">>

And in the lore passage it looks like this:

<<set $_lore to {
	"power": "hello",
	"mobility": "trust"
	}>>
<<set $_description to $_lore.$lore>>
<<print '<span class="lore" lore="'+$_description+'">'+$lore+'</span>'>>

However, I can’t get the $_description to set at all. Essentially, I’m trying to set it based on a variable and that obviously works in Harlowe but not here. I’ve tried a few different ways of expressing it, but to no success.

This isn’t the only place where I’d like to be able to do a similar function. At the minute I’m getting around that with a load of if statements, essentially I’m trying to search a game object based off of a variable - using that to find the right entry based on its string and then pulling out its associated data.

Is this possible? Is there another way around it?

Try <<set $_description to $_lore[$lore]>>

Square brackets are the most general-purpose way to get an element of an an object or array, like Harlowe’s x's first or x's $lore.

The dot syntax only works if you know the name when you’re writing the code (for example <<set $_lore.mobility to "distrust">>) so it doesn’t work if you have the name in a variable, and the name mostly can’t contain special characters.

1 Like

Ah, that’s perfect. Thank you! There are a few areas where I want to do something similar, so I imagine this will help a lot!

A few more comments on your code…

The <<display>> macro is depreciated. You should use the <<include>> macro instead.
 

If you’re trying to use temporary variables there, then they should start with an “_”. If you start the variable names with a “$”, then they will be tracked as a story variable, which doesn’t appear to be necessary here.

Also, instead of using the so-called “stupid print trick™” to create the span, you should use the attribute directive (an “@” in front of the attribute name) to make it work with SugarCube variables.

And if you’re adding custom attributes to an element, it’s recommended that you put “data-” in front of the custom attribute’s name. Especially since there are some built-in methods to access data attributes like that.

Thus your “lore” passage would look like this:

<<set _lore = {
	"power": "hello",
	"mobility": "trust"
}>>
<<set _description = _lore[$lore]>>
<span class="lore" @data-lore="_description">$lore</span>

(Heh… “data-lore”… I’m tempted to make a ST:TNG joke here. :wink: )

That said, instead of setting a variable and then <<include>>ing another passage, it would probably be better to create a <<widget>>. To do that, create a passage with a non-special passage name (see “Special passage names”) and give it a “widget” tag. If you want line breaks to be ignored, then add a “nobr” tag as well.

Then, in that widget passage you’d create the widget like this:

<<widget "lore">>
	<<set _lore = {
		"power": "hello",
		"mobility": "trust"
	}>>
	<<set $lore = $args[0]>>
	<<set _description = _lore[$lore]>>
	<span class="lore" @data-lore="_description">$lore</span>
<</widget>>

(Note: This means that you can have multiple widgets within a single widget passage.)

Once you have that, then instead of doing this:

<<set $lore to "power">><<include "lore">>

you could simply do this:

<<lore "power">>

That will both set the value of $lore and display the <span> as you wanted it. The arguments you pass to the widget like that can be accessed from the $args object within the widget.

Enjoy! :grinning:

This seems extremely useful! Thanks for your help. I was basically just brute-forcing something I knew worked for a different game I’d made.

Do you know how you’d get the text of _description working? Currently, I believe the text for the hover element is being displayed through content: attr(lore); in the css. Since that string isn’t being printed in the passage anymore, I guess I need to use that text in a different way? This is the css for reference:

.lore{
  position:relative;
  color: #73628A;
}

.lore::after {
  pointer-events:none;
  content: attr(lore);
  display: block;
  position: absolute;
  z-index: 1;
  left: -150px;
  width: 300px;
  background-color: #73628A;
  padding: 0.5em;
  border-radius: 10px;
  text-align: center;
  color: white;
  opacity: 0;
  transition: opacity 0.25s;
}

.lore.hover{
  color:rgb(158,180,250);
}

.lore:hover::after {
  opacity:1;
}

You just need to do content: attr(data-lore string); instead. (See the attr() CSS function.)

That said, if you’re looking for a tooltip to appear when you hover over something, you can use the “title” attribute instead, like this:

<span class="lore" @title="_description">$lore</span>

That will show the value of _description when you hover your mouse over that text for a moment (the delay and appearance is controlled by the OS’s tooltip settings).

Alternately, you might want to take a look at my <<hovertip>> and <<HoverTxt>> macros, since they allow you to even add images to the tooltip. (Click “Jump to Start” in the UI bar to see other sample code there.)

Hope that helps! :grinning:

1 Like

I second the hover tools! Very easy to implement and work with and they’ve worked well in all passages and pop-up pages I’ve used so far.

1 Like

Thank you! This is all really useful. I’ll take a look at the hovertip macros though, that does seem like it’ll do what I need it to!