Modding Transcendence:Firing 4 projectiles, into one target

Freeform discussion about anything related to modding Transcendence.
Post Reply
Novak 67
Miner
Miner
Posts: 40
Joined: Wed Mar 11, 2015 1:46 pm
Location: Training himself to create better mods

The only purpose is this: Getting the right code for making a weapon, the "exclusion"

Since I do not have any experience on Globals and all of those complicated modding I can not do anything in that angle.

Currently I am Create this:

Code: Select all

<ItemType UNID="&itExclusion;"
 
 	   attributes=			"commonwealth, majorItem, kabuto, speciality, energyWeapon"

		name=				"[weapon(s)] named "Exclusion""
		level=				"1"
		frequency=			"common"

		value=				"1"
		mass=				"12000"
				  
		description=		"This weapon fires 4 independantly directed ion beams that fire in a expanding formation,"
  		>
    
		<Image	
			imageID=		"&rsItems8;"
			imageX=			"0"	
			imageY=			"96"	
			imageWidth=		"96"	
			imageHeight=	"96"
			/>
 
		<Weapon
			type=				"beam"

			omnidirectional=	"true"
			multiTarget="true"
			damage=				"ion:5d2"
			fireRate=			"5"
			lifetime=			"20"
			powerUse=			"350"
			missilespeed=		"100"
			
			sortName=			"exclusion"

			sound=				"&snLaserCannon;"
			>
			<Effect>
				<Ray
					style=			"jagged"
					shape=			"oval"
					intensity=		"100"
					length=			"50"  
					width=			"10"
					primaryColor=	"#00ffff"
					secondaryColor=	"#00ffff"
					/>
			</Effect>
			
			<Configuration aimTolerance="5">
				<Shot/> <Shot/> <Shot/> <Shot/>
			</Configuration>
			
		</Weapon>                      
	</Itemtype>
So for this weapon I need:
Each shot separated into angles of 90º each (90º, -90º, 135º, -135º)
Each shot can aim independently, and if there is only one target, all four shots focus to that target and if there is 2 targets, two of the shots go to one and the other two another target, if 3, the nearest target will get 2 and the others 1 and for four, each 1 shot will attack the four targets.
The weapon does not shoot when there is no target to be shot.
User avatar
digdug
Fleet Admiral
Fleet Admiral
Posts: 2620
Joined: Mon Oct 29, 2007 9:23 pm
Location: Decoding hieroglyphics on Tan-Ru-Dorem

this is old old, but still useful.
http://xelerus.de/index.php?s=mod&id=61

you can have a look at that as examples, and it will be easy to make a 4 spread weapon configuration.

Try this for example (that is included in that mod file):

<!-- 4-way Shot / xshot -->
<Configuration aimTolerance="5">
<Shot posAngle="0" posRadius="0" angle="-45"/>
<Shot posAngle="0" posRadius="0" angle="45"/>
<Shot posAngle="0" posRadius="0" angle="-135"/>
<Shot posAngle="0" posRadius="0" angle="135"/>

</Configuration>
Novak 67
Miner
Miner
Posts: 40
Joined: Wed Mar 11, 2015 1:46 pm
Location: Training himself to create better mods

digdug wrote:this is old old, but still useful.
http://xelerus.de/index.php?s=mod&id=61

you can have a look at that as examples, and it will be easy to make a 4 spread weapon configuration.

Try this for example (that is included in that mod file):

<!-- 4-way Shot / xshot -->
<Configuration aimTolerance="5">
<Shot posAngle="0" posRadius="0" angle="-45"/>
<Shot posAngle="0" posRadius="0" angle="45"/>
<Shot posAngle="0" posRadius="0" angle="-135"/>
<Shot posAngle="0" posRadius="0" angle="135"/>

</Configuration>
Thanks for your help, but unfortunately it was not really that useful since I want the weapon to fire 4 shots that can focus to one target like four ion omnidirectional turrets that is focused into one target.

