Reprogrammed Launchers: experiment in typGetXML + typCreate

A place to discuss mods in development and concepts for new mods.
gunship256
Militia Commander
Militia Commander
Posts: 451
Joined: Sat Jul 25, 2015 11:41 pm
Location: repairing armor

2016 05 01 Reprogrammed Launchers screen shot.JPG
2016 05 01 Reprogrammed Launchers screen shot.JPG (118.12 KiB) Viewed 11636 times
CURRENT VERSION
2016 May 1
0.15 alpha
Reprogrammed Launchers

This mod experiments with combining typGetXML and typCreate to create new devices based on the ones that are already available through extensions and mods. The code has been nearly completely rewritten since 0.10 alpha.

It contains a CPU-driven launcher that can be upgraded during gameplay to fire any missile in the game, including missiles from extensions and mods. The upgrade process works by consuming missiles that are a higher level than the launcher's.

The launcher has three modes: Normal fire, swivel with a 33% speed reduction, and omni with a 50% speed reduction.

This is an alpha release. Any feedback and suggestions are welcomed!


QUESTIONS

* How can I make the mod more balanced?

* How can I improve my dockscreen code?

* So far, I only have one custom ammo item, a thermo EMP missile. I could use suggestions and coding ideas for new missiles.

* Some ideas for missiles:
Missile that can scare targets away (with showy fireworks but no damage?) (see code for Luminous scare cube) Make chance to do this level based
Device disruption missile
Missile that can heal its target
Missile that can enslave enemy ships and turn them into escorts (see code for Luminous tame cube) Make chance to do this level based and possibly based on armor/internal HP damage of the target ship

(EDIT 2016 May 1: Updated the download link for the new alpha and changed the descriptive text in this post accordingly.)
Last edited by gunship256 on Mon May 02, 2016 4:01 am, edited 10 times in total.
gunship256
Militia Commander
Militia Commander
Posts: 451
Joined: Sat Jul 25, 2015 11:41 pm
Location: repairing armor

BALANCE CALCULATIONS

It's overpowered for a launcher to fire all the missiles in the vanilla game. The first and most obvious thing to do was to limit each launcher to a narrow level band of missiles, which I did.

I determined the fire rate of the launcher by taking the geometric average for the fire rate of every missile in the launcher's level band. I included ammo for front-firing weapons, such as the SmartCannon.

For example, I used this calculation for the Pascal launcher, which can launch level 2-4 missiles:

Shots per second = (4*(2^6)*2*(3^2)*6)^(1/11) = 2.5

Interpretation: That's the SmartCannon (4 shots/second), 6 NAMI missiles (2 shots/second), Dragonfly cartridges (2 shots/second), 2 MAG grenades (3 shots/second), and Akan shells (6 shots/second).

I then applied a 29% speed reduction to the launcher, so its final firing rate is 2.5*0.71 = 1.8 shots/second.

The fire rates for the other launchers were similarly calculated.

I arrived at the 29% reduction because that's the amount that would be exactly cancelled out if an Atalanta speed enhacer were installed.

If anyone's interested, PM me, and I'll send you a copy of the spreadsheet I used.

I'm open to raising or lowering the fire rate, as I'm not as experienced at balance as other people on the forums. Give me feedback!
relanat
Militia Captain
Militia Captain
Posts: 941
Joined: Tue Nov 05, 2013 9:56 am

Aw, I couldn't resist having a look any longer.

Great idea. I only got as far as reprogramming the NAMI launcher in a Wolfen and firing a couple of SmartCannon rounds before I dived into the code.

==============================
This is a new topic I was going to put on the forum. Here will do. Might help with the healing missile:

I've seen a couple of posts mentioning how handy it would be to have a weapon that you could fire at ships to heal their armor damage. Useful for autons or drones.
Prophet's TractorBeam mod http://xelerus.de/index.php?s=mod&id=578 has a healing ray repair cannon included. I don't know if it will work, it's for version 1.01. Just letting everyone know it exists.
Quoting from the xelerus webpage: "Also included is the repair cannon, which shoots small nano-colonies that will perform repairs on the most damaged armor segment on the ship that it hits without adding extra hitpoints."

===============================
I've been wanting to know how to 'grey out' dockscreen actions as well.
The relevant function seems to be scrEnableAction which is set to either True (normal appearance) or Nil (grayed out). There is a xelerus function description of this one.

Her's an example from TransGeek's IdentifyBeforeBuyingOrSelling mod.http://xelerus.de/index.php?s=mod&id=1106

If the player can identify the item the scrEnableAction is true, but if not then the second block sets scrEnableAction to Nil and the option is greyed out.

Code: Select all

