Weapons. Very long.

Weapons. Very long.

Discuss the source code and development of Spring Engine in general from a technical point of view. Patches go here too.

Moderator: Moderators

User avatar
Argh
Posts: 10920
Joined: 21 Feb 2005, 03:38

Weapons. Very long.

Post by Argh »

As promised, in Mantis... here is a first stab at listing all of the weapon variables that are actually used by Spring.

Spring devs, I have a number of questions, now that I have grepped the source a bit. Please, if you can spare a moment, help me out.

Code: Select all

#define WEAPONTYPE_ROCKET 1
#define WEAPONTYPE_CANNON 2
#define WEAPONTYPE_AACANNON 3
Question no. 1: What is the AACANNON class, and how can we use it?

Code: Select all

#define WEAPONTYPE_RIFLE 4
Question no. 2: Same thing- what is this class?

Code: Select all

#define WEAPONTYPE_MELEE 5
Question no. 3: Melee is in here?!? How does it work? Does it work?

Code: Select all

#define WEAPONTYPE_AIRCRAFTBOMB 6
#define WEAPONTYPE_FLAME 7
#define WEAPONTYPE_MISSILELAUNCHER 8
#define WEAPONTYPE_LASERCANNON 9
#define WEAPONTYPE_EMGCANNON 10
#define WEAPONTYPE_STARBURSTLAUNCHER 11
#define WEAPONTYPE_UNKNOWN 12

#define WEAPON_RENDERTYPE_MODEL 1
#define WEAPON_RENDERTYPE_LASER 2
#define WEAPON_RENDERTYPE_PLASMA 3
#define WEAPON_RENDERTYPE_FIREBALL 4

class TdfParser;

struct WeaponDef
{
	std::string name;
	std::string type;

	/*std::string sfiresound;
	std::string ssoundhit;
	int firesoundId;
	int soundhitId;
	float firesoundVolume;
	float soundhitVolume;*/
	GuiSound firesound;
	GuiSound soundhit;
Question number 4: so, can we use firesoundVolume in our FBIs? What does GuiSound firesound do?

Code: Select all

	float range;
	float heightmod;
	float accuracy;				//inaccuracy of whole burst
	float sprayangle;	//inaccuracy of individual shots inside burst
	float movingAccuracy; //inaccuracy while owner moving
	float targetMoveError;	//fraction of targets move speed that is used as error offset
Question no. 5: so, does targetMoveError makes the weapon miss more based on the speed of the target? That might be very useful for AATA or other somewhat-realistic mods.

Code: Select all

	//float damage;
	//float airDamage;
	DamageArray damages;
	float areaOfEffect;
	float impulseFactor;
	bool noSelfDamage;
	float fireStarter;
Question no. 6: does noSelfDamage work?

Code: Select all

	int salvosize;
	float salvodelay;
Question no. 7: what is salvosize, and how does it differ from burst? If it allows for salvos of "individual shots" that can still have a timer between salvos... that's awesome.

Code: Select all

	float reload;
	float beamtime;

	float maxAngle;
Question no. 8: what is maxAngle?

Code: Select all

	float restTime;
Question no. 9: what is restTime?

Code: Select all

	float uptime;
Question no. 10: what is uptime?

Code: Select all

	float metalcost;
	float energycost;
	float supplycost;
Question no. 11: what is supplycost?

Code: Select all

	int id;

	bool turret;
	bool onlyForward;
Question no. 12: what is onlyForward?

Code: Select all

	bool waterweapon;
	bool tracks;
	bool dropped;
	bool paralyzer;			//weapon will only paralyze not do real damage

	bool noAutoTarget;			//cant target stuff (for antinuke,dgun)
	bool manualfire;			//use dgun button
	int interceptor;				//anti nuke
	int targetable;				//nuke (can be shot by interceptor)
	bool stockpile;					
	float coverageRange;		//range of anti nuke
Question 13: are interceptor, targetable and coverageRange the only variables that are required to create weapon/antiweapons?

Code: Select all

	bool isPlasmaRepulser;
	float repulseEnergy;
	float repulseRange;
	float repulseForce;
	float repulseSpeed;

	float intensity;
	float thickness;

	int graphicsType;
Question 14: what is graphicsType?

Code: Select all

	bool soundTrigger;

	bool selfExplode;
Question 15: what is selfExplode?

Code: Select all

	bool gravityAffected;
Question 16: why is gravityAffected defined? I would've thought that was an inherent part of the defines above.

Code: Select all

	bool twophase;
Question 17: is this actually used for anything, or is it just limiting what is a "nuke" for nuke/antinuke interaction?

Code: Select all

	bool guided;
	bool vlaunch;
	bool selfprop;
	bool noExplode;
	float startvelocity;
	float weaponacceleration;
	float turnrate;
	float maxvelocity;

	float projectilespeed;
Question 18: Why is projectilespeed defined when we use weaponvelocity in the FBI? Why is weaponvelocity not here? I take it that I'm missing something that's changed into another name in the CSunParser sections.

Code: Select all

	unsigned int onlyTargetCategory;

