Jump to content
Sign in to follow this  
Teancum

Vexing vectors!

Recommended Posts

I'm trying to program the multiple barrel shots of the Fusion Cutter through code. I have a CASE statement that lets me loop through four firing sections representing four barrels -- that works correctly. The problem is when I try to create an offset vector and add them together for each barrel it crashes. I'm not very good with vectors admittedly. The offending code is commented half way down.

 

 

The offending code:

	vec3_t	start;
	int		damage	= weaponData[WP_DEMP2].damage;
	int		currentbarrel = NULL;
	gentity_t *missile;
	vec3_t offset;
	vec3_t barrelUno;
	vec3_t barrelDos;
	vec3_t barrelTres;
	vec3_t barrelQuatro;


	VectorCopy( muzzle, start );
	WP_TraceSetStart( ent, start, vec3_origin, vec3_origin );//make sure our start point isn't on the other side of a wall

	WP_MissileTargetHint(ent, start, forwardVec);
	/*missile = CreateMissile(start, forwardVec, DEMP2_VELOCITY, 10000, ent);*/
	switch (currentbarrel)
	{
	case 1: //leftmost barrel
		/*offset[0] = -2.0;
		offset[1] = 0.0;
		offset[2] = 0.0;
		VectorAdd(start, offset, barrelUno);*/
		missile = CreateMissile(barrelUno, forwardVec, DEMP2_VELOCITY, 10000, ent);
		break;
	case 2: //left-mid barrel
		missile = CreateMissile(start, forwardVec, DEMP2_VELOCITY, 10000, ent);
		break;
	case 3: //right-mid barrel
		missile = CreateMissile(start, forwardVec, DEMP2_VELOCITY, 10000, ent);
		break;
	case 4: //rightmost barrel
		missile = CreateMissile(start, forwardVec, DEMP2_VELOCITY, 10000, ent);
		break;
	default: //catch all, also during initialization
		//set to 1, but fire from barrel 4
		currentbarrel = 1; 
		missile = CreateMissile(start, forwardVec, DEMP2_VELOCITY, 10000, ent);
	}

Share this post


Link to post

Hi,

 

There are two problems with your code:

For starters, only the first shot will ever fire. You need to loop through the four shots like this:

for (currentShot = 1; currentShot <= 4; currentShot++) {
    ...
}
Your switch would be where the ... are now. You can remove the default case of your switch then, since it starts from 0.

 

I forgot what the second thing was, but maybe you can tell me which commented line is breaking it?

Share this post


Link to post

It was pretty much what you laid out. I figured out it would only fire from the default case. I hadn't thought of a for loop. That should work.

 

***EDIT***

Here's what I've got now. I know I've referenced it wrong in the for loop as barrel shows as invalid. Looking up how to do it right.

	vec3_t offset;
	vec3_t barrel1;
	barrel1[0] = 22.0;
	barrel1[1] = 0.0;
	barrel1[2] = 0.0;
	vec3_t barrel2;
	barrel2[0] = 11.0;
	barrel2[1] = 0.0;
	barrel2[2] = 0.0;
	vec3_t barrel3;
	barrel3[0] = -11.0;
	barrel3[1] = 0.0;
	barrel3[2] = 0.0;
	vec3_t barrel4;
	barrel4[0] = -22.0;
	barrel4[1] = 0.0;
	barrel4[2] = 0.0;
	vec3_t shotVec;


	VectorCopy( muzzle, start );
	WP_TraceSetStart( ent, start, vec3_origin, vec3_origin );//make sure our start point isn't on the other side of a wall

	WP_MissileTargetHint(ent, start, forwardVec);
	/*missile = CreateMissile(start, forwardVec, DEMP2_VELOCITY, 10000, ent);*/
	for (currentShot = 1; currentShot <= 4; currentShot++)
	{
		if (currentShot == 1) {
			VectorAdd(start, barrel1, shotVec);
			missile = CreateMissile(shotVec, forwardVec, DEMP2_VELOCITY, 10000, ent);
		}
		else if (currentShot == 2) {
			VectorAdd(start, barrel2, shotVec);
			missile = CreateMissile(shotVec, forwardVec, DEMP2_VELOCITY, 10000, ent);
		}
		else if (currentShot == 3) {
			VectorAdd(start, barrel3, shotVec);
			missile = CreateMissile(shotVec, forwardVec, DEMP2_VELOCITY, 10000, ent);
		}
		else {
			VectorAdd(start, barrel4, shotVec);
			missile = CreateMissile(shotVec, forwardVec, DEMP2_VELOCITY, 10000, ent);
		}
	}
	

