Forge: more files history

This commit is contained in:
Jeff Teunissen 2001-11-05 19:47:05 +00:00
parent 2ab7a09812
commit 51a17f280b
6 changed files with 0 additions and 13557 deletions

View file

@ -1,3 +0,0 @@
Config.h
Config.h.in
stamp-h

View file

@ -1,883 +0,0 @@
/*
cmdlib.c
Command library
Copyright (C) 1996-1997 id Software, Inc.
Copyright (C) 2001 Jeff Teunissen <deek@dusknet.dhs.org>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of
the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public
License along with this program; if not, write to:
Free Software Foundation, Inc.
59 Temple Place - Suite 330
Boston, MA 02111-1307, USA
$Id$
*/
#include <sys/types.h>
#include <sys/stat.h>
#ifdef __unix__
# ifdef NeXT
# include <libc.h>
# endif
# include <unistd.h>
#endif
#ifdef WIN32
#include <direct.h>
#endif
#include <QF/sys.h>
#include "cmdlib.h"
#define PATHSEPERATOR '/'
// set these before calling CheckParm
int myargc;
char **myargv;
char com_token[1024];
qboolean com_eof;
qboolean archive;
char archivedir[1024];
/*
Error
For abnormal program terminations
*/
void
Error (char *error, ...)
{
va_list argptr;
printf ("************ ERROR ************\n");
va_start (argptr, error);
vprintf (error, argptr);
va_end (argptr);
printf ("\n");
exit (1);
}
/*
qdir will hold the path up to the quake directory, including the slash
f:\quake\
/raid/quake/
gamedir will hold qdir + the game directory (id1, id2, etc)
*/
char qdir[1024];
char gamedir[1024];
void
SetQdirFromPath (char *path)
{
char temp[1024];
char *c;
if (!(path[0] == '/' || path[0] == '\\' || path[1] == ':')) { // partial path
Q_getwd (temp);
strcat (temp, path);
path = temp;
}
// search for "quake" in path
for (c = path; *c; c++) {
if (!Q_strncasecmp (c, "quake", 5)) {
strncpy (qdir, path, c + 6 - path);
printf ("qdir: %s\n", qdir);
c += 6;
while (*c) {
if (*c == '/' || *c == '\\') {
strncpy (gamedir, path, c + 1 - path);
printf ("gamedir: %s\n", gamedir);
return;
}
c++;
}
Error ("No gamedir in %s", path);
return;
}
}
Error ("SeetQdirFromPath: no 'quake' in %s", path);
}
char *
ExpandPath (char *path)
{
static char full[1024];
if (!qdir)
Error ("ExpandPath called without qdir set");
if (path[0] == '/' || path[0] == '\\' || path[1] == ':')
return path;
sprintf (full, "%s%s", qdir, path);
return full;
}
char *
ExpandPathAndArchive (char *path)
{
char *expanded;
char archivename[1024];
expanded = ExpandPath (path);
if (archive) {
sprintf (archivename, "%s/%s", archivedir, path);
CopyFile (expanded, archivename);
}
return expanded;
}
/*
I_FloatTime
*/
double
I_FloatTime (void)
{
time_t t;
time (&t);
return t;
#if 0
// more precise, less portable
struct timeval tp;
struct timezone tzp;
static int secbase;
gettimeofday (&tp, &tzp);
if (!secbase) {
secbase = tp.tv_sec;
return tp.tv_usec / 1000000.0;
}
return (tp.tv_sec - secbase) + tp.tv_usec / 1000000.0;
#endif
}
void
Q_getwd (char *out)
{
#ifdef WIN32
_getcwd (out, 256);
strcat (out, "\\");
#else
getcwd (out, 256);
#endif
}
void
Q_mkdir (char *path)
{
#ifdef WIN32
if (_mkdir (path) != -1)
return;
#else
if (mkdir (path, 0777) != -1)
return;
#endif
if (errno != EEXIST)
Error ("mkdir %s: %s", path, strerror (errno));
}
/*
FileTime
returns -1 if not present
*/
int
FileTime (char *path)
{
struct stat buf;
if (stat (path, &buf) == -1)
return -1;
return buf.st_mtime;
}
/*
COM_Parse
Parse a token out of a string
*/
char *
COM_Parse (char *data)
{
int c;
int len = 0;
com_token[0] = 0;
if (!data)
return NULL;
// skip whitespace
skipwhite:
while ((c = *data) <= ' ') {
if (c == 0) {
com_eof = true;
return NULL; // end of file;
}
data++;
}
// skip // comments
if (c == '/' && data[1] == '/') {
while (*data && *data != '\n')
data++;
goto skipwhite;
}
// handle quoted strings specially
if (c == '\"') {
data++;
do {
c = *data++;
if (c == '\"') {
com_token[len] = 0;
return data;
}
com_token[len] = c;
len++;
} while (1);
}
// parse single characters
if (c == '{' || c == '}' || c == ')' || c == '(' || c == '\'' || c == ':') {
com_token[len] = c;
len++;
com_token[len] = 0;
return data + 1;
}
// parse a regular word
do {
com_token[len] = c;
data++;
len++;
c = *data;
if (c == '{' || c == '}' || c == ')' || c == '(' || c == '\''
|| c == ':')
break;
} while (c > 32);
com_token[len] = 0;
return data;
}
int
Q_strncasecmp (char *s1, char *s2, int n)
{
int c1, c2;
while (1) {
c1 = *s1++;
c2 = *s2++;
if (!n--)
return 0; // strings are equal until end point
if (c1 != c2) {
if (c1 >= 'a' && c1 <= 'z')
c1 -= ('a' - 'A');
if (c2 >= 'a' && c2 <= 'z')
c2 -= ('a' - 'A');
if (c1 != c2)
return -1; // strings not equal
}
if (!c1)
return 0; // strings are equal
}
return -1;
}
int
Q_strcasecmp (char *s1, char *s2)
{
return Q_strncasecmp (s1, s2, 99999);
}
char *
strupr (char *start)
{
char *in;
in = start;
while (*in) {
*in = toupper (*in);
in++;
}
return start;
}
char *
strlower (char *start)
{
char *in;
in = start;
while (*in) {
*in = tolower (*in);
in++;
}
return start;
}
/*
=============================================================================
MISC FUNCTIONS
=============================================================================
*/
/*
CheckParm
Checks for the given parameter in the program's command line arguments
Returns the argument number (1 to argc-1) or 0 if not present
*/
int
CheckParm (char *check)
{
int i;
for (i = 1; i < myargc; i++) {
if (!Q_strcasecmp (check, myargv[i]))
return i;
}
return 0;
}
/*
filelength
*/
int
filelength (FILE *f)
{
int pos;
int end;
pos = ftell (f);
fseek (f, 0, SEEK_END);
end = ftell (f);
fseek (f, pos, SEEK_SET);
return end;
}
FILE *
SafeOpenWrite (char *filename)
{
FILE *f;
f = fopen (filename, "wb");
if (!f)
Error ("Error opening %s: %s", filename, strerror (errno));
return f;
}
FILE *
SafeOpenRead (char *filename)
{
FILE *f;
f = fopen (filename, "rb");
if (!f)
Error ("Error opening %s: %s", filename, strerror (errno));
return f;
}
void
SafeRead (FILE *f, void *buffer, int count)
{
if (fread (buffer, 1, count, f) != (size_t) count)
Error ("File read failure");
}
void
SafeWrite (FILE *f, void *buffer, int count)
{
if (fwrite (buffer, 1, count, f) != (size_t) count)
Error ("File read failure");
}
/*
LoadFile
*/
int
LoadFile (char *filename, void **bufferptr)
{
FILE *f;
int length;
void *buffer;
f = SafeOpenRead (filename);
length = filelength (f);
buffer = malloc (length + 1);
((char *) buffer)[length] = 0;
SafeRead (f, buffer, length);
fclose (f);
*bufferptr = buffer;
return length;
}
/*
SaveFile
*/
void
SaveFile (char *filename, void *buffer, int count)
{
FILE *f;
f = SafeOpenWrite (filename);
SafeWrite (f, buffer, count);
fclose (f);
}
/*
DefaultExtension
Append an extension if the path doesn't have one.
The extension passed should include . at the beginning.
*/
void
DefaultExtension (char *path, char *extension)
{
char *src;
src = path + strlen (path) - 1;
while (*src != PATHSEPERATOR && src != path) {
if (*src == '.')
return; // it has an extension
src--;
}
strcat (path, extension);
}
void
DefaultPath (char *path, char *basepath)
{
char temp[128];
if (path[0] == PATHSEPERATOR)
return; // absolute path location
strcpy (temp, path);
strcpy (path, basepath);
strcat (path, temp);
}
void
StripFilename (char *path)
{
int length;
length = strlen (path) - 1;
while (length > 0 && path[length] != PATHSEPERATOR)
length--;
path[length] = 0;
}
void
StripExtension (char *path)
{
int length;
length = strlen (path) - 1;
while (length > 0 && path[length] != '.') {
length--;
if (path[length] == PATHSEPERATOR) // no extension
return;
}
if (length)
path[length] = 0;
}
/*
====================
Extract file parts
====================
*/
void
ExtractFilePath (char *path, char *dest)
{
char *src;
src = path + strlen (path) - 1;
// back up until a / or the start
while (src != path && *(src - 1) != PATHSEPERATOR)
src--;
memcpy (dest, path, src - path);
dest[src - path] = 0;
}
void
ExtractFileBase (char *path, char *dest)
{
char *src;
src = path + strlen (path) - 1;
// back up until a / or the start
while (src != path && *(src - 1) != PATHSEPERATOR)
src--;
while (*src && *src != '.') {
*dest++ = *src++;
}
*dest = 0;
}
void
ExtractFileExtension (char *path, char *dest)
{
char *src;
src = path + strlen (path) - 1;
// back up until a . or the start
while (src != path && *(src - 1) != '.')
src--;
if (src == path) {
*dest = 0; // no extension
return;
}
strcpy (dest, src);
}
/*
ParseNum / ParseHex
*/
int
ParseHex (char *hex)
{
char *str;
int num;
num = 0;
str = hex;
while (*str) {
num <<= 4;
if (*str >= '0' && *str <= '9')
num += *str - '0';
else if (*str >= 'a' && *str <= 'f')
num += 10 + *str - 'a';
else if (*str >= 'A' && *str <= 'F')
num += 10 + *str - 'A';
else
Error ("Bad hex number: %s", hex);
str++;
}
return num;
}
int
ParseNum (char *str)
{
if (str[0] == '$')
return ParseHex (str + 1);
if (str[0] == '0' && str[1] == 'x')
return ParseHex (str + 2);
return atol (str);
}
/*
============================================================================
BYTE ORDER FUNCTIONS
============================================================================
*/
#ifdef WORDS_BIGENDIAN
short
LittleShort (short l)
{
byte b1, b2;
b1 = l & 255;
b2 = (l >> 8) & 255;
return (b1 << 8) + b2;
}
short
BigShort (short l)
{
return l;
}
int
LittleLong (int l)
{
byte b1, b2, b3, b4;
b1 = l & 255;
b2 = (l >> 8) & 255;
b3 = (l >> 16) & 255;
b4 = (l >> 24) & 255;
return ((int) b1 << 24) + ((int) b2 << 16) + ((int) b3 << 8) + b4;
}
int
BigLong (int l)
{
return l;
}
float
LittleFloat (float l)
{
union {
byte b[4];
float f;
} in, out;
in.f = l;
out.b[0] = in.b[3];
out.b[1] = in.b[2];
out.b[2] = in.b[1];
out.b[3] = in.b[0];
return out.f;
}
float
BigFloat (float l)
{
return l;
}
#else
short
BigShort (short l)
{
byte b1, b2;
b1 = l & 255;
b2 = (l >> 8) & 255;
return (b1 << 8) + b2;
}
short
LittleShort (short l)
{
return l;
}
int
BigLong (int l)
{
byte b1, b2, b3, b4;
b1 = l & 255;
b2 = (l >> 8) & 255;
b3 = (l >> 16) & 255;
b4 = (l >> 24) & 255;
return ((int) b1 << 24) + ((int) b2 << 16) + ((int) b3 << 8) + b4;
}
int
LittleLong (int l)
{
return l;
}
float
BigFloat (float l)
{
union {
byte b[4];
float f;
} in, out;
in.f = l;
out.b[0] = in.b[3];
out.b[1] = in.b[2];
out.b[2] = in.b[1];
out.b[3] = in.b[0];
return out.f;
}
float
LittleFloat (float l)
{
return l;
}
#endif
//=======================================================
// FIXME: byte swap?
// this is a 16 bit, non-reflected CRC using the polynomial 0x1021
// and the initial and final xor values shown below... in other words, the
// CCITT standard CRC used by XMODEM
#define CRC_INIT_VALUE 0xffff
#define CRC_XOR_VALUE 0x0000
static unsigned short crctable[256] = {
0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7, 0x8108,
0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef, 0x1231, 0x0210,
0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6, 0x9339, 0x8318, 0xb37b,
0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de, 0x2462, 0x3443, 0x0420, 0x1401,
0x64e6, 0x74c7, 0x44a4, 0x5485, 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee,
0xf5cf, 0xc5ac, 0xd58d, 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6,
0x5695, 0x46b4, 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d,
0xc7bc, 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823,
0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b, 0x5af5,
0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12, 0xdbfd, 0xcbdc,
0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a, 0x6ca6, 0x7c87, 0x4ce4,
0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41, 0xedae, 0xfd8f, 0xcdec, 0xddcd,
0xad2a, 0xbd0b, 0x8d68, 0x9d49, 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13,
0x2e32, 0x1e51, 0x0e70, 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a,
0x9f59, 0x8f78, 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e,
0xe16f, 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e, 0x02b1,
0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256, 0xb5ea, 0xa5cb,
0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d, 0x34e2, 0x24c3, 0x14a0,
0x0481, 0x7466, 0x6447, 0x5424, 0x4405, 0xa7db, 0xb7fa, 0x8799, 0x97b8,
0xe75f, 0xf77e, 0xc71d, 0xd73c, 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657,
0x7676, 0x4615, 0x5634, 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9,
0xb98a, 0xa9ab, 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882,
0x28a3, 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,
0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92, 0xfd2e,
0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9, 0x7c26, 0x6c07,
0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1, 0xef1f, 0xff3e, 0xcf5d,
0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8, 0x6e17, 0x7e36, 0x4e55, 0x5e74,
0x2e93, 0x3eb2, 0x0ed1, 0x1ef0
};
void
CRC_Init (unsigned short *crcvalue)
{
*crcvalue = CRC_INIT_VALUE;
}
void
CRC_ProcessByte (unsigned short *crcvalue, byte data)
{
*crcvalue = (*crcvalue << 8) ^ crctable[(*crcvalue >> 8) ^ data];
}
unsigned short
CRC_Value (unsigned short crcvalue)
{
return crcvalue ^ CRC_XOR_VALUE;
}
//=============================================================================
/*
CreatePath
Create a path.
*/
void
CreatePath (char *path)
{
char *ofs, c;
for (ofs = path + 1; *ofs; ofs++) {
c = *ofs;
if (c == '/' || c == '\\') { // create the directory
*ofs = 0;
Q_mkdir (path);
*ofs = c;
}
}
}
/*
CopyFile
Used to archive source files
*/
void
CopyFile (char *from, char *to)
{
void *buffer;
int length;
length = LoadFile (from, &buffer);
CreatePath (to);
SaveFile (to, buffer, length);
free (buffer);
}