	float wobble;						//how much the missile will wobble around its course
	float trajectoryHeight;	
User avatar
Argh
Posts: 10920
Joined: 21 Feb 2005, 03:38

Post by Argh »

From WeaponDefHandler.cpp. Forgive me, but I'm going to snip this a bit, to tear out the parts that aren't really relevant (at least, I don't think so)

Code: Select all

	weaponDefs[id].name = weaponname;

	bool lineofsight;
	bool balistic;
"balistic" is miss-spelled. It's "ballistic". ;)

Code: Select all

	//bool twophase;
Aha! This is commented out! So it's probably not really used.

Code: Select all

	bool beamweapon;
	//bool guided;
	//bool vlaunch;
Er... hmm... guided and vlaunch aren't used? What determines that they're guided or vlaunch, then? I'll keep reading downwards...

Code: Select all

	int rendertype;
	int color;
Um, can we add a "colorRGB" category, where we name 3 RGB values, 255 255 255, like this: "colorRGB=255, 255, 255;"? That'd be most helpful.

Code: Select all

	int beamlaser;
	//bool tracking;
	//bool selfprop;
	//bool turret;
	//bool smokeTrail;
	//std::string modelName;
Er... again, what is going on here? Tracking, selfprop, turret, smokeTrail, modelName? Are none of these things actually used? Or does "//" not mean "commented code" in CSun Parser?

Code: Select all

	sunparser->GetDef(weaponDefs[id].dropped, "0", weaponname + "\\dropped");
	sunparser->GetDef(lineofsight, "0", weaponname + "\\lineofsight");
	sunparser->GetDef(balistic, "0", weaponname + "\\balistic");
Again, balistic is miss-spelled. At least it's consistent ;)

Code: Select all

	sunparser->GetDef(weaponDefs[id].twophase, "0", weaponname + "\\twophase");
	sunparser->GetDef(beamweapon, "0", weaponname + "\\beamweapon");
	sunparser->GetDef(weaponDefs[id].guided, "0", weaponname + "\\guidance");
	sunparser->GetDef(rendertype, "0", weaponname + "\\rendertype");
	sunparser->GetDef(color, "0", weaponname + "\\color");
	sunparser->GetDef(beamlaser, "0", weaponname + "\\beamlaser");
	sunparser->GetDef(weaponDefs[id].vlaunch, "0", weaponname + "\\vlaunch");
	sunparser->GetDef(weaponDefs[id].selfprop, "0", weaponname + "\\selfprop");
	sunparser->GetDef(weaponDefs[id].turret, "0", weaponname + "\\turret");
	sunparser->GetDef(weaponDefs[id].visuals.modelName, "", weaponname + "\\model");
	sunparser->GetDef(weaponDefs[id].visuals.smokeTrail, "0", weaponname + "\\smoketrail");
	sunparser->GetDef(weaponDefs[id].noSelfDamage, "0", weaponname + "\\NoSelfDamage");
I've tried to add smoketrails to ballistic weapons... it doesn't work. Yet, here, it seems to read that value. Why doesn't it work?

Code: Select all

	
	sunparser->GetDef(weaponDefs[id].waterweapon, "0", weaponname + "\\waterweapon");
	sunparser->GetDef(weaponDefs[id].tracks, "0", weaponname + "\\tracks");
	sunparser->GetDef(weaponDefs[id].noExplode, "0", weaponname + "\\NoExplode");
	sunparser->GetDef(weaponDefs[id].maxvelocity, "0", weaponname + "\\weaponvelocity");
Ah, here's that "weaponvelocity". Why didn't we just keep it internally/externally consistant, and use maxvelocity? Is that a reserved, global variable or something?

Code: Select all

	sunparser->GetDef(weaponDefs[id].isPlasmaRepulser, "0", weaponname + "\\PlasmaRepulser");
	sunparser->GetDef(weaponDefs[id].beamtime, "1", weaponname + "\\beamtime");
	sunparser->GetDef(weaponDefs[id].thickness, "2", weaponname + "\\thickness");
	sunparser->GetDef(weaponDefs[id].intensity, "0.9", weaponname + "\\intensity");

	if(weaponDefs[id].name.find("disintegrator")!=string::npos){	//fulhack
		weaponDefs[id].visuals.renderType = WEAPON_RENDERTYPE_FIREBALL;}
	else if(weaponDefs[id].visuals.modelName.compare("")!=0){
		weaponDefs[id].visuals.renderType = WEAPON_RENDERTYPE_MODEL;}
	else if(beamweapon){
		weaponDefs[id].visuals.renderType = WEAPON_RENDERTYPE_LASER;}
	else{
		weaponDefs[id].visuals.renderType = WEAPON_RENDERTYPE_PLASMA;}
	//else
	//	weaponDefs[id].visuals.hasmodel = true;

	weaponDefs[id].gravityAffected = false;
	if(weaponDefs[id].dropped || balistic)
		weaponDefs[id].gravityAffected = true;
So, basically we have only four real rendering types. Lightning guns are just "laser beams" strung together. So making lots of colors and varieties of lightning should be relatively simple, yes? Same thing goes for plasma- and I don't see anything about the Flamethrower flame here :P

Secondly, it appears you can't have a ballistic weapon that is "gravityAffected=0;", but you can have a Laser that is "gravityAffected=1;". Very, very cool- AATA needs that, and I might use it for NanoBlobs!

Code: Select all

	if(weaponDefs[id].dropped)	{
		weaponDefs[id].type = "AircraftBomb";

	}	else if(weaponDefs[id].vlaunch){
		weaponDefs[id].type = "StarburstLauncher";

	}	else if(beamlaser){
		weaponDefs[id].type = "BeamLaser";

	}	else if(weaponDefs[id].isPlasmaRepulser){
		weaponDefs[id].type = "PlasmaRepulser";

	} else if(weaponDefs[id].waterweapon) {
		weaponDefs[id].type = "TorpedoLauncher";

Code: Select all

	} else if(weaponDefs[id].name.find("disintegrator")!=string::npos) {
		weaponDefs[id].type = "DGun";
Confirmation that you just need "disintigrator" in the weapon name to have that special effect. Seems a kludge- I think we should just declare it as the called effect.

Code: Select all

	} else if(lineofsight) {
		if(rendertype==7)
			weaponDefs[id].type = "LightingCannon";
		else if(beamweapon)
			weaponDefs[id].type = "LaserCannon";
		else if(weaponDefs[id].visuals.modelName.find("laser")!=std::string::npos)
			weaponDefs[id].type = "LaserCannon";		//swta fix
No offense meant to SWTA, but do they really need kludges to support just their mod? If they need to have their weapons fixed, I can probably develop a grep method that will do it... or just do it by hand.

Code: Select all

		else if(/*selfprop && */weaponDefs[id].visuals.smokeTrail)
			weaponDefs[id].type = "MissileLauncher";
Ah... so this is why smoketrails only work with guided weapons. Sigh. Not ideal, but at least now I know.

Code: Select all

		else if(rendertype == 4 && color == 2)
			weaponDefs[id].type = "EmgCannon";
Ah, interesting. So both states must be true. Another kludge.

Code: Select all

		else if(rendertype == 5)
			weaponDefs[id].type = "flame";
And here's the Flamethower- an effect that I'd love to look at in detail.

Code: Select all

	//	else if(rendertype == 1)
	//		weaponDefs[id].type = "MissileLauncher";
		else
			weaponDefs[id].type = "Cannon";
	}
	else
		weaponDefs[id].type = "Cannon";
So basically, weapons default to "Cannon". Ok.

Code: Select all

	sunparser->GetDef(weaponDefs[id].firesound.name, "", weaponname + "\\soundstart");
	sunparser->GetDef(weaponDefs[id].soundhit.name, "", weaponname + "\\soundhit");

	/*if(weaponDefs[id].firesound.name.find(".wav") == -1)
		weaponDefs[id].firesound.name = weaponDefs[id].firesound.name + ".wav";
	if(weaponDefs[id].soundhit.name.find(".wav") == -1)
		weaponDefs[id].soundhit.name = weaponDefs[id].soundhit.name + ".wav";*/

	//weaponDefs[id].firesoundVolume = 5.0f;
	//weaponDefs[id].soundhitVolume = 5.0f;
Hmm. I don't see any reference to firesoundVolume or soundhitVolume here. Are they valid, or just sitting there teasing me?

Code: Select all

	weaponDefs[id].range = atof(sunparser->SGetValueDef("10", weaponname + "\\range").c_str());
	float accuracy,sprayangle,movingAccuracy;
	sunparser->GetDef(accuracy, "0", weaponname + "\\accuracy");
	sunparser->GetDef(sprayangle, "0", weaponname + "\\sprayangle");
	sunparser->GetDef(movingAccuracy, "-1", weaponname + "\\movingaccuracy");
	if(movingAccuracy==-1)
		movingAccuracy=accuracy;
	weaponDefs[id].accuracy=sin((accuracy) * PI / 0xafff);		//should really be tan but TA seem to cap it somehow
	weaponDefs[id].sprayangle=sin((sprayangle) * PI / 0xafff);		//should also be 7fff or ffff theoretically but neither seems good
	weaponDefs[id].movingAccuracy=sin((movingAccuracy) * PI / 0xafff);

	sunparser->GetDef(weaponDefs[id].targetMoveError, "0", weaponname + "\\targetMoveError");
Confirmation that Experience has zero to do with weapon accuracy.

Code: Select all

	for(int a=0;a<damageArrayHandler->numTypes;++a)
	{
		sunparser->GetDef(weaponDefs[id].damages[a], "0", weaponname + "\\DAMAGE\\default");
		if(weaponDefs[id].damages[a]==0)		//avoid division by zeroes
			weaponDefs[id].damages[a]=1;
	}
Aha! Here's that non-zero zero Damage. Ok... so why does it cause divide-by-zero crashes if zero? There must be a better way.

Code: Select all

	std::map<std::string, std::string> damages=sunparser->GetAllValues(weaponname + "\\DAMAGE");
	for(std::map<std::string, std::string>::iterator di=damages.begin();di!=damages.end();++di){
		int type=damageArrayHandler->GetTypeFromName(di->first);
		float damage=atof(di->second.c_str());
	weaponDefs[id].impulseFactor=atof(sunparser->SGetValueDef("1", weaponname + "\\impulsefactor").c_str());
		if(damage==0)
			damage=1;
		if(type!=0){
			weaponDefs[id].damages[type]=damage;
//			info->AddLine("Weapon %s has damage %f against type %i",weaponname.c_str(),damage,type);
		}
	}
What does this do?

Code: Select all

	weaponDefs[id].areaOfEffect=atof(sunparser->SGetValueDef("8", weaponname + "\\areaofeffect").c_str())*0.5;
Sooo, basically, an "areaeffect" of 1 actually = 0.125? I guess Smoth was dead-on about the "Elmos". 1/8th of a "footprint" = 1 Elmo, which is as small of an x, y, z cube as Spring can actually interact with.

Code: Select all

	weaponDefs[id].projectilespeed = atof(sunparser->SGetValueDef("0", weaponname + "\\weaponvelocity").c_str())/GAME_SPEED;
	weaponDefs[id].startvelocity = max(0.01,atof(sunparser->SGetValueDef("0", weaponname + "\\startvelocity").c_str())/GAME_SPEED);
	weaponDefs[id].weaponacceleration = atof(sunparser->SGetValueDef("0", weaponname + "\\weaponacceleration").c_str())/GAME_SPEED/GAME_SPEED;
	weaponDefs[id].reload = atof(sunparser->SGetValueDef("1", weaponname + "\\reloadtime").c_str());
	weaponDefs[id].salvodelay = atof(sunparser->SGetValueDef("0.1", weaponname + "\\burstrate").c_str());
	sunparser->GetDef(weaponDefs[id].salvosize, "1", weaponname + "\\burst");
Whoa. So if salvosize > 1, then weapons fire more than one shot per shooting instance? Can we really have true shotguns?

Code: Select all

	weaponDefs[id].maxAngle = atof(sunparser->SGetValueDef("3000", weaponname + "\\tolerance").c_str()) * 180.0 / 0x7fff;
Why isn't this divided by ffff?

Code: Select all

	weaponDefs[id].restTime = 0.0f;
	sunparser->GetDef(weaponDefs[id].metalcost, "0", weaponname + "\\metalpershot");
	sunparser->GetDef(weaponDefs[id].energycost, "0", weaponname + "\\energypershot");
	sunparser->GetDef(weaponDefs[id].selfExplode, "0", weaponname + "\\burnblow");
	weaponDefs[id].fireStarter=atof(sunparser->SGetValueDef("0", weaponname + "\\firestarter").c_str())*0.01;
	weaponDefs[id].paralyzer=!!atoi(sunparser->SGetValueDef("0", weaponname + "\\paralyzer").c_str());
	weaponDefs[id].damages.paralyzeDamage=weaponDefs[id].paralyzer;
	weaponDefs[id].soundTrigger=!!atoi(sunparser->SGetValueDef("0", weaponname + "\\SoundTrigger").c_str());

	//sunparser->GetDef(weaponDefs[id].highTrajectory, "0", weaponname + "\\minbarrelangle");
Ok... so minbarrelangle is mentioned here, but it's broken? Is this just commented out? Sorry, this syntax is confusing.

Code: Select all

	sunparser->GetDef(weaponDefs[id].stockpile, "0", weaponname + "\\stockpile");
	sunparser->GetDef(weaponDefs[id].interceptor, "0", weaponname + "\\interceptor");
	sunparser->GetDef(weaponDefs[id].targetable, "0", weaponname + "\\targetable");
	sunparser->GetDef(weaponDefs[id].manualfire, "0", weaponname + "\\commandfire");
	sunparser->GetDef(weaponDefs[id].coverageRange, "0", weaponname + "\\coverage");
Hmmk. So are all 5 of these variables needed to be set to have an antiweapon? No wonder my attempts to make anti-missile lasers have been a failure...

Code: Select all

	sunparser->GetDef(weaponDefs[id].repulseEnergy, "0", weaponname + "\\repulseenergy");
	sunparser->GetDef(weaponDefs[id].repulseForce, "0", weaponname + "\\repulseforce");
	sunparser->GetDef(weaponDefs[id].repulseRange, "0", weaponname + "\\repulserange");
	sunparser->GetDef(weaponDefs[id].repulseSpeed, "0", weaponname + "\\repulsespeed");

	weaponDefs[id].wobble = atof(sunparser->SGetValueDef("0", weaponname + "\\wobble").c_str()) * PI / 0x7fff /30.0f;
	sunparser->GetDef(weaponDefs[id].trajectoryHeight, "0", weaponname + "\\trajectoryheight");

	weaponDefs[id].noAutoTarget= (weaponDefs[id].manualfire || weaponDefs[id].interceptor || weaponDefs[id].isPlasmaRepulser);

	weaponDefs[id].onlyTargetCategory=0xffffffff;
	if(atoi(sunparser->SGetValueDef("0", weaponname + "\\toairweapon").c_str())){
		weaponDefs[id].onlyTargetCategory=CCategoryHandler::Instance()->GetCategories("VTOL");	//fix if we sometime call aircrafts otherwise
//		info->AddLine("air only weapon %s %i",weaponname.c_str(),weaponDefs[id].onlyTargetCategory);
	}
The line about VTOL is interesting.

Code: Select all

	weaponDefs[id].heightmod = 0.2f;
	if(weaponDefs[id].type == "Cannon")
		weaponDefs[id].heightmod = 0.8f;
Whoa... Cannon types do not use heightmods of 1.0???

Code: Select all

	weaponDefs[id].supplycost = 0.0f;
Again, what does this do?

Code: Select all

	weaponDefs[id].onlyForward=!weaponDefs[id].turret && weaponDefs[id].type != "StarburstLauncher";

Code: Select all

	int color2;
	sunparser->GetDef(color2, "0", weaponname + "\\color2");

	float3 rgbcol = hs2rgb(color/float(255), color2/float(255));
	//weaponDefs[id].visuals.redcolor = rgbcol.x;
	//weaponDefs[id].visuals.greencolor = rgbcol.y;
	//weaponDefs[id].visuals.bluecolor = rgbcol.z;
	weaponDefs[id].visuals.color = rgbcol;

	if(weaponDefs[id].visuals.modelName.find("green")!=std::string::npos){	//swta fix
		weaponDefs[id].visuals.color.x = 0.1;
		weaponDefs[id].visuals.color.y = 1;
		weaponDefs[id].visuals.color.z = 0.1;
	}
	if(weaponDefs[id].visuals.modelName.find("red")!=std::string::npos){	//swta fix
		weaponDefs[id].visuals.color.x = 1;
		weaponDefs[id].visuals.color.y = 0.1;
		weaponDefs[id].visuals.color.z = 0.1;
	}
	if(weaponDefs[id].type=="LaserCannon" && weaponDefs[id].visuals.modelName.find("laser")!=std::string::npos)
		weaponDefs[id].reload/=2.0;	//more swta
More SWTA-specific hacks. I want NanoBlobs hacks ;)

Code: Select all