Share this post


Link to post

shotVec is not getting set prior to being added to, so it will likely crash there. Also this code will not get the result that you expect anyway, since shotVec is being altered in each iteration of the loop.

Another thing, this will not actually take the player's viewaxis into account. It will just fire 4 bolts in a straight line, at a 90 degree angle, regardless of where the player is looking.

Here's something that should work, although it won't fix the viewaxis issue. I will have to think about how to fix this.

vec3_t offset;
    vec3_t barrel[] = {
        {22.0f, 0.0f, 0.0f},
        {11.0f, 0.0f, 0.0f},
        {-11.0f, 0.0f, 0.0f},
        {-22.0f, 0.0f, 0.0f}
    };
    vec3_t shotVec;


    VectorCopy( muzzle, start );
    WP_TraceSetStart( ent, start, vec3_origin, vec3_origin );//make sure our start point isn't on the other side of a wall

    WP_MissileTargetHint(ent, start, forwardVec);
    /*missile = CreateMissile(start, forwardVec, DEMP2_VELOCITY, 10000, ent);*/
    for (currentShot = 0; currentShot <= 3; currentShot++) // note the difference here
    {
        VectorCopy(muzzle, shotVec);
        VectorAdd(shotVec, barrel[i], shotVec);
        missile = CreateMissile(shotVec, forwardVec, DEMP2_VELOCITY, 10000, ent);
    }

Share this post


Link to post

In the original code there is also the issue that the barrel is essentially a global in respect to all entities.  Since this function is called everytime any player, NPC, or shooter map entity shoots this weapon it would not work so well.

Share this post


Link to post

Yeah, I think I'll have to store an external cvar for the current barrel or something, as all the variables set get destroyed and reinitialized with each shot.

Share this post


Link to post

Ugh.

 

Well at least I can do the secondary fire. I just have to fire four projectiles at once and that can all happen in the same call of the function. I'll take care of that then move on to the Mortar Gun I suppose.

 

***EDIT***

@@ensiform -- why wouldn't setting a cvar work? I could initialize it in g_main.cpp and then update it using similar code. Can I not set a cvar from a weapon function? I know it's a bit nasty, but having four cvars (A,B,C,D) for the four barrels, turning them on and off and reading them each cycle might work.

Share this post


Link to post

Any ideas? Perhaps a global within the C++ code? Like perhaps initializing the variable for looping elsewhere and then in wp_fusion.cpp

extern int currentShot;

Also two other quick questions:

  • Can I specify a secondary hard-read folder? I want to do without the -path switch for /dfmod and have it hard coded along with the /base folder. -----Yep, in files.cpp, FS_BuildOSPath()
  • Is there a command to write debug info to the console? That'd be incredibly helpful. -- Yep, the function is Com_Printf("TEXT MESSAGE", parameter2);

Share this post


Link to post

So some progress has been made. I programmed the secondary fire, but the four barrels are offsetting relative to the hard vectors in the gameplay world, and not the player's direction. Here's the code for secondary fire:

//---------------------------------------------------------
static void WP_DEMP2_AltFire( gentity_t *ent )
//---------------------------------------------------------
{
	vec3_t	start;
	int		damage = weaponData[WP_DEMP2].damage;
	gentity_t *missileA, *missileB, *missileC, *missileD;

	vec3_t barrelA = { -60.0f, -20.0f, 0.0f };
	vec3_t barrelB = { 35.0f, -20.0f, 0.0f };
	vec3_t barrelC = { -35.0f, -20.0f, 0.0f };
	vec3_t barrelD = { -60.0f, -20.0f, 0.0f };
	vec3_t shotVec;


	VectorCopy(muzzle, start);
	WP_TraceSetStart(ent, start, vec3_origin, vec3_origin); //make sure our start point isn't on the other side of a wall



	//Calculate damages
	if (ent->s.number != 0)
	{
		if (g_spskill->integer == 0)
		{
			damage = DEMP2_NPC_DAMAGE_EASY;
		}
		else if (g_spskill->integer == 1)
		{
			damage = DEMP2_NPC_DAMAGE_NORMAL;
		}
		else
		{
			damage = DEMP2_NPC_DAMAGE_HARD;
		}
	}


	//Barrel A
	WP_MissileTargetHint(ent, start, forwardVec);
	VectorMA(start, 1, barrelA, shotVec);
	//VectorAdd(start, barrelA, shotVec);
	missileA = CreateMissile(shotVec, forwardVec, DEMP2_VELOCITY, 10000, ent);
	//Com_Printf(S_COLOR_YELLOW "wp_demp2.cpp - firing secondary mode, barrel A", "barrel A");
	missileA->classname = "demp2_proj";
	missileA->s.weapon = WP_DEMP2;
	VectorSet(missileA->maxs, DEMP2_SIZE, DEMP2_SIZE, DEMP2_SIZE);
	VectorScale(missileA->maxs, -1, missileA->mins);
	missileA->damage = damage;
	missileA->dflags = DAMAGE_DEATH_KNOCKBACK;
	missileA->methodOfDeath = MOD_DEMP2;
	missileA->clipmask = MASK_SHOT | CONTENTS_LIGHTSABER;
	missileA->bounceCount = 0; // we don't want it to ever bounce


	//Barrel B
	WP_MissileTargetHint(ent, start, forwardVec);
	VectorMA(start, 1, barrelB, shotVec);
	//VectorAdd(start, barrelB, shotVec);
	missileB = CreateMissile(shotVec, forwardVec, DEMP2_VELOCITY, 10000, ent);
	//Com_Printf("wp_demp2.cpp - firing secondary mode, barrel B", "barrel B");
	missileB->classname = "demp2_proj";
	missileB->s.weapon = WP_DEMP2;
	VectorSet(missileB->maxs, DEMP2_SIZE, DEMP2_SIZE, DEMP2_SIZE);
	VectorScale(missileB->maxs, -1, missileB->mins);
	missileB->damage = damage;
	missileB->dflags = DAMAGE_DEATH_KNOCKBACK;
	missileB->methodOfDeath = MOD_DEMP2;
	missileB->clipmask = MASK_SHOT | CONTENTS_LIGHTSABER;
	missileB->bounceCount = 0; // we don't want it to ever bounce


	//Barrel C
	WP_MissileTargetHint(ent, start, forwardVec);
	VectorMA(start, 1, barrelC, shotVec);
	//VectorAdd(start, barrelC, shotVec);
	missileC = CreateMissile(shotVec, forwardVec, DEMP2_VELOCITY, 10000, ent);
	//Com_Printf("wp_demp2.cpp - firing secondary mode, barrel C", "barrel C");
	missileC->classname = "demp2_proj";
	missileC->s.weapon = WP_DEMP2;
	VectorSet(missileC->maxs, DEMP2_SIZE, DEMP2_SIZE, DEMP2_SIZE);
	VectorScale(missileC->maxs, -1, missileC->mins);
	missileC->damage = damage;
	missileC->dflags = DAMAGE_DEATH_KNOCKBACK;
	missileC->methodOfDeath = MOD_DEMP2;
	missileC->clipmask = MASK_SHOT | CONTENTS_LIGHTSABER;
	missileC->bounceCount = 0; // we don't want it to ever bounce


	//Barrel D
	WP_MissileTargetHint(ent, start, forwardVec);
	VectorMA(start, 1, barrelD, shotVec);
	//VectorAdd(start, barrelD, shotVec);
	missileD = CreateMissile(shotVec, forwardVec, DEMP2_VELOCITY, 10000, ent);
	//Com_Printf("wp_demp2.cpp - firing secondary mode, barrel D", "barrel D");
	missileD->classname = "demp2_proj";
	missileD->s.weapon = WP_DEMP2;
	VectorSet(missileD->maxs, DEMP2_SIZE, DEMP2_SIZE, DEMP2_SIZE);
	VectorScale(missileD->maxs, -1, missileD->mins);
	missileD->damage = damage;
	missileD->dflags = DAMAGE_DEATH_KNOCKBACK;
	missileD->methodOfDeath = MOD_DEMP2;
	missileD->clipmask = MASK_SHOT | CONTENTS_LIGHTSABER;
	missileD->bounceCount = 0; // we don't want it to ever bounce

}

