Jump to content
dram

Take On Mars discussion (continued from off-topic)

Recommended Posts

Here is a link to the original discussion:

http://forums.bistudio.com/showthread.php?156296-Take-On-Mars-New-BIS-Game/page15

---------- Post added at 14:48 ---------- Previous post was at 14:40 ----------

Take on Mars looks great. Two questions: Can we land the Viking Lander from 1976? Also, can you explain a bit more about the "run your own space program" part of the game (i.e budgeting and launching probes)? Thanks!

All of our vehicles are based on real vehicles, but made with customizable slots. This means that the large rover (similar to Curiosity) has many slots on top where you can mount instruments, antennas etc.

The Space Program has you starting with a small budget, launching your first lander to Mars. This lander has a low quality camera, to replicate the feeling of getting the first images of Mars. You then continue to improve your technology as you progress through the various missions, which consist of scientific analyses, exploration, and taking photos. For each mission you send a new vehicle, or, assign it to a vehicle already on the surface nearby, that can complete the mission. Thus, reusing vehicles for new missions is also possible.

As for vehicle customization, there is a whole section in the main control room where you can construct various setups (another section is used for assigning missions etc). The vehicle you construct may be tested in the space agency's "Mars Yard" (inspired by the one at JPL), and you can drive it around just like you would later on the surface of Mars. There are no consequences for testing, it is used to test whether the setup you have assembled is usable (for example if you put a drill on the top of a vehicle, it will be quite useless). You can save this as a preset and send it to Mars thereafter. Alternatively, you may start a new mission, assign a pre-defined preset, and customize that.

I expect more questions in this regard, so feel free to ask.

Share this post


Link to post
Share on other sites

Some questions:

1. How many areas/maps will be available at launch and how large are they? (Individually.)

Answered here. Three terrains, 16km² (4x4km) each. :)

2. What is the theoretical upper limit of map sizes in the engine? Does it support streaming/paging for large terrains?

3. How difficult will it be to create new maps? Is it possible from within the game or will there be separate modding tools?

Edited by MadDogX

Share this post


Link to post
Share on other sites
2. What is the theoretical upper limit of map sizes in the engine? Does it support streaming/paging for large terrains?

Theoretically it depends on the grid size chosen and the super-texture resolution chosen, at present. I had tests with 16x16km terrain sizes which had one quarter of the terrain grid detail. Of course, you still have to manually fill that with objects, limiting it more by manpower than anything else. Streaming is not supported as of yet, but is planned.

3. How difficult will it be to create new maps? Is it possible from within the game or will there be separate modding tools?

Creating new maps is actually very easy, but can be time consuming, especially with the level of detail we have chosen (due to the size of the small rover). Workbench (an editor that will be provided with the modding pack) will be available post-launch, allowing users to create custom maps, particle effects, view objects etc. We will make tutorial videos for all of these aspects progressively after launch. Otherwise, really useful features of Workbench are for example "painting objects", allowing for quick covering of large areas with trees, rocks etc. These can then be individually adjusted to suit if needed. Additionally, adjusting terrain height etc is also done with a similar brush.

Share this post


Link to post
Share on other sites

Is there going to be an Pre-Order Option?

Is this digital distributed only?

Share this post


Link to post
Share on other sites
Is there going to be an Pre-Order Option?

We are sorting that at the moment, so I will be able to confirm soon.

Is this digital distributed only?

Yes, we would consider a limited count of boxed version if there was high interest.

Share this post


Link to post
Share on other sites

Forgive my ignorance please I have a few questions that may be obvious but im a little narrow minded in terms of Rv4 centric for 13 years now

The Engine for this will be the space game engine from Gaea mission ?

In terms of the game play is it remotely managing and steering vehicles or are you able to play a character and drive these vehicles ?

Will user made content be easy to add , I.E will there be an equivalent visitor and o2 tool or simply config mods ?

Lastly if the map is merely 4km what happens when you reach the ends , is it space or water and is it instant death or simply infanite procedural of space /water

Cheers

Share this post


Link to post
Share on other sites

I don't know if any of you have looked at Lunar Flight it is a great space explorer game and is only 9.99 on Steam so I am wonder what will Take On Mars be cost wise and what do they think they will accomplish that Lunar Flight hasn't? Will the specs be like TOH? More inportant will it run like TOH? I own TOH and don't even bother playing it because it is nearly unplayable framerate wise. Being it is basic terrain can we see a better running effort this time?

Share this post


Link to post
Share on other sites

Hi,

The Engine for this will be the space game engine from Gaea mission ?

Yes, a very heavily modified, updated version of it, specifically in terms of modability.

In terms of the game play is it remotely managing and steering vehicles or are you able to play a character and drive these vehicles ?

You remotely control the vehicles from the mission control room. Character driving is something that would belong to a human settlement on Mars, but currently we are simulating rovers similar to Opportunity and Curiosity.

Will user made content be easy to add , I.E will there be an equivalent visitor and o2 tool or simply config mods ?

Yes, we will be releasing Workbench, a toolset allowing for particle editing, terrain editing (using something like a brush for editing terrain height, and "painting" trees, rocks etc), viewing objects, and so on. Additionally scenarios will be made using the in-game editor, where you may also try out the various vehicles as you please.

Lastly if the map is merely 4km what happens when you reach the ends , is it space or water and is it instant death or simply infanite procedural of space /water

We have a "border terrain" model which spans on enough so you do not see where the terrain ends, but no, we do not have procedural generated terrain into the distance, especially due to us using real satellite data.

I don't know if any of you have looked at Lunar Flight it is a great space explorer game and is only 9.99 on Steam so I am wonder what will Take On Mars be cost wise and what do they think they will accomplish that Lunar Flight hasn't?

Yes, Lunar Flight is a great game, I've played it and love it, along with Kerbal Space Program, and the free hardcore simulator, Orbiter. Take On Mars will be for 10 Euro, and is a completely different game. In the game you control rovers on mars, perform exploration tasks, analyses, photos, with every rock posing an obstacle. This is very different to Lunar Flight, which is more about flying, delivering cargo and so on.

Will the specs be like TOH? More inportant will it run like TOH? I own TOH and don't even bother playing it because it is nearly unplayable framerate wise. Being it is basic terrain can we see a better running effort this time?