	weaponDefs[id].uptime = atof(sunparser->SGetValueDef("0", weaponname + "\\weapontimer").c_str());

	weaponDefs[id].turnrate = atof(sunparser->SGetValueDef("0", weaponname + "\\turnrate").c_str()) * PI / 0x7fff /30.0f;

	if(weaponDefs[id].type=="AircraftBomb"){
		if(weaponDefs[id].reload<0.5){
			weaponDefs[id].salvodelay=min(0.2f,weaponDefs[id].reload);
			weaponDefs[id].salvosize=(int)(1/weaponDefs[id].salvodelay)+1;
			weaponDefs[id].reload=5;
		} else {
			weaponDefs[id].salvodelay=min(0.4f,weaponDefs[id].reload);
			weaponDefs[id].salvosize=2;			
		}
	}
So this defines how bombs work. No wonder modders have been having problems- this was pretty kludged for XTA.

Code: Select all

//	if(!weaponDefs[id].turret && weaponDefs[id].type!="TorpedoLauncher")
//		weaponDefs[id].maxAngle*=0.4;

	weaponDefs[id].id = id;
	weaponID[weaponname] = id;
}

void CWeaponDefHandler::LoadSound(GuiSound &gsound)
{
	gsound.volume = 5.0f;
	if(gsound.name.compare("")==0)
	{
		gsound.id = 0;
		return;
	}

	if(gsound.name.find(".wav") == -1)
		gsound.name = gsound.name + ".wav";

	CFileHandler sfile("sounds/" + gsound.name);
	if(!sfile.FileExists())
	{
		gsound.id = 0;
		return;
	}

	gsound.id = sound->GetWaveId(gsound.name);

}

