General Helper functions

This is a moderated forum that collects tutorials, guides, and references for creating Transcendence extensions and scripts.
User avatar
Betelgeuse
Fleet Officer
Fleet Officer
Posts: 1920
Joined: Sun Mar 05, 2006 6:31 am

If you have a general helper function like some kind of math or list function or a function that you think that would be useful to many different kinds of mods post it here.

If there are bugs please take it up in a pm. Please no discussion of the functions here (pm the author asking for them to edit their post if they are not clear on use).
Crying is not a proper retort!
User avatar
digdug
Fleet Admiral
Fleet Admiral
Posts: 2620
Joined: Mon Oct 29, 2007 9:23 pm
Location: Decoding hieroglyphics on Tan-Ru-Dorem

I would like to post a helper function.
It's not mine, it was invented by F50
So I'm posting this for him, because I found this helper function very important, it's a shame that nobody thought about it seriously before.
So I stripped down the mod (tractor device prototype) and created a helper function from it.

Name:
intsysVectorAngle

Syntax:
(intsysVectorAngle ship spaceObject [condition])

Argument List:
ship: any ship to calculate the origin of the vector
spaceobject: the second spaceobject to calculate the vector
[condition]: if True the angle of the direction of the ship is computed to give the final angle.

Returns:
number: the angle of the vector from 0 to 359 between the ship and the spaceObject.

Category:
ship, vector operator, spaceobject

Description:
Function that calculates the angle of the vector from a ship to a spaceObject.

Code: Select all

(setq intsysVectorAngle (lambda (src target srcFacingCorr)
	(block (distance srcPos targetPos bestDist bestDegree count finalAngle)
  
	
	(setq distance (objGetDistance target src))
	(setq srcDirection (shpGetDirection src))
	(setq srcPos (objGetPos src))
	(setq targetPos (objGetPos target))
	
	(for count 0 180
		(block (vector currDist)
			(setq vector (sysVectorPolarOffset targetPos (multiply count 2) distance))
			(setq currDist (sysVectorDistance vector srcPos)) 
			(if (ls currDist BestDist)
				(block Nil
					(setq bestDegree (multiply count 2))
					(setq bestDist currDist)
				)
			)
		)	
	)
	
	(if (eq srcFacingCorr True)
		(block Nil
			(setq finalAngle (subtract bestDegree srcDirection))		
			(if (ls finalAngle 0)
				(setq finalAngle (add finalAngle 360))	
			)
		)
		(setq finalAngle bestDegree)
	)
	finalAngle
	)
))
I'm going to post a couple of mods using this function, one of them was a highly requested device in the last few years.
Last edited by digdug on Sun Sep 07, 2008 4:14 pm, edited 2 times in total.
User avatar
Betelgeuse
Fleet Officer
Fleet Officer
Posts: 1920
Joined: Sun Mar 05, 2006 6:31 am

Returns the number of the given item installed on the space object.
spaceObject: the space object you want to see how many of an item is installed on it
UNID: the UNID of the item you want to see how many is installed on the space object

Code: Select all

(setq sobjGetNumberOfItemInstalled (lambda (spaceObject UNID)
	(count (filter (objGetItems spaceObject "*I") testItem (eq (itmGetUNID testItem) UNID)))
))
Last edited by Betelgeuse on Fri Aug 29, 2008 8:14 pm, edited 1 time in total.
Crying is not a proper retort!
george moromisato
Developer
Developer
Posts: 2997
Joined: Thu Jul 24, 2003 9:53 pm
Contact:

digdug wrote:sysVectorAngle
In general, you should try not to create helper functions that look like the built in system functions. Why? Because they might collide with new system functions.

For example, 0.99 already has a function called sysVectorAngle:

(sysVectorAngle vector) -> angle of the given vector

A mod that includes your version of (sysVectorAngle) will break other parts of the game that rely on the system function.

You should name helper functions with your own prefix so that they don't collide.
User avatar
Betelgeuse
Fleet Officer
Fleet Officer
Posts: 1920
Joined: Sun Mar 05, 2006 6:31 am

thanks for that advice George
Crying is not a proper retort!
User avatar
digdug
Fleet Admiral
Fleet Admiral
Posts: 2620
Joined: Mon Oct 29, 2007 9:23 pm
Location: Decoding hieroglyphics on Tan-Ru-Dorem

You should name helper functions with your own prefix so that they don't collide.
ops, sorry George, thanks for the advice.
F50
Fleet Officer
Fleet Officer
Posts: 1004
Joined: Sat Mar 11, 2006 5:25 pm

