TOW Missile for RPG


#1

I’m building a code to make the RPG missile like wire-guided. The easy part is done, some calcs and stuff.
BUT the problem is:
To make this work, I need some way to call the TOWMissile function every time the viewangles are changed. This happens in the pmove function, as i wanna change rocket direction whenever the player changes his position. However, the updating occurs in the bg_pmove.c, and I cannot communicate with the g_missile.c. There is some limitations about this part. Like, the entity is created and maintained only in the g_missile, and only through function calls, no local variable.
Is there someone who already built something like this?
I don’t know much about the Quake code, but I know C programming.
I am grateful if someone can help me on this, or just send me some codes, or ideas.
And, if my english is bad, sorry.


#2

Hello juanvmr,

My english is also not the best so i hope I do understand you correct! You need guided rockets, right? Well, there are also homing rockets that will move towards their target by their own.

For guided rockets there were some very good tutorials in the early days of Quake3 (~1999/2000). Unfortunately lot of those tutorials are lost! One tutorial was at quake3hut.co.uk.
Here is a list of some tutorials at Quake3World.com (the link to the tutorials is broken): https://www.quake3world.com/forum/viewtopic.php?f=16&t=50467
There was some mods that included guided and homing rockets, I think the most advanced mod was called Bazooka Quake or so.
Anyways, lot of good tutorials and mods are lost, probably forever. The only thing I was able to do is to search through my CDs. I found a tutorial that also explains how guided rockets will work. Please note that this tutorial was written in 1999! I absolutely don’t know if the code will work anymore, or not. So just took this as some basic guide!

Here is the tutorial, I past it into here because it’s smalll:

Guided Rockets and Client Prediction

Date : 01/18/99
Author(s) : SpK
Skill(s) : Medium
Source Project(s) : Game
Revision : 1.0

With this tutorial, we’ll learn how to handle the client prediction in Q3:A, with the Guided Rockets ™. Basically, client prediction is used to avoid too much net traffic. In Quake2, the server had to send to all the clients packets holding the origins of the rocket, so the client’s renderer (quake2.exe) could display it using those coords. Okey, that was fun, but now there’s something better ! We’re gonna tells Q3 from where our rocket is fired, and what direction our rocket is taking, and we’ll let the Q3 renderer calculate where the rocket will explode !
In q_shared.h, you’ll find the following structures :

typedef enum {
TR_STATIONARY,
TR_INTERPOLATE, // non-parametric, but interpolate between snapshots
TR_LINEAR,
TR_LINEAR_STOP,
TR_SINE, // value = base + sin( time / duration ) * delta
TR_GRAVITY
} trType_t;

typedef struct {
trType_t trType;
int trTime;
int trDuration; // if non 0, trTime + trDuration = stop time
vec3_t trBase;
vec3_t trDelta; // velocity, etc
} trajectory_t;

The trajectory_t structure will be used when we’ll have to give a movement to an entity. The main fields will be trDelta, the old Q2’s ent->velocity (the velocity vector), and trBase, the origin of the movement/trajectory.
Now, let’s write our guided rocket code. Open up g_missile.c, and write this just above the fire_rocket() function :

void Guided_Missile_Think (gentity_t *missile) {
vec3_t forward, right, up;
vec3_t muzzle;
float dist;
gentity_t *player = missile->parent;

// If our owner can't be found, just return
if (!player) {
	G_Printf ("Guided_Missile_Think : missile has no owner!\n");
	return;
}

// Get our forward, right, up vector from the view angle of the player
AngleVectors (player->client->ps.viewangles, forward, right, up);
// Calculate the player's eyes origin, and store this origin in muzzle
CalcMuzzlePoint ( player, forward, right, up, muzzle );
// Tells the engine that our movement starts at the current missile's origin
VectorCopy (missile->r.currentOrigin, missile->s.pos.trBase );
// Trajectory type setup (linear move - fly)
missile->s.pos.trType = TR_LINEAR;
missile->s.pos.trTime = level.time - 50;
// Get the dir vector between the player's point of view and the rocket
// and store it into muzzle again
VectorSubtract (muzzle, missile->r.currentOrigin, muzzle);
// Add some range to our "line" so we can go behind blocks
// We could have used a trace function here, but the rocket would
// have come back if player was aiming on a block while the rocket is behind it
// as the trace stops on solid blocks
dist = VectorLength (muzzle) + 400; //give the range of our muzzle vector + 400 units
VectorScale (forward, dist, forward);
// line straight forward
VectorAdd (forward, muzzle, muzzle);
// Normalize the vector so it's 1 unit long, but keep its direction
VectorNormalize (muzzle);
// Slow the rocket down a bit, so we can handle it
VectorScale (muzzle, 300, forward);
// Set the rockets's velocity so it'll move toward our new direction
VectorCopy (forward, missile->s.pos.trDelta);
// Change the rocket's angle so it'll point toward the new direction
vectoangles (muzzle, missile->s.angles);
// This should "save net bandwidth" =D
SnapVector(missile->s.pos.trDelta);
// Call this function in 0,1 s
missile->nextthink = level.time + FRAMETIME; 

}

Then move to the fire_rocket(…) function just under our new one, and modify it so it looks like this :

gentity_t *fire_rocket (gentity_t *self, vec3_t start, vec3_t dir) {
gentity_t *bolt;

VectorNormalize (dir);

bolt = G_Spawn();
bolt->classname = "rocket";
//### NEW ###
//bolt->nextthink = level.time + 10000;
//bolt->think = G_ExplodeMissile;
if (self->client) { // && check for bots
	bolt->think = Guided_Missile_Think;
	bolt->nextthink = level.time + FRAMETIME;
} else {
	bolt->nextthink = level.time + 10000;
	bolt->think = G_ExplodeMissile;
}
//### END NEW ###
bolt->s.eType = ET_MISSILE;
bolt->r.svFlags = SVF_USE_CURRENT_ORIGIN;
..........
..........

}

So what we’re doing here is replacing the regular rocket think function (goes straight ahead and explode once it touchs something) by our own think function, Guided_Missile_Think. So when the player will shoot a rocket, he’ll be able to aim his rocket wherever he wants with his mouse. However, we’re testing if “self” is really a client, just in case… Bots will also be able to use guided rockets as they use the same firing function.
Compile your code, and run the game. Take the rocket launcher, and fire… Add some bots and kick their ass around the map… Who said “soooo easy !” ? :wink:
Okey now stop playing… Let’s study our code. In our think function, we’ve played with client prediction. Everytime we change the direction of the rocket, we tells the engine that we’re also changing the rocket’s behaviour, so the client’s renderer knows he has to change the rocket’s movement. We’re using the current rocket’s origin to setup the origin of our new direction change, and then we also change the velocity and angle of the rocket so it’s going to the direction where we’re aiming at. Now, on the client side, the renderer (well, the cgame part) will calculate where the rocket should go, thanks to our trBase and trDelta informations. Just try removing those datas from our new code, and you’ll see your rockets going in VERY strange directions :wink:


#3

Alright! That’s what I wanted! Thank you, ToKu!
I was thinking it was a heat-guided-like missile, until I read everything. :sweat_smile:
Modernizing Quake!
And no, I wanted exactly this. The missile is guided by mouse, and not self-guided. Self-guided would be a little cheating… :stuck_out_tongue_closed_eyes:
Thanks!