Example mod: Hitscan Beam Weapon

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 hitscan beam weapon. 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.

It is a modified and simplified version of the Beamers from my Drake Technologies mod.

Code: Select all

<?xml version="1.0" ?>
<!DOCTYPE TranscendenceExtension
[
	<!ENTITY unid912Hitscan		"0xd912ffe0">

	<!ENTITY ef912Null		"0xd912ffe1">
	<!ENTITY ef912RedLaser		"0xd912ffe2">

	<!ENTITY vt912HiddenLaser	"0xd912ffe3">
	<!ENTITY vt912VisibleLaser	"0xd912ffe4">
	<!ENTITY vt912FakeHiddenLaser	"0xd912ffe5">
	<!ENTITY vt912FakeVisibleLaser	"0xd912ffe6">

	<!ENTITY it912Hitscan		"0xd912ffe7">
]>

; Made for Transcendence v1.6.2 or later.
<TranscendenceExtension UNID="&unid912Hitscan;"
	apiVersion="28"
	name="Hitscan Beam Weapon 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;"/>


;- - - - - - - - - -
; These are effects our beams will reference.
;- - - - - - - - - -
	<Effect UNID="&ef912Null;"> <Null/> </Effect>

	<Effect UNID="&ef912RedLaser;">
		<Ray  style="smooth"  shape="oval"  primaryColor="#ff0000"  secondaryColor="#800000"  length="60"  width="12"  intensity="35" />
	</Effect>


;- - - - - - - - - -
; Our weapon's OnFireWeapon event will reference these types as a base for the beam segments that will be created.
; Each beam segment should last for one tick only.  However, we do not use lifetime of 1 because such shots
; usually disappear as quickly as they are spawned.  We use lifetime of 2 instead for all of them to make
; sure our beam segments persist for one tick.
;- - - - - - - - - -
	<ItemType  UNID="&vt912HiddenLaser;"   virtual="true" >
		<Weapon  type="beam"  damage="laser:1d4"  lifetime="2"  effect="&ef912Null;" />
	</ItemType>

	<ItemType  UNID="&vt912VisibleLaser;"  virtual="true" >
		; NOTE: 'passthrough' is 1 because non-zero passthrough causes beam to be drawn over any object it touches.
		;  1% chance of passthrough is a negligable chance for extra accidental damage.  This is acceptable.
		<Weapon  type="beam"  damage="laser:1d4"  lifetime="2"  passthrough="1"  effect="&ef912RedLaser;" />
	</ItemType>

	;- - - - - - - - - -
	; These next two have no***Hits, which prevents these types from hitting anything except other missiles.
	; Ideally, these should be effects, not weapon types, but some effects do not support things a weapon type can.
	; In other words, they are glorifed effects that have the side-effect of hitting and damaging other missiles.
	; Aside from no***Hits and a different UNID, these two types mirror the previous two types above.
	;- - - - - - - - - -
	<ItemType  UNID="&vt912FakeHiddenLaser;"   virtual="true" >
		<Weapon	type="beam"  damage="laser:1d4"  lifetime="2"  effect="&ef912Null;"
			noImmobileHits="true"  noImmutableHits="true"  noShipHits="true"  noStationHits="true"  noWorldHits="true" />
	</ItemType>

	<ItemType  UNID="&vt912FakeVisibleLaser;"  virtual="true" >
		<Weapon	type="beam"  damage="laser:1d4"  lifetime="2"  passthrough="1"  effect="&ef912RedLaser;"
			noImmobileHits="true"  noImmutableHits="true"  noShipHits="true"  noStationHits="true"  noWorldHits="true" />
	</ItemType>


