Login x
User Name:
Password:
Social Links Facebook Twitter YouTube Steam RSS News Feeds
Watch MODSonair

Members Online

»
0 Active | 243 Guests
Online:

LATEST FORUM THREADS

»
New BF2 Mod
BF2 General

Tutorials

»
Scripting for QuakeC Defined (part 2)
Versions: You must be logged in to view history.
A tutorial style reference for scripting in QuakeC (the scripting language for quake engine based games - including CoD)
A tutorial style reference for scripting in QuakeC (the scripting language for quake engine based games - including CoD)

This is part 2 of 2 the complete (printable) download of this file in its entirety is available here.

6. Global Variables

These variables are accessible in every functions.

Quake C function are not supposed to modify them directly.

Variable : world

the server's world object, which holds all global state for the server, like the deathmatch flags and the body ques.

Variable : time

float time; // in seconds

The current game time, a floating point value in seconds. Note that because the entities in the world are simulated sequentially, time is NOT strictly increasing. An impact late in one entity's time slice may set time higher than the think function of the next entity. The difference is limited to 0.1 seconds.

Variable : frametime

float frametime; // in seconds

No idea what this can be. Used only when jumping in water.

Variable : self

entity self;

The entity that is subject to the current function.

Variable : other

entity other;

The object concerned by an impact, not used for thinks.

Variable : force_retouch

float force_retouch; // counter

Force all entities to touch triggers next frame. this is needed because non-moving things don't normally scan for triggers, and when a trigger is created (like a teleport trigger), it needs to catch everything.

It is decremented each frame, so it is usually set to 2 to guarantee everything is touched.

Variable : mapname

string mapname;

Name of the level map currently being played, like "start".

Variable : deathmatch

float deathmatch; // a boolean value, 0 or 1

True if playing deathmatch.

Variable : coop

float coop; // a boolean value, 0 or 1

True if playing cooperative.

Variable : teamplay

float teamplay; // a boolean value, 0 or 1

True if playing by teams.

Variable : serverflags

float serverflags; // bit fields

Propagated from level to level, and used to keep track of the completed episodes. If serverflag & ( 1 << e) is true, then episode e was already completed. Generally equal to player.spawnflags & 15.

Variable : total_secrets

float total_secrets; // counter

Number of secrets found by the players. Affected only by trigger_secret.

Variable : found_secrets

float found_secrets; // counter

Number of secrets found.

Variable : total_monsters

float total_monsters; // counter

Total number of monsters that were spawned, since the begining of the level.

Variable : killed_monsters

float killed_monsters; // counter

Store the total number of monsters killed.

Variable : parm1...parm16

float parm1; // items bit flag (IT_SHOTGUN | IT_AXE )

float parm2; // health

float parm3; // armorvalue

float parm4, parm5, parm6, parm7; // ammo

float parm8; // weapon

float parm9; // armortype*100

float parm10, parm11, parm12, parm13, parm14, parm15, parm16;

Those parameters seem to be a bit of hack. They are used when a client connects. Spawnparms are used to encode information about clients across server level changes.

Functions that are mandatory in Quake-C

These functions must be defined in Quake C, since they are invoked by Quake under certain conditions.

Misc

void main();

Only used for testing progs.

void StartFrame();

Called at the start of each frame.

Behavior of players

void PlayerPreThink();

Called with self=player, for every frame, before physics are run.

void PlayerPostThink();

Called with self=player, for every frame, after physics are run.

Management of network game clients

void ClientKill();

Called when a player suicides.

void ClientConnect();

Called when a player connects to a server, but also, for every player, when a new level starts. It is used to announces the new player to every other players.

void PutClientInServer();

Call after setting the parm1... parm16.

void ClientDisconnect();

Called when a player disconnects from a server Announce that the player has left the game.

void SetNewParms();

Called when a client first connects to a server. Sets parm1...parm16 so that they can be saved off for restarts.

void SetChangeParms();

Call to set parms for self so they can?

7. Model Pragma

(Derived from informations published by Steve Tietze)

Here are a few definitions that are commonly found in the Quake-C code defining the behavior of animated models (monsters, players, etc...).

Most of this information is not interpreted by the Quake-C compiler, but it's useful for the program modelgen that generates the models.