And for primary fire I've tried the idea that @@ensiform had of tying it to the player/entity. I looked at how the rocket launcher hooked up the tracking values, and came up with this in g_weapon.cpp. Basically each time it's called it'll increment the barrel number and output it.


// some naughty little things that are used cg side
int g_rocketLockEntNum = ENTITYNUM_NONE;
int g_rocketLockTime = 0;
int	g_rocketSlackTime = 0;
int currentFusionShot = 0; //to loop through fusion rifle barrels
......


//-----------------------------------------------------------------------------
void WP_fusionBarrel(int currentFusionShot)
//-----------------------------------------------------------------------------
{
	//whenever this is called, it will increment the number (max of 3, then returns to 0)
	//it will then pass that information to wp_fusion.cpp
	currentFusionShot++;
	if ( currentFusionShot >= 3 )
	{
		currentFusionShot = 0;
	}
}

From there I run the function in wp_fusion.cpp to grab the current int. However it's still not outputting a number to the console, so I can't tell if its actually iterating, or even if it's pulling the value from g_weapon.cpp

//---------------------------------------------------------
static void WP_DEMP2_MainFire( gentity_t *ent )
//---------------------------------------------------------
{
	vec3_t	start;
	int		damage	= weaponData[WP_DEMP2].damage;
	gentity_t *missile;

	vec3_t barrel[] = {
		{ 22.0f, 0.0f, 0.0f },
		{ 11.0f, 0.0f, 0.0f },
		{ -11.0f, 0.0f, 0.0f },
		{ -22.0f, 0.0f, 0.0f }
	};
	vec3_t shotVec;


	VectorCopy(muzzle, start);
	WP_TraceSetStart(ent, start, vec3_origin, vec3_origin);//make sure our start point isn't on the other side of a wall

	WP_MissileTargetHint(ent, start, forwardVec);
	/*missile = CreateMissile(start, forwardVec, DEMP2_VELOCITY, 10000, ent);*/
	WP_fusionBarrel(currentShot); //get the current barrel number from g_weapon.cpp and store it
	Com_Printf(S_COLOR_YELLOW "wp_demp2.cpp - firing primary mode, barrel #", currentShot);
	for (currentShot = 0; currentShot <= 3; currentShot++)
	{
		VectorCopy(muzzle, shotVec);
		VectorAdd(shotVec, barrel[currentShot], shotVec);
		missile = CreateMissile(shotVec, forwardVec, DEMP2_VELOCITY, 10000, ent);
	}


	missile->classname = "demp2_proj";
	missile->s.weapon = WP_DEMP2;

	// Do the damages
	if ( ent->s.number != 0 )
	{
		if ( g_spskill->integer == 0 )
		{
			damage = DEMP2_NPC_DAMAGE_EASY;
		}
		else if ( g_spskill->integer == 1 )
		{
			damage = DEMP2_NPC_DAMAGE_NORMAL;
		}
		else
		{
			damage = DEMP2_NPC_DAMAGE_HARD;
		}
	}

	VectorSet( missile->maxs, DEMP2_SIZE, DEMP2_SIZE, DEMP2_SIZE );
	VectorScale( missile->maxs, -1, missile->mins );

	missile->damage = damage;
	missile->dflags = DAMAGE_DEATH_KNOCKBACK;
	missile->methodOfDeath = MOD_DEMP2;
	missile->clipmask = MASK_SHOT | CONTENTS_LIGHTSABER;

	// we don't want it to ever bounce
	missile->bounceCount = 0;
}

I have to say, being able to spit out debug info to the console is super nice. Glad I found that function.

Share this post


Link to post

Yes, I mentioned that this would be an issue earlier. :P

I can't remember off the top of my head how I handle this. I believe the way to do it is involves axes/axis functions? Dunno. Maybe @@Scooper knows, I always defer vector-related questions to him.

Share this post


Link to post

Hey, didn't notice the notifaction for a few days. Been very busy.

 