; 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="&it912Hitscan;"
		name=		"hitscan laser cannon"
		attributes=	"cannotOrder, energyWeapon, majorItem"
		level=		"2"
		frequency=	"notrandom"
		value=		"0"
		mass=		"1000"
		description=	"This weapon fires an FTL beam that simulates a laser in every way except speed."
		>

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

	;- - - - - - - - - -
	; NOTES!
	;--------
	; Without repeating, our beams last two frames or ticks at most.
	; Use 'type' missile because we need to use missilespeed other than 100.
	; 'damage' is used mainly for stats.  Also used to calculate damage to attack in case of misfire, or to suppress in case attacker has Solon shield installed.
	; 'lifetime' is 1 because AI needs this and missileSpeed to calculate aiming solution if an NPC uses any hitscan weapon.
	; 'missileSpeed' is our beam range multiplied by 50.  Since our beams have range 60, the result is 3000.
	;- - - - - - - - - -
		<Weapon
			repeating=	"9"
			type=		"missile"
			damage=		"laser:1d4"
			fireRate=	"60"
			lifetime=	"1"
			missileSpeed=	"3000"
			powerUse=	"30"
			sound=		"&snLaserCannon;"
			>
		</Weapon>

		<Events>
		; Called every time we fire our weapon.
			<OnFireWeapon>
				(block (shotType  theVel  maxRange)
					;- - - - - - - - - -
					; We will create many shots in a loop and add attacker's velocity to all of them!
					; Therefore, called this function once and remember velocity instead of calling
					; the function multiple times in a loop later.
					;- - - - - - - - - -
					(setq theVel (objGetVel gSource))

					; Remember our weapon range, which is missileSpeed divided by 50.
					(setq maxRange (typGetProperty aWeaponType 'range))

					;- - - - - - - - - -
					; Plot a line of points and spawn a beam at each point.  Each point is one light-second apart.
					; Very thin targets may be missed completely.  That is a minor problem, one not worth fretting over.
					; 'i' represents the range each shot will be after they are placed.
					;- - - - - - - - - -
					(for i 0 maxRange
						(if (ls i maxRange)
							; YES:  Draw beam and hit stuff.
							(block (thePos hitList hitScan drawBeam theShotType)
								; Project a point where the beam will spawn.
								(setq thePos (sysVectorPolarOffset aFirePos aFireAngle i))

								; Determine who we can hit at the projected point.
								; We scan for all objects that are ships, stations, planetoids, and the like.
								; We filter the list to include everyone except the attacker
								; because the attacker cannot hit himself and we do not want the
								; the attacker to block the beam.
								(setq hitList
									(filter	(sysFindObjectAtPos gSource "st" thePos)
										who
										(neq who gSource)
									)
								)
								(if hitList
									; YES:  We hit a ship, station, or similar object, and we want to stop the beam.
									;  Block the beam by failing the loop condition for the next iteration.
									(setq maxRange i)

									; NO:  We did not hit anything that should block the beam.
									;  We may have hit nothing, or we may have hit an enemy missile.
								)

								; Get the first object our beam will expect to hit.
								(setq hitScan (@ hitList 0))

								;- - - - - - - - - -
								; Our visible beam effects are drawn from the center to a point
								; about two light-seconds behind the point.  Therefore, the first
								; two shots we draw should be invisible because we do not want
								; a red beam shown sticking out of the rear of our firing point.
								; Remaining beams after the second, those at range 2 or greater,
								; shot will be visible.
								;- - - - - - - - - -
								(setq drawBeam (geq i 2))

								(if hitScan
									; YES:  We hit someone!
									(setq theshotType
										(if drawBeam
											; YES:  Select visible beam.
											&vt912VisibleLaser;

											; NO:  Select invisible beam.
											&vt912HiddenLaser;
										)
									)
									; NO:  We do not expect to hit anyone important this frame or tick.
									(setq theshotType
										;- - - - - - - - - -
										; We select a beam that cannot hit anything except other missiles.
										; We do this because our beams will last two ticks, and we do not want
										; to hit and damage anything significant after this tick.  This would
										; be important for beams with passthrough, which is beyond the scope of
										; this example mod.
										;- - - - - - - - - -
										(if drawBeam
											; YES:  Select visible beam.
											&vt912FakeVisibleLaser;

											; NO:  Select invisible beam.
											&vt912FakeHiddenLaser;
										)
									)
								)

								; Spawn our beam segment here!  Our beams hit instantly, and should have zero speed
								; on their own.  The only velocity our beams should have is the same velocity as the attacker.
								(objIncVel
									(sysCreateWeaponFire theShotType gSource thePos aFireAngle 0 Nil Nil aWeaponBonus)
									theVel
								)
							)
							; NO:  Pass.
						)
					)

					; We spawned our beams already to override normal attack.  Therefore, return not-Nil.
					0
				)
			</OnFireWeapon>

		; Called when we start a new game, after ship select.
			<OnGlobalUniverseCreated>
				(block (newItem)
				; Create our gift.
					(setq newItem (itmCreate &it912Hitscan; 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