Model name

$modelname name

name is the name of the model file defining the object.

ex: $name armor

directory

$cd dir

Specify the directory where your model file (.MDL) is located.

ex: $cd /evil/models/armor

Special animation flags

$flags rotation

This field is not interpreted by Quake-C, but it's useful for the program modelgen that generates the models.

Rotation of the object.

ex: $flags 8

Possible values for the flags : 8, the object keeps rotating, like armors.

Other values are not known yet.

Origin

$origin x y z

This field is not interpreted by Quake-C, but it's useful for the program modelgen that generates the models. Location of the object within the bounding box, in the quake editor.

ex: $origin 0 0 8

Scale factor

$scale number

This field is not interpreted by Quake-C, but it's useful for the program modelgen that generates the models. Number comes from the texmake number that is generated.

You can use different values if you want.

ex: $scale 4

Base

$base object

This field is not interpreted by Quake-C, but it's useful for the program modelgen that generates the models. Object is the name of a model file, that will be used as a kind of starting position, for animation.

Skin file

$skin skinfile

This field is not interpreted by Quake-C, but it's useful for the program modelgen that generates the models. Skinfile is the name (without extension) of the .lbm file that defines the skin of the object, as generated by the program texmake.

Frame definitions

$frame frame1 frame2 ...

This defines several animation frames of the object.

For every animation frame defined, you must also define a Quake-C function, that will be called during this animation frame. For instance :

$frame walk1 walk2 walk3 walk4

void() man_walk1 = [ $walk1, man_walk2 ] { ... some code ... };

void() man_walk2 = [ $walk2, man_walk3 ] { ... some code ... };

void() man_walk3 = [ $walk3, man_walk4 ] { ... some code ... };

void() man_walk4 = [ $walk4, man_walk1 ] { ... some code ... };

In the brackets, the first parameter defines the name of the frame (as found in the model file), and the second parameter defined the function that is to be executed in the next frame (by setting the value of self.nextthink).

Most of these functions do nothing special, but some can be very complex (for instance, the functions that are called when the monster tries to see a player).

8. Network Protocol

Quake-C is not supposed to handle a lot of network messages, since most are already handled in C.

However, builtin functions have not been built for every kind of messages in the Quake protocol, so you migth end-up composing protocol messages in Quake-C. I highly recommend that you build a single function to handle a given message type, because the structure of those messages might change, and then all your code would have to be checked for bugs.

By that way, ID Software didn't even bothered to write a function to generate temporary entites, though they keep using this message. It's still a long way to ISO 9001, I'm afraid.

Definitions related to protocol messages

Values : How messages are sent

MSG_BROADCAST = 0; // unreliable message, sent to all

MSG_ONE = 1; // reliable message, sent to msg_entity

MSG_ALL = 2; // reliable message, sent to all

MSG_INIT = 3; // write to the init string

Use unreliable (but fast) messages, when it's of no importance that a client misses the message.

Examples : sound, explosions, monster deaths, taunts....

Use reliable messages when it's very important that every client sees the message, or a game incoherency might happen.

Examples : shots, player deaths, door moves, game ends ... and CD track changes!.

Values: Type of message

These are some of message types defined in the Quake network protocol.

SVC_SETVIEWPORT = 5;

SVC_SETANGLES = 10;

SVC_TEMPENTITY = 23;

SVC_KILLEDMONSTER = 27;

SVC_FOUNDSECRET = 28;

SVC_INTERMISSION = 30;

SVC_FINALE = 31;

SVC_CDTRACK = 32;

SVC_SELLSCREEN = 33;

SVC_UPDATE = 128;

Some message structures

Here are some of the messages defined in the Quake network protocol.

Beware, the structure of those messages might change in future version (Satan forbids!).

Message : Set View Position

msg_entity = player

WriteByte (MSG_ONE, SVC_SETVIEWPORT);

WriteEntity( MSG_ONE, camera);

This message is meant for a single client player. It sets the view position to the position of the entity camera.

Message : Set View Angles

msg_entity = player

WriteByte (MSG_ONE, SVC_SETVIEWANGLES);

WriteAngle( MSG_ONE, camera.angles_x);

