struct format and editing help please

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

Tue Feb 26, 2019 1:14 am

Commander's Log mod again!
Looking to create a struct of node IDs and station IDs which can be used to highlight objects.

Currently using a list because I don't know how to use a struct in this case. But I also want to change to a struct because lists are a bit complex to manipulate inside each other.

If the player selects the "Locate" action in a dockscreen object list the ID of that object gets added to a list of IDs under the node ID. Note: the object lists, object IDs and node IDs are saved and can be used out of system.
An example which is the list to locate two stations in Eridani and one in Rigel.

Code: Select all

((SE (15708 15672)) (BA (2098)))
If the player is in the system, eg SE, then the station gets highlighted instantly using 'autoClear and the action desc for the "Locate" feature is changed to say the station has been highlighted. If the station is in another system, here Rigel, the action desc is changed to say the station will be highlighted on system entry and the station is then highlighted in <OnGlobalPlayerEnteredSystem>.

It all works fine as is except the highlight can be cleared by the player flying near the station. With the addition of object property 'showAsDestination in 1.8b5.2 the highlight can now be checked to see if this has happened. I prefer not to use 'autoClearOnDock as IMO 'autoClear is a better gameplay option in this case.

But I don't know the best way to use a struct for this or how to remove a single value from a struct.
As an example if the player flies near obj ID 15708 then this value needs to be removed from the struct so the dockscreen actions can reset to allow the player to select the station again. But the 15672 value needs to remain there under the node ID key.

Object IDs are removed on docking in <GetGlobalDockscreen>. After visiting both stations in Eridani the list looks like this:

Code: Select all

((SE ()) (BA (2098)))
This is to prevent the need to create the node ID list again if required in the same system. I assume this is better codewise but am not sure.

Additionally the entire node ID list is cleared on system exit. The assumption is the player no longer wants to find any remaining highlighted stations so the highlights are cancelled. So after gating out of SE the list is this:

Code: Select all

((BA (2098)))
Has anyone got any ideas on the best way to set up a struct to do this and what code is used to remove individual values from a struct? Or is there another better way to do the same thing? TIA.
Stupid code. Do what I want, not what I typed in!

NMS
Militia Captain
Militia Captain
Posts: 551
Joined: Tue Mar 05, 2013 8:26 am

Tue Feb 26, 2019 10:39 am

Presumably you'd use the node IDs as keys. One option is to allow each value to be an object or list of objects. E.g. { SE:(15708 15672) BA:2098 }
You could add to the struct with:

Code: Select all

(setq theStruct (structAppend theStruct key value))
In many cases this would be OK, but sometimes you might have to check whether the value was a single number or a list. (In fact, I think I'll suggest that George change this so the values are always lists.)

So it's probably better to require the values to be lists. You could add to them with:

Code: Select all

([email protected] theStruct key (append (@ theStruct key) value))
Either way, the struct can be Nil to start.

Removing all entries for a key is easy:

Code: Select all

([email protected] theStruct key Nil)
Removing some values is a little trickier:

Code: Select all

([email protected] theStruct key (filter (@ theStruct key) theItem (neq theItem itemToRemove)))
or

Code: Select all

([email protected] theStruct key (filter (@ theStruct key) theItem (not (find listOfItemsToRemove theItem))))
If you're planning to use these operations a lot, you might want to create helper functions to simplify them.

relanat
Militia Captain
Militia Captain
Posts: 817
Joined: Tue Nov 05, 2013 9:56 am

Fri Mar 29, 2019 2:45 am

Thanks again. More great info explained really well. Using this code will remove a heap of list handling code from the mod.

I couldn't make the 'adding a value' code work unless the 'theStruct' already existed.
I misunderstood what you meant by "theStruct can be Nil to start".
Once I set 'theStruct' to Nil before running the 'adding' code everything worked fine.

Code: Select all

(setq theStruct Nil)
In the mod this info is saved as type data for use out of system. That returns Nil if it doesn't exist anyway.

The info on the list/single check is greatly appreciated. I ran into this and it would have taken me quite a while to work it out; that's if I could have worked it out!

Of note is that setting the values for a key to Nil also deletes the key.

Code: Select all

exampleSEStruct
{ SE:17654 }
([email protected] exampleSEStruct "SE" Nil)
{ }
This also happens if the struct contains a list of values.


And thank you very much for the code to remove a value. I didn't have any ideas about how to make that happen. Although in hindsight it seems really easy, but then most things do!

I'll be using this code a lot. What about a 'structRemove' function which removes a value from a key? Is that a feasible idea? Similar to 'lnkRemove'.

Final code which runs from a dockscreen "Locate This Object" action.
'logGetLocate' and 'logSetLocate' are lambda shortcuts for 'typGet/SetData &evD789CommandersLog; 'locateStation'. This reduces the amount of code text in the mod. 'shownNode' is a nodeID and 'objectID' is an objID.

Code: Select all

(setq rpgD789Locate (lambda (shownNode objectID)
		;Add the ID to a struct. The struct has nodeID keys. Each key has a
		;	value of a list of object IDs from that nodeID to highlight as
		;	required.
		;There is no need to check for an existing key as a new key will be
		;	created if one does not exist.
	(block Nil
		(logSetLocate 
			([email protected] (logGetLocate)
				shownNode
				(append (@ (logGetLocate) shownNode) objectID)
			)
		)
		...
Code which removes the object ID from the struct when the player docks with the object. Runs in a <GetGlobalDockscreen> event.

Code: Select all

	;Remove the stationID from the 'locate' list.
(if (find (@ (logGetLocate) (sysGetNode)) (objGetID gSource))
	(logSetLocate
		([email protected] (logGetLocate)
			(sysGetNode)
			(filter (@ (logGetLocate) (sysGetNode)) theEntry (neq (objGetID gSource) theEntry))
		)
	)
)
And code which removes the nodeID key and values when the player leaves the system. Runs in an <OnGlobalPlayerLeftSystem> event.

Code: Select all

	;Remove the object IDs from the locate list by setting the
	;	value to Nil which also deletes the nodeID key.
(logSetLocate
	([email protected] (logGetLocate)
		(sysGetNode)
		Nil
	)
)
Stupid code. Do what I want, not what I typed in!

NMS
Militia Captain
Militia Captain
Posts: 551
Joined: Tue Mar 05, 2013 8:26 am

Sat Mar 30, 2019 7:04 pm

relanat wrote:
Fri Mar 29, 2019 2:45 am
Thanks again. More great info explained really well. Using this code will remove a heap of list handling code from the mod.

I couldn't make the 'adding a value' code work unless the 'theStruct' already existed.
I misunderstood what you meant by "theStruct can be Nil to start".
Once I set 'theStruct' to Nil before running the 'adding' code everything worked fine.
You're welcome. If you declare a variable in a block, but haven't set its value yet, it will be Nil. If you're using a global variable (which should generally be avoided), you have to define it before you use it or you'll get "no binding for symbol" errors.

relanat wrote:
Fri Mar 29, 2019 2:45 am
What about a 'structRemove' function which removes a value from a key? Is that a feasible idea? Similar to 'lnkRemove'
That's what I meant about a helper function, e.g.:

Code: Select all

(setq structRemoveItemFromKey (lambda (theStruct key itemToRemove)
	([email protected] theStruct key (filter (@ theStruct key) theItem (neq theItem itemToRemove)))
	))

Post Reply