File diff suppressed because it is too large Load diff

View file

@ -1,22 +0,0 @@
{
QuakeEd = {
basePath = "/raid/quake/id1";
maps = "";
desc = "";
WadFiles = (
"gfx/medieval.wad",
"gfx/base.wad",
"gfx/wizard.wad",
"gfx/metal.wad",
"gfx/tim.wad",
"gfx/items.wad",
"gfx/start.wad"
);
bspfullvis = "ssh satan \"/Local/Tools/qbsp $1 $2 ; /Local/Tools/light -extra $2 ; /Local/Tools/vis $2\"";
bspfastvis = "ssh satan \"/Local/Tools/qbsp $1 $2 ; /Local/Tools/light $2 ; /Local/Tools/vis -fast $2\"";
bspnovis = "ssh satan \"/Local/Tools/qbsp $1 $2 ; /Local/Tools/light $2\"";
bsprelight = "ssh satan \"/Local/Tools/qbsp -onlyents $1 $2 ; /Local/Tools/light -extra $2\"";
bspleaktest = "ssh satan \"/Local/Tools/qbsp -mark -notjunc $1 $2 ; /Local/Tools/light $2\"";
bspentities = "ssh satan \"/Local/Tools/qbsp -onlyents $1 $2\"";
};
}

View file