WriteAngle( MSG_ONE, camera.angles_y);

WriteAngle( MSG_ONE, camera.angles_z);

This message is meant for a single client player. It set the orientation of it's view to the same orientation than the entity camera.

Message : Temporary Entity

WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);

WriteByte (MSG_BROADCAST, entityname);

WriteCoord (MSG_BROADCAST, origin_x);

WriteCoord (MSG_BROADCAST, origin_y);

WriteCoord (MSG_BROADCAST, origin_z);

Message : Set CD Track

WriteByte (MSG_ALL, SVC_CDTRACK);

WriteByte (MSG_ALL, val1); // CD start track

WriteByte (MSG_ALL, val2); // CD end track

Message : Final Message

WriteByte (MSG_ALL, SVC_FINALE);

WriteString (MSG_ALL, "any text you liken");

Message : Sell Screen

WriteByte (MSG_ALL, SVC_SELLSCREEN);

Shows the infamous sell screen (like you needed it to understand).

Message : Inter Mission

WriteByte (MSG_ALL, SVC_INTERMISSION);

Shows the inter mission camera view.

Message : Killed Monster

WriteByte (MSG_ALL, SVC_KILLEDMONSTER);

Increase by one the count of killed monsters, as available to the client. Can be displayed with showscores.

Message : Found Secrets

WriteByte (MSG_ALL, SVC_FOUNDSECRET);

Increase by one the count of secrets founds.

Message: Update Entity

This message has a rather complex structure. I already generated some valid update messages, but since the message structure seems highly susceptible to change in the next versions of Quake, I would recommend that you never use such messages : as a matter of fact, Quake itslef is very capable of generating all the required messages... unless you start creating deathmatch cameras or the like.

9. Network Builtin Functions

Beware : when generating messages, you had better respect the format of the existing messages. Otherwise the game clients might not be able to interpret them (and will likely crash).

The functions below all write to clients (players connected via the network, or the local player).

Global variable for network messages

Variable : msg_entity

entity msg_entity;

If you want to send a message to just one entity e, then set msg_entity= e and send the message with flag MSG_ONE, instead of MSG_ALL.

Never used. Maybe it doesn't even work.

Builtin functions for composing network messages

Function : WriteByte

void WriteByte(float to, float value)
to = see messages

Function : WriteChar

void WriteChar(float to, float value)
to = see messages

Function : WriteShort

void WriteShort(float to, float value)
to = see messages

Function : WriteLong

void WriteLong(float to, float value)
to = see messages

Function : WriteCoord

void WriteCoord(float to, float value)
to = see messages

Function : WriteAngle

void WriteAngle(float to, float value)
to = see messages

This function writes a single byte, that represents 256*(angle/380).

Function : WriteString

void WriteString(float to, string value)
to = see messages

This function writes a string, terminated by (the null character in C).

Function : WriteEntity

void WriteEntity(float to, entity value)
to = see messages

This function writes an entity reference, taking two bytes.

10. Tips & Tricks

Here are some characteristics of Quake-C that you had better be aware of.

The names of variable and functions must be unique.

The names of functions, variables and fields must be unique. For instance, you cannot define a variable with the same name as a field. However, local variables can be defined more than once (they had better!).

Composition of function is not supported

Since all the functions use a single parameter marshaling area, and a single global variable to store their reture result, you should NEVER try to call a function within another function call.

Example : printing the coordinate of entity self

sprintf(self, vtos( self.origin ));

will fail miserably (sending the message somewhere in hell), so it should be replaced by :

text = vtos( self.origin );

sprintf(self, text);

Unfortunately, this also applies to operators :

sum = anglestovec( 45) + anglestovec( 90);

will fail an should be replaced by :

sum = anglestovec( 45);

sum = sum + anglestovec( 90);

Actually, Quake-C is rather lame as a compiler, and you will probably make hundred of little mistakes like that, that the compiler will not warn you of. But remember Quake-C was built for "performance", not ease of use. And also that it wasn't designed by people from the MIT. Remember also that you got it for free... you can always get gcc (the Gnu C Compiler) for the same price ;-)

You cannot initialise variable with default values.

If you give a default value to a quake-C variable, this variable will be considered as a constant. And since the value of constants is not supposed to change, your program may not work properly after that.

