XML and CPP

Freeform discussion about anything related to modding Transcendence.
Post Reply
robotarozum
Miner
Miner
Posts: 35
Joined: Sat Nov 30, 2013 10:05 pm

There seem to be two parts to Transcendence modding, XML and CPP, and I'm having trouble understanding how to get between the two.

Specific example: I want to have a weapon that when fired disables my own ship's drive item. My guess via imitating various other bits was this:

<Weapon
stuff
>
<OnFireWeapon>
(block nil
DisruptItem("&itSlasherDrive;", 30);
)
</OnFireWeapon>
more stuff
</Weapon>

The weapon works fine except I don't get any disrupt message or effect. (SlasherDrive is the correct UNID deal for a drive I designed for this purpose.)

.

In general, I don't understand how to make calls in XML language to a general effect that happens in game. Is there a framework for that, or is the point of XML to sit on top of the game and translate only specific effects?
RPC
Fleet Admiral
Fleet Admiral
Posts: 2876
Joined: Thu Feb 03, 2011 5:21 am
Location: Hmm... I'm confused. Anybody have a starmap to the Core?

Yes, there are two parts of the game code.
The first is XML, which provide structure to the game and stuff.
The second is TLISP, which is the stuff in parentheses.

In order to master modding you have to know both.
In order to execute TLISP you have to know the <events> of particular XML types very well. They can be found on these pages:
http://transcendence.kronosaur.com/wiki ... xml/events
http://transcendence.kronosaur.com/wiki ... ect#events
http://transcendence.kronosaur.com/wiki ... ype#events

You can also use timer functions to call blocks of TLISP if you want to be more specific:
http://xelerus.de/index.php?s=functions&c=time

As to getting between the two, it's currently limited.
You'd need to know TypGetDataField and the arguments for it, but it's very hard to easily translate one to the other. TypGetDataField => TLISP, but it's very limited.
The other function I know that uses both TLISP and XML is TypCreate, but it's from TLISP => XML.
Tutorial List on the Wiki and Installing Mods
Get on Discord for mod help and general chat
Image
Image
Der Tod ist der zeitlose Frieden und das leben ist der Krieg
Wir müssen wissen — wir werden wissen!
I don't want any sort of copyright on my Transcendence mods. Feel free to take/modify whatever you want.
User avatar
digdug
Fleet Admiral
Fleet Admiral
Posts: 2620
Joined: Mon Oct 29, 2007 9:23 pm
Location: Decoding hieroglyphics on Tan-Ru-Dorem

hi robotarozum,
welcome to modding :)
Transcendence uses a home-brew version of Lisp that we call TLISP or TransLISP (there is actually another programming language called TransLISP out there not made by George, they are not linked in any way)
TLISP is based on Lisp fully parenthesised syntax, syntax validity is not whitespace dependent.
(block Nil
(function variables)
)

Example:
(+ 1 2)
Returns 3

So the code you wrote, with the correct syntax will look like this, provided that you coded somewhere else the function DisruptItem.

Code: Select all

<OnFireWeapon>
(block nil
(DisruptItem &itSlasherDrive; 30))
)
</OnFireWeapon>
variables can be set using the function setq
(block (var1 var2)
(setq var1 "blah")
(setq var2 3000)
)

Variables must be declared in the code block in which they are used. (if you forget one, the code will run, but you will risk to contaminate your variables with other part of code that uses variables with the same name)

lists can be created with the list function
(setq var3 (list 1 2 3 "a" "b"))

code comments start with ;

custom functions can be coded creating a lambda function. Most people will call these global functions, because they can be put in the XML <Globals> and run from anywhere else. <Globals> is very powerful. Other common places where to quickly run code to test are events (like the <OnFireWeapon> that you identified), <Invoke> that allows you to run code from custom items in your cargo using the menu "u", and of course, the console accessible by F9 while in Debug mode.

Example of global function:
(setq function1 (lambda (params)
(block (variables)
CODE HERE
)))

Usage of the global function will then be (function1 params)

TLISP supports common functions like if, loop, for, enum, enumwhile (and so on)