but fortunately, I managed to reverse-engineer PM's Drake technologies DDT weapons. Now I just need to remove the useless globals that does nothing to the mod and get the useful ones that makes the weapon fire into four omnidirectional ion blasters so it can focus to one target and add like a part when the weapon is out of range to any target (in 30 ticks) to stop shooting.

the code is here.

Code: Select all

<?xml version="1.0" encoding="utf-8"?>

<!DOCTYPE TranscendenceExtension
[
	
<!--My UNID System: 0x UNID T N S I (do not count spaces)
UNID= Your UNID
T= Type of UNID
N= Mod number
S=UNID Catagory no.
I=UNID number of mod
-->

<!--======================================================================================-->
	<!--<!--NOTES-->
	
	-->
	<!--<!--TO DO LIST-->
	
	-->
<!--======================================================================================-->	
	<!--MOD UNID-->

	<!ENTITY unidTCP					"0xD0674301">
	
<!--======================================================================================-->
	<!--WEAPON UNIDS-->
	
	<!--Attack weapons-->
	<!ENTITY itPiscesLightIon5			"0xD0674300">	
<!--======================================================================================-->
	<!--EFFECTS UNIDS-->
	

	
	<!--Sounds-->
	
	]>

<TranscendenceExtension UNID="&unidTCP;"
 apiversion="25"
 name="The Covenant Project"
 credits="Novak 67 (Code) PM (Template Code)"	