Coordinates are relative to the world.

All the geometry (coordinate positions, directions, angles) are relative to the world. They are never relative to a given object. To know the direction an object is facing, you have to require calculation of the v_front vector (respectively v_right and v_up for the right, and the top).

Frequently Asked Questions about Quake-C

How do I change the viewpoint?

You would like that a given player sees through the eyes of another entity. This commonly happens at the end of the level (all players see through a camera), or when the player head is severed (gibbed), or when a player is invisible (he only exists as his eyes).

But the example above work by changing the player entity, and what you want is probably just to see through a camera (Duke3D) or a missile (Descent).

This operation is known in the Quake network protocol as a setview message. But nowhere it's defined in Quake-C, and there's no function to change the view port. So the solution is to encode a set view port message, followed by a set view angles message (to take the orientation of the camera).

This works fine, except that if, for some reason, the entity you are using as a camera was not previously declared to the client, then the view port will be set to '0 0 0', which is usually somewhere in the void.

How do I teleport a player into another server

A trick by Steven Lang (tiger@ecis.com)

// In the slipgate touch function

// other = entity that touched

if(other.classname == "player")

stuffcmd(other, "connect server.addressn"); // send command

When the slipgate is touched, the entity jumps to another server.

Trouble : the player stats and weapons won't be preserved, and the player would be dumped to the console if the other server was full or not available.

That's why John Carmack, will rewrite the code of Quake.exe to implement his Quake World proposal, and advanced server with all kinds of goodies... permission lists, ability to block an IP, etc. (info from quake-c list).

How do I manipulate strings in Quake-C ?

Well, you can have any kind of strings, as long as they cannot be changed.

"In Ford we trust" (Brave New World).

Mind you, pr_comp.c, defines only operations = == != on strings.

How to read string variables, or text messages ?

Well, if you know, tell, that would make a nice addition to this specs.

How do I move an entity in Quake-C ?

You have better not touch it's position, else some stuff in the C code might not be valid anymore. So you call the setposition() built-in function.

How to change the velocity of an entity (make it bounce off walls) ?

Information by Greg Lewis.

It seems that an entity's velocity can't be changed in the Touch function of the entity.

Making the calculations there will be of no use. So just set entity .movetype to MOVETYPE_BOUNCE, entity.nextthink to 0.1 (to let it bounce off), and set entity.think to the name of a function that, when called 0.1 second later, will set entity.velocity to the right direction.

How to calculate the direction a player is facing?

Assuming the player is self, the entity field self.angles contains the orientation angles of the player (as set by moving the mouse).

Then the function makeverctors( self.angles) will calculate three vectors, that point in the direction the player is facing, but also to the right of the player (strafing direction) and to the direction the player is standing.

Note that those vectors are normalised to 1, so if you want to know what lays 100 units in front of the player, use self.origin + 100 * facing.

How to send a message to a client when he logs in ?

It has been noticed that using a sprint() in function ClientConnect just plain doesn't send any message at all. Maybe the client is not ready to receive messages at this point.

However, Doug Keenan has reported he could send such a text message by putting the sprint() close to the begining of the ClientConnect function. It doesn't work at the end, apparently.

Writing Quake-C code

Here are some suggestions that you should really consider when writing Quake-C code. Well, there are no obligations, but that would make life simpler for others when they read your code (and thus for you when you read theirs).

I assume here that you want to develop code that others can re-use, or that can be mixed seamlessly with codes written by others.

(If you are reinventing the whole world all by yourself, you hardly need any help or counsels. By the way, the first command is +light).

1. Please put comments in your code

Of course, the real gurus don't need comments. They understand raw Quake-C, even compiled. They can even imagine all the parts of your code before they read them. Even before you write them. But actually, they seldom read your code. Only normal people do.

2. Please tag the begining and end of your modifications, if you are fixing a code from someone else

Also put a date, and put a reason for the fix.

Example :

// Patch by Nezu The Unworthy 8/3/96
// Gimme a chance to win a deathmatch
if(self.name != "nezu")
self.frag = self.frag - 10;
// Patch End

3. Creating new elements

