Random notes about Spring modding

Random notes about Spring modding

Discuss game development here, from a distinct game project to an accessible third-party mutator, down to the interaction and design of individual units if you like.

Moderator: Moderators

Post Reply
Gnomre
Imperial Winter Developer
Posts: 1754
Joined: 06 Feb 2005, 13:42

Random notes about Spring modding

Post by Gnomre »

This is just a list of things I've run across while messing with SWTA in Spring. Some of it's already known, but I just included it here for consistency.

- The sounds 'button9.wav', 'beep4.wav', and 'beep6.wav' are always required by spring, even if no unit files reference them. They can be replaced however.

- No GAF files are required whatsoever. None. Zero.

- Spring uses the .PCX buildpics in the /unitpics/ folder for build menus.

- The following files in the /gamedata/ dir are unnecessary:
help.tdf
los.tdf
translate.tdf
version.tdf
- Sidedata.tdf only requires the following data:

Code: Select all

[SIDE0]
	{
	name=Imperial;
	commander=IMPCOM;
	}
[SIDE1]
	{
	name=Rebel;
	commander=REBCOM;
	}
[CANBUILD]
	{
	}
- [CANBUILD] may contain your mod's buildtree. It works just as well as .gui or /download/ .tdfs for defining your build tree. I personally prefer download tdfs, but to each his own.

- Spring does not handle build menu order well at all. It completely reorganizes things for no apparent reason regardless of the build menu method used (GUI, TDF, or CANBUILD).

- The "Duration" tag for laser weapons doesn't seem to have an effect in spring.

- Finding laser colors in Spring is slightly difficult, as not all the OTA colors correspond to the Spring ones.

- Laser transparency can't be modified (without source editing). I suggest letting us define laser colors much like the values in .smd files - "color=1.0 0.0 0.0 1.0;" for a solid red laser.

- Spring only supports a texture space of 2048x2048 pixels, all textures combined. It's best to use base two numbers for texture sizes, and to shoot as small as possible.

- Spring doesn't seem to have a max size on models - however, the collision models suck at large scale, and 3DOBuilder can only make a groundplate (the selection square, which I believe the collision sphere is based off as well) up to 256x256 TA units in size (for reference, a Stormtrooper is 1x1). Also, other units bump into the large ones easily and move them around (I'm told increasing the metal cost of the large unit will stop this, however). Pathfinding for these large units also sucks.