@ -1,53 +0,0 @@
5/18/96
This is a dump of the current source code for QuakeEd, our map editing
application.
This does not include everything necessary to build maps. There are graphics
files, prog files, and other utilities needed. I plan on releasing a full
development set of tools after the game ships. This is just intended to help
out anyone working on their own map editor.
This is a NEXTSTEP application, so hardly anyone is going to be able to use the
code as is. This is not an OPENSTEP application. It doesn't even use the
foundation kit, so porting to gnustep or openstep-solaris/mach/nt would not be
trivial.
There are lots of mixed case and >8 character filenames, so I'm using unix
gnutar (compressed) format.
Because most people won't have access to a NEXTSTEP machine, I took pictures of
some of the more important stuff from interface builder:
mainwindow.tiff : a screenshot of the primary window
inspectors.tiff : a screenshot of the important inspector views
help.txt : a dump of the (minimal) help inspector's contents.
I included some sample data to help you follow the code:
quake.qpr : our current project file
jrbase1.map : a sample map
triggers.qc : a sample qc source file that includes some /*QUAKED comments
There will not be any major changes to this code base. I am eagerly looking
forward to writing a brand new editor for windows NT + open GL as soon as Quake
ships.
This application was really not a very good fit for NEXTSTEP. The display
postscript model fundamentally doesn't fit very well with what we need here --
if you run in an 8 bit color mode, the line drawing runs at an ok speed, but the
texture view goes half the speed it should as it dithers from 24 bit color down
to 8 bit. If you run in 24 bit color mode, you get less screen real estate and
significantly slower line drawing as a 3 megabyte XY view is flushed. Sigh. If
anyone does actually run this on NEXTSTEP be advised that you want a fast
machine. I never had the time to properly optimize QuakeEd.
The texture view rendering code in here is crap. Anyone coding a new editor is
strongly advised to just use an available optimized library, like open GL or
direct 3D.
John Carmack
Id Software
johnc@idsoftware.com

View file

@ -1,738 +0,0 @@
entity stemp, otemp, s, old;
void() trigger_reactivate =
{
self.solid = SOLID_TRIGGER;
};
float USED_SPAWN_PARMS = 8;
void() EncodeLevelParms =
{
other.items = other.items - (other.items & (IT_KEY1 | IT_KEY2) );
if (other.health > 100)
other.health = 100;
parm1 = other.items;
parm2 = other.health;
parm3 = other.armorvalue;
parm4 = other.ammo_shells;
parm5 = other.ammo_nails;
parm6 = other.ammo_rockets;
parm7 = other.weapon;
parm8 = other.armortype;
};
void() SetNewGameParms =
{
other = self;
other.health = 100;
other.ammo_shells = 25;
other.ammo_nails = 0;
other.ammo_rockets = 0;
other.ammo_cells = 0;
other.items = IT_SHOTGUN | IT_AXE;
other.weapon = 1;
other.armortype = 0;
other.armorvalue = 0;
EncodeLevelParms ();
};
void() DecodeLevelParms =
{
self.items = parm1;
self.health = parm2;
self.armorvalue = parm3;
self.ammo_shells = parm4;
self.ammo_nails = parm5;
self.ammo_rockets = parm6;
self.weapon = parm7;
self.armortype = parm8;
};
void() T_changelevel =
{
if (other.classname != "player")
return;
self.nextthink = time + 10;
self.think = trigger_reactivate;
self.solid = SOLID_NOT;
EncodeLevelParms ();
bprint ("\n\n");
bprint (other.netname);
bprint (" killed ");
bprint (ftos(other.killed_monsters));
bprint (" monsters out of ");
bprint (ftos(total_monsters));
bprint ("\n");
bprint ("And found ");
bprint (ftos(other.found_secrets));
bprint (" secrets out of ");
bprint (ftos(total_secrets));
bprint ("\n\n");
changelevel (other, self.map, USED_SPAWN_PARMS);
};
/*QUAKED trigger_changelevel (0.5 0.5 0.5) ?
When the player touches this, he gets sent to the map listed in the "map" variable.
*/
void() trigger_changelevel =
{
if (!self.map)
objerror ("chagnelevel trigger doesn't have map");
self.angles = '0 0 0';
self.solid = SOLID_TRIGGER;
settriggermodel (self, self.model);
self.touch = T_changelevel;
};
//=============================================================================
float SPAWNFLAG_NOMESSAGE = 1;
float SPAWNFLAG_NOTOUCH = 1;
// the wait time has passed, so set back up for another activation
void() multi_wait =
{
if (self.max_health)
{
self.health = self.max_health;
self.takedamage = DAMAGE_YES;
self.solid = SOLID_BBOX;
}
else
self.solid = SOLID_TRIGGER;
};
// the delay time has passed, so activate all targets
void() multi_fire =
{
activator = self.enemy;
SUB_UseTargets();
if (self.wait > 0)
{
self.think = multi_wait;
self.nextthink = time + self.wait;
}
else
self.nextthink = -1;
};
// the trigger was just touched/killed/used
// self.enemy should be set to the activator so it can be held through a delay
// so wait for the delay time before firing
void() multi_trigger =
{
if (self.nextthink > time)
{
return; // already been triggered
}
if (self.classname == "trigger_secret")
{
if (self.enemy.classname != "player")
return;
self.enemy.found_secrets = self.enemy.found_secrets + 1;
WriteByte (self.enemy, SVC_FOUNDSECRET);
}
if (self.message)
{
if (self.enemy.classname == "player")
{
sound (self.enemy, 0, "temp/talk.wav", 1,1);
centerprint (self.enemy, self.message);
}
}
if (self.noise)
sound (self, 1, self.noise, 1, 1);
// don't trigger again until reset
self.solid = SOLID_NOT;
self.takedamage = DAMAGE_NO;
// either fire now, or after a delay
if (!self.delay)
{
multi_fire ();
if (self.wait == -1)
remove(self);
}
else
{
self.nextthink = time + self.delay;
self.think = multi_fire;
}
};
void() multi_killed =
{
self.enemy = damage_attacker;
multi_trigger();
};
void() multi_use =
{
self.enemy = activator;
multi_trigger();
};
void() multi_touch =
{
local vector for;
if (other.classname != "player")
return;
// if the trigger has an angles field, check player's facing direction
if (self.angles != '0 0 0')
{
makevectors (self.angles);
for = v_forward;
makevectors (other.angles);
if (v_forward * for < 0)
return; // not facing the right way
}
self.enemy = other;
multi_trigger ();
};
/*QUAKED trigger_multiple (.5 .5 .5) ? notouch
Variable sized repeatable trigger. Must be targeted at one or more entities. If "health" is set, the trigger must be killed to activate each time.
If "delay" is set, the trigger waits some time after activating before firing.
"wait" : Seconds between triggerings. (.2 default)
If notouch is set, the trigger is only fired by other entities, not by touching.
sounds
1) secret
2) beep beep
3) large switch
4)
set "message" to text string
*/
void() trigger_multiple =
{
if (self.sounds == 1)
{
precache_sound ("temp/secret.wav");
self.noise = "temp/secret.wav";
}
else if (self.sounds == 2)
{
precache_sound ("temp/talk.wav");
self.noise = "temp/talk.wav";
}
else if (self.sounds == 3)
{
precache_sound ("misc/trigger1.wav");
self.noise = "misc/trigger1.wav";
}
// self.angles = '0 0 0';
if (!self.wait)
self.wait = 0.2;
self.use = multi_use;
if (self.health)
{
if (self.spawnflags & SPAWNFLAG_NOTOUCH)
objerror ("health and notouch don't make sense\n");
self.max_health = self.health;
self.th_die = multi_killed;
self.takedamage = DAMAGE_YES;
self.solid = SOLID_BBOX;
}
else
{
if ( !(self.spawnflags & SPAWNFLAG_NOTOUCH) )
{
self.touch = multi_touch;
self.solid = SOLID_TRIGGER;
}
}
settriggermodel (self, self.model);
if (!self.target)
{
if (!self.message)
error ("There is no target set!");
}
};
/*QUAKED trigger_once (.5 .5 .5) ? notouch
Variable sized trigger. Triggers once, then removes itself. You must set the key "target" to the name of another object in the level that has a matching
"targetname". If "health" is set, the trigger must be killed to activate.
If notouch is set, the trigger is only fired by other entities, not by touching.
if "killtarget" is set, any objects that have a matching "target" will be removed when the trigger is fired.
if "angle" is set, the trigger will only fire when someone is facing the direction of the angle. Use "360" for an angle of 0.
sounds
1) secret
2) beep beep
3) large switch
4)
set "message" to text string
*/
void() trigger_once =
{
self.wait = -1;
trigger_multiple();
};
/*QUAKED trigger_secret (.5 .5 .5) ?
secret counter trigger
sounds
1) secret
2) beep beep
3)
4)
set "message" to text string
*/
void() trigger_secret =
{
total_secrets = total_secrets + 1;
self.wait = -1;
// self.classname = "trigger_secret";
if (!self.message)
self.message = "You found a secret area!";
if (!self.sounds)
self.sounds = 1;
if (self.sounds == 1)
{
precache_sound ("temp/secret.wav");
self.noise = "temp/secret.wav";
}
else if (self.sounds == 2)
{
precache_sound ("temp/talk.wav");
self.noise = "temp/talk.wav";
}
trigger_multiple ();
};
void() counter_use =
{
local string junk;
self.count = self.count - 1;
if (self.count < 0)
return;
if (self.count != 0)
{
if (activator.classname == "player"
&& (self.spawnflags & SPAWNFLAG_NOMESSAGE) == 0)
{
if (self.count > 4)
centerprint (activator, "There are mroe to go...");
else if (self.count == 3)
centerprint (activator, "Only 3 more to go...");
else if (self.count == 2)
centerprint (activator, "Only 2 more to go...");
else
centerprint (activator, "Only 1 more to go...");
}
return;
}
if (activator.classname == "player"
&& (self.spawnflags & SPAWNFLAG_NOMESSAGE) == 0)
centerprint(activator, "Sequence completed!");
self.enemy = activator;
multi_trigger ();
};
/*QUAKED trigger_counter (.5 .5 .5) ? nomessage
Acts as an intermediary for an action that takes multiple inputs.
If nomessage is not set, t will print "1 more.. " etc when triggered and "sequence complete" when finished.
After the counter has been triggered "count" times (default 2), it will fire all of it's targets and remove itself.
*/
void() trigger_counter =
{
self.wait = -1;
if (!self.count)
self.count = 2;
if (!self.target)
error ("There is no target set!");
self.use = counter_use;
};
/*
==============================================================================
TELEPORT TRIGGERS
==============================================================================
*/
float PLAYER_ONLY = 1;
void() random_telesound =
{
local float v;
local string tmpstr;
v = random() * 5;
if (v < 1)
tmpstr = "misc/r_tele1.wav";
else if (v < 2)
tmpstr = "misc/r_tele2.wav";
else if (v < 3)
tmpstr = "misc/r_tele3.wav";
else if (v < 4)
tmpstr = "misc/r_tele4.wav";
else
tmpstr = "misc/r_tele5.wav";
sound (self, 1, tmpstr, 1, 1);
};
void() tfog1 = [ 0, tfog2 ] {};
void() tfog2 = [ 1, tfog3 ] {random_telesound();};
void() tfog3 = [ 2, tfog4 ] {};
void() tfog4 = [ 3, tfog5 ] {};
void() tfog5 = [ 4, tfog6 ] {};
void() tfog6 = [ 5, tfog7 ] {};
void() tfog7 = [ 6, tfog8 ] {};
void() tfog8 = [ 7, tfog9 ] {};
void() tfog9 = [ 8, tfog10 ] {};
void() tfog10 = [ 9, tfog11 ] {};
void() tfog11 = [ 9, tfog11 ] {remove(self);};
void(vector org) spawn_tfog =
{
s = spawn ();
s.origin = org;
s.angles = '0 0 0';
s.movetype = MOVETYPE_NONE;
s.solid = SOLID_NOT;
setmodel (s, "sprites/s_telep.spr");
old = self;
self = s;
tfog1 ();
self = old;
};
void() tdeath_touch =
{
if (other == self.owner)
return;
if (other.health)
{
self.solid = SOLID_NOT;
T_Damage (other, self, self, 1000);
}
};
void() tdeath_remove =
{
remove (self);
return;
};
void(vector org, entity death_owner) spawn_tdeath =
{
local entity death;
death = spawn();
death.classname = "teledeath";
death.origin = org;
death.movetype = MOVETYPE_NONE;
death.solid = SOLID_TRIGGER;
death.angles = '0 0 0';
// FIX ME (this does not set the size properly)
setsize (death, '-20 -20 -20', '20 20 20');
death.touch = tdeath_touch;
death.nextthink = time + 0.1;
death.think = tdeath_remove;
death.owner = death_owner;
};
void() teleport_touch =
{
local entity t;
local vector org;
if (self.spawnflags & PLAYER_ONLY)
{
if (other.classname != "player")
return;
}
// only teleport living creatures
if (other.health <= 0)
return;
// put a tfog where the player was
spawn_tfog (other.origin);
// FIXME: precalc at awake time
t = find (world, targetname, self.target);
if (!t)
objerror ("couldn't find target");
// spawn a tfog flash in front of the destination
makevectors (t.mangle);
org = t.origin + 32 * v_forward;
spawn_tfog (org);
spawn_tdeath(t.origin, other);
// move the player and lock him down for a little while
if (!other.health)
{
other.origin = t.origin;
other.velocity = (v_forward * other.velocity_x) + (v_forward * other.velocity_y);
return;
}
setorigin (other, t.origin);
other.angles = t.mangle;
if (other.classname == "player")
{
other.fixangle = 1; // turn this way immediately
other.teleport_time = time + 0.7;
if (other.flags & FL_ONGROUND)
other.flags = other.flags - FL_ONGROUND;
other.velocity = v_forward * 300;
}
other.flags = other.flags - other.flags & FL_ONGROUND;
};
/*QUAKED info_teleport_destination (.5 .5 .5) (-8 -8 -8) (8 8 32)
This is the destination marker for a teleporter. It should have a "targetname" field with the same value as a teleporter's "target" field.
*/
void() info_teleport_destination =
{
// this does nothing, just serves as a target spot
self.mangle = self.angles;
self.angles = '0 0 0';
self.model = "";
self.origin = self.origin + '0 0 27';
if (!self.targetname)
objerror ("no targetname");
};
/*QUAKED trigger_teleport (.5 .5 .5) ? PLAYER_ONLY
Any object touching this will be transported to the corresponding info_teleport_destination entity. You must set the "target" field, and create an object with a "targetname" field that matches.
*/
void() trigger_teleport =
{
self.mangle = self.angles;
self.angles = '0 0 0';
setsize (self, self.mins, self.maxs);
self.solid = SOLID_TRIGGER;
settriggermodel (self, self.model);
self.touch = teleport_touch;
self.angles = '0 0 0';
// find the destination
if (!self.target)
objerror ("no target");
};
/*
==============================================================================
trigger_setskill
==============================================================================
*/
void() trigger_skill_touch =
{
if (other.classname != "player")
return;
cvar_set ("skill", self.message);
};
/*QUAKED trigger_setskill (.5 .5 .5) ?
sets skill level to the value of "message".
Only used on start map.
*/
void() trigger_setskill =
{
self.mangle = self.angles;
self.angles = '0 0 0';
setsize (self, self.mins, self.maxs);
self.solid = SOLID_TRIGGER;
settriggermodel (self, self.model);
self.touch = trigger_skill_touch;
self.angles = '0 0 0';
};
/*
==============================================================================
ONLY REGISTERED TRIGGERS
==============================================================================
*/
void() trigger_onlyregistered_touch =
{
if (self.attack_finished > time)
return;
self.attack_finished = time + 2;
if (cvar("registered"))
{
SUB_UseTargets ();
remove (self);
}
else
{
centerprint (other, self.message);
sound (other, 0, "temp/talk.wav", 1,1);
}
};
/*QUAKED trigger_onlyregistered (.5 .5 .5) ?
Only fires if playing the registered version, otherwise prints the message
*/
void() trigger_onlyregistered =
{
self.mangle = self.angles;
self.angles = '0 0 0';
setsize (self, self.mins, self.maxs);
precache_sound ("temp/talk.wav");
self.solid = SOLID_TRIGGER;
settriggermodel (self, self.model);
self.touch = trigger_onlyregistered_touch;
self.angles = '0 0 0';
};
//============================================================================
void() hurt_on =
{
self.solid = SOLID_TRIGGER;
self.nextthink = -1;
};
void() hurt_touch =
{
if (other.health)
{
self.solid = SOLID_NOT;
T_Damage (other, self, self, self.dmg);
self.think = hurt_on;
self.nextthink = time + 1;
}
return;
};
/*QUAKED trigger_hurt (.5 .5 .5) ?
Any object touching this will be hurt
set dmg to damage amount
defalt dmg = 5
*/
void() trigger_hurt =
{
self.mangle = self.angles;
self.angles = '0 0 0';
self.solid = SOLID_TRIGGER;
settriggermodel (self, self.model);
self.touch = hurt_touch;
self.angles = '0 0 0';
if (!self.dmg)
self.dmg = 5;
};
/*QUAKED trigger_push (.5 .5 .5) ? PUSH_ONCE
Pushes the player
*/
float PUSH_ONCE = 1;
void() trigger_push_touch;
void() trigger_push =
{
self.movetype = MOVETYPE_NONE;
self.solid = SOLID_TRIGGER;
settriggermodel (self, self.model);
self.touch = trigger_push_touch;
SetMovedir();
};
void() trigger_push_touch =
{
if (other.classname == "player")
other.velocity = 1000 * self.movedir + 400 * '0 0 1';
if (self.spawnflags & PUSH_ONCE)
remove(self);
};
//============================================================================
void() trigger_monsterjump_touch =
{
if ( other.flags & (FL_MONSTER | FL_FLY | FL_SWIM) != FL_MONSTER )
return;
// set XY even if not on ground, so the jump will clear lips
other.velocity_x = self.movedir_x * self.speed;
other.velocity_y = self.movedir_y * self.speed;
if ( !(other.flags & FL_ONGROUND) )
return;
other.flags = other.flags - FL_ONGROUND;
other.velocity_z = self.height;
};
/*QUAKED trigger_monsterjump (.5 .5 .5) ?
Walking monsters that touch this will jump in the direction of the trigger's angle
"speed" default to 200, the speed thrown forward
"height" default to 200, the speed thrown upwards
*/
void() trigger_monsterjump =
{
if (!self.speed)
self.speed = 200;
if (!self.height)
self.height = 200;
self.movetype = MOVETYPE_NONE;
self.solid = SOLID_TRIGGER;
settriggermodel (self, self.model);
self.touch = trigger_monsterjump_touch;
SetMovedir();
};