Each time you create a new function, a new variable or a new field, please give it a name that will not conflict with function or variable defined by others.

A rather sure way to do this is to prefix every name with some abvreviated module name, or you initials, or whatever rare combination of three or four letter.

Example :

void() NTU_think = // Nezu The Unworthy starts thinking
{
self.skin = 1; // turn red and boil
};

4. Implementing new functions

Each time you implement some set of related functions, you should create a new Quake-C module, and give it a name different from the existing ones.

Please do not use one of the module names used by ID Software, this would be confusing. Try to be original, else we might end-up with two hundred modules called impulse.qc.

5. When you want to distribute some modified Quake-C programs :

Include a file_id.diz file explaining in 5 lines what your patch does, and where it should be stored in the archives (this file is to be read by system administrators).

Include a readme.txt file explaining in details what your patch does, how it does it, and what common files you had to modify.

Include the .qc modules that you created from scratch.

For the modules you modified, please let them pass through the utilities diff (see below), so that the original file can be patched the utility patch. Even if it has been modified since. Do not distribute modified .qc modules. Future versions of Quake will contain different code, and all your work would then be lost.

6. Compile and distribute

You should compile and distribute a version of your code, as a single PROGS.DAT file, to be used by those who just wanna have fun. Don't forget them, they largely overnumber the people who directly deal with Quake-C.

7. Upload your Quake-C patches to the primary quake ftp site at ftp.cdrom.com

Maybe if it's good enough it will also appear in the Quake-C code repository.

Using Diff and Patch

Information by Jeff Epler

You can find a DOS version of diff and patch on all the major ftp archives, for instance Simtelnet

For a Win32 (Windows95 and NT) version, see diffutils.zip and patch.zip.

The full documentation for diff and patch is available on the internet, but here are some shortened instructions :

To make a diff :

· Start with yourdir/ with an entire working set of .qc files, and v101qc/ with the virgin qc files from ID Software,
· diff -ur --new-file v101qc yourdir > patchfil

To patch with a diff :

· Copy everything in v101qc (or yourdir if you want to add these patches to your already-customized setup) to newdir,
· Change to newdir
· Patch -p1 < patchfil
· Look for any "rejected" patches and apply them by hand using your favorite 2-window text editor. These should be few or none if the author kept his changes well-structured or you patched from exactly the same source he diffed from.

11. Basic Types

Simple Types

Type : void

An empty result, mostly used for definition of procedures (i.e. functions that return no result at all).

Type : float

A floating point value.

Floats are also used to store booleans (TRUE, FALSE) or integer values linke counters, or bit flags.

Valid syntax: 12 1.6 0.5 -100
Invalid syntax: .5

A parsing ambiguity is present with negative constants. "a-5" will be parsed as "a", then "-5", causing an error. Separate the - from the digits with a space "a - 5" to get the proper behavior.

Type : vector

A vector, made of 3 float coordinates.
Used to represent positions or directions in 3D space.
Valid syntax : '0 0 0' or '20.5 -10 0.00001'
Note the simple quotes around the vector. Do not use double quotes, they are reserved for strings.
If you declare a vector foobar, then you can access it's x, y and z fields with : foobar_x, foobar_y, foobar_z.

Type : string

Represents a character string.
Used to indicate file names, or messages to be broadcast to players.
Valid syntax: "maps/jrwiz1.bsp" or "ouch!n".
Use n for newline.

Type : entity

The reference of an entity in the game, like things, players, monsters.
For instance, this is the type of the entities self and other.
The entity type is a structured type, made of fields.
A description of each field is available.

Field types

Countrary to the other types, the entity type is a reference to an instance of a structured object, that contains many informations of totally different kinds.

To access all these informations conveniently, they are stored as fields of the entity object, and each field is given a name and a type, that makes it distinct of the others.

Some of the fields do not store value, but instead they store the function to be executed in certain conditions. They are called the methods that can be aplied to the object.

If Quake-C was an object oriented programming language, those method functions and would be distinguished from the other fields. And, above all, you would be able to create new object types, with their own fields.

As Quake-C stands currently, all the field definitions are definitions of entity fields. So anywhere in your code you could add definition of new fields, and the compiler would interpret them as an extension of the entity definition.

