0 votes
by (1.3k points)
edited by

So, I have an idea for a data structure, but I think it might be a bit flaky. Or there might be a better way to organize things. Let me show you what I had in mind:

<<set $pcPierced = {
	ears: { scale: 0, desc: "" },
	navel: { scale: 0, desc: "" },
	tongue: { scale: 0, desc: "" },
	face: { scale: 0, desc: "" } }>>

<<set $pcPiercedList = []>>

I was thinking, to save from having to iterate through the object whenever I wanted to check if something was pierced or not (checking to see if the scale key/value pair was greater than 0), I could instead just use an array to keep track of what was pierced or not. That's what the $pcPiercedList does. Whenever there's a piercing, the "ears" or "navel" string would be added to it. Then I could use an array method to quickly check if it has been, and then use dot notion on the object to access the specifics of it.

So, is that combo approach a good idea? Or should I try to just use an array in the first place, for the data storage as well? Do I need the object? Or maybe that object structure could live in the array? Anyone have any ideas for this? One way or other? Or is this combo approach pretty good (if not a bit wasteful)?

===

Hey, while I'm here... How do I get this to work?

:: Some passage
<<set $pcPierced = {
	ears: { scale: 0, desc: "" },
	navel: { scale: 0, desc: "" },
	tongue: { scale: 0, desc: "" },
	face: { scale: 0, desc: "" } }>>

<<set $pcPiercedList = []>>

<<set $pcPierced.ears.scale = 1>>
<<set $pcPierced.ears.desc = "your ears pierced, little silver sleepers">>
<<set $pcPiercedList.pushUnique("ears")>>

Blahblah.<<if $pcPiercedList.length > 0>> <<piercings>><</if>>

:: Widgets
<<widget "piercings">>
	<<for _i to 0; _i lt $pcPiercedList.length; _i++>>
		<<if $pcPiercedList.length == 1>>
			<<print "You have ">>
		<<else>>
			<<print "You have a few piercings... ">>
		<</if>>
		<<print $pcPierced['`$pcPiercedList[_i]`'].desc>>
	<</for>>
<</widget>>

This one: <<print $pcPierced['`$pcPiercedList[_i]`'].desc>> Doesn't work. I thought the `notation was meant to evaluate code fragments? Or is that not really how you use them? I I just cheat and use <<print $pcPierced['ears'].desc>> it works. As expected. But, how do I get it to work properly?

Also, if I do cheat, I see I'm getting three (3) spaced between "You have" and "your ears pierced..." So, like this: You have<space><space><space>your ears...

I can only account for one space. So, where might the other two come from? Any idea?

===

I got it. So, I'm supposed to use this, right? <<print $pcPierced[($pcPiercedList[_i])].desc>>

That works. But, I'm still getting those three spaces. So, ideas?

===

So, I eliminated the extra spaces, by changing to this: <<print "You have">>\

But, I don't get it. My widgets passage is set to [nobr]. My understanding was that I didn't need to put \ behind everything when I had that [nobr] tag. But results are results.

So, if I have <<print "hello">><<print "world">>

Woudl I expect to have "helloworld" or "hello world" as a result? Because I think that's what I'm seeing. An automatic insertion of a space that I didn't really want or desire. Or is something else happening? My code looks like this now: 

<<widget "piercings">>
	<<for _i = 0; _i < $pcPiercedList.length; _i++>>
		<<if $pcPiercedList.length == 1>>
			<<print "You have">>\
		<<else>>
			<<print "You have a few piercings...">>
		<</if>>
		<<print $pcPierced[($pcPiercedList[_i])].desc>>
	<</for>>
<</widget>>

And I get "You have your ears pierced, little silver sleepers<space><space>" from it. I have no idea where those trailing spaces come from. It's weird. And I don't like it.

===

Alright, this gets rid of most of the annoying spaces:

<<widget "piercings">>
	<<for _i = 0; _i < $pcPiercedList.length; _i++>>
		<<if $pcPiercedList.length == 1>>
			<<print "You have">>\
		<<else>>
			<<print "You have a few piercings...">>\
		<</if>>
		<<print $pcPierced[($pcPiercedList[_i])].desc>>
		<<print "hello">><<print "world">>
		<<print "hello">><<print "world2">>
	<</for>>\
<</widget>>

But it's odd. Because right now it produces this:

You have your ears pierced, little silver sleepers in the earlobes. helloworld helloworld2 .

The way to eliminate that last odd space is it have this:

<<print "hello">><<print "world2">>\

But if I follow the same logic, and put the same behind the first helloworld, it just does this stupid thing like:

helloworld\ helloworld2.

The only way to get those helloworlds together is to format the code like so:

<<print "hello">><<print "world">><<print "hello">><<print "world2">>\

So, do I just have to be extra extra observant when I use widgets to print things out? Is it better to use macros in javascript and then assemble strings to produce the final line? Rather than doing piecemeal stuff like this? I wonder

2 Answers

0 votes
by (68.6k points)
selected by
 
Best answer

SUGGESTION: It's probably best if you try to ask one question per thread.  Questions with multiple facets are fine, but asking multiple questions, even seemingly related ones, is problematic for this format.


So, I have an idea for a data structure, but I think it might be a bit flaky. Or there might be a better way to organize things.

I would probably use functions to accomplish what you want to do here.  There doesn't see to be any reason to have $pcPiercedList at all, it's both redundant in general and bloats the story history/serializations.

For example:

/* Returns whether any parts are pierced. */
setup.pcIsPierced = function () {
	var sv = State.variables;
	return Object.keys(sv.pcPierced).some(function (part) {
		return sv.pcPierced[part].scale > 0;
	});
};