The specs will be like those for Carrier Command: Gaea Mission, however, this version features much higher scalability. Specifically, you can adjust the physics simulation detail, for example, and you can also adjust 3D resolution scaling. That means that on a 1920x1080 monitor your GUI would work in that resolution, but the 3D render would work in 1920x1080 x 3D scale. Thus, you can double that if you have a powerful comp (and get ridiculous fidelity), or you can scale it down as well all the way to 0.1x. At this level, it ran on my really old and crap Fujitsu LifeBook (integrated graphics) at around 18 fps. Which in itself is very impressive. Thief 2 on the machine runs at around 25 fps, to give you an idea.

Edited by Dram

Share this post


Link to post
Share on other sites
Is this digital distributed only?

More important is this Steam exclusive only? Or sprocket and other digital outlets with simple reg and key like arma2/OA?

You mention specs for the Carrier Command game, could you state the exact minimum and recommended specs here at all? Just for the sake of stating it clear :)

Share this post


Link to post
Share on other sites
Here's hoping that this game is Steamworks...

Was already mentioned as a possibility during the E3 interview (in fact, I think he even said it would be ideal), but it was not confirmed as they are still evaluating it.

Share this post


Link to post
Share on other sites
More important is this Steam exclusive only? Or sprocket and other digital outlets with simple reg and key like arma2/OA?

It will be available on Sprocket as well, but will be a Steam key, so you will need to run on Steam.

You mention specs for the Carrier Command game, could you state the exact minimum and recommended specs here at all? Just for the sake of stating it clear :)

[TABLE=class: game_grid, width: 540]

[TR]

[TD=class: grid_sysreqs, bgcolor: #CCCCCC, colspan: 2]MINIMUM PC REQUIREMENTS[/TD]

[/TR]

[TR]

[TD=class: grid_row_body]MINIMUM REQUIREMENTS[/TD]

[/TR]

[TR]

[TD=class: grid_row_body]Windows XP/Vista/7[/TD]

[/TR]

[TR]

[TD=class: grid_row_body]Intel Core 2 Duo 2.2GHz or AMD Dual-Core Athlon 2.5GHz[/TD]

[/TR]

[TR]

[TD=class: grid_row_body]NVIDIA GeForce 8800GT with Shader Model 3 and 512MB VRAM[/TD]

[/TR]

[TR]

[TD=class: grid_row_body]2GB RAM[/TD]

[/TR]

[TR]

[TD=class: grid_row_body]4GB Free HDD Space[/TD]

[/TR]

[TR]

[/TR]

[TR]

[TD=class: grid_row_body]9.0c DirectX

[/TD]

[/TR]

[TR]

[TD=class: grid_row_body]

RECOMMENDED REQUIREMENTS[/TD]

[/TR]

[TR]

[TD=class: grid_row_body]Windows 7[/TD]

[/TR]

[TR]

[TD=class: grid_row_body]Intel Core i5 or AMD Athlon Phenom X4[/TD]

[/TR]

[TR]

[TD=class: grid_row_body]NVIDIA GeForce GTX460 with Shader Model 3 and 1GB VRAM[/TD]

[/TR]

[TR]

[TD=class: grid_row_body]4GB RAM[/TD]

[/TR]

[TR]

[/TR]

[TR]

[TD=class: grid_row_body]9.0c DirectX[/TD]

[/TR]

[/TABLE]

Was already mentioned as a possibility during the E3 interview (in fact, I think he even said it would be ideal), but it was not confirmed as they are still evaluating it.

Yes, we are currently evaluating. We definitely want to have it present, as I know myself how convenient it is in terms of sharing content. As soon as more specific info regarding this is available, I will write it here.

Edited by Dram

Share this post


Link to post
Share on other sites

I can live with the 10 Euro price that works for me and I think we can all live with those specs. I am looking forward to TOM actually. I thank you for answering the questions I had. I see this added to my steam collection rather nicely :)

Share this post


Link to post
Share on other sites
I can live with the 10 Euro price that works for me and I think we can all live with those specs. I am looking forward to TOM actually. I thank you for answering the questions I had. I see this added to my steam collection rather nicely :)

I'm glad you're looking forward to it. I'm hoping the modding will catch on and we see plenty of user content added.

Share this post


Link to post
Share on other sites

Will it be possible to use FSM system to create some automony of ambient machines or other interesting things or this engine uses someother method than FSM ?

Thanks for previous answer I already got my Euro ready , think that price is worth what I already learned and seen so far , great job , I hope some kind of MOD allows the long term future like DayZ for Arma 2 , or of course your own ideas allow it to get more life than TOH

Share this post


Link to post
Share on other sites

One more from me: what scripting language does the game use, if any? (For scenarios and such.)

Share this post


Link to post
Share on other sites
Will it be possible to use FSM system to create some automony of ambient machines or other interesting things or this engine uses someother method than FSM ?

Thanks for previous answer I already got my Euro ready , think that price is worth what I already learned and seen so far , great job , I hope some kind of MOD allows the long term future like DayZ for Arma 2 , or of course your own ideas allow it to get more life than TOH

This engine doesn't use the FSM system that ArmA has, though it is no problem to do the same things via script. As I mentioned before, the script allows really low-level access to the engine, theoretically allowing you to modify settings of the campaign in the script, as well as adjust individual parts of the vehicle, their position, damage and all those standard things, as well as create individual physics bodies, connect them via joints, spawn projectiles, mess with projectiles....the list goes on, and all of this can be done via script. The only issue is of course that as it allows such direct access, you can theoretically make a script which breaks things in the campaign, but this is far outweighed by the positive things that can be done with it. I can go into more detail about what's possible if you wish, but in general, anything game-wise can be changed directly from script. Also, scripts are not fps capped, and thus if complex enough and ridiculously un-optimized, can slow down the game. This is in contrast to ArmA, which ensure a fluid framerate by capping the script time, so some may see this as positive or negative. Both have their advantages and disadvantages.

Share this post


Link to post
Share on other sites

If this is a mod-friendly Carrier command engine, does this mean :

- We could recreate something similar to Carrier command in terms of environnement (with water maybe, different skies...)

- base building ? Scavenging ? research/upgrades?

- Ennemy AI?

- in a nutshell, with enough time and talent, could I make my own Battlezone-like game?

Share this post


Link to post
Share on other sites
One more from me: what scripting language does the game use, if any? (For scenarios and such.)

I guess the closest thing is C++. For example, below projectile.h, the file containing the projectile class definition:

/**************************************************************************** *	PROJECTILE ENTITY DEFINITION
***************************************************************************/
class Projectile extends TKOM_Entity
{
int FXIndex;
float ImpactNextTime;
float DeathTime;
bool DeathByImpact;
string ModelPath;
string ContactPtcSnd;
string PtcPath;
Sound_Point fx_snd[PART_SOUNDS_MAX];
vector lastSimPos;
ParticleEmitter ptc_emit;

// Plays a particle effect, creates it if it does not exist
void SetPTC(string ptcStr)
{
	if (!ptc_emit) {
		ptc_emit = new ParticleEmitter;
		AddChild(this, ptc_emit, -1);
		SetOrigin(ptc_emit, ZeroVec);
		SetAngles(ptc_emit, ZeroVec);
		ptc_emit.Play(ptcStr);
	}
}

// Deletes the attached particle effect
void DeletePTC()
{
	if (ptc_emit) {
		RemoveChild(this, ptc_emit);
		delete ptc_emit;
		ptc_emit = NULL;
	}
}

// Stops a playing sound on the part
void StopSnd(int sndIndex)
{
	if (fx_snd[sndIndex]) {
		/*Sound_Point sndPt = fx_snd[sndIndex];
		if (sndPt.attached)
			RemoveChild(this, sndPt);*/
		delete fx_snd[sndIndex];
		fx_snd[sndIndex] = NULL;
	}
}

// Stops all sounds
void DeleteSnds()
{
	for (int i = 0; i < PART_SOUNDS_MAX; i++) {
		StopSnd(i);
	}
}

// Plays a sound on the part
void PlaySnd(int sndIndex, string sshader, int flags, float volume, float freq)
{
	if (Snd_Global_Vol > 0 && Snd_Global_Freq > 0) { // Don't play sounds if global modulators are null
		Sound_Point sndPt = NULL;
		if (!fx_snd[sndIndex]) {
			sndPt = new Sound_Point(GetOrigin(this), false, sshader, flags, volume, freq);
			if (sndPt.snd_handle == -1) {
				Print(String("VEHICLE_PART - PlaySnd: Could not play sound '" + sshader + "'!!!"));
				delete sndPt;
			} else
				fx_snd[sndIndex] = sndPt;
		}
		if (fx_snd[sndIndex]) {
			sndPt = fx_snd[sndIndex];
			sndPt.snd_vol = volume;
			sndPt.snd_freq = freq;
			if (sndPt.snd_shader != sshader) {
				StopSnd(sndIndex);
				PlaySnd(sndIndex, sshader, flags, volume, freq);
			}
		}
	}
}

// Plays a sound at a location
void PlaySndAt(vector pos, string sshader, int flags, float volume, float freq)
{
	if (Snd_Global_Vol > 0 && Snd_Global_Freq > 0) { // Don't play sounds if global modulators are null
		Sound_Point sndPt = new Sound_Point(pos, true, sshader, flags, volume, freq);
		if (sndPt.snd_handle == -1) {
			Print(String("VEHICLE_PART - PlaySndAt: Could not play sound '" + sshader + "'!!!"));
			delete sndPt;
		}
	}
}

// Returns an empty sound channel slot
int GetFreeSoundChannel()
{
	int result = -1;
	for (int i = 0; i < PART_SOUNDS_MAX; i++) {
		if (!fx_snd[i]) {
			result = i;
			i = PART_SOUNDS_MAX;
		}
	}
	return result;
}

// Updates sounds and their positions
void UpdateSounds()
{
	if (!noUpdate) {
		for (int i = 0; i < PART_SOUNDS_MAX; i++) {
			if (fx_snd[i]) {
				Sound_Point sndPt = fx_snd[i];
				if (sndPt.snd_handle == -1)
					StopSnd(i);
				else
					SetOrigin(sndPt, GetOrigin(this));
			}
		}
	} else
		DeleteSnds();
}

void Projectile(vector mat[], float speed, owned string ptcSnd, owned string modelstr, owned string ptcFx, float mass, float lifeTime, bool impactDel)
{
	lastSimPos = mat[3];
	ptc_emit = NULL;
	FXIndex = -1;
	ImpactNextTime = GetMissionTime(1);
	if (lifeTime <= 0)
		DeathTime = -100;
	else
		DeathTime = lifeTime;
	if (impactDel)
		DeathByImpact = true;
	else
		DeathByImpact = false;
	ModelPath = modelstr;
	vobject model = GetObject(ModelPath);


	SetFlags(this, TFL_VISIBLE|TFL_ACTIVE|TFL_SOLID);
	SetObject(model);
	SetMatrix(this, mat);
	vector vel = mat[0] * speed;
	ContactPtcSnd = ptcSnd;
	if (ContactPtcSnd != "")
		FXIndex = CreateFXType(ContactPtcSnd);

	dBodyCreateDynamic(this, ZeroVec, 0xffffffff);
	dBodySetDamping(this, AirFriction_Global, AirFriction_Global);
	dBodySetSleepingTreshold(this, 0.15, 0.15);
	dBodySetMass(this, mass);
	SetEventMask(this, EV_SIMULATE|EV_CONTACT|EV_FRAME|EV_SOUNDEND);

	PtcPath = ptcFx;
	if (PtcPath != "")
		SetPTC(PtcPath);

	SetVelocity(this, vel);

	if (model)
		ReleaseObject(model, false);
}

void ~Projectile()
{
	DeletePTC();
	DeleteSnds();
	ClearEventMask(this, EV_ALL);
	if (dBodyIsSet(this))
		dBodyDestroy(this);
}

void UpdateAtmosphericDrag()
{
	dBodySetDamping(this, AirFriction_Global, AirFriction_Global);
}

event private void EOnFrame(_entity other, int extra)
{
	UpdateSounds();
	UpdateAtmosphericDrag();
}

private void EOnSimulate(_entity other, float dt)
{
	if (lastSimPos == ZeroVec)
		lastSimPos = GetOrigin(this);

	// Handle back-tracing to look for missed collisions
	vector start = lastSimPos;
	vector end = GetOrigin(this);
	if (start != end) {
		_entity t_ent = NULL;
		float t_plane[4];
		int t_surfparm;
		float result = TraceLineEx(start, end, ZeroVec, ZeroVec, t_ent, t_plane, 0, t_surfparm, TRACE_WORLD|TRACE_ENTS|TRACE_LINE|TRACE_ONLY_PHYSICS|TRACE_RAGDOLLS, NULL);
		//AddDShape(SHAPE_DIAMOND, ARGBF(255, 255, 0, 0), SS_NOOUTLINE, end - "1 1 1", end + "1 1 1");
		if (result < 1 && t_ent && t_ent != this)
			SetOrigin(this, end);
	}
	lastSimPos = GetOrigin(this);

	// Under terrain, so set to correct pos
	float tHgt = lastSimPos[2] - GetTerrainHeight(lastSimPos);
	if (tHgt <= 0) {
		if (tHgt < 0)
			lastSimPos[2] = GetTerrainHeight(lastSimPos);
		else
			lastSimPos[2] = lastSimPos[2] + 1;
		SetOrigin(this, lastSimPos);
		lastSimPos = GetOrigin(this);
	}

	if (DeathTime > -100 && !noUpdate) {
		DeathTime -= dt;
		if (DeathTime <= 0)
			delete this;
	}
}

private void EOnContact(_entity other, Contact extra)
{
	if (!noUpdate) {
		vector mins, maxs;
		GetBoundBox(this, mins, maxs);
		float PartDensity = dBodyGetMass(this) / VectorLength(maxs - mins);
		float ContactVel = VectorLength(dBodyGetVelocityAt(this, extra.Position));
		if (dBodyIsSet(other))
			ContactVel = VectorLength(dBodyGetVelocityAt(other, extra.Position) - dBodyGetVelocityAt(this, extra.Position));
		float ContactImpulse = extra.Impulse * fabs(1 / PartDensity) + ContactVel * 0.5;


		int iLvl = 0;
		if (ContactImpulse >= PART_IMPACT_HEAVY)
			iLvl = 4;
		else {
			if (ContactImpulse >= PART_IMPACT_MEDIUM)
				iLvl = 3;
			else {
				if (ContactImpulse >= PART_IMPACT_LIGHT)
					iLvl = 2;
				else {
					if (ContactImpulse >= PART_IMPACT_SCRAPE)
						iLvl = 1;
				}
			}
		}

		Vehicle_FX fxEnt = NULL;
		if (FXIndex != -1)
			fxEnt = Vehicle_FXList[FXIndex];
		if (fxEnt && GetMissionTime(1) >= ImpactNextTime && iLvl > 0) {
			string iPtc = "";
			string iSnd = "";
			string iSndFar = "";
			float iVol = 1;
			float iVolFar = 1;
			float iDistFar = 3200;
			vector mat[4];
			if (iLvl == 4) {
				ImpactNextTime = GetMissionTime(1) + frand(fxEnt.FX_Lng_Contact_Hvy * 0.9, fxEnt.FX_Lng_Contact_Hvy * 1.1);
				iSnd = fxEnt.FX_Snd_Contact_Hvy;
				iSndFar = fxEnt.FX_Snd_ContactFar_Hvy;
				iVol = fxEnt.FX_Vol_Contact_Hvy;
				iVolFar = fxEnt.FX_Vol_Contact_Hvy;
				iPtc = fxEnt.FX_Ptc_Contact_Hvy;
				iDistFar = fxEnt.FX_Dist_ContactFar_Hvy;
			}
			if (iLvl == 3) {
				ImpactNextTime = GetMissionTime(1) + frand(fxEnt.FX_Lng_Contact_Med * 0.9, fxEnt.FX_Lng_Contact_Med * 1.1);
				iSnd = fxEnt.FX_Snd_Contact_Med;
				iSndFar = fxEnt.FX_Snd_ContactFar_Med;
				iVol = fxEnt.FX_Vol_Contact_Med;
				iVolFar = fxEnt.FX_Vol_Contact_Med;
				iPtc = fxEnt.FX_Ptc_Contact_Med;
				iDistFar = fxEnt.FX_Dist_ContactFar_Med;
			}
			if (iLvl == 2) {
				ImpactNextTime = GetMissionTime(1) + frand(fxEnt.FX_Lng_Contact_Lgt * 0.9, fxEnt.FX_Lng_Contact_Lgt * 1.1);
				iSnd = fxEnt.FX_Snd_Contact_Lgt;
				iSndFar = fxEnt.FX_Snd_ContactFar_Lgt;
				iVol = fxEnt.FX_Vol_Contact_Lgt;
				iVolFar = fxEnt.FX_Vol_Contact_Lgt;
				iPtc = fxEnt.FX_Ptc_Contact_Lgt;
				iDistFar = fxEnt.FX_Dist_ContactFar_Lgt;
			}
			GetCamera(CurrentListenCam, mat);
			float dist = VectorLength(GetOrigin(this) - mat[3]);
			if (iLvl == 1) {
				if (dist <= PART_SCRAPE_MAXDIST && GetMissionTime(1) > Part_LastScrape) {
					if (ContactVel >= PART_SCRAPE_HEAVY) {
						Part_LastScrape = GetMissionTime(1) + frand(fxEnt.FX_Lng_Scrape_Hvy * 0.9, fxEnt.FX_Lng_Scrape_Hvy * 1.1);
						iSnd = fxEnt.FX_Snd_Scrape_Hvy;
						iVol = fxEnt.FX_Vol_Scrape_Hvy;
						iPtc = fxEnt.FX_Ptc_Scrape_Hvy;
					} else {
						if (ContactVel >= PART_SCRAPE_MEDIUM) {
							Part_LastScrape = GetMissionTime(1) + frand(fxEnt.FX_Lng_Scrape_Med * 0.9, fxEnt.FX_Lng_Scrape_Med * 1.1);
							iSnd = fxEnt.FX_Snd_Scrape_Med;
							iVol = fxEnt.FX_Vol_Scrape_Med;
							iPtc = fxEnt.FX_Ptc_Scrape_Med;
						} else {
							Part_LastScrape = GetMissionTime(1) + frand(fxEnt.FX_Lng_Scrape_Lgt * 0.9, fxEnt.FX_Lng_Scrape_Lgt * 1.1);
							iSnd = fxEnt.FX_Snd_Scrape_Lgt;
							iVol = fxEnt.FX_Vol_Scrape_Lgt;
							iPtc = fxEnt.FX_Ptc_Scrape_Lgt;
						}
					}
				}
			}
			GetMatrix4(this, mat);
			if (iSnd != "" && dist < iDistFar) 
				PlaySndAt(mat[3], iSnd, SFX_ONCE|SFX_3D|SFX_DISCARDABLE, iVol, frand(0.9, 1.1));
			if (iSndFar != "" && dist >= iDistFar) 
				PlaySndAt(mat[3], iSndFar, SFX_ONCE|SFX_3D|SFX_DISCARDABLE, iVolFar, frand(0.9, 1.1));
			if (iPtc != "") {
				vector up = extra.Normal;
				vector forward = mat[0];
				vector aside = up * forward;
				VectorNormalize(aside);
				forward = aside * up;
				mat[0] = forward;
				mat[1] = aside;
				mat[2] = up;
				mat[3] = extra.Position;
				PlayParticleEffect(iPtc, mat);
			}
		}
		if (DeathByImpact)
			delete this;
	}
}
}