(if (and (not (itmIsKnown (scrGetItem gScreen)))(geq (objGetBalance gPlayerShip (objGetDefaultCurrency gSource)) (divide (itmGetPrice (scrGetItem gScreen)) 10)) )
	(block nil
	(if (eq (objGetDefaultCurrency gsource) &ecRinEconomy;)
		(setq cost1 (divide (divide (itmGetPrice (scrGetItem gScreen)) 10) 5))
		(setq cost1 (divide (itmGetPrice (scrGetItem gScreen)) 10))
	)
	(scrEnableAction gScreen 'identifyMe  true)
	(scrSetActionLabel gscreen 'identifyMe (cat "Identify this item for "(fmtCurrency (objGetDefaultCurrency gsource) cost1)""))
	)
	(block nil
	(scrEnableAction gScreen 'identifyMe  Nil)
	)								
)
===============================
From the README
To self-identify the ROM, even if not used, try itmSetKnown in with the cancel action. Might work, I don't have the coding knowledge to do more than suggest this (and it may not even be right!)
Edit: Tried it, didn't work or I couldn't make it work.
Version 2: It's possible that the code isn't being told that gItem is the ROM. From looking at the code it might be trying to identify one of the launchers (possibly newLauncher). Dunno how to check this.

===============================
The only idea I have for a missile it to have one create a 'smokescreen'. Sort of a nebula effect in an area that would blind your enemies and/or hide you. It could show up on the LRS as a nebula static effect too.

===============================
And looking through the code in the <OnGlobalUniverseCreated> section, you can replace the whole 'block' with just

Code: Select all

(objAddItem gPlayerShip (itmCreate &itLauncherReprogramROM; 1))
My thinking is that because you don't refer to 'freeROM' anywhere else you don't need to define it here. I tried it and it seems to work.
Edit: unless you can use freeROM to help self-identify it. (I'm getting dizzy working code around in circles, I think I'll go and have a nap :lol:.)

And thanks because I was trying to work out how to put items into ships easily and you have shown me how.
Stupid code. Do what I want, not what I typed in!
gunship256
Militia Commander
Militia Commander
Posts: 451
Joined: Sat Jul 25, 2015 11:41 pm
Location: repairing armor

Thanks for the feedback! It's always appreciated.

Before I forget, I should mention that I've done a disgustingly large amount of work trying to update this mod, and I've run into so many roadblocks that I am hesitant to make even a second alpha release at this point.

I'm trying to use typCreate to create the launcher in-game. In theory, this would offer a lot of benefits, not the least of which would be the ability for the launcher to fire Corporate Command, Eternity Port, and mod missiles. It would also allow the launcher to be re-programmed on the fly to accept a user-defined list of missiles, such as only NotForSale missiles or only non-tracking missiles. To do this, I would need to be able to read the XML of game items in-game.

Other forum members, including Atarlost and Pixelfck, have mentioned this on the forums a number of times, so I think the point might be worth repeating:

It would be very, very helpful to be able to read the XML of any game item, including mod items, while the game is running.

I could use some feedback on where my code is going wrong:

https://forums.kronosaur.com/viewtopic.php?f=5&t=7583

and

https://forums.kronosaur.com/viewtopic.php?f=5&t=7582

I also think that the alpha release I posted earlier is overpowered, especially since the NAMI Heavy only fires at 1.5 shots/second. I nerfed the fire rate of all the launchers but haven't posted another alpha yet for the reasons given above.

Thanks for the link to the mod with the healing item. I remember seeing that mod on Xelerus a while back, but I did some searching and couldn't find it again. Now I have something to work with!

For some reason, the Identify Before Buying and Selling mod is broken for me in 1.7. I can't get it to work at all, although it sort of worked in 1.6 in that I could identify items when selling them but not when buying them. If I get really motivated, I may install the mod and run it on 1.5 to see if I can figure out how it works.
To self-identify the ROM, even if not used, try itmSetKnown in with the cancel action. Might work, I don't have the coding knowledge to do more than suggest this (and it may not even be right!)
Edit: Tried it, didn't work or I couldn't make it work.
Version 2: It's possible that the code isn't being told that gItem is the ROM. From looking at the code it might be trying to identify one of the launchers (possibly newLauncher). Dunno how to check this.


I suspect that the problem is the <Exit/> tag. The ROM identification code works in every context I've tried it except when that tag is involved. When an action item is chosen that leads to an exit, the dockscreen seems to go away immediately, and the code before the <Exit/> tag isn't executed, at least for me. I could get around this problem by identifying the ROM and then bringing the user to a new dockscreen where I can then use the <Exit/> tag, but that seems to me like a worse UI problem than not identifying the ROM at all.

I'm open to suggestions on how to fix the problem!
The only idea I have for a missile it to have one create a 'smokescreen'. Sort of a nebula effect in an area that would blind your enemies and/or hide you. It could show up on the LRS as a nebula static effect too.
This is something I would like too so that I can create a cloaking device for the Defiant. As far as I know, blinding effects don't work on NPCs, and I haven't figured out how to increase the player's stealth, although I haven't tried very hard.

I haven't seen a function that controls a playership's stealth rating. If anyone knows of one, please let me know.

I think I could do it *IF* I could dynamically read the XML for the armor the player has installed. I could then use string functions to add the code necessary to increase the armors' stealth rating, typCreate the new armor, and install the armor on the ship.

Again: It would be really helpful to be able to read XML for items on the fly.
And looking through the code in the <OnGlobalUniverseCreated> section, you can replace the whole 'block' with just

Code: Select all

(objAddItem gPlayerShip (itmCreate &itLauncherReprogramROM; 1))
My thinking is that because you don't refer to 'freeROM' anywhere else you don't need to define it here. I tried it and it seems to work.
That would work too, but after spending some time with PM's code, I think I know why he chooses to put those items on separate lines. For some reason, creating an item, enhancing it, adding the item to the ship's hold, and then installing it seems to work, but creating the item, (EDIT) adding it to the ship's hold, then enhancing it, and then trying to install it doesn't. I have to apply the enhancements before spawning the items for the installation code to work.

Here's an example of what I mean, taken from the Reprogrammable Launchers mod:

Code: Select all

						; Make the new launcher like the old one
						; Similar code at PM's Drake Technologies Alpha (DrakeTech.xml, line 1286ff; accessed 2015 12 26)
						(setq newLauncher (itmSetProperty newLauncher 'damaged damaged))
						(setq newLauncher (itmSetEnhanced newLauncher enhancement))

						; Add the new launcher to the ship's cargo hold
						(objAddItem gSource newLauncher)
						   
						; Install the launcher
						(shpInstallDevice gSource newLauncher)
I suspect that when an item is enhanced, the game deletes the old item and makes a new one and forgets that the new item should be seen as a replacement for the old one.
And thanks because I was trying to work out how to put items into ships easily and you have shown me how.
PM deserves the credit for that, as I figured out how to do it from reading his forum posts!
EDIT: https://forums.kronosaur.com/viewtopic.php?f=8&t=7384
relanat
Militia Captain
Militia Captain
Posts: 941
Joined: Tue Nov 05, 2013 9:56 am

For the Exit/identify problem try (scrExitScreen gScreen 'forceUndock) without the <Exit/>. I copied it from somewhere. I'd never seen <Exit/> before this. Possibly <Exit/> was never meant to be used with code. It may have been designed as a straight 'get back to space' function with nothing able to be added (possibly for use with nested screens but I'm really guessing here).
========================
This is as close as I've got to the compatibility problem with the Identify mod. I think it doesn't work because the game doesn't refer to dsExchangeSell (or Buy) anymore but uses another function (scrShowSellScreen) somehow. I ran out of time to get any further. Info from anyone on how to do this would be great. scrShowSellScreen isn't listed in the 1.7 function list.
This is from StdDockScreens.xml in 1.7a1a Trans_Source

Code: Select all

<!-- Commodities Exchange

		NOTE: Use the scrShowSellScreen function instead of showing
		this screen directly.

		gMargin: This is the discount as a percentage of the item price.
		gMaxPrice: Max price that station will pay for any item.
		gTitle: Title for screen (or Nil for station name)
		
		gResult: Incremented with the total value sold

		-->

	<DockScreen UNID="&dsExchangeSell;"
			name=				"=(if gTitle gTitle (objGetName gSource 0x400))"
			type=				"itemPicker"
			nestedScreen=		"true"
			>
Or much simpler; there are a heap of examples in Trans_Source. Teraton.xml has a simple one. As does StdTypes.xml.
==========================
And thanks for the tip on putting items in the hold before installing them. Noted for future reference.

=======================
With the stealth thing, I vaguely recall DigaRW doing something with stealth in the Semesta Corp mod. Could be worth a look.
Stupid code. Do what I want, not what I typed in!
gunship256
Militia Commander
Militia Commander
Posts: 451
Joined: Sat Jul 25, 2015 11:41 pm
Location: repairing armor

d064_ReprogrammedLaunchers 0.11 alpha.zip
(14.56 KiB) Downloaded 266 times
OK - major overhaul! I've almost completely rewritten the code to use typGetXML and typCreate dynamically generate the launchers, which means that (1) they can now fire missiles from extensions and mods, and (2) they can be upgraded in-game by feeding higher-level missiles to lower-level launchers.

I've also overhauled dockscreens and made everything easier to do. Invoking launchers provides access to upgrade options and swivel and omni settings (at the cost of a lower fire rate when those settings are enabled).

I still haven't fixed the <Exit /> bug, and I still need to gray out unusable dockscreen options. I'll try to hit those on the next pass.

Let me know what else I can do to improve the mod!

---
Major changes:

Rewrote the code from the ground up to use typGetXML + typCreate to import whatever missiles are available from extensions and mods.

Launchers are now upgraded by feeding them missiles one level higher. Once a launcher has been fed 200 missiles, it automatically upgrades by one level and is able to fire missiles at that level.

Missiles that don't have a <Missile type="missile"> element can't be fired by the special launchers. I overwrote the vanilla missiles that don't have that element and put the element in (getting the code from the weapons that fire those missiles).

Came up with equations for value and powerUse based on vanilla launchers at various levels.

All the launchers fire 1.5 shots/second, consistent with the slowest vanilla launcher, the NAMI Heavy.

Added swivel mode, which gives the launcher a 90 degree fire arc and lowers speed by 33%, and omnidirectional mode, which lowers speed by 50%.

Smaller changes:

EMP missile: Changed primary color of the flare effect from 0xff, 0xff, 0xf0 to 0xa0, 0xf0, 0xff. The flare behind the explosion is now a bluish white. I got the color from the EMP cannon.

Changed the EMP missile from NAMI to Rasiermesser to be consistent with the manufacturer of the reprogrammed launchers.

Updated missile code to Transcendence 1.7 alpha 1 to get updated balance and visual effects.
User avatar
digdug
Fleet Admiral
Fleet Admiral
Posts: 2620
Joined: Mon Oct 29, 2007 9:23 pm
Location: Decoding hieroglyphics on Tan-Ru-Dorem

love it.
great use of typCreate to do something new. :D

I think that typCreate has a great potential and we just barely started to take advantage of it ! :)
gunship256
Militia Commander
Militia Commander
Posts: 451
Joined: Sat Jul 25, 2015 11:41 pm
Location: repairing armor

Thanks for the feedback, digdug! I'd like to eventually let the player fabricate custom weapons by mashing vanilla/mod weapons together, so hopefully, this is just a start.

Here's a new alpha for now:
d064_ReprogrammedLaunchers 0.12 alpha.zip
(16.02 KiB) Downloaded 272 times
CHANGES

It was too easy to game the system by upgrading the launcher using cheap missiles. Changed the requirement from 200 missiles to a credit requirement that goes up exponentially with launcher level. About 100 of the more expensive missiles in a level band is enough to upgrade the launcher to that level.

Changed the launcher reprogramming ROM to notrandom and changed the code to provide the player with the level 1 launcher instead of the ROM at the beginning of the game. The launcher isn't too expensive and is crippled until it's upgraded, so it's not that much better than getting the ROM.

Fixed a bug where the launcher's swivel/omni fire arc were not transferring to the new launcher upon an upgrade. Added code to save the fire arc and then write it to the new launcher.

Tried unsuccessfully to change the "Use Ammo" action to use scrAddAction, which would allow the action to be grayed out if no ammo is available to use. Unfortunately, several functions do not seem to function properly inside the (block) part of scrAddAction. I made notes in the 2016 03 31 development versions of the code that I can forward to anyone interested. Here's a brief summary: For some reason, objRemoveItem and typDynamicUNID don't function properly within the block area of scrAddAction. objRemoveItem removes items but keeps all the code after it from executing. typDymanicUNID does not seem to create valid UNIDs.
relanat
Militia Captain
Militia Captain
Posts: 941
Joined: Tue Nov 05, 2013 9:56 am

gunship256 wrote:Unfortunately, several functions do not seem to function properly inside the (block) part of scrAddAction. I made notes in the 2016 03 31 development versions of the code that I can forward to anyone interested. Here's a brief summary: For some reason, objRemoveItem and typDynamicUNID don't function properly within the block area of scrAddAction. objRemoveItem removes items but keeps all the code after it from executing. typDymanicUNID does not seem to create valid UNIDs.
Yep, this is annoying me a great deal too. Try using objFireItemEvent in the scrAddAction block area and putting the code below it in an <OtherCode> </OtherCode> block. With objFireItemEvent you have to specify the item in this form, &unidWhatever;, that's the only way I've got it to work so far.

And I'm interested in any notes you've got on this, thanks.
Stupid code. Do what I want, not what I typed in!
gunship256
Militia Commander
Militia Commander
Posts: 451
Joined: Sat Jul 25, 2015 11:41 pm
Location: repairing armor

relanat wrote:Yep, this is annoying me a great deal too. Try using objFireItemEvent in the scrAddAction block area and putting the code below it in an <OtherCode> </OtherCode> block. With objFireItemEvent you have to specify the item in this form, &unidWhatever;, that's the only way I've got it to work so far.

And I'm interested in any notes you've got on this, thanks.
Thanks for the suggestion! I'm trying to figure out what you mean. Should I fire an event and then use <Events> to execute the code that would have gone into the scrAddAction (block)?

Something I have not tried yet: moving the (block) code into a separate function and calling the function from scrAddAction (block).

I've since found another way to gray out dockscreen actions without using scrAddAction. It's possible to add an id="..." attribute to an <Action> tag, which allows that action to be grayed out. Here's an example from a new mod I started on this weekend:

Code: Select all

          <Action name="Disassemble Weapon" id="disassembleWeapon" imageID="&rsItemListScreen;" imageIndex="1" default="1" key="W">
can be grayed out using

Code: Select all

(scrEnableAction gScreen 'disassembleWeapon Nil)
That solves my small, narrow problem in the two mods where graying out options has been a problem for me. Of course, you're working on something wider in scope where I'm guessing you won't be able to dodge the bug we're talking about.

Here's some code from the March 31 version of the launcher mod.

When I was using the code below, typDynamicUNID was not generating valid UNIDs, and it was not a problem that could be solved by moving code around like I had to do with (objRemoveItem). For that reason, I've since thrown the code away, and the currently uploaded alpha does not incorporate the code below.

Code: Select all

				(scrAddAction 
					gScreen 
					'gsUseAmmo 
					0
					"Use Ammo"
					"U" 
					(block Nil

						; This is the ammo that was chosen from the itemPicker list
						; Similar code in RPGAnalayzers.xml, Transcendence 1.6.1, line 128
						(setq chosenAmmo (scrGetItem gScreen))
						
						; For debugging purposes
						; (objSendMessage gSource gPlayerShip (itmGetName chosenAmmo 32))
						
						; Don't upgrade the launcher until we are ready.
						(setq upgradeLauncher Nil)
						
						; It's possible no ammo was selected if the ship has no ammo of the correct level in the cargo hold.
						; Only consume ammo if some was actually selected.
						(if chosenAmmo				
							
							(block Nil
							
								; See how many missiles there were in the stack that was chosen
								(setq numberofMissiles (itmGetCount chosenAmmo))
								
								; Get the value of each individual missile
								(setq individualMissilePrice (itmGetPrice chosenAmmo))
								
								; Get the value of the stack
								(setq missileStackValue (multiply numberofMissiles individualMissilePrice))
								
								; Determine how many missiles need to be consumed
								(if (geq missileStackValue ammoStillNeeded)
									(block Nil
										(setq numberOfMissilesToConsume (divide ammoStillNeeded individualMissilePrice))
										(setq upgradeLauncher True)
										)
									(block Nil
										(setq numberOfMissilesToConsume numberofMissiles)
										(setq upgradeLauncher Nil)
										)
									)
									
								; Remove the missiles
								; THERE IS A PROBLEM WITH THIS LINE OF CODE.
								; IT EXECUTES, BUT FOR SOME REASON, NONE OF THE CODE BELOW IT EXECUTES.
								; WHY?
								; (objRemoveItem gSource chosenAmmo numberOfMissilesToConsume)
								
								; FOR DEBUGGING PURPOSES
								; (ERROR ERROR)
								
								; Update the variable ammoConsumed because we've just consumed some missiles
								(setq ammoConsumed (add ammoConsumed (multiply numberofMissilesToConsume individualMissilePrice)))
								
								(if upgradeLauncher
									(block Nil
																		
										; There were enough missiles consumed to upgrade the launcher
										
										; The new launcher will be one level higher than the old one was
										(setq newLauncherLevel (add currentLauncherLevel 1))
										
										; Generate the missile code for the new launcher
										(setq missileCode (gsCreateMissileCode newLauncherLevel))
					
										; Create a custom UNID for the launcher
										(setq newUNID (typDynamicUNID (cat "gsReprogrammableLauncher" newLauncherLevel)))
										
										; Create the launcher
										(typCreate newUNID 
												(subst (typGetStaticData &tmLauncher; "Template")
													{	itemName : (cat (item '("" "programmable" "BASIC" "Logo" "Pascal" "Lisp" "XML" "Java" "PHP" "C" "Ajax" "SQL" "Python" "Ruby"  "Perl") 
															newLauncherLevel) " launcher")
														itemLevel : newLauncherLevel
														itemFrequency : "notrandom"
														itemValue : (multiply 250 (power 2 newLauncherLevel))
														itemPowerUse : (divide (power 2 newLauncherLevel) 2)
														
														missileElements : missileCode
													}
													)
											)
						
										; Get data on the old launcher so it can be applied to the new one
										; Similar code at PM's Drake Technologies Alpha (DrakeTech.xml, line 1257ff; accessed 2015 12 26)
										(setq enhancement (itmIsEnhanced gItem))
										(setq damaged (itmGetProperty gItem 'damaged))
										
										; Uninstall the launcher and remove it from the ship's cargo hold
										; Just using objRemoveItem on chosenLauncher doesn't work, probably because once the launcher is uninstalled,
										; it is no longer the same item as it was when it was still installed.
										; Found the solution at PM's Drake Technologies Alpha (DrakeTech.xml, line 1267-1271; accessed 2015 12 26)
										(setq uninstalledItem (shpRemoveDevice gSource gItem))
										(objRemoveItem gSource uninstalledItem 1)	
										
										; New launcher
										(setq newLauncher (itmCreate newUNID 1))

										; Make the new launcher like the old one
										; Similar code at PM's Drake Technologies Alpha (DrakeTech.xml, line 1286ff; accessed 2015 12 26)
										(setq newLauncher (itmSetProperty newLauncher 'damaged damaged))
										(setq newLauncher (itmSetEnhanced newLauncher enhancement))

										; Add the new launcher to the ship's cargo hold
										(objAddItem gSource newLauncher)
										   
										; Install the launcher
										(shpInstallDevice gSource newLauncher)
										
										; Re-set gsAmmoConsumed to zero because the upgrade process starts over now that we have a new launcher
										(objSetData gSource "gsAmmoConsumed" 0)
										)
										
									(block Nil
										; Launcher will not be upgraded because not enough missiles were available
										; Some missiles were consumed, so update the data stored on the ship to reflect the change
										(objSetData gSource "gsAmmoConsumed" ammoConsumed)
										
										; We need to calculate the number of missiles still needed to upgrade the launcher
										; so we can give the player this information in the next dockscreen pane
										(setq ammoStillNeeded (subtract ammoTotalNeeded ammoConsumed))
										)
										
									)
									
								; Remove the missiles
								; THERE IS A PROBLEM WITH THIS LINE OF CODE.
								; IT EXECUTES, BUT FOR SOME REASON, NONE OF THE CODE BELOW IT EXECUTES.
								; WHY?
								; MOVED THE CODE DOWN HERE SO THAT ALL THE CODE THAT WOULD OTHERWISE HAVE BEEN BELOW IT WOULD EXECUTE
								(objRemoveItem gSource chosenAmmo numberOfMissilesToConsume)

							)
						)
							
						; If the launcher was upgraded, go to the next screen.
						; Otherwise, refresh the current one.
						(if upgradeLauncher
							(scrShowPane gScreen "LauncherReprogrammed")
							(scrRefreshScreen gScreen)
							)
						
						)
					)
Tried unsuccessfully to change the "Use Ammo" action to use scrAddAction, which would allow the action to be grayed out if no ammo is available to use. Unfortunately, several functions do not seem to function properly inside the (block) part of scrAddAction. I made notes in the 2016 03 31 development versions of the code that I can forward to anyone interested. Here's a brief summary: For some reason, objRemoveItem and typDynamicUNID don't function properly within the block area of scrAddAction. objRemoveItem removes items but keeps all the code after it from executing. typDymanicUNID does not seem to create valid UNIDs.
relanat
Militia Captain
Militia Captain
Posts: 941
Joined: Tue Nov 05, 2013 9:56 am

gunship256 wrote:I'm trying to figure out what you mean. Should I fire an event and then use <Events> to execute the code that would have gone into the scrAddAction (block)?

Something I have not tried yet: moving the (block) code into a separate function and calling the function from scrAddAction (block).
Yes. I'm not good with all the jargon but I think this is what I meant! It will be a bit clunky but should work that way.
Here's a couple of examples.

I was trying to get timer events running (sysAddObjTimerEvent and similar functions) from scrAddAction inside a virtual item. Couldn't get it to happen for valid reasons I still don't understand but have been noted before. This ran code except for timer event stuff. So I never got a working mod from it but it "should" run non timer code.

Code: Select all

<ItemType UNID="&vtAddAutoPointToShipsInteriorDockscreen;"
	virtual=	"true"
	>
	<Events>
		<OnGlobalPaneInit>
			(if (eq aScreenUNID &dsShipInterior;)
				(scrAddAction
				 gScreen
				 'addPointOption
				 4
				 "Point"
				 "P"
					(block nil
						(setq now (objGetProperty gPlayerShip 'rotation))
						(if (or (and (geq now 1) (leq now 45) (stuff cut out to make the post smaller))
							(objFireItemEvent gSource &vtAddAutoPointToShipsInteriorDockscreen; 'Clockwise)
							(objFireItemEvent gSource &vtAddAutoPointToShipsInteriorDockscreen; "AntiClockwise"))
						(scrExitScreen gScreen 'forceUndock)
					);block
				);scrAddAction
			);if
		</OnGlobalPaneInit>

		<Clockwise>
			(block Nil etc etc

				then I had the code in here and another lot after it called <AntiClockwise>"
In the end I stole marsrocks idea (and code :lol:) and used a virtual ship to run the timer events. I did try using a virtual item instead of a virtual ship with an <OnCreate> section but this wouldn't work. Not sure why and it may have been errors in my code.

Code: Select all

<ItemType UNID="&vtAddRotatingPointToShipsInteriorDockscreen;"
	virtual=	"true"
	>
	<Events>
		<OnGlobalPaneInit>
			(if (eq aScreenUNID &dsShipInterior;)
				(scrAddAction
				gScreen
				'addPointOption
				4
				"Point"
				"P"
					(block nil
						;here we create a not-real ship to give a framework for the timer events to run
						;for whatever reason timer events won't run in items code here
						(sysCreateShip &scVirtualCodeShip; nil &svPlayer;)
						(scrExitScreen gScreen 'forceUndock)
					)
				);scrAddAction
			);if
		</OnGlobalPaneInit>
		</Events>
</ItemType>
	
<ShipClass UNID="&scVirtualCodeShip;"
			>
	;looks like the only thing a ship needs is an image. Game crashes without it
	<Image	imageID="&rsItems1;" imageX="0" imageY="0" imageWidth="1" imageHeight="1" imageFrameCount="0" imageTicksPerFrame="0"/>

	<Events>
		<OnCreate>
			(block Nil
				;here we start with a timer event. OnCreate is a good place apparently for this
				;there is also a command to go to "CarDirection"
				(sysAddObjTimerEvent 2 gSource 'CarDirection)
				(sysAddObjTimerEvent (random 100 200) gSource 'Disappear)
			then more events code below
We then ran the code starting in the <OnCreate> areas. So creating the virtual ship in the scrAddAction block area triggered the <OnCreate> code below it. This method does work so may be one way that will work for you.

I still can't work out why some code won't run inside scrAddAction. I'll keep poking around with it but won't spend hours like I have before. And it was nice to know it's not just me that can't make it work :) . And moving the code down in your example is a brilliant idea. Good thinking.

Thanks for the tip on the graying out of actions using 'id=', I can use that when I finally get past the hiccups that are stalling some of my mods. Much appreciated.
Stupid code. Do what I want, not what I typed in!
relanat
Militia Captain
Militia Captain
Posts: 941
Joined: Tue Nov 05, 2013 9:56 am

This is excellent work. I don't know what else to say. Well done.

No bugs, no crashes. Easy to use.

Only thing was, as it is, you can't select the mod without Corporate Command installed. There must be some way of making that optional in the final release. And you might need to find a way, if it's possible at all, to have the mod search for libraries. So that you don't have to specify in the code which mods it will look for.

Also I used GODMod to produce the missiles I needed so can't comment on using this mod in actual gameplay.

Minor quibbles.
The wording of the upgrade screen only if you haven't started upgrading the launcher.
It says your ammo is worth 1234 credits. You need an additional 4000 credits. But you only need 2766 (4000-1234) credits. In other words if you haven't started the upgrade you don't need the 'additional' there. "You need 4000 credits worth of ammo to upgrade your launcher." is one alternative or something like that. Once you've put some ammo through the text works.

And maybe if you have just upgraded and you have missiles on board which will start the next upgrade process have the screen go straight to the next upgrade. ATM it goes back to space when you finish an upgrade. No biggie but convenient.

And possibly change the wording if you have no missiles of the right level available. ATM it says "Which missiles do you want to use?" If you don't have any missiles showing in the listscreen this could say "You have no missiles of the right type." and it could be combined with that pesky 'graying out' action :).

Not a bug but something weird I noticed is that the missiles don't scroll through the missile select (when you press Tab) in order of highest level to lowest like they do in an itemscreen list. This might happen in unmodded games too. I've never looked.

Nice one. I'm impressed.

From the Read Me:
Missile that can enslave enemy ships and turn them into escorts (see code for Luminous tame cube) Make chance to do this level based and possibly based on armor/internal HP damage of the target ship
Great idea. Maybe you could put something in so that if the playership was badly damaged and the slave ship intact, it could revolt and turn on you again.
Stupid code. Do what I want, not what I typed in!
gunship256
Militia Commander
Militia Commander
Posts: 451
Joined: Sat Jul 25, 2015 11:41 pm
Location: repairing armor

Here's a new alpha:
d064_ReprogrammedLaunchers 0.13 alpha.zip
(28.55 KiB) Downloaded 264 times
CHANGES

Having to upgrade the launcher one level at a time is a serious limitation in mid and late game because it prevents the user from buying high-level missiles using upgrade dockscreens (CW fortresses and CSCs). Raised the fire rate of the launchers to 2 shots/second, the same as the NAMI launcher, to compensate, so that the launchers don't feel more crippled than the upgrade process should already make them feel.

Added the FreightersAndMore attribute to the launchers and the EMP missile.

Removed the Corporate Command library inclusion because it was keeping the mod from being enabled unless Corporate Command was also enabled. The mod doesn't use any &entitites; from Corporate Command anyway.

Changed the typCreate XML so that the Tab key correctly cycles missiles through from the lowest level to the highest level in order. For future reference, the Tab key order mirrors the order in which the missiles' <Missile> elements show up in the launcher's XML code.

Changed screen descriptions and grayed out "Use Ammo" action if player has no missiles available for the launcher upgrade.

Changed apiVersion from 27 to 29.
relanat wrote:So creating the virtual ship in the scrAddAction block area triggered the <OnCreate> code below it. This method does work so may be one way that will work for you.
I need to go through the forum thread where you guys went through the steps to figure this out. Has the code been giving you any problems because of hard-to-anticipate situations? For example, if you gate out, does the virtual ship have to be re-created?

Alternatively, have you guys tried creating a function using setq and lambda and calling the function within scrAddAction? I haven't tried that yet, but it was going to be my next attempt. I never got around to it after figuring out how to use id="..." with normal <Action> tags to gray out the actions and to change the actions' text.
relanat wrote:Only thing was, as it is, you can't select the mod without Corporate Command installed. There must be some way of making that optional in the final release. And you might need to find a way, if it's possible at all, to have the mod search for libraries. So that you don't have to specify in the code which mods it will look for.
Fixed! Yes - I would also like to be able to search for libraries and then selectively include them. Searching for Corporate Command itself could probably be done with something like this:

Code: Select all

(isError (itmCreate corporateCommandItem 1))
corporateCommandItem would have to be a hexadecimal UNID, not &thisKind;, in order to keep the XML parser from generating an error.

I'm not sure how to dynamically choose whether to include a library, though. I'm also not aware of anything analogous to (isError) to catch errors in the XML library inclusion, such as the error that would be generated if a mod tries to include a library that doesn't exist.

The mod doesn't actually need to include the CC library to function properly. I think including the library makes the use of &entities; possible, but since the mod is dynamically searching for missiles and adding them using typCreate, it's using hexadecimal UNIDs and doesn't need &thisStuff;.
The wording of the upgrade screen only if you haven't started upgrading the launcher.
It says your ammo is worth 1234 credits. You need an additional 4000 credits. But you only need 2766 (4000-1234) credits. In other words if you haven't started the upgrade you don't need the 'additional' there. "You need 4000 credits worth of ammo to upgrade your launcher." is one alternative or something like that.
Fixed!
And maybe if you have just upgraded and you have missiles on board which will start the next upgrade process have the screen go straight to the next upgrade. ATM it goes back to space when you finish an upgrade. No biggie but convenient.
I tried to do this, but it generated bugs that I didn't know how to fix. The code I tried to use is commented out in lines 457-486 of the new alpha (0.13) in case you're interested in taking a look or trying to fix it.
And possibly change the wording if you have no missiles of the right level available. ATM it says "Which missiles do you want to use?" If you don't have any missiles showing in the listscreen this could say "You have no missiles of the right type." and it could be combined with that pesky 'graying out' action :).
Fixed!
Not a bug but something weird I noticed is that the missiles don't scroll through the missile select (when you press Tab) in order of highest level to lowest like they do in an itemscreen list. This might happen in unmodded games too. I've never looked.
This wasn't a bug, but it *was* a big inconvenience. The point of using looted missiles is to shoot them really fast and get rid of them so you can use better ones, right? That's really hard to do if the Tab key doesn't scroll through the missiles in order from lowest to highest level.

As it turns out, the Tab scroll order exactly reflects the order of the <Missile> elements inside the launcher's XML. In other words, it can be controlled by the modder who made the launcher but probably not in any other way.

I fixed the problem in 0.13 alpha. The Tab key causes the missiles to cycle in order from lowest to highest level now.

As always, thanks for the very detailed and very specific feedback. I wouldn't have addressed most of these problems otherwise!
relanat
Militia Captain
Militia Captain
Posts: 941
Joined: Tue Nov 05, 2013 9:56 am

gunship256 wrote:Has the code been giving you any problems because of hard-to-anticipate situations? For example, if you gate out, does the virtual ship have to be re-created?
I don't anticipate any problems from running code like this. marsrocks might have more info on what could go wrong. We only created 'not-real' ships (technically they weren't virtual) to use the <OnCreate> section to initiate relatively short-lived timer events within a system. <OnCreate> is guaranteed to run timer events. Other ways are probably available but weren't known at the time. In my mod all the 'not-real' ship did was turn the playership up to 45 degrees. Once that was done it was no longer needed. Nothing needed to be stored or preserved for future reference. So gating won't (in this case) present any problems. The 'not-real' ship gets re-created whenever its needed.

That said, I ended up using that method because scrAddAction was messing me around as well. Putting the code in an <Event> section got it out of scrAddAction which (I was hoping) would stop any interference from whatever is messing with code inside scrAddAction. It worked.

The only two times I would recommend using the 'not-real' ship method are:
1.) If you want an <OnCreate> section to run timer events, and
2.) To get code away from scrAddAction to be sure that it can't be interfered with.

I've no experience with lambdas yet but would think that it has the same effect as option 2. Removing the code from scrAddAction to stop interference. Easier too, I would think. Certainly worth a try.
Stupid code. Do what I want, not what I typed in!
gunship256
Militia Commander
Militia Commander
Posts: 451
Joined: Sat Jul 25, 2015 11:41 pm
Location: repairing armor

Here's 0.14 alpha:
d064_ReprogrammedLaunchers 0.14 alpha.zip
(19.28 KiB) Downloaded 283 times
I think this is getting pretty close to beta, at which point I'd feel comfortable putting it on Xelerus. If there's anything I should improve, please let me know!

CHANGES

Launcher upgrade data (credit amount of missiles still needed for the upgrade) was previously stored on gSource, which causes problems if the player installs a new launcher or switches ships in PlayerShip drones. This is especially problematic since playership data seems to migrate with the player even if the player changes ships. Switched from objSetData to itmSetData to store the upgrade data on the launcher instead of the ship.

If a programmable launcher is upgraded to a type that already exists - for example, if a drone has a launcher that is upgraded to a type the player has already typCreated - the game throws an error. Fixed this by feeding (typCreate) to (isError) to prevent problems if typCreate is called to recreate a type that already exists.

Improved upgrade dockscreen UI. The dockscreen now tells the player the level and name of the current launcher. It no longer exits upon a launcher upgrade; instead, the player has a chance to feed more missiles to the launcher and upgrade it again without having to re-invoke the launcher.

relanat wrote:The only two times I would recommend using the 'not-real' ship method are:
1.) If you want an <OnCreate> section to run timer events, and
2.) To get code away from scrAddAction to be sure that it can't be interfered with.

I've no experience with lambdas yet but would think that it has the same effect as option 2. Removing the code from scrAddAction to stop interference. Easier too, I would think. Certainly worth a try.
Interesting. Is there an advantage to using a virtual ship as opposed to a virtual station? I'm trying to figure out how to reconfigure all omni and swivel weapons on the fly without rewriting their XML so that the player can apply global settings to turn then into point-defense weapons.

Functions are pretty useful. George uses a function, intEnhanceWeaponUse, that he calls from the laser amplifier and variety of other weapon enhancement devices. It's in UsefulItems.xml, line 2868ff, Transcendence 1.7 alpha 1.

Here's a wiki page with an example:

https://wiki.kronosaur.com/modding/func ... s[]=lambda

I think I've figured out why some functions force an exit out of the scrAddAction block. When a function throws an error, the game stocks execution of the entire (block). Sometimes, the error is unavoidable because there's something the code doesn't know. For example, it might be trying to access a variable that isn't defined yet or trying to call typCreate for a type (UNID) that already exists.

In the case of the itemPicker refresh problem we've discussed for Smart Spiders and Arrays, the solution was to store the itemPicker cursor position, THEN move the spider or array, then refresh the screen, and then restore the original cursor position. (Thanks for the suggestion to use the screen refresh, by the way!) Manipulating a dockscreen when one isn't currently open causes errors, so I had to wrap the relevant functions in (isError) to allow the code below them to execute:

Code: Select all

(isError (setq theCursor (scrGetListCursor gScreen)))
                           
(shpInstallDevice gSource theDevice)
                           
; Refresh the dockscreen pane in case moving this device around broke itemPicker
; Used isError in case scrRefreshScreen is called while a dockscreen is not currently pulled up
; Use scrGetListCursor and scrSetListCursor to remember where we were in
; the itemPicker list

(isError (scrRefreshScreen gScreen))
(isError (scrSetListCursor gScreen theCursor))
I'll put the fixed version of Smart Spiders and Arrays on Xelerus today. Maybe using (isError) will fix the problems with scrAddAction, though I haven't tried, and it's still confusing why errors are generated in the first place. I don't remember what the debug log records, but if errors show up there, that will be a clue as to what lines need to be wrapped in (isError).
And maybe if you have just upgraded and you have missiles on board which will start the next upgrade process have the screen go straight to the next upgrade. ATM it goes back to space when you finish an upgrade. No biggie but convenient.
I tried to do this, but it generated bugs that I didn't know how to fix. The code I tried to use is commented out in lines 457-486 of the new alpha (0.13) in case you're interested in taking a look or trying to fix it.
Fixed! I couldn't fix the bugs on lines 457-486, so I did a workaround by avoiding switching to the new pane altogether. The game forced the issue, since it refused to switch panes no matter what I tried after I upgraded the code from objSetData to use itmSetData.

Now, the dockscreen description always gives the name and item level of the launcher so there's no question which launcher is currently being upgraded. The refresh also works correctly so that the level of missiles shown in itemPicker is updated after a launcher is upgraded.
Post Reply