- Groundplates don't rotate with the unit, so if a unit is rectangular and pointing north/south when it is built, its groundplate will always point N/S regardless of the unit orientation. I'm not sure if this is only a SWTA thing or if XTA/OTA in Spring does it as well (I haven't checked).

- Spring doesn't crash when it encounters missing features :D

- rand() doesn't work in scripts in Spring.

- dont-shade piecename; doesn't work in Spring.

- Air transports can easily carry more than one unit at a time.

- Most anything innovated by zwzsg in OTA doesn't work in Spring, except for his sand worms :P

[edit1]
-Nothing in the /guis/ folder is required if your mod doesn't depend on OTA unit build trees (like the armcom1.gui etc stuff). You can still use guis to define that stuff, but none of the ones in taenheter.ccx are needed. Not even the .FNT files are.

That's all I can remember off the top of my head.
User avatar
Buggi
Posts: 875
Joined: 29 Apr 2005, 07:46

Post by Buggi »

Did you know that SWTA got props in the latest PC Gamer as well?

Page 83, "Star Wars Mods"

^_^

-Buggi
User avatar
Dragon45
Posts: 2883
Joined: 16 Aug 2004, 04:36

Post by Dragon45 »

The rand() function does work, just not properly- It does not return a number inclusive between the two numbers, but Fnordia said this will be fixed in next release.

- MoveRate doesn't work (yet) but i'm working on it, and i'll finish it as soon as... well, as soon as i feel like it :P
Last edited by Dragon45 on 30 Jul 2009, 08:50, edited 2 times in total.
User avatar
zwzsg
Kernel Panic Co-Developer
Posts: 7052
Joined: 16 Nov 2004, 13:08

Post by zwzsg »

Spring Smoothing:
Fnordia wrote:It basically works like this: When a move-now or a turn-now command is detected, it is saved to a list of delayed animations, instead of updating the piece coordinates directly. When the script is finished, if the script finished because of a call to sleep with a 30 < sleeptime < 300, these delayed animations are translated into interpolated ones for the duration of the sleep. Otherwise the values are updated directly.

The following checks are made to make sure these interpolatations are transparent: If a move/turn on the same piece and axis is done later during the same tick, the delayed animation is commited first. Also, an interpolation is not allowed to overwrite a turn or move in progress (unless it originated from a previous interpolation), if one is running the values are updated directly instead.
As plainly obviously expectable, it breaks lots of script. Things like:

Code: Select all

move piece ... now;
if (get PIECE_XZ(piece) ....
Fails completly. You'd have to adding a sleep 1 between the two lines. But creating pauses in the middle of script that isn't supposed to have any bring its share of problems too. For instance any pause in an AimPrimary will mean the AimPrimary will be killed by the next AimPrimary, since Spring really enjoy calling AimPrimary constantly and not only once like TA.

Something like:

Code: Select all

move turret_center to y-axis [2000] now;
sleep 100;
Caused my turret_center to take several minutes to reach its desired position. I scripted it to be instant, according to Fnordia it should have take 0.1s, yet in reality it tooks several minutes. During which the unit couldn't fire since it doesn't like firing with a moving turret_center.

I don't even understand what kind of script that smoothing could improve. I mean, if the scripter types NOW; he means now. If he wanted to have smooth movement, he'd have typed himself a speed.

The whole "let's suppose walking animation always last between 30ms and 300ms" is completly wrong for something supposed to adapt to all units past present and future. For instance Sean Mirssen sleeps are 500ms.

It doesn't improve anything.

It breaks scripts.

It doesn't even work like it is supposed to do.

It is a pain to counter.

That thing was breaking my AimPrimary in many ways, took me days to understand and fix it.

Just remove it. Please.
Fnordia
Former Engine Dev
Posts: 425
Joined: 13 Aug 2004, 16:11

Post by Fnordia »

move now; get ..
Right, it should commit any delayed moves before allowing any operation that could depend on the values.. I'll fix that.
I don't even understand what kind of script that smoothing could improve. I mean, if the scripter types NOW; he means now. If he wanted to have smooth movement, he'd have typed himself a speed.

The animation interpolation was created to make the walk animations in the original kbot scripts look better. While it could be argued that the creators of these scripts really wanted the animation to be choppy, in my opinion it looks noticeably better when they are interpolated.

I guess we could add support for a DontInterpolate tag, but it will probably stay enabled as default.
Gnomre
Imperial Winter Developer
Posts: 1754
Joined: 06 Feb 2005, 13:42

Post by Gnomre »

Fnordia, can I get a word on how Spring handles the buildmenus? Surely there is *some* way to make Spring display the units in the order you specify. Is there new download tdf syntax? Should we start at 0,0 for page one, slot one instead of 2,0 like TA?
User avatar
Buggi
Posts: 875
Joined: 29 Apr 2005, 07:46

Post by Buggi »

Code below, look for my "// one here" comments to see where the build menus are being created. If you mean MiniSpring, I do not use this type of build menu creation as all conflicts must be resolved prior to use, in my builds, an index is incremented every time a new item is added the the array.

Code: Select all

void CUnitDefHandler::FindTABuildOpt()
{
	CSunParser sunparser;
	sunparser.LoadFile("gamedata\\sidedata.tdf");

	std::vector<std::string> sideunits = sunparser.GetSectionList("CANBUILD");
	for(unsigned int i=0; i<sideunits.size(); i++)
	{
		std::map<std::string, std::string>::iterator it;

		UnitDef *builder=NULL;
		std::transform(sideunits[i].begin(), sideunits[i].end(), sideunits[i].begin(), (int (*)(int))std::tolower);
		std::map<std::string, int>::iterator it1 = unitID.find(sideunits[i]);
		if(it1!= unitID.end())
			builder = &unitDefs[it1->second];

		if(builder)
		{
			std::map<std::string, std::string> buildoptlist = sunparser.GetAllValues("CANBUILD\\" + sideunits[i]);
			for(it=buildoptlist.begin(); it!=buildoptlist.end(); it++)
			{
				UnitDef *buildopt=0;
				std::transform(it->second.begin(),it->second.end(), it->second.begin(), (int (*)(int))std::tolower);

				if(unitID.find(it->second)!= unitID.end()){
					int num=atoi(it->first.substr(8).c_str());
					builder->buildOptions[num]=it->second; // one here...
				}
			}
		}
	}

	std::vector<std::string> files = CFileHandler::FindFiles("download\\*.tdf");
	for(unsigned int i=0; i<files.size(); i++)
	{
		CSunParser dparser;
		dparser.LoadFile(files[i]);

		std::vector<std::string> sectionlist = dparser.GetSectionList("");

		for(unsigned int j=0; j<sectionlist.size(); j++)
		{
			UnitDef *builder=NULL;
			std::string un1 = dparser.SGetValueDef("", sectionlist[j] + "\\UNITMENU");
			std::transform(un1.begin(), un1.end(), un1.begin(), (int (*)(int))std::tolower);
			std::map<std::string, int>::iterator it1 = unitID.find(un1);
			if(it1!= unitID.end())
				builder = &unitDefs[it1->second];

			if(builder)
			{
				UnitDef *buildopt=NULL;
				string un2 = dparser.SGetValueDef("", sectionlist[j] + "\\UNITNAME");
				std::transform(un2.begin(), un2.end(), un2.begin(), (int (*)(int))std::tolower);

				if(unitID.find(un2)!= unitID.end()){
					int menu=atoi(dparser.SGetValueDef("", sectionlist[j] + "\\MENU").c_str());
					int button=atoi(dparser.SGetValueDef("", sectionlist[j] + "\\BUTTON").c_str());
					int num=(menu-2)*6+button+1;
					builder->buildOptions[num]=un2; // One here...
				} else {
					info->AddLine("couldnt find %s",un2.c_str());
				}
			}
		}

	}
}
Gnomre
Imperial Winter Developer
Posts: 1754
Joined: 06 Feb 2005, 13:42

Post by Gnomre »

Yep, it's a minispring thing. The menus work fine in normal Spring. You broke it Buggi!! :P
User avatar
Buggi
Posts: 875
Joined: 29 Apr 2005, 07:46

Post by Buggi »

:D

Yep... darn right I did. And until I get my custom conflict resolver working for my 600+ units, that's how it'll stay. After which time I'll revert back to the original code.

-Buggi
User avatar
zwzsg
Kernel Panic Co-Developer
Posts: 7052
Joined: 16 Nov 2004, 13:08

Post by zwzsg »

Fnordia, even if you try to add all kinds of exception, there will be always be unthought-of cases where it breaks scripts. For instance what if there's another function running in parallel using the same piece? What if it is supposed to interact with other units? The approach behind smoothing is inherently wrong, when someone purposefully write "now" in his script, that should be respected.

I have watched the little comparaison avi and couldn't really see any improvment, but if you insist it does improve the animation of cavedog units, fine. Since I understand you want to keep this smoothing, can we please settle to have it only for the old official TA units, to add a fbi tag to control what unit should be smoothed and what unit shouldn't? But the default must remain non smoothed, so third party units don't risk being broken.

I have already repacked all data to add a SmoothAnim=1; tag in the fbi of all XTA and all OTA units:
SpringData_SmoothAnim_tag.zip
Gnomre
Imperial Winter Developer
Posts: 1754
Joined: 06 Feb 2005, 13:42

Post by Gnomre »

Static_Var_4 = get PIECE_XZ(base);

Putting that in Create() in a script (the var name doesn't matter) will crash Spring 100% of the time when you click the unit's buildpic. I've confirmed this with both the Speeder bike and Hailfire tank in SWTA.
User avatar
NOiZE
Balanced Annihilation Developer
Posts: 3984
Joined: 28 Apr 2005, 19:29

Post by NOiZE »

can any1 explain how buildtree's work?
User avatar
zwzsg
Kernel Panic Co-Developer
Posts: 7052
Joined: 16 Nov 2004, 13:08

Post by zwzsg »

In [SIDE0] and [SIDE1], the name must be ARM and CORE. Or else in the multiplayer lobby when starting a game you have no commander. The commander can be whatever you want however.
User avatar
munch
Posts: 311
Joined: 26 May 2005, 20:00

Post by munch »

Did any body put this stuff on the wiki? I'm not a modder myself, but it looks really useful. I've created a "Mod Development" page here:

I've cut and pasted the very first post of the thread in to get you started, but it'll need editing and adding to:

http://taspring.clan-sy.com/wiki/Mod_Development

Happy editing (and modding) =)

Munch
Gnomre
Imperial Winter Developer
Posts: 1754
Joined: 06 Feb 2005, 13:42

Post by Gnomre »

Err, we already had the bottom of this page: http://taspring.clan-sy.com/wiki/Create_units

But either way, I've updated http://taspring.clan-sy.com/wiki/Mod_Development with slightly more up to date information. Someone else can go through the other page.
User avatar
munch
Posts: 311
Joined: 26 May 2005, 20:00

Post by munch »

Ooops OK!
Benito
Posts: 72
Joined: 15 Aug 2004, 13:17

Post by Benito »

zwzsg wrote: Something like:

Code: Select all

move turret_center to y-axis [2000] now;
sleep 100;
Caused my turret_center to take several minutes to reach its desired position. I scripted it to be instant, according to Fnordia it should have take 0.1s, yet in reality it tooks several minutes. During which the unit couldn't fire since it doesn't like firing with a moving turret_center.
Would that actually work under OTA anyway? That's quite a large value you're moving to. Integer overflow springs to mind...
User avatar
zwzsg
Kernel Panic Co-Developer
Posts: 7052
Joined: 16 Nov 2004, 13:08

Post by zwzsg »

That worked very fine in OTA. That works in Spring when I add a sleep 1; right after (funny thing is in First person mode in that unit, you can see the map zoomed out further that what you can with free roaming camera). That still didn't work in Spring when the [2000] was replaced by something much lower.

[2000] is more or less 327680000, still far from the limit which is 2147483648.

But anyway, now I got my SmoothAnims tag idea implemented in the main, so all is good.

Is it possible to:
- Delete munch wiki page
- Make a clear and easy to access list of wiki page
Fnordia
Former Engine Dev
Posts: 425
Joined: 13 Aug 2004, 16:11

Post by Fnordia »

You can find a list of all wiki pages here: http://taspring.clan-sy.com/wiki/Special:Allpages.

Since both pages look to have been updated I'm not sure if I should delete it. It would be nice if someone merged them and made sure the info is only on one page. :)
Post Reply

Return to “Game Development”