Here are all the possible definitions of entity fields, with their types :

  • float field_name;

  • string field_name;

  • vector field_name;

  • entity field_name;


Reserved field types (beware of the hack!)

In the first file read by the Quake-C compiler, defs.qc, there must be a definition for the entity fields, and world fields. This definition is hard coded. You had better not touch it, or you will have to recompile Quake itself.

The globals are defined before the special definition void end_sys_globals;. The entity fields are defined before the special definition void end_sys_fields;.

It's not important if you don't understand the nonsense above. It's an ugly hack. Just don't modify defs.qc before those two tags, and you won't be in trouble.

12. Compilation of QuakeC

The language is strongly typed and there are no casts.

Source files are processed sequentially without dumping any state, so if a defs file is the first one processed, the definitions will be available to all other files.

Error recovery during compilation is minimal. It will skip to the next global definition, so you will never see more than one error at a time in a given function. All compilation aborts after ten error messages.

Names can be defined multiple times until they are defined with an initialization, allowing functions to be prototyped before their definition.

// in headers
void() MyFunction; // the prototype
// later
void() MyFunction = // the initialization
{ dprint ("we're heren"); };

Beware of the Quake-C compiler

13. Execution of QuakeC

Code execution is initiated by C code in quake from two main places : the timed think routines for periodic control, and the touch function when two objects impact each other.

Execution is also caused by a few uncommon events, like the addition of a new client to an existing server.

There is a runnaway counter that stops a program if 100000 statements are executed, assuming it is in an infinite loop.

It is acceptable to change the system set global variables. This is usually done to pose as another entity by changing self and calling a function.

The interpretation is fairly efficient, but it is still over an order of magnitude slower than compiled C code. All time consuming operations should be made into built in functions.

A profile counter is kept for each function, and incremented for each interpreted instruction inside that function. The "profile" console command in Quake will dump out the top 10 functions, then clear all the counters. The "profile all" command will dump sorted stats for every function that has been executed.

14. Examples

These are examples taken from the QuakeC patch archives. Two of them are made by Ferrara.

14.1 Looping between all Monsters

float() Pet_FindTarget =
{
local entity client;
local float r;
local entity head, selected;
local float dist;
dist = 10000;
selected = world;
head = findradius(self.origin, 10000);
while(head)
{
if( (head.health > 1) && (head != self) && (head != self.owner))
{
traceline(self.origin,head.origin,TRUE,self);
if ( (trace_fraction >= 1) && (vlen(head.origin - self.origin) < dist)
&& (head.owner != self.owner))
{
selected = head;
dist = vlen(head.origin - self.origin);
}
}
head = head.chain;
}
if (selected != world)
{
sprint (self.owner,"Pet attacking -> ");
if (selected.classname == "player")
{
sprint (self.owner,selected.netname);
sprint (selected,self.owner.netname);
sprint (selected," sent one of his minions after you!n");
}
else
sprint (self.owner,selected.classname);
sprint (self.owner,"n");
self.enemy = selected;
FoundTarget ();
return TRUE;
}
if (self.goalentity != self.owner)
{
self.goalentity = self.owner;
self.think = self.th_run;
}
self.ideal_yaw = vectoyaw(self.owner.origin - self.origin);
self.nextthink = time+0.1;
return FALSE;
};

14.2 Creating a New Entity

void(entity myself) ActivateHolo =
{
local entity newholo;
newholo = spawn();
newholo.solid = SOLID_NOT;
newholo.movetype = MOVETYPE_NOCLIP;
newholo.origin = myself.origin;
newholo.angles = myself.angles;
newholo.colormap = myself.colormap;
setmodel (newholo, "progs/player.mdl");
newholo.classname = "holo";
newholo.owner=myself;
newholo.frame=13;
newholo.nextthink = time + 8;
newholo.think = RemoveHolo;
myself.currentammo = myself.ammo_cells = myself.ammo_cells - 10;
myself.items = myself.items | IT_HOLO;
stuffcmd (newholo.owner, "bfn");
sprint(newholo.owner,"holograph activatedn");
};

14.3 Setting a Point of View