These functions make setting/getting lists of references easy. They work just like their regular counterparts, except for lists of references instead of plain lists or references or numbers.

Take note that these functions reserve the data name (cat "FOO" x) where x is all numbers from 0 to the number of items in your list, as well as (cat "FOO" "X") where FOO is the name you want to save the list under. These functions do not reserve the data name "FOO".

Special thanks to speedofsquid for some help with extGetObjListData.

Code: Select all

<Globals>
	(block Nil
		(setq extSetObjListData (lambda (source name refList)
			(block (x thisObj)
				(setq x 0)
				(enum refList thisObj
					(block Nil
						(objSetObjRefData source (cat name x) thisObj)
						(setq x (add x 1))
					)
				)
				(objSetData source (cat name "X") x)
			)
		))
		(setq extGetObjListData (lambda (source name)
        		(block (x finXValue newObj refList)
				(setq finXValue (objGetData source (cat name "X")))
				(setq refList Nil)
				(for x 0 (subtract finXValue 1)
					(block Nil
						(setq newObj (objGetObjRefData source (cat name x)))
						(setq refList (append refList (list newObj)))
					)
				)
				refList ;return value - actually redundant for this function
			)
		)) 
	)
</Globals>
User avatar
alterecco
Fleet Officer
Fleet Officer
Posts: 1658
Joined: Wed Jan 14, 2009 3:08 am
Location: Previously enslaved by the Iocrym

This is an alternate way of getting the angle between two spaceObjects.
Due credit to F50 for his original function, Apemant for his vector functions, and Atarlost for trig help.

The function is very simple. It takes two space objects and an optional 3'rd boolean.
It will return the angle in degrees, from the first object to the second, relative to the global coordinate system. If True is passed as the 3'rd argument, it will take the first ships facing into consifderation, and return the same angle, but in a local coordinate system.

As an example, if object B is directly in front of object A, it will return 0 if the last parameter is True.

The result returned should be the same as F50's function above, but it avoids the 180 iterations.

Feel free to PM about questions

Code: Select all

;; takes two space objects, and returns the angle between them,
;; relative to system origin.
;; Pass True as the last argument to get an adjustment
;; for the first objects facing, thereby returning
;; the angle between a objects facing and another object.
;; Note: The first object must be a ship for that to work
(setq attackOfTheSpaceAngles (lambda (a b local)
	(block (angle facing return break)
		;; if local is true, but a is not a ship, return Nil
		(if (and local (not (objIsShip a)))
			(seq break True)
		)
		
		(if (not break)
			;; we are set to continue
			(block Nil
				;; calculate the angle. This is the Trap way
				;; of doing atan((Ay-By)/(Ax-Bx))
				;; Thanks to Atarlost for the trig!!
				(setq angle (sysVectorAngle
					(sysVectorSubtract
						(objGetPos b)
						(objGetPos a)
					)
				))
				;; do we want the local angle
				(if local
					(block Nil
						;; get the ship facing
						(setq facing (shpGetDirection a))
						;; subtract facing from angle
						(setq angle (subtract angle facing))
						;; do some adjustments to get a nice number
						(if (ls angle -180)
							(setq angle (add angle 360))
						)
						(if (gr angle 180)
							(setq angle (subtract angle 360))
						)
						;; make sure that the number we return is positive
						(if (ls angle 0)
							(setq angle (multiply angle -1))
						)
					)
				)
				(setq return angle)
			)
		)
		return
	)
))
User avatar
Betelgeuse
Fleet Officer
Fleet Officer
Posts: 1920
Joined: Sun Mar 05, 2006 6:31 am

This is the cos * 100 of the index. (in degrees)