/****************************************************************************
***************************************************************************/

Share this post


Link to post
Share on other sites

Sounds great , thanks for informative answer

I guessthe detail woukd be better in the form of a wiki entry so I wont trouble you with that at this stage ,as always believe most questions will come from the how do I format than the what can I do with this kind of game

First thing I will be trying is replicate the beagle disaster of europe and UK attempt to land a rover on mars , I take it gravity etc is moddelled as it should ?

Share this post


Link to post
Share on other sites
If this is a mod-friendly Carrier command engine, does this mean :

- We could recreate something similar to Carrier command in terms of environnement (with water maybe, different skies...)

- base building ? Scavenging ? research/upgrades?

- Ennemy AI?

- in a nutshell, with enough time and talent, could I make my own Battlezone-like game?

Well what you're writing there is essentially a total conversion, and yes it would be possible. Every part of the game is accessible in scripts, so you could actually write a whole new game if you liked, but that would require editing the base files I guess. But specifically, environments with water will be possible as well as different skies (for example the planned Deimos addon). Base building and the likes are also possible if you took the time to write it. Essentially, you could do it sort of hack-wise by making a base vehicle that when selected runs a script that allows this type of gameplay, with a custom hud allowing buying of vehicles, buildings, setting them waypoints, and if you're a good scripter/programmer, some AI would be possible to write as well. Alternatively, the locations themselves can run scripts, so you could call it from there I guess.