WeaponDef *CWeaponDefHandler::GetWeapon(const std::string weaponname2)
{
	std::string weaponname(weaponname2);
	std::transform(weaponname.begin(), weaponname.end(), weaponname.begin(), (int (*)(int))std::tolower);

	std::map<std::string,int>::iterator ii=weaponID.find(weaponname);
	if(ii == weaponID.end())
		return NULL;

	return &weaponDefs[ii->second];
}
Sooo, this is the stub of work on having a second weapon type spawn from the first one?

Code: Select all

float3 CWeaponDefHandler::hs2rgb(float h, float s)
{
	if(h>0.5)
		h+=0.1f;
	if(h>1)
		h-=1;

	s=1;
	float invSat=1-s;
	float3 col(invSat/2,invSat/2,invSat/2);

	if(h<1/6.0){
		col.x+=s;
		col.y+=s*(h*6);
	} else if(h<1/3.0){
		col.y+=s;
		col.x+=s*((1/3.0-h)*6);

	} else if(h<1/2.0){
		col.y+=s;
		col.z+=s*((h-1/3.0)*6);

	} else if(h<2/3.0){
		col.z+=s;
		col.y+=s*((2/3.0-h)*6);

	} else if(h<5/6.0){
		col.z+=s;
		col.x+=s*((h-2/3.0)*6);

	} else {
		col.x+=s;
		col.z+=s*((3/3.0-h)*6);
	}
	return col;
}
If I'm reading this right, it explains why the weapon colors aren't matching OTA. I really think that this whole system should be scrapped in favor of straight-up and user-friendly RGB values. Spring is a 32-bit-color game... why kludge it down to a color table, especially one that isn't OTA's? Instead... have lasers and other weapons that do not have RGB values defined just have "colorRGB=255, 0, 0", so that older games that haven't been properly ported see all lasers as bright red? That should offend very few people, and get rid of one of the kludges here.
Tobi
Spring Developer
Posts: 4598
Joined: 01 Jun 2005, 11:36