Code: Select all

	  (setq cosList '(100 100 100 100 100 100 99 99 99 99 98 98 98 
	  		97 97 97 96 96 95 95 94 93 93 92 91 91 90 89 
	  		88 87 87 86 85 84 83 82 81 80 79 78 77 75 74 
	  		73 72 71 69 68 67 66 64 63 62 60 59 57 56 54 
	  		53 52 50 48 47 45 44 42 41 39 37 36 34 33 31 
	  		29 28 26 24 22 21 19 17 16 14 12 10 9 7 5 3 
	  		2 0 -2 -3 -5 -7 -9 -10 -12 -14 -16 -17 -19 
	  		-21 -22 -24 -26 -28 -29 -31 -33 -34 -36 -37 
	  		-39 -41 -42 -44 -45 -47 -48 -50 -52 -53 -54 
	  		-56 -57 -59 -60 -62 -63 -64 -66 -67 -68 -69 
	  		-71 -72 -73 -74 -75 -77 -78 -79 -80 -81 -82 
	  		-83 -84 -85 -86 -87 -87 -88 -89 -90 -91 -91 
	  		-92 -93 -93 -94 -95 -95 -96 -96 -97 -97 -97 
	  		-98 -98 -98 -99 -99 -99 -99 -100 -100 -100 
	  		-100 -100 -100 -100 -100 -100 -100 -100 -99 
	  		-99 -99 -99 -98 -98 -98 -97 -97 -97 -96 -96 
	  		-95 -95 -94 -93 -93 -92 -91 -91 -90 -89 -88 
	  		-87 -87 -86 -85 -84 -83 -82 -81 -80 -79 -78 
	  		-77 -75 -74 -73 -72 -71 -69 -68 -67 -66 -64 
	  		-63 -62 -60 -59 -57 -56 -54 -53 -52 -50 -48 
	  		-47 -45 -44 -42 -41 -39 -37 -36 -34 -33 -31 
	  		-29 -28 -26 -24 -22 -21 -19 -17 -16 -14 -12 
	  		-10 -9 -7 -5 -3 -2 0 2 3 5 7 9 10 12 14 16 
	  		17 19 21 22 24 26 28 29 31 33 34 36 37 39 
	  		41 42 44 45 47 48 50 52 53 54 56 57 59 60 
	  		62 63 64 66 67 68 69 71 72 73 74 75 77 78 
	  		79 80 81 82 83 84 85 86 87 87 88 89 90 91 
	  		91 92 93 93 94 95 95 96 96 97 97 97 98 98 
	  		98 99 99 99 99 100 100 100 100 100 100))
and sinList


Code: Select all

(setq sinList '(0 2 3 5 7 9 10 12 14 16
	17 19 21 22 24 26 28 29 31 33 34 
	36 37 39 41 42 44 45 47 48 50 52 
	53 54 56 57 59 60 62 63 64 66 67 
	68 69 71 72 73 74 75 77 78 79 80 
	81 82 83 84 85 86 87 87 88 89 90 
	91 91 92 93 93 94 95 95 96 96 97 
	97 97 98 98 98 99 99 99 99 100 
	100 100 100 100 100 100 100 100 
	100 100 99 99 99 99 98 98 98 97 
	97 97 96 96 95 95 94 93 93 92 91 
	91 90 89 88 87 87 86 85 84 83 82 
	81 80 79 78 77 75 74 73 72 71 69 
	68 67 66 64 63 62 60 59 57 56 54 
	53 52 50 48 47 45 44 42 41 39 37 
	36 34 33 31 29 28 26 24 22 21 19 
	17 16 14 12 10 9 7 5 3 2 0 -2 -3 
	-5 -7 -9 -10 -12 -14 -16 -17 -19 
	-21 -22 -24 -26 -28 -29 -31 -33 
	-34 -36 -37 -39 -41 -42 -44 -45 
	-47 -48 -50 -52 -53 -54 -56 -57 
	-59 -60 -62 -63 -64 -66 -67 -68 
	-69 -71 -72 -73 -74 -75 -77 -78 
	-79 -80 -81 -82 -83 -84 -85 -86 
	-87 -87 -88 -89 -90 -91 -91 -92 
	-93 -93 -94 -95 -95 -96 -96 -97 
	-97 -97 -98 -98 -98 -99 -99 -99 
	-99 -100 -100 -100 -100 -100 -100 
	-100 -100 -100 -100 -100 -99 -99 
	-99 -99 -98 -98 -98 -97 -97 -97 
	-96 -96 -95 -95 -94 -93 -93 -92 
	-91 -91 -90 -89 -88 -87 -87 -86 
	-85 -84 -83 -82 -81 -80 -79 -78 
	-77 -75 -74 -73 -72 -71 -69 -68 
	-67 -66 -64 -63 -62 -60 -59 -57 
	-56 -54 -53 -52 -50 -48 -47 -45 
	-44 -42 -41 -39 -37 -36 -34 -33 
	-31 -29 -28 -26 -24 -22 -21 -19 
	-17 -16 -14 -12 -10 -9 -7 -5 -3 -2 0))
Crying is not a proper retort!
User avatar
Betelgeuse
Fleet Officer
Fleet Officer
Posts: 1920
Joined: Sun Mar 05, 2006 6:31 am

log * 100 of given number (estimation)