void(entity me, entity camera) NezuSetViewPoint =
{
// Set view point
msg_entity = me; // target of message
WriteByte (MSG_ONE, SVC_SETVIEWPORT); // 5 = SVC_SETVIEWPORT;
WriteEntity (MSG_ONE, camera); // view port
// Also set angles, otherwise it feels strange
// NezuSetViewAngle(me, camera.angles);
WriteByte (MSG_ONE, SVC_SETVIEWANGLES); // 10 = SVC_SETVIEWANGLES
WriteAngle(MSG_ONE, camera.angles_x); // tilt
WriteAngle(MSG_ONE, camera.angles_y); // yaw
WriteAngle(MSG_ONE, camera.angles_z); // flip
};

14.4 Teleporting

void() Teleport_to_bomb =
{
local entity oldself,bdest;
bdest=spawn();
bdest.origin = self.telebomb.origin + '0 0 27';
// Blow up the bomb...
oldself=self;
self=self.telebomb;
GrenadeExplode();
self=oldself;

// Teleport to the bomb's old location
if(self.health <= 0) {
remove(bdest);
return;
}

// Recreating the "teleport_touch" function here, once again
spawn_tfog (bdest.origin);
spawn_tfog (bdest.origin);
spawn_tdeath (bdest.origin,self);
setorigin (self,bdest.origin);
self.teleport_time = time + 1; // Longer teleport recovery time
self.flags = self.flags - self.flags & FL_ONGROUND;
remove(bdest);
};

14.5 Throwing Your Eyes

if (self.impulse == 254)
{
local vector v;
eyes = spawn();
setmodel (eyes,"progs/eyes.mdl");
eyes.movetype = MOVETYPE_BOUNCE;
eyes.solid = SOLID_BBOX;
eyes.effects = eyes.effects | EF_DIMLIGHT;
msg_entity = self;
WriteByte (MSG_ONE, SVC_SETVIEWPORT);
WriteEntity (MSG_ONE, eyes);
WriteByte (MSG_ONE, SVC_SETVIEWANGLES);
WriteAngle(MSG_ONE, self.angles_x);
WriteAngle(MSG_ONE, self.angles_y);
WriteAngle(MSG_ONE, self.angles_z);
makevectors (self.v_angle);
if (self.v_angle_x)
eyes.velocity = v_forward*600 + v_up * 200 + crandom()*v_right*10 + crandom()*v_up*10;
else
{
eyes.velocity = aim(self, 10000);
eyes.velocity = eyes.velocity * 600;
eyes.velocity_z = 200;
}
eyes.avelocity = '300 300 300';
eyes.angles = vectoangles(eyes.velocity);
setsize (eyes, '-3 -3 -3', '3 3 3');
setorigin (eyes, self.origin);
}
if (self.impulse == 253)
{
local vector v;
msg_entity = self;
WriteByte (MSG_ONE, SVC_SETVIEWPORT);
WriteEntity (MSG_ONE, self);
WriteByte (MSG_ONE, SVC_SETVIEWANGLES);
v = vectoangles(eyes.origin - self.origin);
WriteAngle(MSG_ONE, v_x);
WriteAngle(MSG_ONE, v_y);
WriteAngle(MSG_ONE, v_z);
remove(eyes);
}

14.6 Radar

if (cvar("temp1")==1)
{
local entity head,selected;
local float min,dist;
if (radar_time==0) radar_time=time;
if (time>=radar_time)
{
min=2000;
head = findradius(self.origin,1000);
selected = world;
while (head)
{
dist = vlen(self.origin - head.origin);
if( (head.health > 1) && (head != self) && (head != self.owner) && (dist
{
min=dist;
selected=head;
}
head = head.chain;
}
sound (selected, CHAN_AUTO, "radar.wav", 1, ATTN_NORM);
radar_time = min / 600;
radar_time = radar_time + time;
}
}

Latest Syndicated News

»
Codutility.com up and runn...
Nice, and there still using the logo and template for the screenshots, which...
Codutility.com up and runn...
dundy writes...Quote:Call of Duty modding and mapping is barly alive only a ...
Codutility.com up and runn...
Mystic writes...Quote:It seems to me the like the site is completely dead? ...
Codutility.com up and runn...
It seems to me the like the site is completely dead?

Partners & Friends

»