Re: Weapons. Very long.

Post by Tobi »

Argh wrote:

Code: Select all

#define WEAPONTYPE_AIRCRAFTBOMB 6
#define WEAPONTYPE_FLAME 7
#define WEAPONTYPE_MISSILELAUNCHER 8
#define WEAPONTYPE_LASERCANNON 9
#define WEAPONTYPE_EMGCANNON 10
#define WEAPONTYPE_STARBURSTLAUNCHER 11
#define WEAPONTYPE_UNKNOWN 12

#define WEAPON_RENDERTYPE_MODEL 1
#define WEAPON_RENDERTYPE_LASER 2
#define WEAPON_RENDERTYPE_PLASMA 3
#define WEAPON_RENDERTYPE_FIREBALL 4

class TdfParser;

struct WeaponDef
{
	std::string name;
	std::string type;

	/*std::string sfiresound;
	std::string ssoundhit;
	int firesoundId;
	int soundhitId;
	float firesoundVolume;
	float soundhitVolume;*/
	GuiSound firesound;
	GuiSound soundhit;
Question number 4: so, can we use firesoundVolume in our FBIs? What does GuiSound firesound do?
It's commented out (/* ... */) so you can't use it. I've no clue what firesound does.
Argh wrote: Question 18: Why is projectilespeed defined when we use weaponvelocity in the FBI? Why is weaponvelocity not here? I take it that I'm missing something that's changed into another name in the CSunParser sections.
If there's only projectilespeed and not weaponvelocity I assume it just has a different name in the engine...

For you other questions I don't know the code well enough :|
Tobi
Spring Developer
Posts: 4598
Joined: 01 Jun 2005, 11:36

Post by Tobi »

Argh wrote:

Code: Select all

	int rendertype;
	int color;
Um, can we add a "colorRGB" category, where we name 3 RGB values, 255 255 255, like this: "colorRGB=255, 255, 255;"? That'd be most helpful.
I assume the color is already a RGB pattern. It's just stored in a single 32 bit integer by bit shifting.

Of course it is be possible to load it differently (I don't know how it's loaded now).
Argh wrote:

Code: Select all

	int beamlaser;
	//bool tracking;
	//bool selfprop;
	//bool turret;
	//bool smokeTrail;
	//std::string modelName;
Er... again, what is going on here? Tracking, selfprop, turret, smokeTrail, modelName? Are none of these things actually used? Or does "//" not mean "commented code" in CSun Parser?
'//' and '/* ... */' are both comments in all C/C++ code (*.h *.hpp *.c *.cpp).

So, no, they aren't used.

And note that CSunParser has been replaced by TdfParser.
Argh wrote:

Code: Select all

	sunparser->GetDef(weaponDefs[id].dropped, "0", weaponname + "\\dropped");
	sunparser->GetDef(lineofsight, "0", weaponname + "\\lineofsight");
	sunparser->GetDef(balistic, "0", weaponname + "\\balistic");
Again, balistic is miss-spelled. At least it's consistent ;)
It must be or the code wouldn't compile :D

Code: Select all

	sunparser->GetDef(weaponDefs[id].twophase, "0", weaponname + "\\twophase");
	sunparser->GetDef(beamweapon, "0", weaponname + "\\beamweapon");
	sunparser->GetDef(weaponDefs[id].guided, "0", weaponname + "\\guidance");
	sunparser->GetDef(rendertype, "0", weaponname + "\\rendertype");
	sunparser->GetDef(color, "0", weaponname + "\\color");
	sunparser->GetDef(beamlaser, "0", weaponname + "\\beamlaser");
	sunparser->GetDef(weaponDefs[id].vlaunch, "0", weaponname + "\\vlaunch");
	sunparser->GetDef(weaponDefs[id].selfprop, "0", weaponname + "\\selfprop");
	sunparser->GetDef(weaponDefs[id].turret, "0", weaponname + "\\turret");
	sunparser->GetDef(weaponDefs[id].visuals.modelName, "", weaponname + "\\model");
	sunparser->GetDef(weaponDefs[id].visuals.smokeTrail, "0", weaponname + "\\smoketrail");
	sunparser->GetDef(weaponDefs[id].noSelfDamage, "0", weaponname + "\\NoSelfDamage");
I've tried to add smoketrails to ballistic weapons... it doesn't work. Yet, here, it seems to read that value. Why doesn't it work?
Only reading the value doesn't have to be enough. There are a lot of implementation of an abstract projectile class (dunno the exact name). Probably the CBallisticProjectile or whatever it's called doesn't have code for smoketrails.

Code: Select all

	sunparser->GetDef(weaponDefs[id].firesound.name, "", weaponname + "\\soundstart");
	sunparser->GetDef(weaponDefs[id].soundhit.name, "", weaponname + "\\soundhit");

	/*if(weaponDefs[id].firesound.name.find(".wav") == -1)
		weaponDefs[id].firesound.name = weaponDefs[id].firesound.name + ".wav";
	if(weaponDefs[id].soundhit.name.find(".wav") == -1)
		weaponDefs[id].soundhit.name = weaponDefs[id].soundhit.name + ".wav";*/

	//weaponDefs[id].firesoundVolume = 5.0f;
	//weaponDefs[id].soundhitVolume = 5.0f;
Hmm. I don't see any reference to firesoundVolume or soundhitVolume here. Are they valid, or just sitting there teasing me?
They just sit there teasing you.

Code: Select all

