new language guidelines help please

Freeform discussion about anything related to modding Transcendence.
Post Reply
relanat
Militia Commander
Militia Commander
Posts: 438
Joined: Tue Nov 05, 2013 9:56 am

Wed Nov 01, 2017 3:28 am

I'm modifying dsRPGLoot as part of an upgrade/update for an old mod, TransGeek's Elysium Player Storage.

Most of it is pretty easy but I'm getting confused on how to swap the multi-line screen desc for dsRPGLoot over to the translate friendly code as per https://ministry.kronosaur.com/record.hexm?id=72242

Here's the original code:

Code: Select all

<OnPaneInit>
	(block (thisItem)
		(setq thisItem (scrGetItem gScreen))
		(if thisItem
			(block (fitCount availCount desc)
				(setq availCount (itmGetCount thisItem))
				(setq fitCount (objGetFitCount gPlayerShip thisItem))
								
				(setq gMaxCount (min availCount fitCount))

				(setq desc (cat "Unit mass: " (strMassString (itmGetMass thisItem))))
				(if (gr gMaxCount 1)
					(setq desc (cat desc " (" gMaxCount " at " (strMassString (multiply (itmGetMass thisItem) gMaxCount)) ")"))
					)

				(setq desc (cat desc "\n\n"))

				(switch
					(eq gMaxCount 0)
						(setq desc (cat desc "You do not have enough space to carry " (itmGetName thisItem 4) "."))
					(eq gMaxCount 1)
						(setq desc (cat desc "You have enough room to carry one " (itmGetName thisItem 0) "."))
					(gr availCount fitCount)
						(setq desc (cat desc "You have enough room to carry only " fitCount " " (itmGetName thisItem 2) "."))
					(setq desc (cat desc "You have enough room to carry all " (itmGetName thisItem 8) "."))
					)

				(scrSetDesc gScreen desc)
				)
			(setq gMaxCount 0)
			)

		; Enable/disable actions
		(scrEnableAction gScreen 0 (gr gMaxCount 0))
		)
</OnPaneInit>
I'm thinking because all the variables are controlled by the mod the code should go in <OnPaneInit> (possibly except the itmGetName code? which might need to be in a separate <Text id> entry).
But would it be better to have the actual <Text id> as a single entry with three variables, unitMass for the first line, doNotHave/nil to cater for gMaxCount=0, and carryAmount to fill after "enough room to carry"?
Rather than having three separate Texts for unit mass, the empty line and then the final line of text and merging them into one?

Roughly something like this:

Code: Select all

<Text id="descElysiumLoot"
     (cat
          "Unit Mass: " %unitMass% " /n/n"
          "You " %doNotHave% "have enough room to carry " %carryAmount% "."
     )
</Text>
with unitMass being either a number or 'gMaxCount at number',
doNotHave being either the text "do not " or nothing, and
carryAmount being the relevant item name and one/only/all/fitCount as required.

Also do the %variables% need scrTranslate or scrSetDescTranslate here or will the game recognize variables from the code in the same dockscreen?

Any ideas about what should go where and why will be greatly appreciated because I probably should have started with something simpler! I've looked at the Trading Post code in 1.8a3 but it is confusing me more than helping.

Actually there probably needs to be a variable for one/only/all on the last line as well.
Attachments
Elysium Storage.xml
(6.93 KiB) Downloaded 3 times
Loot scrDesc.JPG
Loot scrDesc.JPG (40.49 KiB) Viewed 129 times

NMS
Militia Commander
Militia Commander
Posts: 400
Joined: Tue Mar 05, 2013 8:26 am

Wed Nov 01, 2017 8:10 am

I've already updated this screen in this commit.

Here's the new version (sorry about the indentation; it looks better with indent size 4):