You could try something like this. Not 100% sure if it will compile, didn't test it =p Good luck.

//---------------------------------------------------------
void G_CreateRotationMatrix(vec3_t angles, matrix3_t matrix); // Function decleration/prototype so we can use it. You can put this in a header file.
static void WP_DEMP2_AltFire( gentity_t *ent )
//---------------------------------------------------------
{
	int damage = weaponData[WP_DEMP2].damage;
	int currentShot = 0;
	vec3_t start;
	
	matrix3_t rotMatrix;
	vec3_t barrel[] = {
			{22.0f, 0.0f, 0.0f},
			{11.0f, 0.0f, 0.0f},
			{-11.0f, 0.0f, 0.0f},
			{-22.0f, 0.0f, 0.0f}
		};
	
	VectorCopy(muzzle, start);
	WP_TraceSetStart(ent, start, vec3_origin, vec3_origin); //make sure our start point isn't on the other side of a wall
	
	//Calculate damages
	if (ent->s.number != 0)
	{
		if (g_spskill->integer == 0)
		{
			damage = DEMP2_NPC_DAMAGE_EASY;
		}
		else if (g_spskill->integer == 1)
		{
			damage = DEMP2_NPC_DAMAGE_NORMAL;
		}
		else
		{
			damage = DEMP2_NPC_DAMAGE_HARD;
		}
	}
	
	// I don't have the source for this function, not 100% sure what it does.
	// I assume it finds and adjusted muzzle point as well as the forward vector of the player.
	WP_MissileTargetHint(ent, start, forwardVec);

	// Create a rotation matrix from the player view angles.
	G_CreateRotationMatrix(ent->client->ps.viewangles, rotMatrix);

	for (currentShot = 0; currentShot <= 3; currentShot++)
	{
		vec3_t muzzleOffset;
		
		VectorCopy(barrel[currentShot], muzzleOffset);
		RotatePoint(muzzleOffset, rotMatrix);			// Rotate the current barrel/muzzle offset to be relative to the player rotation.
		
		VectorAdd(start, muzzleOffset, muzzleOffset);
		
		missile = CreateMissile( muzzleOffset, forwardVec, DEMP2_VELOCITY, 10000, ent);
		
		missile->classname = "demp2_proj";
		missile->s.weapon = WP_DEMP2;
		VectorSet(missileA->maxs, DEMP2_SIZE, DEMP2_SIZE, DEMP2_SIZE);
		VectorScale(missileA->maxs, -1, missileA->mins);
		missile->damage = damage;
		missile->dflags = DAMAGE_DEATH_KNOCKBACK;
		missile->methodOfDeath = MOD_DEMP2;
		missile->clipmask = MASK_SHOT | CONTENTS_LIGHTSABER;
		missile->bounceCount = 0; // we don't want it to ever bounce
		
	}
}
Teancum and Darth Futuza like this

Share this post


Link to post

I've decided to shelve the Fusion Cutter. Even using AngleVectors() then VectorScale() to get the right-angle vector relative to the player, the move it out each time the gun is fired makes no difference. The projectile switches sides from right to left as you rotate the player and fire. It's not worth the time to write something totally custom, and would take a lot of trigonometry/calc to do so.

 

***EDIT***

 

This bit of code from g_weapon.cpp might hold a clue. It seems to deal with each axis of the vector separately rather than trying to do so all at once. Posting it here mostly so I remember to look at it later. Additional comments have been added by me

// Muzzle point table...
vec3_t WP_MuzzlePoint[WP_NUM_WEAPONS] =
{//	Fwd,	right,	up.
	{0,		0,		0	},	// WP_NONE,
	{8	,	16,		0	},	// WP_SABER,
	{12,	6,		-6	},	// WP_BLASTER_PISTOL,
	{12,	6,		-6	},	// WP_BLASTER,
	{12,	6,		-6	},	// WP_DISRUPTOR,
	{12,	2,		-6	},	// WP_BOWCASTER,
	{12,	4.5,	-6	},	// WP_REPEATER,
	{12,	6,		-6	},	// WP_DEMP2,
	{12,	6,		-6	},	// WP_FLECHETTE,
	{12,	8,		-4	},	// WP_ROCKET_LAUNCHER,
	{12,	0,		-4	},	// WP_THERMAL,
	{12,	0,		-10	},	// WP_TRIP_MINE,
	{12,	0,		-4	},	// WP_DET_PACK,
	{12,	8,		-4	},	// WP_CONCUSSION,
	{0	,	8,		0	},	// WP_MELEE,
	{0,		0,		0	},	// WP_ATST_MAIN,
	{0,		0,		0	},	// WP_ATST_SIDE,
	{0	,	8,		0	},	// WP_STUN_BATON,
	{12,	6,		-6	},	// WP_BRYAR_PISTOL,
};