	std::map<std::string, std::string> damages=sunparser->GetAllValues(weaponname + "\\DAMAGE");
	for(std::map<std::string, std::string>::iterator di=damages.begin();di!=damages.end();++di){
		int type=damageArrayHandler->GetTypeFromName(di->first);
		float damage=atof(di->second.c_str());
	weaponDefs[id].impulseFactor=atof(sunparser->SGetValueDef("1", weaponname + "\\impulsefactor").c_str());
		if(damage==0)
			damage=1;
		if(type!=0){
			weaponDefs[id].damages[type]=damage;
//			info->AddLine("Weapon %s has damage %f against type %i",weaponname.c_str(),damage,type);
		}
	}
What does this do?
By taking a quick look it loads all name=value pairs in weaponname+"\\DAMAGE" section.

Then it loops through all of them and loads the impulsefactor corresponding to that damage type.

(I think.)

Code: Select all

	weaponDefs[id].projectilespeed = atof(sunparser->SGetValueDef("0", weaponname + "\\weaponvelocity").c_str())/GAME_SPEED;
	weaponDefs[id].startvelocity = max(0.01,atof(sunparser->SGetValueDef("0", weaponname + "\\startvelocity").c_str())/GAME_SPEED);
	weaponDefs[id].weaponacceleration = atof(sunparser->SGetValueDef("0", weaponname + "\\weaponacceleration").c_str())/GAME_SPEED/GAME_SPEED;
	weaponDefs[id].reload = atof(sunparser->SGetValueDef("1", weaponname + "\\reloadtime").c_str());
	weaponDefs[id].salvodelay = atof(sunparser->SGetValueDef("0.1", weaponname + "\\burstrate").c_str());
	sunparser->GetDef(weaponDefs[id].salvosize, "1", weaponname + "\\burst");
Whoa. So if salvosize > 1, then weapons fire more than one shot per shooting instance? Can we really have true shotguns?
Note that salvoize value is loaded from 'burstrate' tdf tag in the code you pasted.

Code: Select all

	weaponDefs[id].restTime = 0.0f;
	sunparser->GetDef(weaponDefs[id].metalcost, "0", weaponname + "\\metalpershot");
	sunparser->GetDef(weaponDefs[id].energycost, "0", weaponname + "\\energypershot");
	sunparser->GetDef(weaponDefs[id].selfExplode, "0", weaponname + "\\burnblow");
	weaponDefs[id].fireStarter=atof(sunparser->SGetValueDef("0", weaponname + "\\firestarter").c_str())*0.01;
	weaponDefs[id].paralyzer=!!atoi(sunparser->SGetValueDef("0", weaponname + "\\paralyzer").c_str());
	weaponDefs[id].damages.paralyzeDamage=weaponDefs[id].paralyzer;
	weaponDefs[id].soundTrigger=!!atoi(sunparser->SGetValueDef("0", weaponname + "\\SoundTrigger").c_str());

	//sunparser->GetDef(weaponDefs[id].highTrajectory, "0", weaponname + "\\minbarrelangle");
Ok... so minbarrelangle is mentioned here, but it's broken? Is this just commented out? Sorry, this syntax is confusing.
Yeah commented out.

Code: Select all

float3 CWeaponDefHandler::hs2rgb(float h, float s)
{
	if(h>0.5)
		h+=0.1f;
	if(h>1)
		h-=1;

	s=1;
	float invSat=1-s;
	float3 col(invSat/2,invSat/2,invSat/2);

	if(h<1/6.0){
		col.x+=s;
		col.y+=s*(h*6);
	} else if(h<1/3.0){
		col.y+=s;
		col.x+=s*((1/3.0-h)*6);

	} else if(h<1/2.0){
		col.y+=s;
		col.z+=s*((h-1/3.0)*6);

	} else if(h<2/3.0){
		col.z+=s;
		col.y+=s*((2/3.0-h)*6);

	} else if(h<5/6.0){
		col.z+=s;
		col.x+=s*((h-2/3.0)*6);

	} else {
		col.x+=s;
		col.z+=s*((3/3.0-h)*6);
	}
	return col;
}
If I'm reading this right, it explains why the weapon colors aren't matching OTA. I really think that this whole system should be scrapped in favor of straight-up and user-friendly RGB values. Spring is a 32-bit-color game... why kludge it down to a color table, especially one that isn't OTA's? Instead... have lasers and other weapons that do not have RGB values defined just have "colorRGB=255, 0, 0", so that older games that haven't been properly ported see all lasers as bright red? That should offend very few people, and get rid of one of the kludges here.
No you're not reading it right. The code you quoted is 'just' a helper function which converts HS (Hue Saturation probably) color values to RGB color values (note that float3 is a vector with 3 components, x y and z. Here x is red, y is green and z is blue).
User avatar
Argh
Posts: 10920
Joined: 21 Feb 2005, 03:38

Post by Argh »

Firstly... I know I don't have the current source. I winded my way through the links, and got the source for 0.7b1, not b3.

Very helpful, especially this: Tracking, selfprop, turret, smokeTrail, modelName aren't valid TDF values. Along with a whole bunch of other stuff that modders will probably find very interesting. I think it's kind've amusing that Spring just assumes that everything that's not a "onlyforward" is a turret, but that's deal-able, even if I don't like the way that constrained turret angles work (I described what I think would be a better alternative elsewhere).

As for the projectile class stuff, you guys could add the smoketrail code and then if smoketrail=1, then ballistic weapons could have smoketrails... that'd be sweet, and fix certain problems with gameplay/special effects.

ImpulseFactor is a big, big problem. It really needs to get de-coupled from damage, and de-coupled from ground deformation, and whatever's causing unit explosions to ignore ImpulseFactor needs to get fixed. I've described why in great detail elsewhere, but now at least I can see how it's going about this, sort've.

Ok, as for the color of shots, yeah, I'd strongly prefer that we use the method I'm describing. Every modder/artist thinks in terms of RGB values. Using this bitshifting approach is very weird, and un-intuitive... and the fact that the game is (I think) referring to that non-standard PAL file, that I can't even manipulate in Photoshop, so I can't even make a map of what values correspond to what color... is very aggravating.

Ok, so salvo isn't any different from burst. Drat. I was hoping I'd found hidden gold- I, and many modders, would probably like a salvo TDF value that fired individual shots (allowing the COB parser to move on to the next bit of code, i.e., switching weapon barrels, etc.) and then waited. The only ways we can do this right now are horrible, icky kludges straight from OTA :P

And minbarrelangle is commented. Ok, at least now I know what a comment looks like. I already knew it was broken.
User avatar
Argh
Posts: 10920
Joined: 21 Feb 2005, 03:38

Post by Argh »

Hmmm...

turret=1 is a valid variable! I tested it... and here's the fascinating part: unlike OTA, which could not handle this variable being left undefined for standard weapon types, Spring interprets it as, "fire on a fixed-forward arc, if tolerance allows". Very, very interesting, for those who'd like to make HTH-combat mods, or mods with very limited frontal arc units. May be an alternative route to the current cone limitations.

So, I must've mis-read that part entirely. Ignore that. I will keep testing.
User avatar
Argh
Posts: 10920
Joined: 21 Feb 2005, 03:38

Post by Argh »

Smoketrail is also valid. Scratch all of that paragraph, it is obviously completely wrong. Sorry if that annoyed anybody, please do not throw things at the modder in the small wire cage ;)
User avatar
FLOZi
MC: Legacy & Spring 1944 Developer
Posts: 6240
Joined: 29 Apr 2005, 01:14