/* Returns whether a specific part is pierced. */
setup.pcHasPiercing = function (part) {
	return State.variables.pcPierced[part].scale > 0;
};

/* Returns a new array of all piercing part names, where scale > 0. */
setup.pcGetPiercingNames = function () {
	var sv = State.variables;
	return Object.keys(sv.pcPierced).reduce(function (a, c) {
		return sv.pcPierced[c].scale > 0 ? a.concat(c) : a;
	}, []);
};

/* Returns a new array of all piercing part objects, where scale > 0. */
setup.pcGetPiercings = function () {
	var sv = State.variables;
	return Object.keys(sv.pcPierced).reduce(function (a, c) {
		return sv.pcPierced[c].scale > 0 ? a.concat(sv.pcPierced[c]) : a;
	}, []);
};

Hey, while I'm here... How do I get this to work?

Using the functions from my above example:

:: StoryInit
<<set $pcPierced = {
	ears   : { scale : 0, desc : "" },
	navel  : { scale : 0, desc : "" },
	tongue : { scale : 0, desc : "" },
	face   : { scale : 0, desc : "" }
}>>

:: Some passage
<<set $pcPierced.ears.scale to 1>>
<<set $pcPierced.ears.desc to "your ears pierced with little silver sleepers">>

Blahblah.<<if setup.pcIsPierced()>> <<piercings>><</if>>

:: Widgets [widget]
<<widget "piercings">>
	\<<set _piercingList to setup.pcGetPiercings()>>
	\<<if _piercingList.length is 1>>
		\You have 
	\<<else>>
		\You have a few piercings... 
	\<</if>>
	\<<print _piercingList.map(function (obj) {
		return obj.desc;
	}).join(', ')>>.
\<</widget>>

NOTE: You could use a range form <<for>> macro in place of the .map(…).join(…) construct there, but the JavaScript is a little easier to get nice results with in this case.  Though, as an example of what using the macro would basically look like:

	\<<for _piercing range _piercingList>>
		<<print _piercing.desc>>
	<</for>>

[EDIT]

But, I don't get it. My widgets passage is set to [nobr]. My understanding was that I didn't need to put \ behind everything when I had that [nobr] tag. But results are results.

I'm unsure where you got your understanding from, however, you seem to be confused about what the nobr special tag actually does.  From its documentation, "Causes leading/trailing newlines to be removed and all remaining sequences of newlines to be replaced with single spaces before the passage is rendered." (emphasis added)—the <<nobr>> macro and Config.passages.nobr setting work the same way.

Contrast line continuations which actually delete line breaks (and other whitespace between the backslash and the line break).

by (1.3k points)
Ah I see! Yeah, I'm a bit rusty on this kind of thing. But, I do appreciate the examples. I had't really thought to define functions. But now that I've seen them demonstrated, I'll look through my other stuff to see if I can structure things that way. I like that I'm getting the basics down now, before I launch into the story more.

I will copy and study these things . I think they're great. I do like working with javascript for more complex stuff. But I guess it comes back to practice and experience. Anyway, thanks a lot. I'll take it and multiply!

Yeah, and thanks for the edit stuff. From your code, I could see I'd done that wrong. So, more study. Thanks though. I appreciate it.
by (1.3k points)

Hey tme, if you happen to read this, you spoke a little about bloat in the history. And yeah, I can see that. Storing data when that data can just be calculated is pretty stupid.

But, what about if I have a lot of these kinds of things:

<<set $pcFace = "uncomfortably pretty">>
<<set $pcEyes = "clear blue">>
<<set $pcLips = "soft and tender">>
<<set $pcHair = "rich, lustrous auburn">>

It all relates directly to the PC. So, would it be better to just make a PC object and have all that stuff as properties of it? So, rather than a lot of variables like this set, we have one object set, with a lot of properties. There wouldn't be that much more typing to use them that way. So good? I should change over. Or in the end, is there little difference. If the data itself is important, then does it not really matter if it's stored as a variable by itself, or rolled up into an object and stored that way?

I'm curious. I'm still changing a lot of how I have things. So, if you can suggest one way or another, that would be cool?

by (68.6k points)

For most things, it doesn't really matter if you store your data in discrete story variables or as properties of a generic object which is itself stored in a story variable.  I'd use whichever made the most sense for you.  Basically, it's mostly down to personal preference.  For example:

Your $pcEyes eyes sparkle in the moonlight.
	/* VERSUS */
Your $pc.eyes eyes sparkle in the moonlight.

Which would you rather type more often?

The only case where it's more clear cut are instances where you might want to iterate over a set of related items—e.g. your piercings object.  Having things like that as properties on a generic object or members of an array make iterating over the individual items simpler than if they were done as discrete variables.

0 votes
by (159k points)

EDIT: Again two answers for the price of one, it must be that time of day. *smile* 

I have no idea where those trailing spaces come from

Widgets aren't automatically silent, which means that any visual content they contain (like white-space characters and un-escaped line-breaks) may/will be displayed when the widget is used. eg. A widget like the following.

<<widget "piercings">>
Hi there!
<</widget>>

... used in a Passage like so.

[<<piercings>>]

... produces the following visual output.

[
Hi there!
]

I believe you will find that the the extra spaces are coming from the code in your widget.

warning: Using one of the nobr related techniques will not remove all white-space because those techniques replace (continuous?) line-breaks with a white-space character. In use-cases like this one it is better to use Line Continuation markup instead, because that removes/suppresses the line-break(s) instead. 

by (1.3k points)
Yeah, double answers indeed. Thanks though, greyelf. Every bit helps in the end. I'll take some time to read. I promise.
...