Example mod: Multitargeting Shotgun

This is a moderated forum that collects tutorials, guides, and references for creating Transcendence extensions and scripts.
Post Reply
PM
Fleet Admiral
Fleet Admiral
Posts: 2570
Joined: Wed Sep 01, 2010 12:54 am

This example mod adds a shotgun that acquires a list of targets then fires missiles at up to five targets. The weapon is installed on the playership at the start of a new game. The mod is fully functional and should work after a simple copy-and-paste to a blank xml file.

Made for those who want a weapon like the Dragonfly missile system, but has functional multitargeting.

Code: Select all

<?xml version="1.0" ?>
<!DOCTYPE TranscendenceExtension
[
	<!ENTITY unid912Multitarget	"0xd912fffe">
	<!ENTITY it912Multitarget	"0xd912ffff">
]>

; Made for Transcendence v1.6.2 or later.
<TranscendenceExtension UNID="&unid912Multitarget;"
	apiVersion="28"
	name="Multitargeting Shotgun Tutorial"
	credits="PM"
>

; Since we are using resources from the standard game, we need to include this library!
; Including libraries is the first thing we need to do before anything else in this file.
	<Library unid="&unidHumanSpaceLibrary;"/>

; This weapon is a heavily modified version of the Dragonfly missile system.