The full list of available functions is here:
http://forums.kronosaur.com/viewtopic.php?f=8&t=6136
(sorry, it's for version 1.2RC2, I haven't updated the list to 1.2, yet. Will do soon.)
Xelerus has a function list, divided by categories, as well as the wiki (but i'm not sure if they have been recently updated to latest)
http://transcendence.kronosaur.com/wiki ... n&s[]=list
http://xelerus.de/index.php?s=functions
robotarozum
Miner
Miner
Posts: 35
Joined: Sat Nov 30, 2013 10:05 pm

Thanks!

I don't think I'm getting it. If I do this...

<OnFireWeapon>
(block nil
(objSetItemProperty &scSlasher; &itSlasherDrive; 'disrupted True)
)
</OnFireWeapon>

...I think that when the event of weapon fire occurs, the SlasherDrive item on the player ship (Slasher) should get disrupted. This does not happen.

In looking through github it looks like my syntax is correct. Does TLISP name things differently than XML (the &; bit), and if so how so? Or am I misunderstanding it in some other way?
User avatar
digdug
Fleet Admiral
Fleet Admiral
Posts: 2620
Joined: Mon Oct 29, 2007 9:23 pm
Location: Decoding hieroglyphics on Tan-Ru-Dorem

your syntax is perfect. The problem here is that you passed UNIDs to the function objSetItemProperty instead of the actual object and item
(objSetItemProperty obj item property value [count]) -> item
some modders tends to use "spaceObj" for obj and "itmStruct" for item.

&scSlasher; is just a UNID, a reference number for the game engine. When the game starts, the engine will convert all &something; to the actual UNID number. In the console you can't use &something;, only the UNID number, in hex or in decimal format.

a spaceObj is instead an actual object spawned in the solar system, as well as itmStruct is the actual item spawned inside a ship or a station.
objSetItemProperty will accept only those.

Since you are trying to that code in weapon instealled on the playership, you can use the special variables gSource or gPlayership.
gPlayership is the spaceObj of the playership, and it's always set at game start.
gSource is the spaceObj that is running the code, since the weapon is on the playership, gSource in this case will be the playership. gSource is extremely useful.
gItem, similarly, will be the itmStruct running the code, the weapon in this case. (so not useful right now)

back to your code, we have to find itmStruct of the drive on the playership.
(objGetItems gSource "vI") will return a list with 1 itmStruct, v=drive I=installed of the queried spaceObj.
do
(@ (objGetItems gSource "vI") 0) will return the first element of the list, the itmStruct we want !
For a list of all the available criteria, here:
http://transcendence.kronosaur.com/wiki ... m_criteria

so, to sum up everything your code will be:
<OnFireWeapon>
(block nil
(objSetItemProperty gSource (@ (objGetItems gSource "vI") 0) 'disrupted True)
)
</OnFireWeapon>

I believe that should work :)
robotarozum
Miner
Miner
Posts: 35
Joined: Sat Nov 30, 2013 10:05 pm

Thanks, that makes a lot of sense! It didn't work though. :( Same deal: the mod loads fine and weapon otherwise behaves fine, but no disrupt occurs.
robotarozum
Miner
Miner
Posts: 35
Joined: Sat Nov 30, 2013 10:05 pm

I'm slowly getting it, it turns out I need to have it all inside an <Events> tag to make it go, but now I have a new problem.

When I took a C++ course once I found it useful during debugging to put echos here and there, so I could see where the code was actually going vs. where I wanted it to go. I felt like this bit...

<Events>
<OnFireWeapon>
(block nil
(plyMessage gPlayer (cat "Test"))
)
</OnFireWeapon>
</Events>

...would be good for that, and it definitely displays Test (hooray! although in retrospect I ought to have used Hello World), but the weapon gets really hinky. It makes sound and uses power, but produces no image or damage. This is especially odd to me because the sound and power part is coded in the same <Weapon yadda yadda> as the damage part.

I added a (sysCreateWeaponFire) in the same block and now it all works, but it seems like there must be an easier way, especially since at least some of the weapon fire code is still getting through...?
EditorRUS
Militia Lieutenant
Militia Lieutenant
Posts: 148
Joined: Tue Oct 30, 2012 6:30 pm

You mustn't put blocks in blocks in XML

Not!
<weapon ... <image/>>

But
<weapon damage="kinetic:0"...><image unid="bla-blah"/></Weapon>
robotarozum
Miner
Miner
Posts: 35
Joined: Sat Nov 30, 2013 10:05 pm

I don't follow. What I have is:

<ItemType
stuff
>

<Image stuff />

<Weapon
stuff
>

<Effect>
stuff
</Effect>

</Weapon>

<Events>
stuff
</Events>

</ItemType>

No good?
User avatar
digdug
Fleet Admiral
Fleet Admiral
Posts: 2620
Joined: Mon Oct 29, 2007 9:23 pm
Location: Decoding hieroglyphics on Tan-Ru-Dorem

It makes sound and uses power, but produces no image or damage.
This is normal when using <OnFireWeapon>.
If you want the weapon to also fire normally after running your code in <OnFireWeapon>, the event must end with a Nil.

<Events>
<OnFireWeapon>
(block nil
(plyMessage gPlayer (cat "Test"))
Nil
)
</OnFireWeapon>
</Events>

This should do it.
robotarozum
Miner
Miner
Posts: 35
Joined: Sat Nov 30, 2013 10:05 pm

Ahh, yes indeed! Thanks again! :)
bluebird5
Anarchist
Anarchist
Posts: 1
Joined: Thu Feb 06, 2014 5:01 am

The spaceObj that is running the code, since the weapon is on the playership, gSource in this case will be the playership. gSource is extremely useful. gSource is the spaceObj that is running the code, since the weapon is on the playership, gSource in this case will be the playership. gSource is extremely useful. I believe that should work :)
Post Reply