Code: Select all

			(setq log (lambda (number)
				(block (result guess bestguess)
					(setq result 0)
					(loop (gr number 1)
						(block nil
							(setq guess 2)
							(setq bestguess 2)
							(loop (ls guess (count shortLogList)) 
								(block nil
									(if (ls (modulo number guess) (modulo number bestguess))
										(setq bestguess guess)
									)
									(if (eq 0 (modulo number guess))
										(setq guess (count shortLogList))
									)
									(setq guess (add 1 guess))
								)
							)
							
							(setq result (add result (item shortLogList bestguess)))
							(setq number (divide number bestguess))
						)
					)
					
					(divide result 100)
				)				
			))
			
			(setq shortLogList '(0 0 3010 4771 6020 6989 8450 9030 9542))
Crying is not a proper retort!
User avatar
Betelgeuse
Fleet Officer
Fleet Officer
Posts: 1920
Joined: Sun Mar 05, 2006 6:31 am

tan * 100 of the given index

Code: Select all

			(setq tanList '(
				0 2 3 5 7 9 11 12 14 16
				18 19 21 23 25 27 29 31
				32 34 36 38 40 42 45 47
				49 51 53 55 58 60 62 65
				67 70 73 75 78 81 84 87
				90 93 97 100 104 107 111
				115 119 123 128 133 138
				143 148 154 160 166 173
				180 188 196 205 214 225
				236 248 261 275 290 308 
				327 349 373 401 433 470 
				514 567 631 712 814 951 
				1143 1430 1908 2864 5729
				1633123935319540000 -5729 
				-2864 -1908 -1430 -1143 
				-951 -814 -712 -631 -567 
				-514 -470 -433 -401 -373 
				-349 -327 -308 -290 -275 
				-261 -248 -236 -225 -214 
				-205 -196 -188 -180 -173 
				-166 -160 -154 -148 -143 
				-138 -133 -128 -123 -119 
				-115 -111 -107 -104 -100 
				-97 -93 -90 -87 -84 -81 
				-78 -75 -73 -70 -67 -65 
				-62 -60 -58 -55 -53 -51 
				-49 -47 -45 -42 -40 -38 
				-36 -34 -32 -31 -29 -27 
				-25 -23 -21 -19 -18 -16 
				-14 -12 -11 -9 -7 -5 -3 
				-2 0 2 3 5 7 9 11 12 14 
				16 18 19 21 23 25 27 29 
				31 32 34 36 38 40 42 45 
				47 49 51 53 55 58 60 62 
				65 67 70 73 75 78 81 84 
				87 90 93 97 100 104 107 
				111 115 119 123 128 133 
				138 143 148 154 160 166 
				173 180 188 196 205 214 
				225 236 248 261 275 290 
				308 327 349 373 401 433 
				470 514 567 631 712 814 
				951 1143 1430 1908 2864 
				5729 544374645106512000 
				-5729 -2864 -1908 -1430 
				-1143 -951 -814 -712 -631 
				-567 -514 -470 -433 -401
				-373 -349 -327 -308 -290 
				-275 -261 -248 -236 -225 
				-214 -205 -196 -188 -180 
				-173 -166 -160 -154 -148 
				-143 -138 -133 -128 -123
				-119 -115 -111 -107 -104 
				-100 -97 -93 -90 -87 -84 
				-81 -78 -75 -73 -70 -67 
				-65 -62 -60 -58 -55 -53 
				-51 -49 -47 -45 -42 -40 
				-38 -36 -34 -32 -31 -29 
				-27 -25 -23 -21 -19 -18 
				-16 -14 -12 -11 -9 
				-7 -5 -3 -2 0))
and a helper function to get the inverse functions

Code: Select all

(setq inverseTrig (lambda (number trigList)
	(block (guess bestGuess bestGuessValue)
		(setq bestGuess 0)
		(for guess 0 (count trigList)  
			(if (ls (abs (subtract (item trigList guess) number)) bestGuessValue)
				(block nil
					(setq bestGuessValue (abs (subtract (item trigList guess) number)))
					(setq bestGuess guess)
				)
			)
		)
		bestGuess
	)
))

(setq abs (lambda (number)
	(if (ls number 0)
		(subtract 0 number)
		number
	)
))
Crying is not a proper retort!
User avatar
Atarlost
Fleet Admiral
Fleet Admiral
Posts: 2391
Joined: Tue Aug 26, 2008 12:02 am

syscrerateweaponfire wrapper taking both drift and firing impetus into account. Missilespeed must be passed as an argument because I know of no way to extract it from an item, but apart from the ability to adjust missilespeed this will act exactly like the ship firing the weapon, at least so long as the weapon is forward firing.

Code: Select all