void WP_RocketLock( gentity_t *ent, float lockDist )
{
	// Not really a charge weapon, but we still want to delay fire until the button comes up so that we can
	//	implement our alt-fire locking stuff
	vec3_t		ang;
	trace_t		tr;

	vec3_t muzzleOffPoint, muzzlePoint, forwardVec, right, up;

	AngleVectors( ent->client->ps.viewangles, forwardVec, right, up ); //Get the forward, right and up axes to form a vector based on our angle

	AngleVectors(ent->client->ps.viewangles, ang, NULL, NULL); //do it again, but save only the forward as "ang"

	VectorCopy( ent->client->ps.origin, muzzlePoint ); //copy the player's origin as "muzzlePoint"
	VectorCopy(WP_MuzzlePoint[WP_ROCKET_LAUNCHER], muzzleOffPoint); //Copy the muzzle point from the table above as "muzzleOffPoint"

	VectorMA(muzzlePoint, muzzleOffPoint[0], forwardVec, muzzlePoint); //forwardVec * the forward vector from muzzleOffPoint, add muzzlePoint, save as muzzlePoint
	VectorMA(muzzlePoint, muzzleOffPoint[1], right, muzzlePoint); //do the same process for the right vector
	muzzlePoint[2] += ent->client->ps.viewheight + muzzleOffPoint[2]; //for the up vector, take the player's viewheight + the up vector from muzzleOffPoint

	ang[0] = muzzlePoint[0] + ang[0]*lockDist;
	ang[1] = muzzlePoint[1] + ang[1]*lockDist;
	ang[2] = muzzlePoint[2] + ang[2]*lockDist;

	gi.trace(&tr, muzzlePoint, NULL, NULL, ang, ent->client->ps.clientNum, MASK_PLAYERSOLID, (EG2_Collision)0, 0);

	if (tr.fraction != 1 && tr.entityNum < ENTITYNUM_NONE && tr.entityNum != ent->client->ps.clientNum)
	{
		gentity_t *bgEnt = &g_entities[tr.entityNum];
		if ( bgEnt && (bgEnt->s.powerups&PW_CLOAKED) )
		{
			ent->client->rocketLockIndex = ENTITYNUM_NONE;
			ent->client->rocketLockTime = 0;
		}
		else if (bgEnt && bgEnt->s.eType == ET_PLAYER )
		{
			if (ent->client->rocketLockIndex == ENTITYNUM_NONE)
			{
				ent->client->rocketLockIndex = tr.entityNum;
				ent->client->rocketLockTime = level.time;
			}
			else if (ent->client->rocketLockIndex != tr.entityNum && ent->client->rocketTargetTime < level.time)
			{
				ent->client->rocketLockIndex = tr.entityNum;
				ent->client->rocketLockTime = level.time;
			}
			else if (ent->client->rocketLockIndex == tr.entityNum)
			{
				if (ent->client->rocketLockTime == -1)
				{
					ent->client->rocketLockTime = ent->client->rocketLastValidTime;
				}
			}

			if (ent->client->rocketLockIndex == tr.entityNum)
			{
				ent->client->rocketTargetTime = level.time + 500;
			}
		}
	}
	else if (ent->client->rocketTargetTime < level.time)
	{
		ent->client->rocketLockIndex = ENTITYNUM_NONE;
		ent->client->rocketLockTime = 0;
	}
	else
	{
		if (ent->client->rocketLockTime != -1)
		{
			ent->client->rocketLastValidTime = ent->client->rocketLockTime;
		}
		ent->client->rocketLockTime = -1;
	}
}

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this  

×
×
  • Create New...