Re: Weapons. Very long.

Post by FLOZi »

Argh wrote:As promised, in Mantis... here is a first stab at listing all of the weapon variables that are actually used by Spring.

Spring devs, I have a number of questions, now that I have grepped the source a bit. Please, if you can spare a moment, help me out.

Code: Select all

	float range;
	float heightmod;
	float accuracy;				//inaccuracy of whole burst
	float sprayangle;	//inaccuracy of individual shots inside burst
	float movingAccuracy; //inaccuracy while owner moving
	float targetMoveError;	//fraction of targets move speed that is used as error offset
Question no. 5: so, does targetMoveError makes the weapon miss more based on the speed of the target? That might be very useful for AATA or other somewhat-realistic mods.
That is what it is supposed to do. not gotten around to experimenting with it yet.

Code: Select all

	//float damage;
	//float airDamage;
	DamageArray damages;
	float areaOfEffect;
	float impulseFactor;
	bool noSelfDamage;
	float fireStarter;
Question no. 6: does noSelfDamage work?
Yes it does. (At one point some AATA aircraft used it so their bombs didn't blow themselves up)

Code: Select all

	bool soundTrigger;

	bool selfExplode;
Question 15: what is selfExplode?
I would guess this might be BurnBlow - the tag to make a weapon detonate at the end of its range. Just a guess of course, can't be sure without checking the code. (And my C++ is really shocking :wink: )
User avatar
Argh
Posts: 10920
Joined: 21 Feb 2005, 03:38

Post by Argh »

gravityAffected is not a valid TDF variable, or is only called when weapons are ballistic. Drat, I was hoping that we could have lasers that were affected by gravity (a fast 'n dirty way to do machineguns with "tracers" that actually obeyed the laws of physics, but ah well).
SJ
Posts: 618
Joined: 13 Aug 2004, 17:13

Post by SJ »

I didnt read the entire thing but as a high level explanation of why some thing look as they do its because Spring was at first programmed as a 19th century RTS that we then retrofitted to use TA stuff. Since most stuff in TA already worked in that system we never bothered to change internal names but just tried to map the TA weapon variables to the already existing ones which caused some inconsistensies. The biggest problem being that TA probably doesnt really have any different weapon "classes" but just hangs on different movement/graphical attributes on a standard weapon while Spring has always had a fixed number of different classes that we then mapped the different TA weapons to according to some more or less arbitary criteria.
User avatar
Argh
Posts: 10920
Joined: 21 Feb 2005, 03:38

Post by Argh »

Yeah, that's pretty much what I thought happened. So, from a coding standpoint, how much of a spaghetti mess is this going to be, if (a big if) my/Zaphod's dream of moving towards a scriping system that covered all game objects is to be realised?

I can see where various things were shoehorned in to support XTA specifically, as well as SWTA (which, given the screenshots that resulted, and the public reaction, was probably well worth the kludge, my elbowing aside) ... but I really think that it might be a good idea to consolidate things under a #WEAPON, though.

In the interests of flexibility and simplicity... instead of having really arbitrary things like "ballistic", period, we could just have a weapon system where "myGravity=SomeFloat", and values of 0 could be used for LOS weapons and guided projectiles. I have a feeling that if we all sort've sat down and thought it out, we could probably cut down the number of "tags" by a great deal, and yet end up with a better system- many of OTA's weapons were very purpose-built, and I have a feeling that they, like you folks, were under some time pressure, and built what they needed now, not with an endless future of modding in mind. Looking at where things are in the code, though... even with my lack of C++ experience, I can see that this is do-able, and probably not even too painful.

As a practical example, if we had a limited-traverse system + tolerance, we'd have everything we needed for vertical (or, whatever angle) launch systems- give it a a limited traverse of straight up, 0 degree cone (or a teeny-tiny float) and give it a tolerance of 65536 (or, better yet, for those of us who don't think in squares of two, something like "toleranceX=360; toleranceY=360; toleranceZ=360;" and voila... a weapon that will shoot straight up, if a valid target enters its range. If we can have a counter we can set before a weapon's "engine" engages (i.e., before acceleration/guidance began) then we have everything we need for Starburst missiles... only, unlike what we have now, it'd be flexible. We could, for example, do anime-style rocket-pods, that would shoot out from crazy angles, then engage acceleration after a half-second pause, begin guiding, and look frickin' awesome... and it'd be the same system used to also do things like nuclear subs launching missiles, nuke silos firing, etc.

These are just random thoughts, of course- I do not know if anybody really wants my opinion on this stuff, and I don't have a super-detailed plan for Everything anyhow, even if I thought anybody would be interested.

I'm gonna mod with whatever tools I have available, really, as this engine already rocks, and I'm having fun (which is, after all, the main goal here, at least for me). But it'd definately be much, much cooler if we modders could have a lot more control over these sorts of things. When I'm doing weapons design, for example... I want persnickety, fine-tuned control. I may want the end result to be fun, but I'm deadly serious about how things interact- I want it right. The current system has been pretty frustrating in places, but I've dealt anyhow- and compared to some of the problems I've had with closed-source games, this is really not too bad- at least here I can bug developers and read the source... really, a pretty darn good deal :-)
Gnomre
Imperial Winter Developer
Posts: 1754
Joined: 06 Feb 2005, 13:42

Post by Gnomre »

We don't even use the SWTA hacks. The laser model hack is from a time when only missiles (and SWTA's lasers) could have models. The other stuff is irrelevent at this point. We even moved away from modelled lasers months before release because spring shades the models, which looks very bad on a model that's supposed to be light/plasma/something that puts off a glow of its own.

Also, I'm pretty sure the experience/accuracy thing is defined elsewhere. The file you quoted simply parses and loads the information when the unit is created, other things modify the values with veteranacy or due to script based changes or whatever.

One way you could control the firing sound of a unit would be to use the play-sound operator in the script instead of the start sound in the weapon TDF. However, you couldn't do something similar for the hit sound.

I'd also like to see fully scriptable weapon "plugins" rather than the system we have now. By all means, include the default easy plugins (your basic laser, ballistic cannon, TA style v-launch, flamethrower, and so on) but it'd be nice to be able to go in and hack stuff up ourselves without needing the changes committed to the engine itself.
User avatar
Argh
Posts: 10920
Joined: 21 Feb 2005, 03:38

Post by Argh »

Thanks for the update, Gnome. As I said before, I'm not really jealous about the hacks to support SWTA in Spring- after all, it was those sexxxy screenshots and early movies that got me paying serious attention to it as a game engine in the first place :lol:

Hmm. Forgot about play-sound- I really should be using that, instead of using the TDF method, as it would provide better control for certain things. Plus, I'd really like my units to make walking/driving noises, instead of being boring and silent. After all, if I'm going to have NanoBlobs break people's computers, I shouldn't go half-way, right? ;)