; The weapon will be given for free at the start of a game.
; Value will be zero so that the player cannot sell for quick cash.
; We do not want this weapon to appear anywhere else.
; Frequency is notrandom, and attribute includes CannotOrder.

	<ItemType UNID="&it912Multitarget;"
		name=		"multitargeting shotgun"
		attributes=	"cannotOrder, majorItem"
		level=		"5"
		frequency=	"notrandom"
		value=		"0"
		mass=		"2000"
		description=	"This weapon acquires a list of targets then fires up to five seekers at them."
		>

		<Image imageID="&rsItemsEI2;" imageX="96" imageY="288" imageWidth="96" imageHeight="96"/>

		<Weapon
			autoAcquireTarget=	"true"

			type=		"missile"
			damage=		"blast:1d6+1; momentum:1; WMD:3"
			fireRate=	"40"
			missilespeed=	"50"
			lifetime=	"60"
			maneuverRate=	"12"
			powerUse=	"20"
 			sound=		"&snRecoillessCannon;"
			>
			; Fires five times, needed to display (x5) in our stats.
			<Configuration aimTolerance="5">
				<Shot/> <Shot/> <Shot/> <Shot/> <Shot/>
			</Configuration>

			; Our missile appears as defined here.
			<Effect>
				<ParticleJet    fixedPos="true"  emitRate="20"  tangentSpeed="3d3-2"  particleLifetime="3-9"  XformTime="10">
					<ParticleEffect>  <Particle    style="plain"  minWidth="1"  maxWidth="3"  primaryColor="#effeff"  secondaryColor="#5b777a"/>
				</ParticleEffect>  </ParticleJet>

				<Ray    style="smooth"  shape="diamond"  primaryColor="#feffa1"  secondaryColor="#f76e24" length="30" width="12" intensity="30"/>
			</Effect>
		</Weapon>

		<Events>
		; Called every time we fire our weapon.
			<OnFireWeapon>
				(block (shotCount)
					; If not used previously, this will probably be Nil.
					(setq shotCount (objGetData gSource "d912_Count"))

					; ...if so, make it zero!
					(if (not shotCount)  (setq shotCount 0))

					; Increment for the next shot in configuration, or roll over to zero after the fifth shot.
					(objSetData gSource "d912_Count" (modulo (add shotCount 1) 5) )

					; Check if we should fire our salvo.
					(if (eq shotCount 0)
						; YES:  Fire all missiles.  This happens at configuration's first shot.
						(block (shotType  theAttacker  allTargets theSpeed objVel angleList missiles maxIndex)
							; Remember who is the attacker.  Here gSource is the attacker.
							(setq theAttacker gSource)

							; We will use this weapon's stats.
							(setq shotType aWeaponType)

							; Get our list of targets.
							(if (and (eq gSource gPlayerShip) (objGetTarget gSource))
								; YES:  Playership may focus-fire all missiles at selected target.
								;  We do this by putting only the selected target on the list.
								(setq allTargets (list (objGetTarget gSource)))

								; NO:  Find all nearby targets.
								(block (theTarget)
									; Our maximum missile range is 60.  Look for enemies up to range 50.
									; We filter our list because there is a bug that includes miners as enemies
									; even if they do not appear to be angry.
									(setq allTargets (filter
										(sysFindObject gSource "s T A N:50 P S:d;")
										thisOne
										(or	(objIsEnemy theAttacker thisOne)
											(and (objIsAngryAt thisOne theAttacker) (neq (shpGetOrder thisOne) 'mine))
										)
									))
									; Move primary target to the head of the hitlist.
									(if (setq theTarget aTargetObj)
										(setq allTargets (append
											(list theTarget)
											(filter	allTargets thisTarget (neq thisTarget theTarget))
										))
									)
								)
							)

							; Lookup missile speed once for reference so we don't need to do it each time we loop below.
							(setq theSpeed (typGetProperty aWeaponType "speed"))

							; Ditto for velocity.
							(setq objVel (objGetVel gSource))

							; List of angles, missiles begin at the center, then left, right, left, and right.
							(setq angleList (list 0 15 345 30 330))

							; Maximum number of shots per salvo.
							(setq missiles (count angleList))

							; We need this to ascend 'angleList' instead of descending it.
							(setq maxIndex (subtract missiles 1))

							; Launch all missiles.
							(loop (gr missiles 0)
								(if allTargets
									; YES:  Fire at our targets!
									; We fire at least one missile, possibly up to the maximum of five, here!
									; enumwhile ends when we use all targets or missiles, whichever comes first.
									(enumwhile allTargets (gr missiles 0) who
										(block (theFireAngle)
											; Advance missile loop.
											(setq missiles (subtract missiles 1))

											; Get direction to aim at.
											(setq theFireAngle (modulo 'degrees (add (@ angleList (subtract maxIndex missiles)) aFireAngle) 360) )

											; Fire one missile at our target.  Remember to inherit attacker's velocity.
											(objIncVel (sysCreateWeaponFire shotType gSource aFirePos theFireAngle theSpeed who Nil aWeaponBonus) objVel)
										)
									)
									; NO:  No targets, fire one missile.
									(block (theFireAngle)
										; Comments above apply here too.
										(setq missiles (subtract missiles 1))

										(setq theFireAngle (modulo 'degrees (add (@ angleList (subtract maxIndex missiles)) aFireAngle) 360) )

										(objIncVel (sysCreateWeaponFire shotType gSource aFirePos theFireAngle theSpeed aTargetObj Nil aWeaponBonus) objVel)
									)
								)
							)
						)
						; NO:  Do nothing now.  This is configuration's shot two, three, four, and five!
					)

					; Either fired all missiles already or did nothing above, so return not-Nil.
					0
				)
			</OnFireWeapon>

		; Called when we start a new game, after ship select.
			<OnGlobalUniverseCreated>
				(block (newItem)
				; Create our gift.
					(setq newItem (itmCreate &it912Multitarget; 1))
				; Add the new weapon to ship's cargo hold.
					(objAddItem gPlayerShip newItem)
				; Install the weapon.
					(shpInstallDevice gPlayerShip newItem)
				)
			</OnGlobalUniverseCreated>
		</Events>
	</ItemType>

</TranscendenceExtension>
Download and Play in 1.9 beta 1...
Drake Technologies (Alpha): More hardware for combat in parts 1 and 2!
Star Castle Arcade: Play a classic arcade game adventure, with or without more features (like powerups)!
Playership Drones: Buy or restore exotic ships to command!

Other playable mods from 1.8 and 1.7, waiting to be updated...
Godmode v3 (WIP): Dev/cheat tool compatible with D&O parts 1 or 2.
Post Reply