(setq shotmaker (lambda (unid missilespeed ship)
		(block (shot objVel unitvector shotvectorcomponent)

				; store the vector of the ship
				(setq objVel (objGetVel ship))
				; get unit vector
				(setq unitvector (sysvectordivide (sysvectorpolaroffset nil (shpgetdirection ship) 1) 299792))
				; set the vector the shot would receive from thegun
				(setq shotvectorcomponent (sysvectormultiply unitvector missilespeed))
                                ;fire a weapon and save the shot
                                (sysCreateWeaponFire unid ship (objGetPos ship) (sysvectorangle (sysvectoradd objvel shotvectorcomponent)) (sysvectorspeed 

(sysvectoradd shotvectorcomponent objvel))  nil)
                        

                        )
	))
User avatar
Betelgeuse
Fleet Officer
Fleet Officer
Posts: 1920
Joined: Sun Mar 05, 2006 6:31 am

This code returns a random value as determined by the weighted value pairs. This function can mimic any function curve.
Total weight is optional to pass in, it is just the sum of all the weights.
The value pairs do not have to be in any order or continuous but the weights must all be greater than zero.

Code: Select all

			(setq randomSet (lambda (valuePairs totalWeight)
				(block (runningTotal target result position)
					;initializing some variables 
					(setq result nil)
					(setq runningTotal 0)

					(if (not totalWeight)
						(block nil
							(setq totalWeight 0)
							(enum valuePairs pair 
								(setq totalWeight (add totalWeight (item pair 1)))
							)
						)
						;already have a totalWeight
					)

					(setq target (random 0 totalWeight))
					(setq position 0)

					(loop (not result)
						(block nil
							(setq runningTotal (add runningTotal (item (item valuePairs position) 1)))
							(if (geq runningTotal target)
								(setq result (item (item valuePairs position) 0))
							)
							(setq position (add 1 position))
						)
					)
					result
				)
			))
an example of use would be

Code: Select all

(randomSet '((-5 20) (5 5) (24 42)))
That would give you the number 24 back about 63% of the time, 5 back 7.5% of the time, and -5 back about 30% of the time.
Crying is not a proper retort!
User avatar
alterecco
Fleet Officer
Fleet Officer
Posts: 1658
Joined: Wed Jan 14, 2009 3:08 am
Location: Previously enslaved by the Iocrym

A couple of conversion functions I use often. On converts a list of space objects to a list of object id's the other converts a list of object id's to a list of space objects. Very handy for saving lists across sessions.

Code: Select all

;; transform a list of spaceobjects to a list of unique ID's
(setq extLstToID (lambda (lst)
    (block (tmp)
        (setq tmp (list))
        (enum lst el (lnkAppend tmp (objGetID el)))
        tmp
    )
))

;; transform a list of id's back to space o's
(setq extLstFromID (lambda (lst)
    (block (tmp)
        (setq tmp (list))
        (enum lst el (lnkAppend tmp (objGetObjByID el)))
        tmp
    )
))
User avatar
alterecco
Fleet Officer
Fleet Officer
Posts: 1658
Joined: Wed Jan 14, 2009 3:08 am
Location: Previously enslaved by the Iocrym

Here are a couple more functions that go well together. They basically wrap setting and getting data, with a few built in commodities.

All data is stored on the playership to make cross session use easy.

extGetData takes an additional argument which is the default value to return if the key requested is not set.

extSetData takes an optional arguemnt `store' which should be a string. When this argument is provided the key is saved to a list on the ship which itself has the key (cat "extDataStore" store). This means several data stores can be created with little hassle.

The reason for the data store, is to allow easy resetting of data pertaining to a certain mod or functionality. I use it in BattleZone for example, where I need to provide a clean data slate if the player starts a new BattleZone game. Just call (extResetData 'MyStore) and you are good to go.

Code: Select all

(setq extGetData (lambda (key default)
    (block (value)
        (setq value (objGetData gPlayerShip key))
        (if (and (not value) (or default (not (isAtom default))))
            (setq value default)
        )
        value
    )
))

(setq extSetData (lambda (key value store)
    (block Nil
        (objSetData gPlayerShip key value)
        (if store (block (dstore)
            (setq dstore (extGetData (cat "extDataStore" store) (list)))
            (if (not (find dstore key))
                (extSetData (cat "extDataStore" store) (lnkAppend dstore key))
            )
        ))
        value
    )
))

(setq extResetData (lambda (store)
    (block (dstore)
        (setq dstore (extGetData (cat "extDataStore" store) (list)))
        (enum dstore key
            (extSetData key Nil)
        )
        (extSetData (cat "extDataStore" store) Nil)
    )
))
Post Reply