Code: Select all

	<DockScreen UNID="&dsRPGLoot;"
			type=				"itemPicker"
			nestedScreen=		"true"
			inherit=			"&dsDockScreenBase;"
			>

		<ListOptions
			dataFrom=	"=(or (@ gData 'sourceObj) 'station)"
			list=		"*U"
			/>

		<Panes>
			<Default>
				<OnPaneInit>
					(block (thisItem)
						(setq thisItem (scrGetItem gScreen))
						(if thisItem
							(block (
								(availCount (itmGetCount thisItem))
								(fitCount (objGetFitCount gPlayerShip thisItem))
								(maxCount (min availCount fitCount))
								totalMassString spaceString
								)
								
								(scrSetData gScreen 'maxCount maxCount)
								(setq totalMassString (if (gr maxCount 1)
															(scrTranslate gScreen 'totalMassString {
																quantity:maxCount
																mass:(strMassString (* (itmGetMass thisItem) maxCount))
																})
															" "
															)
									)

								(switch
									(eq maxCount 0)
										(block Nil
											(setq spaceString (scrTranslate gScreen 'spaceStringNone { itemName:(itmGetName thisItem 'article) }))
											(scrEnableAction gScreen 'actionLootThis Nil)
											)
									(eq maxCount 1)
										(setq spaceString (scrTranslate gScreen 'spaceStringOne { itemName:(itmGetName thisItem) }))
									(gr availCount fitCount)
										(setq spaceString (scrTranslate gScreen 'spaceStringSome {
																count:fitCount
																itemName:(itmGetName thisItem 'plural)
																})
											)
									(setq spaceString (scrTranslate gScreen 'spaceStringAll { itemName:(itmGetName thisItem 'count) }))
									)

								(scrSetDescTranslate gScreen 'descDefault {
									unitMass:(strMassString (itmGetMass thisItem))
									totalMassString:totalMassString
									spaceString:spaceString
									})
								)
							
							(block Nil
								(scrSetData gScreen 'maxCount 0)
								(scrSetDescTranslate gScreen 'descNoItemsHere)
								(scrEnableAction gScreen 'actionLootThis Nil)
								(scrSetActionLabel gScreen 'actionDone Nil Nil '(default cancel))
								)
							)
						)
				</OnPaneInit>

				<Actions>
					<Action id="actionLootThis" default="1">
						(if (gr (scrGetData gScreen 'maxCount) 1)
							(scrShowPane gScreen "LootQuantity")
							(block (itemsToLoot)
								(setq itemsToLoot (scrRemoveItem gScreen 1))
								(objAddItem gPlayerShip itemsToLoot)
								(typSetData &svPlayer; 'tutorialLooted True)
								(scrShowPane gScreen "Default")
								)
							)
					</Action>

					<Action id="actionDone" cancel="1">
						(block Nil
							(scrExitScreen gScreen (@ gData 'forceUndock))

							(if (@ gData 'nextScreen)
								(scrShowScreen gScreen (@ gData 'nextScreen))
								)
							)
					</Action>
				</Actions>
			</Default>

			<LootQuantity
					showCounter=	"true">

				<OnPaneInit>
					(block Nil
						(scrSetDescTranslate gScreen 'descLootQuantity)
						(scrSetCounter gScreen (scrGetData gScreen 'maxCount))
						)
				</OnPaneInit>

				<Actions>
					<Action id="actionLoot" default="1">
						(block (
							(count (scrGetCounter gScreen))
							(maxCount (scrGetData gScreen 'maxCount))
							)
							(if (gr count maxCount)
								(scrSetCounter gScreen maxCount)
								(block (itemsToLoot)
									(setq itemsToLoot (scrRemoveItem gScreen count))
									(objAddItem gPlayerShip itemsToLoot)
									(typSetData &svPlayer; 'tutorialLooted True)
									(scrShowPane gScreen "Default")
									)
								)
							)
					</Action>

					<Action id="actionCancel" cancel="1">
						<ShowPane pane="Default"/>
					</Action>
				</Actions>
			</LootQuantity>
		</Panes>
		
		<Language>
			<Text id="descDefault">
				Unit mass: %unitMass%%totalMassString%
				
				%spaceString%
			</Text>
			<Text id="totalMassString">" (%quantity% at %mass%)"</Text>
			<Text id="spaceStringNone">You do not have enough space to carry %itemName%.</Text>
			<Text id="spaceStringOne">You have enough room to carry one %itemName%.</Text>
			<Text id="spaceStringSome">You have enough room to carry only %count% %itemName%.</Text>
			<Text id="spaceStringAll">You have enough room to carry all %itemName%.</Text>
			<Text id="actionLootThis">[L]oot this Item</Text>
			<Text id="descLootQuantity">How many items do you wish to loot?</Text>
		</Language>

</DockScreen>
As you can hopefully see, one Text element provides the outline, with replaceable parameters for all the parts that can vary. A few parameters (listed in the guidelines) are replaced automatically, but for the others, you have to pass the value in the data argument to the translation function. Some of those are replaced with values directly from a function like itmGetName. (At some point these functions will need to be changed to get their text from translatable Text elements also.) Others are replaced with calls to translate other Text elements which can have their own parameters. Currently, if you want a parameter to be replaced with nothing sometimes, you have to pass a space (" "). If you pass Nil or an empty string (""), it will show up as the parameter name with percent signs. I think this is a bug in the case of empty strings, which will hopefully be fixed soon.

This isn't the only approach you can take. For instance, you can also put code in a Text element that calls scrTranslate or a related function one or more times to assemble the string using cat from text in other Text elements. Just make sure that code and text that needs to be translated are never in the same Text element. But in this case I think it would be more complicated because you would have to pass the necessary data into the function that translated that element. In this case you access the values with (@ gData variable).

If this doesn't answer all your questions, feel free to follow up.

relanat
Militia Commander
Militia Commander
Posts: 438
Joined: Tue Nov 05, 2013 9:56 am

Wed Nov 01, 2017 10:59 pm

This is excellent. Thank you. Saved for further study and, thanks, yes, there may be more questions! :lol:

relanat
Militia Commander
Militia Commander
Posts: 438
Joined: Tue Nov 05, 2013 9:56 am

Fri Nov 03, 2017 11:35 pm

Couple of questions.

I can't see why you set 'totalMassString' as 'spaceString' in the 'if thisItem' section. 'spaceString' doesn't exist yet, does it? I'm thinking it's so 'totalMassString ' is local but can't see why 'spaceString' is there.

Ah, Wait, got it. It's not (totalMassString spaceString).
It's the same as:

Code: Select all

(block (totalMassString spaceString)
	(setq (availCount (itmGetCount thisItem)))
	(setq (fitCount (objGetFitCount gPlayerShip thisItem)))
	(setq (maxCount (min availCount fitCount))).
	....
Where both 'totalMassString' and 'spaceString' are being set as locals but not having any value set yet like the three variables below.
My bad. Sometimes it takes a while for stuff to click.
---

I didn't know about the non-hex name flags. Good stuff and much easier.
So for future reference. From the function list 1.8a3:

(itmGetName item|type [flags]) -> name of item
flags

0x0001 capitalize capitalize first letter
0x0002 plural pluralize name
0x0004 article prefix with 'the' or 'a'
0x0008 count prefix with count or singular article
0x0010 countOnly prefix with count or nothing
0x0020 noModifiers no modifiers ('damaged' etc)
0x0040 demonstrative prefix with 'the' or 'this' or 'these'
0x0080 short use short name
0x0100 actual actual name (not unidentified name)
0x0200 noEvent do not fire GetName event
0x0400 titleCapitalize capitalize as a title
0x0800 installedState prefix with 'installed' if necessary
0x1000 countAlways always prefix with count
0x40000 noDeterminer no prefix, but pluralize if necessary
0x80000 noQuotes replace double-quotes with single-quotes

More of your work, I believe.
--

Code: Select all

(scrSetActionLabel gScreen 'actionDone Nil Nil '(default cancel))
I finally worked out that this line of code is to set both 'Esc' and 'Enter' as exit keys for the 'Done' action but only when all items have been looted and the station is empty. Nice touch. Otherwise when there are items in the station 'Done' only has the 'Esc' or 'cancel' property as set in "Action id="Done".

I'm assuming the two Nil values are just null fillers to allow the special code at the end without changing the look of the screen? If they weren't there the function would think '(default cancel) was the label code? They don't change 'label' or 'key' in any way in this function? You would need to use actual values to change something? I think that's what 'scrSetActionLabel' is for.
---

So to get the variables into percentage form they have to be put through one of the xxxxxxTranslate functions inside {} brackets? I think that's what you mean by "you have to pass the value in the data argument to the translation function."
Except for the preset ones like %he/she%. I'm assuming that the long term goal is to have all text in raw form and all variables in % form.
---

Interestingly in <Text id="descDefault"> leaving an empty line will result in an empty line in the screen desc. No need to use '\n'. Is this because it is in raw format and the game takes it as it is? Do we have to worry about the width of text in raw form or will the game automatically wrap-around raw text that is too long for the scr Desc area?
----

Thanks. I've learnt heaps from this. It's also a lot simpler than what I was thinking of doing.
---

Minor point.
Testing the updated Elysium mod I noticed there isn't an option for "you can carry only one" item.

From "you can carry only two" the screen desc doesn't go to "you can carry only one" but to "you can carry one". It's like this in the standard un-updated code too.
See image.
Attachments
should be carry only one combined.jpg
should be carry only one combined.jpg (95.59 KiB) Viewed 96 times

NMS
Militia Commander
Militia Commander
Posts: 400
Joined: Tue Mar 05, 2013 8:26 am

Sat Nov 04, 2017 3:24 pm

relanat wrote:
Fri Nov 03, 2017 11:35 pm
I didn't know about the non-hex name flags. Good stuff and much easier.
...
More of your work, I believe.
I'm not responsible for the human-readable flags, but I did suggest the need for the last two.
relanat wrote:
Fri Nov 03, 2017 11:35 pm

Code: Select all

(scrSetActionLabel gScreen 'actionDone Nil Nil '(default cancel))
I finally worked out that this line of code is to set both 'Esc' and 'Enter' as exit keys for the 'Done' action but only when all items have been looted and the station is empty. Nice touch. Otherwise when there are items in the station 'Done' only has the 'Esc' or 'cancel' property as set in "Action id="Done".

I'm assuming the two Nil values are just null fillers to allow the special code at the end without changing the look of the screen? If they weren't there the function would think '(default cancel) was the label code? They don't change 'label' or 'key' in any way in this function? You would need to use actual values to change something? I think that's what 'scrSetActionLabel' is for.
Exactly. I probably should comment that line. I'll also add that info to the function help when I get to that one.
relanat wrote:
Fri Nov 03, 2017 11:35 pm
So to get the variables into percentage form they have to be put through one of the xxxxxxTranslate functions inside {} brackets? I think that's what you mean by "you have to pass the value in the data argument to the translation function."
Except for the preset ones like %he/she%. I'm assuming that the long term goal is to have all text in raw form and all variables in % form.
More or less. The {}s create a struct. You could do it with (struct) and you could do it in advance and save it to a variable, but usually it's easier to do it inside the translate function call. The key/value pairs in the data argument are added to gData and parameters (words with % signs on either side) in the text being translated that match a key are replaced with the corresponding value.
relanat wrote:
Fri Nov 03, 2017 11:35 pm
Interestingly in <Text id="descDefault"> leaving an empty line will result in an empty line in the screen desc. No need to use '\n'. Is this because it is in raw format and the game takes it as it is? Do we have to worry about the width of text in raw form or will the game automatically wrap-around raw text that is too long for the scr Desc area?
George upgraded the engine's text parsing at some point. In raw form, it will keep double line breaks, but ignore single line breaks. And of course it still inserts line breaks where needed. So paragraphs separated by double line breaks will still be separate in-game, even though the line breaks within them may be in different places. However, if you need there to be a single line break in a specific place, you still need to use \n.
relanat wrote:
Fri Nov 03, 2017 11:35 pm
Thanks. I've learnt heaps from this. It's also a lot simpler than what I was thinking of doing.
You're welcome.
relanat wrote:
Fri Nov 03, 2017 11:35 pm
Minor point.
Testing the updated Elysium mod I noticed there isn't an option for "you can carry only one" item.

From "you can carry only two" the screen desc doesn't go to "you can carry only one" but to "you can carry one". It's like this in the standard un-updated code too.
Yes, I kept the logic and resulting text the same. If I were to revise it, I'd probably have:

You do not have enough space to carry this %item%.
You do not have enough space to carry any of these %items%.
You have enough space to carry this %item%.
You only have enough space to carry %number% of these %items%.
You have enough space to carry all %number% of these %items%.

relanat
Militia Commander
Militia Commander
Posts: 438
Joined: Tue Nov 05, 2013 9:56 am

Sun Nov 05, 2017 9:27 am

NMS wrote:The {}s create a struct. You could do it with (struct) and you could do it in advance and save it to a variable, but usually it's easier to do it inside the translate function call. The key/value pairs in the data argument are added to gData and parameters (words with % signs on either side) in the text being translated that match a key are replaced with the corresponding value.
Excellent. Thanks. This makes things a lot clearer. Just one question. Will the %parameters% recognize a single variable? They don't need to be in key/value pairs? Eg, (setq textToShow "This text") would cause %textToShow% to show 'This text'. Is that right?

And thanks for the parsing/formatting info too. Invaluable.

NMS
Militia Commander
Militia Commander
Posts: 400
Joined: Tue Mar 05, 2013 8:26 am

Tue Nov 07, 2017 3:28 pm

I'm pretty sure global variables will not replace parameters, they have to be in a struct. But (scrSetData gScreen parameter value) or ([email protected] gData parameter value) might work if the screen is already open but the text you want to affect isn't generated yet.

Post Reply