---------- Post added at 19:15 ---------- Previous post was at 19:13 ----------

First thing I will be trying is replicate the beagle disaster of europe and UK attempt to land a rover on mars , I take it gravity etc is moddelled as it should ?

Funny that, we do have a beagle model in there as well :) And yes, gravity is modelled correctly, and is defined in the location's config file (so can be set per location, along with longitude/latitude, air friction, gravity etc etc).

Share this post


Link to post
Share on other sites

Is the space agency called DramSpace?

Oh and is there a possibility to get your hands on the wallpaper which the E3 machines were using?

Share this post


Link to post
Share on other sites
Is the space agency called DramSpace?

That was a joke by some of our team :) It's actually MARS-X:

Multinational Agency for Robotic Space eXploration.

Oh and is there a possibility to get your hands on the wallpaper which the E3 machines were using?

Hmm, I'm surprised they weren't on the site. They should be available tomorrow on the page, I'll post on the forums with them.

---------- Post added at 22:10 ---------- Previous post was at 22:06 ----------

...mod-friendly Carrier command engine...

Just to re-iterate, the whole game is written entirely in script, save for a few menu options and closed source parts (renderer, sound engine etc, as well as input controller), so if one wanted to make a completely different game using the absolute base (that is remove all TOM assets and put one's own), then that is also possible. I would warn though that such an option is obviously extremely time consuming (essentially making a game from scratch), nevertheless, it is possible.

Share this post


Link to post
Share on other sites
One more from me: what scripting language does the game use, if any? (For scenarios and such.)
I guess the closest thing is C++.
(...) Essentially, you could do it sort of hack-wise by making a base vehicle that when selected runs a script that allows this type of gameplay, (...)

First of all, thanks for the extremely detailed answer (including example config!), but I think you mistook my meaning. :)

My question was about the in-game scripting environment (like SQF in Arma), e.g. which scripting language is used and how it works. When you say "run a script that allows this type of gameplay", I'm sure you don't mean people have to write C++ code, right? ;)

Share this post


Link to post
Share on other sites
First of all, thanks for the extremely detailed answer (including example config!), but I think you mistook my meaning. :)

My question was about the in-game scripting environment (like SQF in Arma), e.g. which scripting language is used and how it works. When you say "run a script that allows this type of gameplay", I'm sure you don't mean people have to write C++ code, right? ;)

Ah, I misunderstood. In any case, in game scripts are the same format. It allows compiling even in game, meaning you can edit a script and have it be recompiled while in game (using script modules). There are of course low-level functions and high-level functions. The low level ones being things like I mentioned, allowing creating physics objects etc etc etc, while high level functions being things like BreakJoint(int jointNum), which is a function for the vehicle that tells it to break a specific joint (and in the function it handles the low-level deleting of the joint and everything around it).

Obviously that can startle people at first, that it is essentially similar to c++, however it is extremely powerful, and very performance efficient, hence the choice for this. Like I said, it's not exactly c++, but think of it more like a simplified version of it.

Here is the in-game script that controls the rover movement, for example:

/**************************************************************************** *	6-WHEELED ROVER CONTROLLER
***************************************************************************/
void Controller_OnSim(Vehicle_Controller controller)
{
Vehicle_Handler vehicle = controller.ownerVehicle;

int i1 = 0;
int i2 = 0;
int i3 = 0;
int i4 = 0;
bool b1 = false;
bool b2 = false;
bool b3 = false;
bool b4 = false;
bool b5 = false;
bool b6 = false;
bool b7 = false;
float f1 = 0;
float f2 = 0;
float f3 = 0;
float f4 = 0;
float f5 = 0;
Vehicle_Part e1 = NULL;
vector v1 = ZeroVec;
vector v2 = ZeroVec;
vector v3 = ZeroVec;
vector v4 = ZeroVec;
vector v5 = ZeroVec;
vector v6 = ZeroVec;
vector v7 = ZeroVec;
Vehicle_FX fxEnt = NULL;

/*b1 = false;
b2 = false;
if (parts_ents[CurrentPriPart] && parts_types[CurrentPriPart] == "Rover6")
	b1 = true;
if (parts_ents[CurrentSecPart] && parts_types[CurrentSecPart] == "Rover6")
	b2 = true;
if (b1 || b2) {*/
	// Get wheel offsets center
	for (i1 = 0; i1 < vehicle.parts_num; i1++)
	{
		if (vehicle.parts_ents[i1] && vehicle.parts_types[i1] == "Wheel") {
			if (vehicle.parts_pos[i1][0] > v2[0])
				v2[0] = vehicle.parts_pos[i1][0];
			if (vehicle.parts_pos[i1][0] < v2[1])
				v2[1] = vehicle.parts_pos[i1][0];
		}
		if (vehicle.parts_ents[i1] && vehicle.parts_types[i1] == "Steering") {
			if (vehicle.parts_pos[i1][0] > v3[0])
				v3[0] = vehicle.parts_pos[i1][0];
			if (vehicle.parts_pos[i1][0] < v3[1])
				v3[1] = vehicle.parts_pos[i1][0];
		}
	}
	// Update wheel status indicators if selected
	if (vehicle.isSelected) {
		for (i1 = 0; i1 < vehicle.parts_num; i1++)
		{
			if (vehicle.parts_ents[i1] && vehicle.parts_types[i1] == "Wheel") {
				e1 = vehicle.parts_ents[i1];
				v1 = vehicle.parts_pos[i1];
				i4 = -1;
				// Get the position of the wheel to determine which HUD indicator applies
				if (v1[1] > 0 && v1[0] == v2[0]) // Left-Front
					i4 = 0;
				if (v1[1] > 0 && v1[0] < v2[0] - 1 && v1[0] > v2[1] + 1) // Left-Middle
					i4 = 1;
				if (v1[1] > 0 && v1[0] == v2[1]) // Left-Back
					i4 = 2;
				if (v1[1] < 0 && v1[0] == v2[0]) // Right-Front
					i4 = 3;
				if (v1[1] < 0 && v1[0] < v2[0] - 1 && v1[0] > v2[1] + 1) // Right-Middle
					i4 = 4;
				if (v1[1] < 0 && v1[0] == v2[1]) // Right-Back
					i4 = 5;
				if (i4 >= 0 && vehicle.CheckPartConnect(i1, 0)) {
					if (e1.GenVec[0] < 1) { // Not jammed
						vehicle.stat_state[i4] = 0; // Set status indicator state to Working
					} else {
						vehicle.stat_state[i4] = 1; // Set status indicator state to Malfunction
					}
				} else {
					if (i4 >= 0)
						vehicle.stat_state[i4] = 2; // Set status indicator state to Destroyed
				}
			}
		}
	}
	f2 = 0;
	f3 = 0;

	b1 = false;
	b2 = false;
	if (vehicle.parts_ents[vehicle.CurrentPriPart] && vehicle.parts_types[vehicle.CurrentPriPart] == "Rover6")
		b1 = true;
	if (vehicle.parts_ents[vehicle.CurrentSecPart] && vehicle.parts_types[vehicle.CurrentSecPart] == "Rover6")
		b2 = true;


	if (b1 && b2) {
		f2 = vehicle.input_arc_pri0;
		f3 = vehicle.input_arc_pri1;
		if (fabs(vehicle.input_arc_sec0) > fabs(f2))
			f2 = vehicle.input_arc_sec0;
		if (fabs(vehicle.input_arc_sec1) > fabs(f3))
			f3 = vehicle.input_arc_sec1;
	} else {
		if (b1) {
			f2 = vehicle.input_arc_pri0;
			f3 = vehicle.input_arc_pri1;
		}
		if (b2) {
			f2 = vehicle.input_arc_sec0;
			f3 = vehicle.input_arc_sec1;
		}
	}

	b4 = true; // Whether to allow wheel spin
	b5 = true; // Whether to allow steering
	b6 = false; // Whether to force on-spot steering
	b7 = true; // Whether to allow gripping
	v4 = "-9 -9 -9"; // Left wheels joint num (front, middle, back)
	v5 = "-9 -9 -9"; // Right wheels joint num (front, middle, back)
	v6 = "-9 -9 -9"; // Left steering joint num (front, back)
	v7 = "-9 -9 -9"; // Right steering joint num (front, back)

	if (!vehicle.SystemsActivated) // Disallow gripping if vehicle systems are not online
		b7 = false;


	// Run through and get joint numbers
	for (i1 = 0; i1 < vehicle.joints_num; i1++)
	{
		if (vehicle.joints_ents[i1]) {
			if (vehicle.joints_type[i1] == JOINT_MOTOR || vehicle.joints_type[i1] == JOINT_TMOTOR) {
				i2 = vehicle.joints_part2[i1];
				if (vehicle.parts_ents[i2]) {
					e1 = vehicle.parts_ents[i2];
					if (vehicle.parts_types[i2] == "Wheel" && vehicle.CheckPartConnect(i2, 0)) {
						v1 = vehicle.parts_pos[i2];
						if (v1[1] > 0 && v1[0] == v2[0]) // Left-Front
							v4[0] = fabs(i1);
						if (v1[1] > 0 && v1[0] < v2[0] - 1 && v1[0] > v2[1] + 1) // Left-Middle
							v4[1] = fabs(i1);
						if (v1[1] > 0 && v1[0] == v2[1]) // Left-Back
							v4[2] = fabs(i1);
						if (v1[1] < 0 && v1[0] == v2[0]) // Right-Front
							v5[0] = fabs(i1);
						if (v1[1] < 0 && v1[0] < v2[0] - 1 && v1[0] > v2[1] + 1) // Right-Middle
							v5[1] = fabs(i1);
						if (v1[1] < 0 && v1[0] == v2[1]) // Right-Back
							v5[2] = fabs(i1);
					}
					if (vehicle.parts_types[i2] == "Steering" && vehicle.CheckPartConnect(i2, 0)) {
						v1 = vehicle.parts_pos[i2];
						if (v1[1] > 0 && v1[0] == v3[0]) // Left-Front
							v6[0] = fabs(i1);
						if (v1[1] > 0 && v1[0] == v3[1]) // Left-Back
							v6[2] = fabs(i1);
						if (v1[1] < 0 && v1[0] == v3[0]) // Right-Front
							v7[0] = fabs(i1);
						if (v1[1] < 0 && v1[0] == v3[1]) // Right-Back
							v7[2] = fabs(i1);
					}
				}
			}
		}
	}
	// Get spin rates
	for (i1 = 0; i1 < 3; i1++) {
		if (v4[i1] != -9) {
			i2 = floor(v4[i1]);
			i2 = vehicle.joints_part2[i2];
			e1 = vehicle.parts_ents[i2];
			f4 = e1.GenVec[2];
			v4[i1] = f4;
		}
		if (v5[i1] != -9) {
			i2 = floor(v5[i1]);
			i2 = vehicle.joints_part2[i2];
			e1 = vehicle.parts_ents[i2];
			f4 = e1.GenVec[2];
			v5[i1] = f4;
		}
		if (v4[i1] == -9 && v5[i1] == -9) {
			if (f2 == 0 && f3 != 0) { // Turning on spot
				v4[i1] = 1;
				v5[i1] = -1;
			} else {
				v4[i1] = 0;
				v5[i1] = 0;
			}
		} else {
			if (v4[i1] == -9) {
				if (f2 == 0 && f3 != 0) // Turning on spot
					v4[i1] = v5[i1] * -1;
				else
					v4[i1] = v5[i1];
			}
			if (v5[i1] == -9) {
				if (f2 == 0 && f3 != 0) // Turning on spot
					v5[i1] = v4[i1] * -1;
				else
					v5[i1] = v4[i1];
			}
		}
	}
	// Get turn angles
	for (i1 = 0; i1 < 3; i1++) {
		if (v6[i1] != -9) {
			i2 = floor(v6[i1]);
			i2 = vehicle.joints_part2[i2];
			e1 = vehicle.parts_ents[i2];
			f4 = e1.GenVec[2];
			v6[i1] = f4;
		}
		if (v7[i1] != -9) {
			i2 = floor(v7[i1]);
			i2 = vehicle.joints_part2[i2];
			e1 = vehicle.parts_ents[i2];
			f4 = e1.GenVec[2];
			v7[i1] = f4;
		}
		if (v6[i1] == -9 && v7[i1] == -9) {
			if (f2 == 0 && f3 != 0) { // Turning on spot
				v6[i1] = -1;
				v7[i1] = 1;
			} else {
				v6[i1] = 0;
				v7[i1] = 0;
			}
		} else {
			if (v6[i1] == -9) {
				if (f2 == 0 && f3 != 0) // Turning on spot
					v6[i1] = v7[i1] * -1;
				else
					v6[i1] = v7[i1];
			}
			if (v7[i1] == -9) {
				if (f2 == 0 && f3 != 0) // Turning on spot
					v7[i1] = v6[i1] * -1;
				else
					v7[i1] = v6[i1];
			}
		}
	}


	for (i1 = 0; i1 < 3; i1++) {
		// Turning on spot
		if (f2 == 0 && f3 != 0) {
			f1 = v4[i1] + v5[i1];
			f4 = fabs(v6[i1]) + fabs(v7[i1]);
			if (fabs(f1) > 0) { // Wheels spinning in same direction, so allow them to stop
				b4 = false; // Disallow spin
				b5 = false; // Disallow turning
			}
			if (f4 < 2) // Wheels not fully turned yet, so allow them to turn
				b4 = false; // Disallow spin
		}

		// Normal driving
		if (f2 != 0) {
			f1 = v4[i1] - v5[i1];
			f4 = v6[i1] - v7[i1];
			if (fabs(f4) > 0 && fabs(f1) == 0) // Wheels turned in opposing directions, so allow them to turn
				b4 = false; // Disallow spin
			if (fabs(f4) > 0 && fabs(f1) > 0) { // Wheels not stopped yet from on-spot turn, so let the wheels stop spinning first
				b4 = false; // Disallow spin
				b6 = true; // Force on-spot turn
			}
		}

		// Nothing
		if (f2 == 0 && f3 == 0) {
			f1 = fabs(v4[i1]) + fabs(v5[i1]);
			f4 = v6[i1] - v7[i1];
			if (fabs(f4) > 0 && f1 > 0) // Wheels not stopped yet from on-spot turn, so let the wheels stop spinning first
				b6 = true; // Force on-spot turn
		}

		f1 = fabs(v4[i1]) + fabs(v5[i1]) + fabs(v6[i1]) + fabs(v7[i1]);
		if (f1 != 0)
			b7 = false; // Disallow gripping if moving or turning at all
	}

	// Now run through and set engine status etc
	for (i1 = 0; i1 < vehicle.joints_num; i1++)
	{
		if (vehicle.joints_ents[i1]) {
			if (vehicle.joints_type[i1] == JOINT_MOTOR || vehicle.joints_type[i1] == JOINT_TMOTOR) {
				i2 = vehicle.joints_part2[i1];
				if (vehicle.parts_ents[i2]) {
					e1 = vehicle.parts_ents[i2];
					if (vehicle.parts_types[i2] == "Wheel") {
						// =======================================
						// =========== Wheel handling ============
						// =======================================
						/*	For vehicle log:
							GenVec2[0] - if 1, logged a minor malfunction
							GenVec2[0] - if 2, logged a major malfunction
						*/
						f4 = e1.GenVec[0];
						e1.GenVec[1] = e1.GenVec[1] + phys_FixedTick;
						if (e1.GenVec[1] >= 0.5 && vehicle.parts_damage[i2] > 0.25) { // Only check once per 1/2 second and only if damaged
							e1.GenVec[1] = 0;
							if (f2 != 0 || f3 != 0) { // Only check if the vehicle has input
								f1 = frand(0, 1);
								// If wheel not jammed, % chance of jamming relative to the damage
								if (f4 < 1 && f1 <= vehicle.parts_damage[i2] - 0.25 / 0.75)
									f4 = 1;
								else {
									// If wheel jammed, % chance of jamming permanently relative to the damage, and only above 0.6 damage
									if (f4 == 1 && vehicle.parts_damage[i2] > 0.6 && f1 <= vehicle.parts_damage[i2] - 0.6 / 0.4)
										f4 = 2;
									// If wheel jammed, % chance of unjamming relative to the damage
									if (f4 == 1 && f1 >= vehicle.parts_damage[i2] - 0.25 / 0.75)
										f4 = 0;
								}
								if (f4 == 0 && e1.GenVec[0] > 0)
									e1.GenVec[0] = 0;
								if (f4 == 1 && e1.GenVec[0] == 0) {
									e1.GenVec[0] = 1;
									vehicle.storage.AddLogEntry("#tkom_log_malfmin " + vehicle.parts_title[i2] + " " + itoa(vehicle.PartTypeGetNum(i2, vehicle.parts_types[i2])));
								}
								if (f4 == 2 && e1.GenVec[0] != 2) {
									e1.GenVec[0] = 2;
									vehicle.storage.AddLogEntry("#tkom_log_malfmaj " + vehicle.parts_title[i2] + " " + itoa(vehicle.PartTypeGetNum(i2, vehicle.parts_types[i2])));
								}
								e1.GenVec[0] = f4;
							}
						}

						b3 = false;
						if (vehicle.CheckPartConnect(i2, 0)) {
							b3 = true;
							e1.SetGrip(1.5, 2.5);
						}

						// Set power drainage if connected
						if (b3) {
							if (f2 == 0 && f3 != 0)
								vehicle.parts_pwrdrain[i2] = fabs(f3) * vehicle.joints_pwrdrain[i1];
							else
								vehicle.parts_pwrdrain[i2] = fabs(f2) * vehicle.joints_pwrdrain[i1];
						} else
							vehicle.parts_pwrdrain[i2] = 0;

						if (f4 < 1 && b3) { // Not jammed, connected
							f1 = f2;
							if (f2 == 0 && f3 != 0) { // Turning on spot
								f1 = f3;
								v1 = vehicle.parts_pos[i2];
								if (v1[1] < 0) // Right side
									f1 *= -1;
								if (v1[0] < v2[0] - 1 && v1[0] > v2[1] + 1) // Middle
									f1 *= 0.5;
							}
							if (!b4) // Not allowed to spin
								f1 = 0;

							float maxSpeed = 0;


							if (g_Campaign)
								maxSpeed = g_Campaign.Scale_Speed * vehicle.joints_limits_lo[i1][1];
							f5 = vehicle.joints_limits_hi[i1][1] / maxSpeed * phys_FixedTick;
							f4 = e1.GenVec[2]; // Get the current spin rate
							if (f1 < f4) {
								if (f1 > f4 - f5)
									f5 = f4 - f1;
								f4 -= f5;
							}
							if (f1 > f4) {
								if (f1 < f4 + f5)
									f5 = f1 - f4;
								f4 += f5;
							}
							e1.GenVec[2] = f4;
							f1 = f4;
							// Ungrip the part if it is gripped and is not allowed
							if (e1.Gripped && !b7)
								e1.Grip(false);

							// Awaken part if sleeping
							if (!dBodyIsActive(vehicle.parts_ents[i2]) && f1 != 0)
								dBodyActive(vehicle.parts_ents[i2], true);

							if (f1 != 0) {
								fxEnt = NULL;
								if (e1.FXIndex != -1)
									fxEnt = Vehicle_FXList[e1.FXIndex];
								if (fxEnt && fxEnt.FX_Snd_Engine != "")
									e1.PlaySnd(PART_SOUNDS_EXTCHNL1, fxEnt.FX_Snd_Engine, SFX_3D, fxEnt.FX_Vol_Engine * fabs(f1), 0.2 * fabs(f1) + 1.2);
							} else
								e1.StopSnd(PART_SOUNDS_EXTCHNL1);
							if (e1.Gripped)
								dJointSliderSetAngularMotor(vehicle.joints_ents[i1], 0, 0);
							else
								dJointSliderSetAngularMotor(vehicle.joints_ents[i1], f1 * maxSpeed, vehicle.joints_limits_lo[i1][2]);
						} else {
							e1.StopSnd(PART_SOUNDS_EXTCHNL1);
							dJointSliderSetAngularMotor(vehicle.joints_ents[i1], 0, vehicle.joints_limits_lo[i1][2]);
						}
						// =======================================
					}
					if (vehicle.parts_types[i2] == "Steering") {
						// =======================================
						// ========== Steering handling ==========
						// =======================================
						if (vehicle.CheckPartConnect(i2, 0)) { // Connected
							vehicle.parts_pwrdrain[i2] = fabs(f3) * vehicle.joints_pwrdrain[i1]; // Set power drainage
							f1 = f3;
							v1 = vehicle.parts_pos[i2];
							if (f2 == 0 || b6) {
								if (f1 != 0 || b6)
									f1 = 1;
								if (v1[1] < 0)
									f1 *= -1;
							}
							if (v1[0] > 0)
								f1 *= -1;
							if (!b5 && !b6) // Not allowed to turn, but not forced to turn on-spot
								f1 = 0;

							f5 = vehicle.joints_limits_lo[i1][2] * 0.25 * phys_FixedTick;
							f4 = e1.GenVec[2]; // Get the current turn
							if (b5 || b6) { // Not allowed to turn, but not forced to turn on-spot
								if (f1 < f4) {
									if (f1 > f4 - f5)
										f5 = f4 - f1;
									f4 -= f5;
								}
								if (f1 > f4) {
									if (f1 < f4 + f5)
										f5 = f1 - f4;
									f4 += f5;
								}
							}
							float tDiff = sin(fabs(f4 - f1) * 180 * DEG2RAD);
							e1.GenVec[2] = f4;
							f1 = f4;

							// Awaken part if sleeping
							if (!dBodyIsActive(vehicle.parts_ents[i2]) && f1 != 0)
								dBodyActive(vehicle.parts_ents[i2], true);

							if (tDiff != 0) {
								fxEnt = NULL;
								if (e1.FXIndex != -1)
									fxEnt = Vehicle_FXList[e1.FXIndex];
								if (fxEnt && fxEnt.FX_Snd_Engine != "")
									e1.PlaySnd(PART_SOUNDS_EXTCHNL1, fxEnt.FX_Snd_Engine, SFX_3D, fxEnt.FX_Vol_Engine * fabs(tDiff) + 0.1, 0.3 * fabs(tDiff) + 0.9);
							} else
								e1.StopSnd(PART_SOUNDS_EXTCHNL1);
							dJointHingeSetMotorTargetAngle(vehicle.joints_ents[i1], f1 * 50 * DEG2RAD, vehicle.joints_limits_lo[i1][1], vehicle.joints_limits_lo[i1][2]);
						} else {
							e1.StopSnd(PART_SOUNDS_EXTCHNL1);
							vehicle.parts_pwrdrain[i2] = 0; // Clear power drainage
							dJointHingeSetMotorTargetAngle(vehicle.joints_ents[i1], 0, vehicle.joints_limits_lo[i1][1], vehicle.joints_limits_lo[i1][2]);
						}
						// =======================================
					}
					if (vehicle.parts_types[i2] == "Suspension")
						dJointHingeSetMotorTargetAngle(vehicle.joints_ents[i1], 0, vehicle.joints_limits_lo[i1][1], vehicle.joints_limits_lo[i1][2]);
				}
			}
		}
	}
//}
// Enable wheel tracks only if main part is rover6 and only for attached wheels
if (vehicle.parts_types[0] == "Rover6") {
	for (i1 = 0; i1 < vehicle.parts_num; i1++)
	{
		if (vehicle.parts_ents[i1] && vehicle.parts_types[i1] == "Wheel") {
			e1 = vehicle.parts_ents[i1];
			if (vehicle.CheckPartConnect(i1, 0))
				e1.EnableTracks(true);
			else
				e1.EnableTracks(false);
		}
	}
}
}
/****************************************************************************
***************************************************************************/

Share this post


Link to post
Share on other sites

Please sign in to comment

You will be able to leave a comment after signing in



Sign In Now

×