>
	<Globals>
		(block Nil
			; This function will be a global after I add more phaser style weapons.
			(setq drak912PhasersOnFire (lambda (typeList)
				(block (allTargets thisWay shotType oneShot maxShots finalList focusFire theTarget lo hi misFire)
				; Checks if an angle is within a firearc.
					(setq inArc (lambda (thisWay lo hi)
						(block (angDiff inSide)
							(setq angleDifference (lambda (theta)
								(modulo	'degrees
									(subtract theta (if (objIsShip gSource) (shpGetDirection gSource) 0))
									360
								)
							))

							(setq angDiff (angleDifference thisWay))

							(setq inSide (switch
								(eq lo 'omnidirectional)
									True
								(ls lo hi)
									(if (and (geq angDiff lo) (ls angDiff hi)) True Nil)
								(gr lo hi)
									(if (or (geq angDiff lo) (ls angDiff hi)) True Nil)
								(if (eq angDiff lo) True Nil)
							))
						)
					))

					(setq lo (@ (objGetItemProperty gSource gItem 'fireArc) 0))
					(setq hi (@ (objGetItemProperty gSource gItem 'fireArc) 1))

				; Check given data.
					(setq maxRange (typGetDataField aWeaponType "range"))
					(if (not typeList) (setq typeList (list aWeaponType)))

					(setq oneShot (@ typeList 0))
					(setq maxShots (count typeList))

					(setq misFire
						(if	(and	(eq (random 0 1) 0)
								(or (itmGetProperty gItem 'damaged) (itmGetProperty gItem 'disrupted))
							)
							; YES:  Distortion
							True
							; NO:  Normal aim
							Nil
						)
					)

				; Check for focus-fire mode.
					(if (and (eq gSource gPlayerShip) (setq theTarget (objGetTarget gPlayerShip)) )
						; YES:  Playership with target.
						(if (typHasAttribute aWeaponType "auxMountDevice")
							; YES:  Side gun with fire arc.
							(block Nil
								(setq thisWay (sysCalcFireSolution
									(sysVectorSubtract (objGetPos theTarget) aFirePos)
									(sysVectorSubtract (objGetVel theTarget) (objGetVel gSource))
									100
								))
								(setq focusFire (inArc thisWay lo hi))
							)
							; NO:  Main gun, always focus.
							(setq focusFire True)
						)
						; NO:  Attacker is either PC without target or NPC.
						(setq focusFire Nil)
					)

				; Acquire all targets.
					(if focusFire
						; YES:  Focus on one target, the default, which will be appended later.
						(setq allTargets Nil)

						; NO:  No target, get all targets.
						(block (allShips allStations)
							; Omni weapons have a default targeting range of 30.
							; Get all enemies and anyone angry at target.
							; Closer targets within the same class get higher priority.
							(setq allShips (filter
								(sysFindObject gSource (cat "s A N:" (min 30 maxRange) " P S:d;"))
								thisOne
								(or (objIsEnemy gSource thisOne) (and (objIsAngryAt thisOne gSource) (neq (shpGetOrder thisOne) 'mine)) )
							))
							(setq allStations (filter
								(sysFindObject gSource (cat "T A N:" (min 30 maxRange) " P S:d;"))
								thisOne
								(or (objIsEnemy gSource thisOne) (objIsAngryAt thisOne gSource))
							))
							; Ships have first priority because beams do not have WMD.
							; Stations are last.
							(setq allTargets (append allShips allStations))
						)
					)

					(if aTargetObj
						; YES:  Move primary target to top of the list.
						(setq allTargets (append
							(list aTargetObj)
							(filter	allTargets
								thisTarget
								(neq thisTarget aTargetObj)
							)
						))
						; NO:  Nothing more.
					)

				; Initialize final target list with default data.
					(setq finalList Nil)
					(enum allTargets thisOne
						(if	(and	(or	(not finalList)
									(ls (count finalList) maxShots)
								)
								(setq thisWay (sysCalcFireSolution
									(sysVectorSubtract (objGetPos thisOne) aFirePos)
									(sysVectorSubtract (objGetVel thisOne) (objGetVel gSource))
									100
								))
							)
							; YES:  Can aim at target.
							(block (unUsed)
								(setq unUsed True)
								(enum finalList thisOne
									(if (eq (@ thisOne 0) thisWay) (setq unUsed Nil))
								)
								(if (and unUsed (inArc thisWay lo hi))
									; YES:  Angle not used yet.
									(block (criteria firstTarget)
										(setq criteria (cat
											"s T A I:"
											thisWay
											" N:"
											maxRange
											" P S:d;"
										))

										; Scan for targets in the line-of-fire and grab the first one.
										(setq firstTarget (@ (sysFindObject gSource criteria) 0))

										; Check our target, if any.
										(if	(or	(not firstTarget)
												(objIsEnemy gSource firstTarget)
												(and (objIsAngryAt firstTarget gSource) (neq (shpGetOrder firstTarget) 'mine))
											)
											; YES:  Add target to the list.
											(block Nil
												(if misFire
													(setq thisWay (modulo 'degrees (add (random -60 60) thisWay) 360) )
												)
												(setq finalList (lnkAppend finalList (list thisWay thisOne)))
											)

											; NO:  Reject due to probable friendly fire.
										)
									)
									; NO:  Already aiming another shot this way.
								)
							)
							; NO:  No aim solution or got enough targets, pass this target.
						)
					)

					; Fire our guns!
					; Determine power based on number of targets.
					(switch
						(and finalList (setq shotType (@ typeList (subtract (count finalList) 1))) )
							; Got things to kill!
							(block Nil
								; Shoot a beam at each target on the list.
								(enum finalList theData
									; Fire a beam to all targets.
									(objIncVel
										(sysCreateWeaponFire shotType gSource aFirePos (@ theData 0) 100 (@ theData 1) Nil aWeaponBonus)
										(objGetVel gSource)
									)
								)
								; Fired our guns, so return not-Nil to bypass default attack.
								0
							)

						; From this point on, we have nothing to shoot at.  Check default firing.
						(typHasAttribute aWeaponType "auxMountDevice")
							; Side-mounted Phasers need special attention.
							(block (theFireAngle)
								(setq theFireAngle (if (objIsShip gSource) (shpGetDirection gSource) 0) )
								(if misFire
									(setq theFireAngle (modulo 'degrees (add (random -60 60) theFireAngle) 360) )
								)
								(objIncVel
									(sysCreateWeaponFire oneShot gSource aFirePos theFireAngle 100 aTargetObj Nil aWeaponBonus)
									(objGetVel gSource)
								)
								; Fired our guns, so return not-Nil to bypass default attack.
								0
							)

						(neq aWeaponType oneShot)
							; Using a substitute beam type.
							(block Nil
								(objIncVel
									(sysCreateWeaponFire oneShot gSource aFirePos aFireAngle 100 aTargetObj Nil aWeaponBonus)
									(objGetVel gSource)
								)
								; Fired our guns, so return not-Nil to bypass default attack.
								0
							)

						; Use default attack.
						Nil
					)
				)
			))

		;- - - - - - - - - -
		; Update 9/5/2014:  Update for new Duplex/DDT weapons.
			(setq drak912VectorPolarPixelOffset (lambda (theCenter theAngle thePixels)
				; range 1 = 24 pixels.
				(sysVectorAdd theCenter (sysVectorDivide
					(sysVectorSubtract (sysVectorPolarOffset theCenter theAngle thePixels) theCenter)
					24
				))
			))

			(setq drak912OnFireTargetAngle (lambda Nil
				(modulo	'degrees
					(subtract (sysVectorAngle (objGetPos aTargetObj) aFirePos) (objGetProperty gSource 'rotation) )
					360
				)
			))

			(setq drak912InArc (lambda (theAngle lo hi addAngle)
				(block Nil
					(if addAngle
						(block Nil
							(setq lo (modulo 'degrees (add lo addAngle) 360))
							(setq hi (modulo 'degrees (add hi addAngle) 360))
						)
					)
					(switch
						(ls lo hi)
							(if (and (geq theAngle lo) (leq theAngle hi))  True Nil)
						(gr lo hi)
							(if (or (geq theAngle hi) (leq theAngle lo))  True Nil)
						(if (eq theAngle lo) True Nil)
					)
				)
			))

			(setq drak912MultiTargetWeapon (lambda (allPos theWeaponType)
				(block (offSet  centerAngle  theAngle theVel maxRange  posList  forceFire  theTarget allTargets )
					; If the weapon is broken, distort aim half of the time.
					(setq offSet
						(if	(and	(eq (random 0 1) 0)
								(or (itmGetProperty gItem 'damaged) (itmGetProperty gItem 'disrupted))
							)
							; YES:  Distortion
							(random -60 60)

							; NO:  Normal aim
							0
						)
					)

					(setq centerAngle (@ (objGetItemProperty gSource gItem 'pos) 0))
					(if (not centerAngle) (setq centerAngle 0))

					(if (not allPos)
						; YES:  Make our default position list.  It has two points,
						;  and the first one varies by target position.  The closer
						;  of the two gets priority.
						(setq allPos (if (drak912InArc (drak912OnFireTargetAngle) 0 179 centerAngle)
							; YES:  Primary target is to the left.
							(list (list 90 12) (list 270 12) )
							(list (list 270 12) (list 90 12) )

							; NO:  Primary target is to the right.
							(list (list 270 12) (list 90 12) )
							(list (list 90 12) (list 180 12) )
						))

						; NO:  Use the list that was passed.
					)
					(if (not theWeaponType)  (setq theWeaponType aWeaponType))
					<!-- (if (not w2Type)  (setq w2Type theWeaponType)) -->

					(setq maxRange (typGetDataField theWeaponType "range"))

					(setq theVel (objGetVel gSource))
					(setq theAngle (add (objGetProperty gSource 'rotation) centerAngle))

					(setq posList Nil)
					(enum allPos thisPos
						(setq posList (lnkAppend posList
							(list	(drak912VectorPolarPixelOffset aFirePos
									(modulo	'degrees
										(add theAngle (@ thisPos 0))
										360
									)
									(@ thisPos 1)
								)
								(if (@ thisPos 2)  (@ thisPos 2) 0)
							)
						))
					)

					(setq forceFire True)

					(if (and (eq gSource gPlayerShip) (setq theTarget (objGetTarget gPlayerShip)) )
						; YES:  Only shoot at the selected target.
						(setq allTargets (list theTarget))

						; NO:  Find some targets!
						(block (allShips allStations)
							; Helper function to sort by degrees of separation between firing angle and angle toward target.
							(setq sort912ByYaw (lambda (oldList maxAngle)
								(block (swapList newList)
									(if (not maxAngle)  (setq maxAngle 180))

									; Resort based on degrees of separation between target and line-of-fire.
									(setq newList (setq swapList Nil))
									(enum oldList thisOne (block Nil
										(setq swapList (lnkAppend swapList (list
											; NOTE: aFireAngle only works if no target was auto-aimed at.
											thisOne
											(abs (subtract
												180
												(modulo 'degrees (subtract aFireAngle (sysVectorAngle aFirePos (objGetPos thisOne)) ) 360)
											))
										)))
									))
									(setq swapList (sort swapList 'ascending 1))

									; Reconstruct list by degrees of separation between target and line-of-fire.
									; If maxAngle is low enough, we filter out some items.
									(enum swapList thisOne (block Nil
										(if (leq (@ thisOne 1) maxAngle)
											(setq newList (lnkAppend newList (@ thisOne 0)))
										)
									))

									; Normally, return new sorted list, but if filter rejected all, return original list.
									(if newList  newList oldList)
								)
							))

							(setq forceFire Nil)

							; Omni weapons have a default targeting range of 30.
							; Get all enemies and anyone angry at target.
							; Closer targets within the same class get higher priority.
							(setq allShips (filter
								(sysFindObject gSource (cat "s A N:" (min 30 maxRange) " P S:d;"))
								thisOne
								(or (objIsEnemy gSource thisOne) (and (objIsAngryAt thisOne gSource) (neq (shpGetOrder thisOne) 'mine)) )
							))
							(setq allStations (filter
								(sysFindObject gSource (cat "T A N:" (min 30 maxRange) " P S:d;"))
								thisOne
								(or (objIsEnemy gSource thisOne) (objIsAngryAt thisOne gSource))
							))

							; Ships have first priority because beams do not have WMD.
							; Stations are last
							(setq allTargets (append allShips allStations))

							(if aTargetObj
								; YES:  Move primary target to top of the list.
								(setq allTargets (append
									(list aTargetObj)
									(filter allTargets thisTarget (neq thisTarget aTargetObj) )
								))
								; NO:  No change.
							)

							(if	(and	(not allTargets)
									(or	(typHasAttribute theWeaponType "MiningEquipment")
										(typHasAttribute theWeaponType "MinerGear")
									)
								)
								; YES:  Check for asteroids to shoot at, if no high priority targets.
								(block (allRocks allLodes swapList)
									; All asteroids.
									(setq allRocks (sysFindObject gSource (cat "t +asteroid; N:" (min 30 maxRange) " S:d;")) )

									; Re-sort list and favor rocks infront of the weapon.
									; NOTE:  We have no targets or else we would fire at them instead.
									(setq allRocks (sort912ByYaw allRocks 60))

									; Search for ore among the rocks to be shot at, and shoot only them if found.
									(setq allLodes Nil)
									(for i 0 (subtract (count allPos) 1)
										(block (thisRock)
											(setq thisRock (@ allRocks i))
											(if (and thisRock (objGetItems thisRock "*U"))
												(setq allLodes (lnkAppend allLodes thisRock))
											)
										)
									)

									(setq allTargets (if allLodes allLodes allRocks))
								)
								; NO:  No more targets!
							)
						)
					)

					(enum posList thisGun (block (fired who thisPos offAngle)
						(setq thisPos (@ thisGun 0))
						(setq offAngle (@ thisGun 1))

						(setq fired Nil)
						(setq who Nil)

						(if allTargets
							(block (thisWay)
								(enum allTargets thisOne
									(if	(and	(not fired)
											(setq thisWay (sysCalcFireSolution
												(sysVectorSubtract (objGetPos thisOne) thisPos)
												(sysVectorSubtract (objGetVel thisOne) theVel)
												100
											))
										)
										(block (criteria firstTarget)
											(setq criteria (cat
												"s T A I:"
												thisWay
												" N:"
												maxRange
												" P S:d;"
											))

											; Scan for targets in the line-of-fire and grab the first one.
											(setq firstTarget (@ (sysFindObject gSource criteria) 0))

											; Check our target, if any.
											(if	(or	forceFire
													(not firstTarget)
													(objIsEnemy gSource firstTarget)
													(and (objIsAngryAt firstTarget gSource) (neq (shpGetOrder firstTarget) 'mine))
												)
												; YES:  Fire!
												(block Nil
													(setq fired (modulo 'degrees (add thisWay offSet) 360))
													(setq who thisOne)
												)
											)
										)
									)
								)
								(if (and who (gr (count allTargets) 1) )
									; YES:  Move current target to the end of the list, so followup shots target it last.
									(setq allTargets (lnkAppend
										(filter allTargets thisTarget (neq thisTarget who) )
										who
									))
									; NO:  Leave the list alone.
								)
							)
						)

						(if (not fired)
							(setq fired (modulo 'degrees (add aFireAngle offAngle) 360))
						)

						(objIncVel
							(sysCreateWeaponFire theWeaponType gSource thisPos fired 100 aTargetObj Nil aWeaponBonus)
							theVel
						)

						<!-- (setq theWeaponType w2Type) -->
					))

					; Fired already, return non-Nil.
					0
				)
			))
;- - - - - - - - - -
		)
	</Globals>
	
	<ItemType UNID="&itPiscesLightIon5;"
		name=		"weapon(s) named "exclusion""
		attributes=	"commonwealth, energyWeapon, majorItem"
		level=		"1"
		frequency=	"common"
		value=		"1"
		mass=		"1"
		description=	"This weapon fires 4 independantly directed ion beams that fire in a expanding formation."
		>

		<Image imageID="&rsItems1;" imageX="96" imageY="0" imageWidth="96" imageHeight="96"/>

		<Weapon
			type=		"beam"
			omnidirectional="true"
			damage=		"ion:1d6+1"
			fireRate=	"5"
			lifetime=	"20"
			powerUse=	"750"
			effect=		"&efIonBeamDefault;"
			sound=		"&snLaserCannon;"
			>

			; Fires 4 times!
			<Configuration>
				<Shot/> <Shot/> <Shot/> <Shot/>
			</Configuration>
		</Weapon>

			<Events>
			<OnFireWeapon>
				(block (theCharges)
					(setq theCharges (itmGetProperty gItem 'charges))
					(setq gItem (objSetItemProperty gSource gItem 'charges
						(modulo (add theCharges 1) 3)
					))
					(if (eq theCharges 0)
						(block (centerAngle diff allPos)
							(setq centerAngle (@ (objGetItemProperty gSource gItem 'pos) 0))
							(if (not centerAngle) (setq centerAngle 0))

							(setq diff (drak912OnFireTargetAngle))

							(setq allPos (switch
								; Left to right.
								(drak912InArc diff 0 179 centerAngle)
									(list (list 135 12 135) (list 45 12 45) (list 225 12 225) (list 315 12 315))
								; Right to left.
								(drak912InArc diff 180 359 centerAngle)
									(list (list 315 12 315) (list 225 12 225) (list 45 12 45) (list 135 12 135) )
								; upper left, left, upper right, right.
								(list (list 45 12 45) (list 135 12 135) (list 315 12 315) (list 225 12 225))
							))

							(drak912MultiTargetWeapon allPos)
						)

						; Return not-Nil to override default attack.
						0
					)
				)
			</OnFireWeapon>

			<OnInstall>
				; Make sure charges are reset so that firing occurs in the proper order.
				(setq gItem (objSetItemProperty gSource gItem 'charges 0))
			</OnInstall>

			<OnUninstall>
				; Remove all charges to let items stack.
				(setq gItem (objSetItemProperty gSource gItem 'charges 0))
			</OnUninstall>
		</Events>
	</ItemType>
</TranscendenceExtension>
Post Reply