As for hit sounds... just hack up the code used for SmokeUnit, that checks HealthNow vs. HealthThen, and play a sound if it's lower... a different sound if lower by X%, etc. In fact, you could do that and a weaponhit sound, to make really kewl damage noises... hmmmm... I have a big collection of metallic "clunks", electrical crackles, etc.... hmmmmm

Maybe it's time to lay out a theoretical talk-talk about this stuff, like I did with AI at several points. At the very least, it might get everybody thinking about it, and better ideas might arrive.

I would like to think that it won't get brushed off as just another wish-list, but I lack the C++ skills to back up my wants with work, which sucks- I hate requesting other people to do something I cannot do myself, but I have rather poor math skills, which is kind've a problem- I just don't have that kind of brain :|

But I do think we could create a very simple, streamlined set of physical definitions that could be combined with one another to create just about every possible weapon system. I will give this some thought before laying it out, though.
Gnomre
Imperial Winter Developer
Posts: 1754
Joined: 06 Feb 2005, 13:42

Post by Gnomre »

Yeah, those screenshots/movies were purely the work of the SYs. Obviously we couldn't start work on porting until we got a hold of the engine ;)

You should dig up my topic on using play-sound (posted in the mod forum). A custom .h file had to be made for using it, and there was some theory about using it to create engine sounds as you describe (footsteps wouldn't be hard, you'd just have to sync it into the walk animation).

The thing about using SmokeUnit or anything like that is that you can't detect what hit it. Did I just get whapped with an intimidator shell or a BLoD? It'd be pretty odd if the timmy shell didn't have the oomph sound of artillery, and vice versa. I do like the "system failure" sound idea, though. Perhaps even grunts for mods with infantry.

Also, Hoosier pride!!
User avatar
FizWizz
Posts: 1998
Joined: 17 Aug 2005, 11:42

Post by FizWizz »

Argh, what you usually ask for or throw out for suggestion are not just your everyday wishlist, and just so you know, I look forward to reading them because I can expect them to be different from the rest, in a good way.
User avatar
jcnossen
Former Engine Dev
Posts: 2440
Joined: 05 Jun 2005, 19:13

Post by jcnossen »

Mostly I think it all comes down to being able to script weapons, effects, and projectiles. Aside from how the scripting support works, we can already think about what the interface should be like.
But I do think we could create a very simple, streamlined set of physical definitions that could be combined with one another to create just about every possible weapon system. I will give this some thought before laying it out, though.
This could be very useful: If the weapons system has to be improved (And I absolutely agree that it should), LUA is probably not an option because of it's speed. Spring should have a less general scripting language focused on speed of execution, or a TDF like system that is better organised and designed. In both cases a clear vision on the requirements of the weapons system would be good to have.
Gnomre
Imperial Winter Developer
Posts: 1754
Joined: 06 Feb 2005, 13:42

Post by Gnomre »

I'd personally like to see that kind of scripting integrated with direct access to everything in the engine relating to weapons... to control how big the explosion graphic is, what color it is, how much smoke the weapon puts off, even the ability to make it play sounds while in the air (whistling artillery!). A TDF system could certainly still work for all that, but I personally think it'd be easier for you guys who do the engine coding to ration the work off to us modders for such special effects, instead of adding a tag every version.

I personally wouldn't even mind doing it as a DLL (or something like it) plugin in C++. Of course, like I said before, you'd have to ship the default types, but it'd open up so much more to us modders without making the others do more work themselves.
User avatar
Argh
Posts: 10920
Joined: 21 Feb 2005, 03:38

Post by Argh »

I am in the midst of writing up a proposal for such a system. Please bear with me, it will take at least 24 more hours, I am guessing- proposing a re-design of a lot of game code areas, and figuring out elegant ways to solve the current issues is rather daunting.
User avatar
Argh
Posts: 10920
Joined: 21 Feb 2005, 03:38

Post by Argh »

Now that I have put some thought into things, here's my thought. This may strike people as very radical, but I think it's elegant. I can break it down to one sentence:

"Weapons are nothing but particle systems with additional gameplay effects."

More on this as I get closer to finish.
User avatar
mecha
Posts: 98
Joined: 30 Sep 2005, 09:53

Post by mecha »

For a given muzzle velocity there are two solutions for the angle by which a target can be hit in 3 dimensional space. From what I understand the purpose of the ballistic tag is to select the solution with the greatest angle rather than the smallest angle which is the default.
Just my 2 cents!
Locked

Return to “Engine”