This commit is contained in:
Literally A Penguin
2024-09-25 15:38:23 -05:00
committed by GitHub
parent b585e51a81
commit e8bd66b89c
89 changed files with 49934 additions and 0 deletions

769
game/g_save.c Normal file
View File

@ -0,0 +1,769 @@
/*
Copyright (C) 1997-2001 Id Software, Inc.
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 the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "g_local.h"
#define Function(f) {#f, f}
mmove_t mmove_reloc;
field_t fields[] = {
{"classname", FOFS(classname), F_LSTRING},
{"model", FOFS(model), F_LSTRING},
{"spawnflags", FOFS(spawnflags), F_INT},
{"speed", FOFS(speed), F_FLOAT},
{"accel", FOFS(accel), F_FLOAT},
{"decel", FOFS(decel), F_FLOAT},
{"target", FOFS(target), F_LSTRING},
{"targetname", FOFS(targetname), F_LSTRING},
{"pathtarget", FOFS(pathtarget), F_LSTRING},
{"deathtarget", FOFS(deathtarget), F_LSTRING},
{"killtarget", FOFS(killtarget), F_LSTRING},
{"combattarget", FOFS(combattarget), F_LSTRING},
{"message", FOFS(message), F_LSTRING},
{"team", FOFS(team), F_LSTRING},
{"wait", FOFS(wait), F_FLOAT},
{"delay", FOFS(delay), F_FLOAT},
{"random", FOFS(random), F_FLOAT},
{"move_origin", FOFS(move_origin), F_VECTOR},
{"move_angles", FOFS(move_angles), F_VECTOR},
{"style", FOFS(style), F_INT},
{"count", FOFS(count), F_INT},
{"health", FOFS(health), F_INT},
{"sounds", FOFS(sounds), F_INT},
{"light", 0, F_IGNORE},
{"dmg", FOFS(dmg), F_INT},
{"mass", FOFS(mass), F_INT},
{"volume", FOFS(volume), F_FLOAT},
{"attenuation", FOFS(attenuation), F_FLOAT},
{"map", FOFS(map), F_LSTRING},
{"origin", FOFS(s.origin), F_VECTOR},
{"angles", FOFS(s.angles), F_VECTOR},
{"angle", FOFS(s.angles), F_ANGLEHACK},
{"goalentity", FOFS(goalentity), F_EDICT, FFL_NOSPAWN},
{"movetarget", FOFS(movetarget), F_EDICT, FFL_NOSPAWN},
{"enemy", FOFS(enemy), F_EDICT, FFL_NOSPAWN},
{"oldenemy", FOFS(oldenemy), F_EDICT, FFL_NOSPAWN},
{"activator", FOFS(activator), F_EDICT, FFL_NOSPAWN},
{"groundentity", FOFS(groundentity), F_EDICT, FFL_NOSPAWN},
{"teamchain", FOFS(teamchain), F_EDICT, FFL_NOSPAWN},
{"teammaster", FOFS(teammaster), F_EDICT, FFL_NOSPAWN},
{"owner", FOFS(owner), F_EDICT, FFL_NOSPAWN},
{"mynoise", FOFS(mynoise), F_EDICT, FFL_NOSPAWN},
{"mynoise2", FOFS(mynoise2), F_EDICT, FFL_NOSPAWN},
{"target_ent", FOFS(target_ent), F_EDICT, FFL_NOSPAWN},
{"chain", FOFS(chain), F_EDICT, FFL_NOSPAWN},
{"prethink", FOFS(prethink), F_FUNCTION, FFL_NOSPAWN},
{"think", FOFS(think), F_FUNCTION, FFL_NOSPAWN},
{"blocked", FOFS(blocked), F_FUNCTION, FFL_NOSPAWN},
{"touch", FOFS(touch), F_FUNCTION, FFL_NOSPAWN},
{"use", FOFS(use), F_FUNCTION, FFL_NOSPAWN},
{"pain", FOFS(pain), F_FUNCTION, FFL_NOSPAWN},
{"die", FOFS(die), F_FUNCTION, FFL_NOSPAWN},
{"stand", FOFS(monsterinfo.stand), F_FUNCTION, FFL_NOSPAWN},
{"idle", FOFS(monsterinfo.idle), F_FUNCTION, FFL_NOSPAWN},
{"search", FOFS(monsterinfo.search), F_FUNCTION, FFL_NOSPAWN},
{"walk", FOFS(monsterinfo.walk), F_FUNCTION, FFL_NOSPAWN},
{"run", FOFS(monsterinfo.run), F_FUNCTION, FFL_NOSPAWN},
{"dodge", FOFS(monsterinfo.dodge), F_FUNCTION, FFL_NOSPAWN},
{"attack", FOFS(monsterinfo.attack), F_FUNCTION, FFL_NOSPAWN},
{"melee", FOFS(monsterinfo.melee), F_FUNCTION, FFL_NOSPAWN},
{"sight", FOFS(monsterinfo.sight), F_FUNCTION, FFL_NOSPAWN},
{"checkattack", FOFS(monsterinfo.checkattack), F_FUNCTION, FFL_NOSPAWN},
{"currentmove", FOFS(monsterinfo.currentmove), F_MMOVE, FFL_NOSPAWN},
{"endfunc", FOFS(moveinfo.endfunc), F_FUNCTION, FFL_NOSPAWN},
// temp spawn vars -- only valid when the spawn function is called
{"lip", STOFS(lip), F_INT, FFL_SPAWNTEMP},
{"distance", STOFS(distance), F_INT, FFL_SPAWNTEMP},
{"height", STOFS(height), F_INT, FFL_SPAWNTEMP},
{"noise", STOFS(noise), F_LSTRING, FFL_SPAWNTEMP},
{"pausetime", STOFS(pausetime), F_FLOAT, FFL_SPAWNTEMP},
{"item", STOFS(item), F_LSTRING, FFL_SPAWNTEMP},
//need for item field in edict struct, FFL_SPAWNTEMP item will be skipped on saves
{"item", FOFS(item), F_ITEM},
{"gravity", STOFS(gravity), F_LSTRING, FFL_SPAWNTEMP},
{"sky", STOFS(sky), F_LSTRING, FFL_SPAWNTEMP},
{"skyrotate", STOFS(skyrotate), F_FLOAT, FFL_SPAWNTEMP},
{"skyaxis", STOFS(skyaxis), F_VECTOR, FFL_SPAWNTEMP},
{"minyaw", STOFS(minyaw), F_FLOAT, FFL_SPAWNTEMP},
{"maxyaw", STOFS(maxyaw), F_FLOAT, FFL_SPAWNTEMP},
{"minpitch", STOFS(minpitch), F_FLOAT, FFL_SPAWNTEMP},
{"maxpitch", STOFS(maxpitch), F_FLOAT, FFL_SPAWNTEMP},
{"nextmap", STOFS(nextmap), F_LSTRING, FFL_SPAWNTEMP},
{0, 0, 0, 0}
};
field_t levelfields[] =
{
{"changemap", LLOFS(changemap), F_LSTRING},
{"sight_client", LLOFS(sight_client), F_EDICT},
{"sight_entity", LLOFS(sight_entity), F_EDICT},
{"sound_entity", LLOFS(sound_entity), F_EDICT},
{"sound2_entity", LLOFS(sound2_entity), F_EDICT},
{NULL, 0, F_INT}
};
field_t clientfields[] =
{
{"pers.weapon", CLOFS(pers.weapon), F_ITEM},
{"pers.lastweapon", CLOFS(pers.lastweapon), F_ITEM},
{"newweapon", CLOFS(newweapon), F_ITEM},
{NULL, 0, F_INT}
};
/*
============
InitGame
This will be called when the dll is first loaded, which
only happens when a new game is started or a save game
is loaded.
============
*/
void InitGame (void)
{
gi.dprintf ("==== InitGame ====\n");
gun_x = gi.cvar ("gun_x", "0", 0);
gun_y = gi.cvar ("gun_y", "0", 0);
gun_z = gi.cvar ("gun_z", "0", 0);
//FIXME: sv_ prefix is wrong for these
sv_rollspeed = gi.cvar ("sv_rollspeed", "200", 0);
sv_rollangle = gi.cvar ("sv_rollangle", "2", 0);
sv_maxvelocity = gi.cvar ("sv_maxvelocity", "2000", 0);
sv_gravity = gi.cvar ("sv_gravity", "800", 0);
// noset vars
dedicated = gi.cvar ("dedicated", "0", CVAR_NOSET);
// latched vars
sv_cheats = gi.cvar ("cheats", "0", CVAR_SERVERINFO|CVAR_LATCH);
gi.cvar ("gamename", GAMEVERSION , CVAR_SERVERINFO | CVAR_LATCH);
gi.cvar ("gamedate", __DATE__ , CVAR_SERVERINFO | CVAR_LATCH);
maxclients = gi.cvar ("maxclients", "4", CVAR_SERVERINFO | CVAR_LATCH);
maxspectators = gi.cvar ("maxspectators", "4", CVAR_SERVERINFO);
deathmatch = gi.cvar ("deathmatch", "0", CVAR_LATCH);
coop = gi.cvar ("coop", "0", CVAR_LATCH);
skill = gi.cvar ("skill", "1", CVAR_LATCH);
maxentities = gi.cvar ("maxentities", "1024", CVAR_LATCH);
// change anytime vars
dmflags = gi.cvar ("dmflags", "0", CVAR_SERVERINFO);
fraglimit = gi.cvar ("fraglimit", "0", CVAR_SERVERINFO);
timelimit = gi.cvar ("timelimit", "0", CVAR_SERVERINFO);
password = gi.cvar ("password", "", CVAR_USERINFO);
spectator_password = gi.cvar ("spectator_password", "", CVAR_USERINFO);
filterban = gi.cvar ("filterban", "1", 0);
g_select_empty = gi.cvar ("g_select_empty", "0", CVAR_ARCHIVE);
run_pitch = gi.cvar ("run_pitch", "0.002", 0);
run_roll = gi.cvar ("run_roll", "0.005", 0);
bob_up = gi.cvar ("bob_up", "0.005", 0);
bob_pitch = gi.cvar ("bob_pitch", "0.002", 0);
bob_roll = gi.cvar ("bob_roll", "0.002", 0);
// flood control
flood_msgs = gi.cvar ("flood_msgs", "4", 0);
flood_persecond = gi.cvar ("flood_persecond", "4", 0);
flood_waitdelay = gi.cvar ("flood_waitdelay", "10", 0);
// dm map list
sv_maplist = gi.cvar ("sv_maplist", "", 0);
// items
InitItems ();
Com_sprintf (game.helpmessage1, sizeof(game.helpmessage1), "");
Com_sprintf (game.helpmessage2, sizeof(game.helpmessage2), "");
// initialize all entities for this game
game.maxentities = maxentities->value;
g_edicts = gi.TagMalloc (game.maxentities * sizeof(g_edicts[0]), TAG_GAME);
globals.edicts = g_edicts;
globals.max_edicts = game.maxentities;
// initialize all clients for this game
game.maxclients = maxclients->value;
game.clients = gi.TagMalloc (game.maxclients * sizeof(game.clients[0]), TAG_GAME);
globals.num_edicts = game.maxclients+1;
}
//=========================================================
void WriteField1 (FILE *f, field_t *field, byte *base)
{
void *p;
int len;
int index;
if (field->flags & FFL_SPAWNTEMP)
return;
p = (void *)(base + field->ofs);
switch (field->type)
{
case F_INT:
case F_FLOAT:
case F_ANGLEHACK:
case F_VECTOR:
case F_IGNORE:
break;
case F_LSTRING:
case F_GSTRING:
if ( *(char **)p )
len = strlen(*(char **)p) + 1;
else
len = 0;
*(int *)p = len;
break;
case F_EDICT:
if ( *(edict_t **)p == NULL)
index = -1;
else
index = *(edict_t **)p - g_edicts;
*(int *)p = index;
break;
case F_CLIENT:
if ( *(gclient_t **)p == NULL)
index = -1;
else
index = *(gclient_t **)p - game.clients;
*(int *)p = index;
break;
case F_ITEM:
if ( *(edict_t **)p == NULL)
index = -1;
else
index = *(gitem_t **)p - itemlist;
*(int *)p = index;
break;
//relative to code segment
case F_FUNCTION:
if (*(byte **)p == NULL)
index = 0;
else
index = *(byte **)p - ((byte *)InitGame);
*(int *)p = index;
break;
//relative to data segment
case F_MMOVE:
if (*(byte **)p == NULL)
index = 0;
else
index = *(byte **)p - (byte *)&mmove_reloc;
*(int *)p = index;
break;
default:
gi.error ("WriteEdict: unknown field type");
}
}
void WriteField2 (FILE *f, field_t *field, byte *base)
{
int len;
void *p;
if (field->flags & FFL_SPAWNTEMP)
return;
p = (void *)(base + field->ofs);
switch (field->type)
{
case F_LSTRING:
if ( *(char **)p )
{
len = strlen(*(char **)p) + 1;
fwrite (*(char **)p, len, 1, f);
}
break;
}
}
void ReadField (FILE *f, field_t *field, byte *base)
{
void *p;
int len;
int index;
if (field->flags & FFL_SPAWNTEMP)
return;
p = (void *)(base + field->ofs);
switch (field->type)
{
case F_INT:
case F_FLOAT:
case F_ANGLEHACK:
case F_VECTOR:
case F_IGNORE:
break;
case F_LSTRING:
len = *(int *)p;
if (!len)
*(char **)p = NULL;
else
{
*(char **)p = gi.TagMalloc (len, TAG_LEVEL);
fread (*(char **)p, len, 1, f);
}
break;
case F_EDICT:
index = *(int *)p;
if ( index == -1 )
*(edict_t **)p = NULL;
else
*(edict_t **)p = &g_edicts[index];
break;
case F_CLIENT:
index = *(int *)p;
if ( index == -1 )
*(gclient_t **)p = NULL;
else
*(gclient_t **)p = &game.clients[index];
break;
case F_ITEM:
index = *(int *)p;
if ( index == -1 )
*(gitem_t **)p = NULL;
else
*(gitem_t **)p = &itemlist[index];
break;
//relative to code segment
case F_FUNCTION:
index = *(int *)p;
if ( index == 0 )
*(byte **)p = NULL;
else
*(byte **)p = ((byte *)InitGame) + index;
break;
//relative to data segment
case F_MMOVE:
index = *(int *)p;
if (index == 0)
*(byte **)p = NULL;
else
*(byte **)p = (byte *)&mmove_reloc + index;
break;
default:
gi.error ("ReadEdict: unknown field type");
}
}
//=========================================================
/*
==============
WriteClient
All pointer variables (except function pointers) must be handled specially.
==============
*/
void WriteClient (FILE *f, gclient_t *client)
{
field_t *field;
gclient_t temp;
// all of the ints, floats, and vectors stay as they are
temp = *client;
// change the pointers to lengths or indexes
for (field=clientfields ; field->name ; field++)
{
WriteField1 (f, field, (byte *)&temp);
}
// write the block
fwrite (&temp, sizeof(temp), 1, f);
// now write any allocated data following the edict
for (field=clientfields ; field->name ; field++)
{
WriteField2 (f, field, (byte *)client);
}
}
/*
==============
ReadClient
All pointer variables (except function pointers) must be handled specially.
==============
*/
void ReadClient (FILE *f, gclient_t *client)
{
field_t *field;
fread (client, sizeof(*client), 1, f);
for (field=clientfields ; field->name ; field++)
{
ReadField (f, field, (byte *)client);
}
}
/*
============
WriteGame
This will be called whenever the game goes to a new level,
and when the user explicitly saves the game.
Game information include cross level data, like multi level
triggers, help computer info, and all client states.
A single player death will automatically restore from the
last save position.
============
*/
void WriteGame (char *filename, qboolean autosave)
{
FILE *f;
int i;
char str[16];
if (!autosave)
SaveClientData ();
f = fopen (filename, "wb");
if (!f)
gi.error ("Couldn't open %s", filename);
memset (str, 0, sizeof(str));
strcpy (str, __DATE__);
fwrite (str, sizeof(str), 1, f);
game.autosaved = autosave;
fwrite (&game, sizeof(game), 1, f);
game.autosaved = false;
for (i=0 ; i<game.maxclients ; i++)
WriteClient (f, &game.clients[i]);
fclose (f);
}
void ReadGame (char *filename)
{
FILE *f;
int i;
char str[16];
gi.FreeTags (TAG_GAME);
f = fopen (filename, "rb");
if (!f)
gi.error ("Couldn't open %s", filename);
fread (str, sizeof(str), 1, f);
if (strcmp (str, __DATE__))
{
fclose (f);
gi.error ("Savegame from an older version.\n");
}
g_edicts = gi.TagMalloc (game.maxentities * sizeof(g_edicts[0]), TAG_GAME);
globals.edicts = g_edicts;
fread (&game, sizeof(game), 1, f);
game.clients = gi.TagMalloc (game.maxclients * sizeof(game.clients[0]), TAG_GAME);
for (i=0 ; i<game.maxclients ; i++)
ReadClient (f, &game.clients[i]);
fclose (f);
}
//==========================================================
/*
==============
WriteEdict
All pointer variables (except function pointers) must be handled specially.
==============
*/
void WriteEdict (FILE *f, edict_t *ent)
{
field_t *field;
edict_t temp;
// all of the ints, floats, and vectors stay as they are
temp = *ent;
// change the pointers to lengths or indexes
for (field=fields ; field->name ; field++)
{
WriteField1 (f, field, (byte *)&temp);
}
// write the block
fwrite (&temp, sizeof(temp), 1, f);
// now write any allocated data following the edict
for (field=fields ; field->name ; field++)
{
WriteField2 (f, field, (byte *)ent);
}
}
/*
==============
WriteLevelLocals
All pointer variables (except function pointers) must be handled specially.
==============
*/
void WriteLevelLocals (FILE *f)
{
field_t *field;
level_locals_t temp;
// all of the ints, floats, and vectors stay as they are
temp = level;
// change the pointers to lengths or indexes
for (field=levelfields ; field->name ; field++)
{
WriteField1 (f, field, (byte *)&temp);
}
// write the block
fwrite (&temp, sizeof(temp), 1, f);
// now write any allocated data following the edict
for (field=levelfields ; field->name ; field++)
{
WriteField2 (f, field, (byte *)&level);
}
}
/*
==============
ReadEdict
All pointer variables (except function pointers) must be handled specially.
==============
*/
void ReadEdict (FILE *f, edict_t *ent)
{
field_t *field;
fread (ent, sizeof(*ent), 1, f);
for (field=fields ; field->name ; field++)
{
ReadField (f, field, (byte *)ent);
}
}
/*
==============
ReadLevelLocals
All pointer variables (except function pointers) must be handled specially.
==============
*/
void ReadLevelLocals (FILE *f)
{
field_t *field;
fread (&level, sizeof(level), 1, f);
for (field=levelfields ; field->name ; field++)
{
ReadField (f, field, (byte *)&level);
}
}
/*
=================
WriteLevel
=================
*/
void WriteLevel (char *filename)
{
int i;
edict_t *ent;
FILE *f;
void *base;
f = fopen (filename, "wb");
if (!f)
gi.error ("Couldn't open %s", filename);
// write out edict size for checking
i = sizeof(edict_t);
fwrite (&i, sizeof(i), 1, f);
// write out a function pointer for checking
base = (void *)InitGame;
fwrite (&base, sizeof(base), 1, f);
// write out level_locals_t
WriteLevelLocals (f);
// write out all the entities
for (i=0 ; i<globals.num_edicts ; i++)
{
ent = &g_edicts[i];
if (!ent->inuse)
continue;
fwrite (&i, sizeof(i), 1, f);
WriteEdict (f, ent);
}
i = -1;
fwrite (&i, sizeof(i), 1, f);
fclose (f);
}
/*
=================
ReadLevel
SpawnEntities will allready have been called on the
level the same way it was when the level was saved.
That is necessary to get the baselines
set up identically.
The server will have cleared all of the world links before
calling ReadLevel.
No clients are connected yet.
=================
*/
void ReadLevel (char *filename)
{
int entnum;
FILE *f;
int i;
void *base;
edict_t *ent;
f = fopen (filename, "rb");
if (!f)
gi.error ("Couldn't open %s", filename);
// free any dynamic memory allocated by loading the level
// base state
gi.FreeTags (TAG_LEVEL);
// wipe all the entities
memset (g_edicts, 0, game.maxentities*sizeof(g_edicts[0]));
globals.num_edicts = maxclients->value+1;
// check edict size
fread (&i, sizeof(i), 1, f);
if (i != sizeof(edict_t))
{
fclose (f);
gi.error ("ReadLevel: mismatched edict size");
}
// check function pointer base address
fread (&base, sizeof(base), 1, f);
#ifdef _WIN32
if (base != (void *)InitGame)
{
fclose (f);
gi.error ("ReadLevel: function pointers have moved");
}
#else
gi.dprintf("Function offsets %d\n", ((byte *)base) - ((byte *)InitGame));
#endif
// load the level locals
ReadLevelLocals (f);
// load all the entities
while (1)
{
if (fread (&entnum, sizeof(entnum), 1, f) != 1)
{
fclose (f);
gi.error ("ReadLevel: failed to read entnum");
}
if (entnum == -1)
break;
if (entnum >= globals.num_edicts)
globals.num_edicts = entnum+1;
ent = &g_edicts[entnum];
ReadEdict (f, ent);
// let the server rebuild world links for this ent
memset (&ent->area, 0, sizeof(ent->area));
gi.linkentity (ent);
}
fclose (f);
// mark all clients as unconnected
for (i=0 ; i<maxclients->value ; i++)
{
ent = &g_edicts[i+1];
ent->client = game.clients + i;
ent->client->pers.connected = false;
}
// do any load time things at this point
for (i=0 ; i<globals.num_edicts ; i++)
{
ent = &g_edicts[i];
if (!ent->inuse)
continue;
// fire any cross-level triggers
if (ent->classname)
if (strcmp(ent->classname, "target_crosslevel_target") == 0)
ent->nextthink = level.time + ent->delay;
}
}

984
game/g_spawn.c Normal file
View File

@ -0,0 +1,984 @@
/*
Copyright (C) 1997-2001 Id Software, Inc.
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 the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "g_local.h"
typedef struct
{
char *name;
void (*spawn)(edict_t *ent);
} spawn_t;
void SP_item_health (edict_t *self);
void SP_item_health_small (edict_t *self);
void SP_item_health_large (edict_t *self);
void SP_item_health_mega (edict_t *self);
void SP_info_player_start (edict_t *ent);
void SP_info_player_deathmatch (edict_t *ent);
void SP_info_player_coop (edict_t *ent);
void SP_info_player_intermission (edict_t *ent);
void SP_func_plat (edict_t *ent);
void SP_func_rotating (edict_t *ent);
void SP_func_button (edict_t *ent);
void SP_func_door (edict_t *ent);
void SP_func_door_secret (edict_t *ent);
void SP_func_door_rotating (edict_t *ent);
void SP_func_water (edict_t *ent);
void SP_func_train (edict_t *ent);
void SP_func_conveyor (edict_t *self);
void SP_func_wall (edict_t *self);
void SP_func_object (edict_t *self);
void SP_func_explosive (edict_t *self);
void SP_func_timer (edict_t *self);
void SP_func_areaportal (edict_t *ent);
void SP_func_clock (edict_t *ent);
void SP_func_killbox (edict_t *ent);
void SP_trigger_always (edict_t *ent);
void SP_trigger_once (edict_t *ent);
void SP_trigger_multiple (edict_t *ent);
void SP_trigger_relay (edict_t *ent);
void SP_trigger_push (edict_t *ent);
void SP_trigger_hurt (edict_t *ent);
void SP_trigger_key (edict_t *ent);
void SP_trigger_counter (edict_t *ent);
void SP_trigger_elevator (edict_t *ent);
void SP_trigger_gravity (edict_t *ent);
void SP_trigger_monsterjump (edict_t *ent);
void SP_target_temp_entity (edict_t *ent);
void SP_target_speaker (edict_t *ent);
void SP_target_explosion (edict_t *ent);
void SP_target_changelevel (edict_t *ent);
void SP_target_secret (edict_t *ent);
void SP_target_goal (edict_t *ent);
void SP_target_splash (edict_t *ent);
void SP_target_spawner (edict_t *ent);
void SP_target_blaster (edict_t *ent);
void SP_target_crosslevel_trigger (edict_t *ent);
void SP_target_crosslevel_target (edict_t *ent);
void SP_target_laser (edict_t *self);
void SP_target_help (edict_t *ent);
void SP_target_actor (edict_t *ent);
void SP_target_lightramp (edict_t *self);
void SP_target_earthquake (edict_t *ent);
void SP_target_character (edict_t *ent);
void SP_target_string (edict_t *ent);
void SP_worldspawn (edict_t *ent);
void SP_viewthing (edict_t *ent);
void SP_light (edict_t *self);
void SP_light_mine1 (edict_t *ent);
void SP_light_mine2 (edict_t *ent);
void SP_info_null (edict_t *self);
void SP_info_notnull (edict_t *self);
void SP_path_corner (edict_t *self);
void SP_point_combat (edict_t *self);
void SP_misc_explobox (edict_t *self);
void SP_misc_banner (edict_t *self);
void SP_misc_satellite_dish (edict_t *self);
void SP_misc_actor (edict_t *self);
void SP_misc_gib_arm (edict_t *self);
void SP_misc_gib_leg (edict_t *self);
void SP_misc_gib_head (edict_t *self);
void SP_misc_insane (edict_t *self);
void SP_misc_deadsoldier (edict_t *self);
void SP_misc_viper (edict_t *self);
void SP_misc_viper_bomb (edict_t *self);
void SP_misc_bigviper (edict_t *self);
void SP_misc_strogg_ship (edict_t *self);
void SP_misc_teleporter (edict_t *self);
void SP_misc_teleporter_dest (edict_t *self);
void SP_misc_blackhole (edict_t *self);
void SP_misc_eastertank (edict_t *self);
void SP_misc_easterchick (edict_t *self);
void SP_misc_easterchick2 (edict_t *self);
void SP_monster_berserk (edict_t *self);
void SP_monster_gladiator (edict_t *self);
void SP_monster_gunner (edict_t *self);
void SP_monster_infantry (edict_t *self);
void SP_monster_soldier_light (edict_t *self);
void SP_monster_soldier (edict_t *self);
void SP_monster_soldier_ss (edict_t *self);
void SP_monster_tank (edict_t *self);
void SP_monster_medic (edict_t *self);
void SP_monster_flipper (edict_t *self);
void SP_monster_chick (edict_t *self);
void SP_monster_parasite (edict_t *self);
void SP_monster_flyer (edict_t *self);
void SP_monster_brain (edict_t *self);
void SP_monster_floater (edict_t *self);
void SP_monster_hover (edict_t *self);
void SP_monster_mutant (edict_t *self);
void SP_monster_supertank (edict_t *self);
void SP_monster_boss2 (edict_t *self);
void SP_monster_jorg (edict_t *self);
void SP_monster_boss3_stand (edict_t *self);
void SP_monster_commander_body (edict_t *self);
void SP_turret_breach (edict_t *self);
void SP_turret_base (edict_t *self);
void SP_turret_driver (edict_t *self);
spawn_t spawns[] = {
{"item_health", SP_item_health},
{"item_health_small", SP_item_health_small},
{"item_health_large", SP_item_health_large},
{"item_health_mega", SP_item_health_mega},
{"info_player_start", SP_info_player_start},
{"info_player_deathmatch", SP_info_player_deathmatch},
{"info_player_coop", SP_info_player_coop},
{"info_player_intermission", SP_info_player_intermission},
{"func_plat", SP_func_plat},
{"func_button", SP_func_button},
{"func_door", SP_func_door},
{"func_door_secret", SP_func_door_secret},
{"func_door_rotating", SP_func_door_rotating},
{"func_rotating", SP_func_rotating},
{"func_train", SP_func_train},
{"func_water", SP_func_water},
{"func_conveyor", SP_func_conveyor},
{"func_areaportal", SP_func_areaportal},
{"func_clock", SP_func_clock},
{"func_wall", SP_func_wall},
{"func_object", SP_func_object},
{"func_timer", SP_func_timer},
{"func_explosive", SP_func_explosive},
{"func_killbox", SP_func_killbox},
{"trigger_always", SP_trigger_always},
{"trigger_once", SP_trigger_once},
{"trigger_multiple", SP_trigger_multiple},
{"trigger_relay", SP_trigger_relay},
{"trigger_push", SP_trigger_push},
{"trigger_hurt", SP_trigger_hurt},
{"trigger_key", SP_trigger_key},
{"trigger_counter", SP_trigger_counter},
{"trigger_elevator", SP_trigger_elevator},
{"trigger_gravity", SP_trigger_gravity},
{"trigger_monsterjump", SP_trigger_monsterjump},
{"target_temp_entity", SP_target_temp_entity},
{"target_speaker", SP_target_speaker},
{"target_explosion", SP_target_explosion},
{"target_changelevel", SP_target_changelevel},
{"target_secret", SP_target_secret},
{"target_goal", SP_target_goal},
{"target_splash", SP_target_splash},
{"target_spawner", SP_target_spawner},
{"target_blaster", SP_target_blaster},
{"target_crosslevel_trigger", SP_target_crosslevel_trigger},
{"target_crosslevel_target", SP_target_crosslevel_target},
{"target_laser", SP_target_laser},
{"target_help", SP_target_help},
{"target_actor", SP_target_actor},
{"target_lightramp", SP_target_lightramp},
{"target_earthquake", SP_target_earthquake},
{"target_character", SP_target_character},
{"target_string", SP_target_string},
{"worldspawn", SP_worldspawn},
{"viewthing", SP_viewthing},
{"light", SP_light},
{"light_mine1", SP_light_mine1},
{"light_mine2", SP_light_mine2},
{"info_null", SP_info_null},
{"func_group", SP_info_null},
{"info_notnull", SP_info_notnull},
{"path_corner", SP_path_corner},
{"point_combat", SP_point_combat},
{"misc_explobox", SP_misc_explobox},
{"misc_banner", SP_misc_banner},
{"misc_satellite_dish", SP_misc_satellite_dish},
{"misc_actor", SP_misc_actor},
{"misc_gib_arm", SP_misc_gib_arm},
{"misc_gib_leg", SP_misc_gib_leg},
{"misc_gib_head", SP_misc_gib_head},
{"misc_insane", SP_misc_insane},
{"misc_deadsoldier", SP_misc_deadsoldier},
{"misc_viper", SP_misc_viper},
{"misc_viper_bomb", SP_misc_viper_bomb},
{"misc_bigviper", SP_misc_bigviper},
{"misc_strogg_ship", SP_misc_strogg_ship},
{"misc_teleporter", SP_misc_teleporter},
{"misc_teleporter_dest", SP_misc_teleporter_dest},
{"misc_blackhole", SP_misc_blackhole},
{"misc_eastertank", SP_misc_eastertank},
{"misc_easterchick", SP_misc_easterchick},
{"misc_easterchick2", SP_misc_easterchick2},
{"monster_berserk", SP_monster_berserk},
{"monster_gladiator", SP_monster_gladiator},
{"monster_gunner", SP_monster_gunner},
{"monster_infantry", SP_monster_infantry},
{"monster_soldier_light", SP_monster_soldier_light},
{"monster_soldier", SP_monster_soldier},
{"monster_soldier_ss", SP_monster_soldier_ss},
{"monster_tank", SP_monster_tank},
{"monster_tank_commander", SP_monster_tank},
{"monster_medic", SP_monster_medic},
{"monster_flipper", SP_monster_flipper},
{"monster_chick", SP_monster_chick},
{"monster_parasite", SP_monster_parasite},
{"monster_flyer", SP_monster_flyer},
{"monster_brain", SP_monster_brain},
{"monster_floater", SP_monster_floater},
{"monster_hover", SP_monster_hover},
{"monster_mutant", SP_monster_mutant},
{"monster_supertank", SP_monster_supertank},
{"monster_boss2", SP_monster_boss2},
{"monster_boss3_stand", SP_monster_boss3_stand},
{"monster_jorg", SP_monster_jorg},
{"monster_commander_body", SP_monster_commander_body},
{"turret_breach", SP_turret_breach},
{"turret_base", SP_turret_base},
{"turret_driver", SP_turret_driver},
{NULL, NULL}
};
/*
===============
ED_CallSpawn
Finds the spawn function for the entity and calls it
===============
*/
void ED_CallSpawn (edict_t *ent)
{
spawn_t *s;
gitem_t *item;
int i;
if (!ent->classname)
{
gi.dprintf ("ED_CallSpawn: NULL classname\n");
return;
}
// check item spawn functions
for (i=0,item=itemlist ; i<game.num_items ; i++,item++)
{
if (!item->classname)
continue;
if (!strcmp(item->classname, ent->classname))
{ // found it
SpawnItem (ent, item);
return;
}
}
// check normal spawn functions
for (s=spawns ; s->name ; s++)
{
if (!strcmp(s->name, ent->classname))
{ // found it
s->spawn (ent);
return;
}
}
gi.dprintf ("%s doesn't have a spawn function\n", ent->classname);
}
/*
=============
ED_NewString
=============
*/
char *ED_NewString (char *string)
{
char *newb, *new_p;
int i,l;
l = strlen(string) + 1;
newb = gi.TagMalloc (l, TAG_LEVEL);
new_p = newb;
for (i=0 ; i< l ; i++)
{
if (string[i] == '\\' && i < l-1)
{
i++;
if (string[i] == 'n')
*new_p++ = '\n';
else
*new_p++ = '\\';
}
else
*new_p++ = string[i];
}
return newb;
}
/*
===============
ED_ParseField
Takes a key/value pair and sets the binary values
in an edict
===============
*/
void ED_ParseField (char *key, char *value, edict_t *ent)
{
field_t *f;
byte *b;
float v;
vec3_t vec;
for (f=fields ; f->name ; f++)
{
if (!(f->flags & FFL_NOSPAWN) && !Q_stricmp(f->name, key))
{ // found it
if (f->flags & FFL_SPAWNTEMP)
b = (byte *)&st;
else
b = (byte *)ent;
switch (f->type)
{
case F_LSTRING:
*(char **)(b+f->ofs) = ED_NewString (value);
break;
case F_VECTOR:
sscanf (value, "%f %f %f", &vec[0], &vec[1], &vec[2]);
((float *)(b+f->ofs))[0] = vec[0];
((float *)(b+f->ofs))[1] = vec[1];
((float *)(b+f->ofs))[2] = vec[2];
break;
case F_INT:
*(int *)(b+f->ofs) = atoi(value);
break;
case F_FLOAT:
*(float *)(b+f->ofs) = atof(value);
break;
case F_ANGLEHACK:
v = atof(value);
((float *)(b+f->ofs))[0] = 0;
((float *)(b+f->ofs))[1] = v;
((float *)(b+f->ofs))[2] = 0;
break;
case F_IGNORE:
break;
}
return;
}
}
gi.dprintf ("%s is not a field\n", key);
}
/*
====================
ED_ParseEdict
Parses an edict out of the given string, returning the new position
ed should be a properly initialized empty edict.
====================
*/
char *ED_ParseEdict (char *data, edict_t *ent)
{
qboolean init;
char keyname[256];
char *com_token;
init = false;
memset (&st, 0, sizeof(st));
// go through all the dictionary pairs
while (1)
{
// parse key
com_token = COM_Parse (&data);
if (com_token[0] == '}')
break;
if (!data)
gi.error ("ED_ParseEntity: EOF without closing brace");
strncpy (keyname, com_token, sizeof(keyname)-1);
// parse value
com_token = COM_Parse (&data);
if (!data)
gi.error ("ED_ParseEntity: EOF without closing brace");
if (com_token[0] == '}')
gi.error ("ED_ParseEntity: closing brace without data");
init = true;
// keynames with a leading underscore are used for utility comments,
// and are immediately discarded by quake
if (keyname[0] == '_')
continue;
ED_ParseField (keyname, com_token, ent);
}
if (!init)
memset (ent, 0, sizeof(*ent));
return data;
}
/*
================
G_FindTeams
Chain together all entities with a matching team field.
All but the first will have the FL_TEAMSLAVE flag set.
All but the last will have the teamchain field set to the next one
================
*/
void G_FindTeams (void)
{
edict_t *e, *e2, *chain;
int i, j;
int c, c2;
c = 0;
c2 = 0;
for (i=1, e=g_edicts+i ; i < globals.num_edicts ; i++,e++)
{
if (!e->inuse)
continue;
if (!e->team)
continue;
if (e->flags & FL_TEAMSLAVE)
continue;
chain = e;
e->teammaster = e;
c++;
c2++;
for (j=i+1, e2=e+1 ; j < globals.num_edicts ; j++,e2++)
{
if (!e2->inuse)
continue;
if (!e2->team)
continue;
if (e2->flags & FL_TEAMSLAVE)
continue;
if (!strcmp(e->team, e2->team))
{
c2++;
chain->teamchain = e2;
e2->teammaster = e;
chain = e2;
e2->flags |= FL_TEAMSLAVE;
}
}
}
gi.dprintf ("%i teams with %i entities\n", c, c2);
}
/*
==============
SpawnEntities
Creates a server's entity / program execution context by
parsing textual entity definitions out of an ent file.
==============
*/
void SpawnEntities (char *mapname, char *entities, char *spawnpoint)
{
edict_t *ent;
int inhibit;
char *com_token;
int i;
float skill_level;
skill_level = floor (skill->value);
if (skill_level < 0)
skill_level = 0;
if (skill_level > 3)
skill_level = 3;
if (skill->value != skill_level)
gi.cvar_forceset("skill", va("%f", skill_level));
SaveClientData ();
gi.FreeTags (TAG_LEVEL);
memset (&level, 0, sizeof(level));
memset (g_edicts, 0, game.maxentities * sizeof (g_edicts[0]));
strncpy (level.mapname, mapname, sizeof(level.mapname)-1);
strncpy (game.spawnpoint, spawnpoint, sizeof(game.spawnpoint)-1);
// set client fields on player ents
for (i=0 ; i<game.maxclients ; i++)
g_edicts[i+1].client = game.clients + i;
ent = NULL;
inhibit = 0;
// parse ents
while (1)
{
// parse the opening brace
com_token = COM_Parse (&entities);
if (!entities)
break;
if (com_token[0] != '{')
gi.error ("ED_LoadFromFile: found %s when expecting {",com_token);
if (!ent)
ent = g_edicts;
else
ent = G_Spawn ();
entities = ED_ParseEdict (entities, ent);
// yet another map hack
if (!Q_stricmp(level.mapname, "command") && !Q_stricmp(ent->classname, "trigger_once") && !Q_stricmp(ent->model, "*27"))
ent->spawnflags &= ~SPAWNFLAG_NOT_HARD;
// remove things (except the world) from different skill levels or deathmatch
if (ent != g_edicts)
{
if (deathmatch->value)
{
if ( ent->spawnflags & SPAWNFLAG_NOT_DEATHMATCH )
{
G_FreeEdict (ent);
inhibit++;
continue;
}
}
else
{
if ( /* ((coop->value) && (ent->spawnflags & SPAWNFLAG_NOT_COOP)) || */
((skill->value == 0) && (ent->spawnflags & SPAWNFLAG_NOT_EASY)) ||
((skill->value == 1) && (ent->spawnflags & SPAWNFLAG_NOT_MEDIUM)) ||
(((skill->value == 2) || (skill->value == 3)) && (ent->spawnflags & SPAWNFLAG_NOT_HARD))
)
{
G_FreeEdict (ent);
inhibit++;
continue;
}
}
ent->spawnflags &= ~(SPAWNFLAG_NOT_EASY|SPAWNFLAG_NOT_MEDIUM|SPAWNFLAG_NOT_HARD|SPAWNFLAG_NOT_COOP|SPAWNFLAG_NOT_DEATHMATCH);
}
ED_CallSpawn (ent);
}
gi.dprintf ("%i entities inhibited\n", inhibit);
#ifdef DEBUG
i = 1;
ent = EDICT_NUM(i);
while (i < globals.num_edicts) {
if (ent->inuse != 0 || ent->inuse != 1)
Com_DPrintf("Invalid entity %d\n", i);
i++, ent++;
}
#endif
G_FindTeams ();
PlayerTrail_Init ();
}
//===================================================================
#if 0
// cursor positioning
xl <value>
xr <value>
yb <value>
yt <value>
xv <value>
yv <value>
// drawing
statpic <name>
pic <stat>
num <fieldwidth> <stat>
string <stat>
// control
if <stat>
ifeq <stat> <value>
ifbit <stat> <value>
endif
#endif
char *single_statusbar =
"yb -24 "
// health
"xv 0 "
"hnum "
"xv 50 "
"pic 0 "
// ammo
"if 2 "
" xv 100 "
" anum "
" xv 150 "
" pic 2 "
"endif "
// armor
"if 4 "
" xv 200 "
" rnum "
" xv 250 "
" pic 4 "
"endif "
// selected item
"if 6 "
" xv 296 "
" pic 6 "
"endif "
"yb -50 "
// picked up item
"if 7 "
" xv 0 "
" pic 7 "
" xv 26 "
" yb -42 "
" stat_string 8 "
" yb -50 "
"endif "
// timer
"if 9 "
" xv 262 "
" num 2 10 "
" xv 296 "
" pic 9 "
"endif "
// help / weapon icon
"if 11 "
" xv 148 "
" pic 11 "
"endif "
;
char *dm_statusbar =
"yb -24 "
// health
"xv 0 "
"hnum "
"xv 50 "
"pic 0 "
// ammo
"if 2 "
" xv 100 "
" anum "
" xv 150 "
" pic 2 "
"endif "
// armor
"if 4 "
" xv 200 "
" rnum "
" xv 250 "
" pic 4 "
"endif "
// selected item
"if 6 "
" xv 296 "
" pic 6 "
"endif "
"yb -50 "
// picked up item
"if 7 "
" xv 0 "
" pic 7 "
" xv 26 "
" yb -42 "
" stat_string 8 "
" yb -50 "
"endif "
// timer
"if 9 "
" xv 246 "
" num 2 10 "
" xv 296 "
" pic 9 "
"endif "
// help / weapon icon
"if 11 "
" xv 148 "
" pic 11 "
"endif "
// frags
"xr -50 "
"yt 2 "
"num 3 14 "
// spectator
"if 17 "
"xv 0 "
"yb -58 "
"string2 \"SPECTATOR MODE\" "
"endif "
// chase camera
"if 16 "
"xv 0 "
"yb -68 "
"string \"Chasing\" "
"xv 64 "
"stat_string 16 "
"endif "
;
/*QUAKED worldspawn (0 0 0) ?
Only used for the world.
"sky" environment map name
"skyaxis" vector axis for rotating sky
"skyrotate" speed of rotation in degrees/second
"sounds" music cd track number
"gravity" 800 is default gravity
"message" text to print at user logon
*/
void SP_worldspawn (edict_t *ent)
{
ent->movetype = MOVETYPE_PUSH;
ent->solid = SOLID_BSP;
ent->inuse = true; // since the world doesn't use G_Spawn()
ent->s.modelindex = 1; // world model is always index 1
//---------------
// reserve some spots for dead player bodies for coop / deathmatch
InitBodyQue ();
// set configstrings for items
SetItemNames ();
if (st.nextmap)
strcpy (level.nextmap, st.nextmap);
// make some data visible to the server
if (ent->message && ent->message[0])
{
gi.configstring (CS_NAME, ent->message);
strncpy (level.level_name, ent->message, sizeof(level.level_name));
}
else
strncpy (level.level_name, level.mapname, sizeof(level.level_name));
if (st.sky && st.sky[0])
gi.configstring (CS_SKY, st.sky);
else
gi.configstring (CS_SKY, "unit1_");
gi.configstring (CS_SKYROTATE, va("%f", st.skyrotate) );
gi.configstring (CS_SKYAXIS, va("%f %f %f",
st.skyaxis[0], st.skyaxis[1], st.skyaxis[2]) );
gi.configstring (CS_CDTRACK, va("%i", ent->sounds) );
gi.configstring (CS_MAXCLIENTS, va("%i", (int)(maxclients->value) ) );
// status bar program
if (deathmatch->value)
gi.configstring (CS_STATUSBAR, dm_statusbar);
else
gi.configstring (CS_STATUSBAR, single_statusbar);
//---------------
// help icon for statusbar
gi.imageindex ("i_help");
level.pic_health = gi.imageindex ("i_health");
gi.imageindex ("help");
gi.imageindex ("field_3");
if (!st.gravity)
gi.cvar_set("sv_gravity", "800");
else
gi.cvar_set("sv_gravity", st.gravity);
snd_fry = gi.soundindex ("player/fry.wav"); // standing in lava / slime
PrecacheItem (FindItem ("Blaster"));
gi.soundindex ("player/lava1.wav");
gi.soundindex ("player/lava2.wav");
gi.soundindex ("misc/pc_up.wav");
gi.soundindex ("misc/talk1.wav");
gi.soundindex ("misc/udeath.wav");
// gibs
gi.soundindex ("items/respawn1.wav");
// sexed sounds
gi.soundindex ("*death1.wav");
gi.soundindex ("*death2.wav");
gi.soundindex ("*death3.wav");
gi.soundindex ("*death4.wav");
gi.soundindex ("*fall1.wav");
gi.soundindex ("*fall2.wav");
gi.soundindex ("*gurp1.wav"); // drowning damage
gi.soundindex ("*gurp2.wav");
gi.soundindex ("*jump1.wav"); // player jump
gi.soundindex ("*pain25_1.wav");
gi.soundindex ("*pain25_2.wav");
gi.soundindex ("*pain50_1.wav");
gi.soundindex ("*pain50_2.wav");
gi.soundindex ("*pain75_1.wav");
gi.soundindex ("*pain75_2.wav");
gi.soundindex ("*pain100_1.wav");
gi.soundindex ("*pain100_2.wav");
// sexed models
// THIS ORDER MUST MATCH THE DEFINES IN g_local.h
// you can add more, max 15
gi.modelindex ("#w_blaster.md2");
gi.modelindex ("#w_shotgun.md2");
gi.modelindex ("#w_sshotgun.md2");
gi.modelindex ("#w_machinegun.md2");
gi.modelindex ("#w_chaingun.md2");
gi.modelindex ("#a_grenades.md2");
gi.modelindex ("#w_glauncher.md2");
gi.modelindex ("#w_rlauncher.md2");
gi.modelindex ("#w_hyperblaster.md2");
gi.modelindex ("#w_railgun.md2");
gi.modelindex ("#w_bfg.md2");
//-------------------
gi.soundindex ("player/gasp1.wav"); // gasping for air
gi.soundindex ("player/gasp2.wav"); // head breaking surface, not gasping
gi.soundindex ("player/watr_in.wav"); // feet hitting water
gi.soundindex ("player/watr_out.wav"); // feet leaving water
gi.soundindex ("player/watr_un.wav"); // head going underwater
gi.soundindex ("player/u_breath1.wav");
gi.soundindex ("player/u_breath2.wav");
gi.soundindex ("items/pkup.wav"); // bonus item pickup
gi.soundindex ("world/land.wav"); // landing thud
gi.soundindex ("misc/h2ohit1.wav"); // landing splash
gi.soundindex ("items/damage.wav");
gi.soundindex ("items/protect.wav");
gi.soundindex ("items/protect4.wav");
gi.soundindex ("weapons/noammo.wav");
gi.soundindex ("infantry/inflies1.wav");
sm_meat_index = gi.modelindex ("models/objects/gibs/sm_meat/tris.md2");
gi.modelindex ("models/objects/gibs/arm/tris.md2");
gi.modelindex ("models/objects/gibs/bone/tris.md2");
gi.modelindex ("models/objects/gibs/bone2/tris.md2");
gi.modelindex ("models/objects/gibs/chest/tris.md2");
gi.modelindex ("models/objects/gibs/skull/tris.md2");
gi.modelindex ("models/objects/gibs/head2/tris.md2");
//
// Setup light animation tables. 'a' is total darkness, 'z' is doublebright.
//
// 0 normal
gi.configstring(CS_LIGHTS+0, "m");
// 1 FLICKER (first variety)
gi.configstring(CS_LIGHTS+1, "mmnmmommommnonmmonqnmmo");
// 2 SLOW STRONG PULSE
gi.configstring(CS_LIGHTS+2, "abcdefghijklmnopqrstuvwxyzyxwvutsrqponmlkjihgfedcba");
// 3 CANDLE (first variety)
gi.configstring(CS_LIGHTS+3, "mmmmmaaaaammmmmaaaaaabcdefgabcdefg");
// 4 FAST STROBE
gi.configstring(CS_LIGHTS+4, "mamamamamama");
// 5 GENTLE PULSE 1
gi.configstring(CS_LIGHTS+5,"jklmnopqrstuvwxyzyxwvutsrqponmlkj");
// 6 FLICKER (second variety)
gi.configstring(CS_LIGHTS+6, "nmonqnmomnmomomno");
// 7 CANDLE (second variety)
gi.configstring(CS_LIGHTS+7, "mmmaaaabcdefgmmmmaaaammmaamm");
// 8 CANDLE (third variety)
gi.configstring(CS_LIGHTS+8, "mmmaaammmaaammmabcdefaaaammmmabcdefmmmaaaa");
// 9 SLOW STROBE (fourth variety)
gi.configstring(CS_LIGHTS+9, "aaaaaaaazzzzzzzz");
// 10 FLUORESCENT FLICKER
gi.configstring(CS_LIGHTS+10, "mmamammmmammamamaaamammma");
// 11 SLOW PULSE NOT FADE TO BLACK
gi.configstring(CS_LIGHTS+11, "abcdefghijklmnopqrrqponmlkjihgfedcba");
// styles 32-62 are assigned by the light program for switchable lights
// 63 testing
gi.configstring(CS_LIGHTS+63, "a");
}

300
game/g_svcmds.c Normal file
View File

@ -0,0 +1,300 @@
/*
Copyright (C) 1997-2001 Id Software, Inc.
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 the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "g_local.h"
void Svcmd_Test_f (void)
{
gi.cprintf (NULL, PRINT_HIGH, "Svcmd_Test_f()\n");
}
/*
==============================================================================
PACKET FILTERING
You can add or remove addresses from the filter list with:
addip <ip>
removeip <ip>
The ip address is specified in dot format, and any unspecified digits will match any value, so you can specify an entire class C network with "addip 192.246.40".
Removeip will only remove an address specified exactly the same way. You cannot addip a subnet, then removeip a single host.
listip
Prints the current list of filters.
writeip
Dumps "addip <ip>" commands to listip.cfg so it can be execed at a later date. The filter lists are not saved and restored by default, because I beleive it would cause too much confusion.
filterban <0 or 1>
If 1 (the default), then ip addresses matching the current list will be prohibited from entering the game. This is the default setting.
If 0, then only addresses matching the list will be allowed. This lets you easily set up a private game, or a game that only allows players from your local network.
==============================================================================
*/
typedef struct
{
unsigned mask;
unsigned compare;
} ipfilter_t;
#define MAX_IPFILTERS 1024
ipfilter_t ipfilters[MAX_IPFILTERS];
int numipfilters;
/*
=================
StringToFilter
=================
*/
static qboolean StringToFilter (char *s, ipfilter_t *f)
{
char num[128];
int i, j;
byte b[4];
byte m[4];
for (i=0 ; i<4 ; i++)
{
b[i] = 0;
m[i] = 0;
}
for (i=0 ; i<4 ; i++)
{
if (*s < '0' || *s > '9')
{
gi.cprintf(NULL, PRINT_HIGH, "Bad filter address: %s\n", s);
return false;
}
j = 0;
while (*s >= '0' && *s <= '9')
{
num[j++] = *s++;
}
num[j] = 0;
b[i] = atoi(num);
if (b[i] != 0)
m[i] = 255;
if (!*s)
break;
s++;
}
f->mask = *(unsigned *)m;
f->compare = *(unsigned *)b;
return true;
}
/*
=================
SV_FilterPacket
=================
*/
qboolean SV_FilterPacket (char *from)
{
int i;
unsigned in;
byte m[4];
char *p;
i = 0;
p = from;
while (*p && i < 4) {
m[i] = 0;
while (*p >= '0' && *p <= '9') {
m[i] = m[i]*10 + (*p - '0');
p++;
}
if (!*p || *p == ':')
break;
i++, p++;
}
in = *(unsigned *)m;
for (i=0 ; i<numipfilters ; i++)
if ( (in & ipfilters[i].mask) == ipfilters[i].compare)
return (int)filterban->value;
return (int)!filterban->value;
}
/*
=================
SV_AddIP_f
=================
*/
void SVCmd_AddIP_f (void)
{
int i;
if (gi.argc() < 3) {
gi.cprintf(NULL, PRINT_HIGH, "Usage: addip <ip-mask>\n");
return;
}
for (i=0 ; i<numipfilters ; i++)
if (ipfilters[i].compare == 0xffffffff)
break; // free spot
if (i == numipfilters)
{
if (numipfilters == MAX_IPFILTERS)
{
gi.cprintf (NULL, PRINT_HIGH, "IP filter list is full\n");
return;
}
numipfilters++;
}
if (!StringToFilter (gi.argv(2), &ipfilters[i]))
ipfilters[i].compare = 0xffffffff;
}
/*
=================
SV_RemoveIP_f
=================
*/
void SVCmd_RemoveIP_f (void)
{
ipfilter_t f;
int i, j;
if (gi.argc() < 3) {
gi.cprintf(NULL, PRINT_HIGH, "Usage: sv removeip <ip-mask>\n");
return;
}
if (!StringToFilter (gi.argv(2), &f))
return;
for (i=0 ; i<numipfilters ; i++)
if (ipfilters[i].mask == f.mask
&& ipfilters[i].compare == f.compare)
{
for (j=i+1 ; j<numipfilters ; j++)
ipfilters[j-1] = ipfilters[j];
numipfilters--;
gi.cprintf (NULL, PRINT_HIGH, "Removed.\n");
return;
}
gi.cprintf (NULL, PRINT_HIGH, "Didn't find %s.\n", gi.argv(2));
}
/*
=================
SV_ListIP_f
=================
*/
void SVCmd_ListIP_f (void)
{
int i;
byte b[4];
gi.cprintf (NULL, PRINT_HIGH, "Filter list:\n");
for (i=0 ; i<numipfilters ; i++)
{
*(unsigned *)b = ipfilters[i].compare;
gi.cprintf (NULL, PRINT_HIGH, "%3i.%3i.%3i.%3i\n", b[0], b[1], b[2], b[3]);
}
}
/*
=================
SV_WriteIP_f
=================
*/
void SVCmd_WriteIP_f (void)
{
FILE *f;
char name[MAX_OSPATH];
byte b[4];
int i;
cvar_t *game;
game = gi.cvar("game", "", 0);
if (!*game->string)
sprintf (name, "%s/listip.cfg", GAMEVERSION);
else
sprintf (name, "%s/listip.cfg", game->string);
gi.cprintf (NULL, PRINT_HIGH, "Writing %s.\n", name);
f = fopen (name, "wb");
if (!f)
{
gi.cprintf (NULL, PRINT_HIGH, "Couldn't open %s\n", name);
return;
}
fprintf(f, "set filterban %d\n", (int)filterban->value);
for (i=0 ; i<numipfilters ; i++)
{
*(unsigned *)b = ipfilters[i].compare;
fprintf (f, "sv addip %i.%i.%i.%i\n", b[0], b[1], b[2], b[3]);
}
fclose (f);
}
/*
=================
ServerCommand
ServerCommand will be called when an "sv" command is issued.
The game can issue gi.argc() / gi.argv() commands to get the rest
of the parameters
=================
*/
void ServerCommand (void)
{
char *cmd;
cmd = gi.argv(1);
if (Q_stricmp (cmd, "test") == 0)
Svcmd_Test_f ();
else if (Q_stricmp (cmd, "addip") == 0)
SVCmd_AddIP_f ();
else if (Q_stricmp (cmd, "removeip") == 0)
SVCmd_RemoveIP_f ();
else if (Q_stricmp (cmd, "listip") == 0)
SVCmd_ListIP_f ();
else if (Q_stricmp (cmd, "writeip") == 0)
SVCmd_WriteIP_f ();
else
gi.cprintf (NULL, PRINT_HIGH, "Unknown server command \"%s\"\n", cmd);
}

809
game/g_target.c Normal file
View File

@ -0,0 +1,809 @@
/*
Copyright (C) 1997-2001 Id Software, Inc.
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 the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "g_local.h"
/*QUAKED target_temp_entity (1 0 0) (-8 -8 -8) (8 8 8)
Fire an origin based temp entity event to the clients.
"style" type byte
*/
void Use_Target_Tent (edict_t *ent, edict_t *other, edict_t *activator)
{
gi.WriteByte (svc_temp_entity);
gi.WriteByte (ent->style);
gi.WritePosition (ent->s.origin);
gi.multicast (ent->s.origin, MULTICAST_PVS);
}
void SP_target_temp_entity (edict_t *ent)
{
ent->use = Use_Target_Tent;
}
//==========================================================
//==========================================================
/*QUAKED target_speaker (1 0 0) (-8 -8 -8) (8 8 8) looped-on looped-off reliable
"noise" wav file to play
"attenuation"
-1 = none, send to whole level
1 = normal fighting sounds
2 = idle sound level
3 = ambient sound level
"volume" 0.0 to 1.0
Normal sounds play each time the target is used. The reliable flag can be set for crucial voiceovers.
Looped sounds are always atten 3 / vol 1, and the use function toggles it on/off.
Multiple identical looping sounds will just increase volume without any speed cost.
*/
void Use_Target_Speaker (edict_t *ent, edict_t *other, edict_t *activator)
{
int chan;
if (ent->spawnflags & 3)
{ // looping sound toggles
if (ent->s.sound)
ent->s.sound = 0; // turn it off
else
ent->s.sound = ent->noise_index; // start it
}
else
{ // normal sound
if (ent->spawnflags & 4)
chan = CHAN_VOICE|CHAN_RELIABLE;
else
chan = CHAN_VOICE;
// use a positioned_sound, because this entity won't normally be
// sent to any clients because it is invisible
gi.positioned_sound (ent->s.origin, ent, chan, ent->noise_index, ent->volume, ent->attenuation, 0);
}
}
void SP_target_speaker (edict_t *ent)
{
char buffer[MAX_QPATH];
if(!st.noise)
{
gi.dprintf("target_speaker with no noise set at %s\n", vtos(ent->s.origin));
return;
}
if (!strstr (st.noise, ".wav"))
Com_sprintf (buffer, sizeof(buffer), "%s.wav", st.noise);
else
strncpy (buffer, st.noise, sizeof(buffer));
ent->noise_index = gi.soundindex (buffer);
if (!ent->volume)
ent->volume = 1.0;
if (!ent->attenuation)
ent->attenuation = 1.0;
else if (ent->attenuation == -1) // use -1 so 0 defaults to 1
ent->attenuation = 0;
// check for prestarted looping sound
if (ent->spawnflags & 1)
ent->s.sound = ent->noise_index;
ent->use = Use_Target_Speaker;
// must link the entity so we get areas and clusters so
// the server can determine who to send updates to
gi.linkentity (ent);
}
//==========================================================
void Use_Target_Help (edict_t *ent, edict_t *other, edict_t *activator)
{
if (ent->spawnflags & 1)
strncpy (game.helpmessage1, ent->message, sizeof(game.helpmessage2)-1);
else
strncpy (game.helpmessage2, ent->message, sizeof(game.helpmessage1)-1);
game.helpchanged++;
}
/*QUAKED target_help (1 0 1) (-16 -16 -24) (16 16 24) help1
When fired, the "message" key becomes the current personal computer string, and the message light will be set on all clients status bars.
*/
void SP_target_help(edict_t *ent)
{
if (deathmatch->value)
{ // auto-remove for deathmatch
G_FreeEdict (ent);
return;
}
if (!ent->message)
{
gi.dprintf ("%s with no message at %s\n", ent->classname, vtos(ent->s.origin));
G_FreeEdict (ent);
return;
}
ent->use = Use_Target_Help;
}
//==========================================================
/*QUAKED target_secret (1 0 1) (-8 -8 -8) (8 8 8)
Counts a secret found.
These are single use targets.
*/
void use_target_secret (edict_t *ent, edict_t *other, edict_t *activator)
{
gi.sound (ent, CHAN_VOICE, ent->noise_index, 1, ATTN_NORM, 0);
level.found_secrets++;
G_UseTargets (ent, activator);
G_FreeEdict (ent);
}
void SP_target_secret (edict_t *ent)
{
if (deathmatch->value)
{ // auto-remove for deathmatch
G_FreeEdict (ent);
return;
}
ent->use = use_target_secret;
if (!st.noise)
st.noise = "misc/secret.wav";
ent->noise_index = gi.soundindex (st.noise);
ent->svflags = SVF_NOCLIENT;
level.total_secrets++;
// map bug hack
if (!Q_stricmp(level.mapname, "mine3") && ent->s.origin[0] == 280 && ent->s.origin[1] == -2048 && ent->s.origin[2] == -624)
ent->message = "You have found a secret area.";
}
//==========================================================
/*QUAKED target_goal (1 0 1) (-8 -8 -8) (8 8 8)
Counts a goal completed.
These are single use targets.
*/
void use_target_goal (edict_t *ent, edict_t *other, edict_t *activator)
{
gi.sound (ent, CHAN_VOICE, ent->noise_index, 1, ATTN_NORM, 0);
level.found_goals++;
if (level.found_goals == level.total_goals)
gi.configstring (CS_CDTRACK, "0");
G_UseTargets (ent, activator);
G_FreeEdict (ent);
}
void SP_target_goal (edict_t *ent)
{
if (deathmatch->value)
{ // auto-remove for deathmatch
G_FreeEdict (ent);
return;
}
ent->use = use_target_goal;
if (!st.noise)
st.noise = "misc/secret.wav";
ent->noise_index = gi.soundindex (st.noise);
ent->svflags = SVF_NOCLIENT;
level.total_goals++;
}
//==========================================================
/*QUAKED target_explosion (1 0 0) (-8 -8 -8) (8 8 8)
Spawns an explosion temporary entity when used.
"delay" wait this long before going off
"dmg" how much radius damage should be done, defaults to 0
*/
void target_explosion_explode (edict_t *self)
{
float save;
gi.WriteByte (svc_temp_entity);
gi.WriteByte (TE_EXPLOSION1);
gi.WritePosition (self->s.origin);
gi.multicast (self->s.origin, MULTICAST_PHS);
T_RadiusDamage (self, self->activator, self->dmg, NULL, self->dmg+40, MOD_EXPLOSIVE);
save = self->delay;
self->delay = 0;
G_UseTargets (self, self->activator);
self->delay = save;
}
void use_target_explosion (edict_t *self, edict_t *other, edict_t *activator)
{
self->activator = activator;
if (!self->delay)
{
target_explosion_explode (self);
return;
}
self->think = target_explosion_explode;
self->nextthink = level.time + self->delay;
}
void SP_target_explosion (edict_t *ent)
{
ent->use = use_target_explosion;
ent->svflags = SVF_NOCLIENT;
}
//==========================================================
/*QUAKED target_changelevel (1 0 0) (-8 -8 -8) (8 8 8)
Changes level to "map" when fired
*/
void use_target_changelevel (edict_t *self, edict_t *other, edict_t *activator)
{
if (level.intermissiontime)
return; // already activated
if (!deathmatch->value && !coop->value)
{
if (g_edicts[1].health <= 0)
return;
}
// if noexit, do a ton of damage to other
if (deathmatch->value && !( (int)dmflags->value & DF_ALLOW_EXIT) && other != world)
{
T_Damage (other, self, self, vec3_origin, other->s.origin, vec3_origin, 10 * other->max_health, 1000, 0, MOD_EXIT);
return;
}
// if multiplayer, let everyone know who hit the exit
if (deathmatch->value)
{
if (activator && activator->client)
gi.bprintf (PRINT_HIGH, "%s exited the level.\n", activator->client->pers.netname);
}
// if going to a new unit, clear cross triggers
if (strstr(self->map, "*"))
game.serverflags &= ~(SFL_CROSS_TRIGGER_MASK);
BeginIntermission (self);
}
void SP_target_changelevel (edict_t *ent)
{
if (!ent->map)
{
gi.dprintf("target_changelevel with no map at %s\n", vtos(ent->s.origin));
G_FreeEdict (ent);
return;
}
// ugly hack because *SOMEBODY* screwed up their map
if((Q_stricmp(level.mapname, "fact1") == 0) && (Q_stricmp(ent->map, "fact3") == 0))
ent->map = "fact3$secret1";
ent->use = use_target_changelevel;
ent->svflags = SVF_NOCLIENT;
}
//==========================================================
/*QUAKED target_splash (1 0 0) (-8 -8 -8) (8 8 8)
Creates a particle splash effect when used.
Set "sounds" to one of the following:
1) sparks
2) blue water
3) brown water
4) slime
5) lava
6) blood
"count" how many pixels in the splash
"dmg" if set, does a radius damage at this location when it splashes
useful for lava/sparks
*/
void use_target_splash (edict_t *self, edict_t *other, edict_t *activator)
{
gi.WriteByte (svc_temp_entity);
gi.WriteByte (TE_SPLASH);
gi.WriteByte (self->count);
gi.WritePosition (self->s.origin);
gi.WriteDir (self->movedir);
gi.WriteByte (self->sounds);
gi.multicast (self->s.origin, MULTICAST_PVS);
if (self->dmg)
T_RadiusDamage (self, activator, self->dmg, NULL, self->dmg+40, MOD_SPLASH);
}
void SP_target_splash (edict_t *self)
{
self->use = use_target_splash;
G_SetMovedir (self->s.angles, self->movedir);
if (!self->count)
self->count = 32;
self->svflags = SVF_NOCLIENT;
}
//==========================================================
/*QUAKED target_spawner (1 0 0) (-8 -8 -8) (8 8 8)
Set target to the type of entity you want spawned.
Useful for spawning monsters and gibs in the factory levels.
For monsters:
Set direction to the facing you want it to have.
For gibs:
Set direction if you want it moving and
speed how fast it should be moving otherwise it
will just be dropped
*/
void ED_CallSpawn (edict_t *ent);
void use_target_spawner (edict_t *self, edict_t *other, edict_t *activator)
{
edict_t *ent;
ent = G_Spawn();
ent->classname = self->target;
VectorCopy (self->s.origin, ent->s.origin);
VectorCopy (self->s.angles, ent->s.angles);
ED_CallSpawn (ent);
gi.unlinkentity (ent);
KillBox (ent);
gi.linkentity (ent);
if (self->speed)
VectorCopy (self->movedir, ent->velocity);
}
void SP_target_spawner (edict_t *self)
{
self->use = use_target_spawner;
self->svflags = SVF_NOCLIENT;
if (self->speed)
{
G_SetMovedir (self->s.angles, self->movedir);
VectorScale (self->movedir, self->speed, self->movedir);
}
}
//==========================================================
/*QUAKED target_blaster (1 0 0) (-8 -8 -8) (8 8 8) NOTRAIL NOEFFECTS
Fires a blaster bolt in the set direction when triggered.
dmg default is 15
speed default is 1000
*/
void use_target_blaster (edict_t *self, edict_t *other, edict_t *activator)
{
int effect;
if (self->spawnflags & 2)
effect = 0;
else if (self->spawnflags & 1)
effect = EF_HYPERBLASTER;
else
effect = EF_BLASTER;
fire_blaster (self, self->s.origin, self->movedir, self->dmg, self->speed, EF_BLASTER, MOD_TARGET_BLASTER);
gi.sound (self, CHAN_VOICE, self->noise_index, 1, ATTN_NORM, 0);
}
void SP_target_blaster (edict_t *self)
{
self->use = use_target_blaster;
G_SetMovedir (self->s.angles, self->movedir);
self->noise_index = gi.soundindex ("weapons/laser2.wav");
if (!self->dmg)
self->dmg = 15;
if (!self->speed)
self->speed = 1000;
self->svflags = SVF_NOCLIENT;
}
//==========================================================
/*QUAKED target_crosslevel_trigger (.5 .5 .5) (-8 -8 -8) (8 8 8) trigger1 trigger2 trigger3 trigger4 trigger5 trigger6 trigger7 trigger8
Once this trigger is touched/used, any trigger_crosslevel_target with the same trigger number is automatically used when a level is started within the same unit. It is OK to check multiple triggers. Message, delay, target, and killtarget also work.
*/
void trigger_crosslevel_trigger_use (edict_t *self, edict_t *other, edict_t *activator)
{
game.serverflags |= self->spawnflags;
G_FreeEdict (self);
}
void SP_target_crosslevel_trigger (edict_t *self)
{
self->svflags = SVF_NOCLIENT;
self->use = trigger_crosslevel_trigger_use;
}
/*QUAKED target_crosslevel_target (.5 .5 .5) (-8 -8 -8) (8 8 8) trigger1 trigger2 trigger3 trigger4 trigger5 trigger6 trigger7 trigger8
Triggered by a trigger_crosslevel elsewhere within a unit. If multiple triggers are checked, all must be true. Delay, target and
killtarget also work.
"delay" delay before using targets if the trigger has been activated (default 1)
*/
void target_crosslevel_target_think (edict_t *self)
{
if (self->spawnflags == (game.serverflags & SFL_CROSS_TRIGGER_MASK & self->spawnflags))
{
G_UseTargets (self, self);
G_FreeEdict (self);
}
}
void SP_target_crosslevel_target (edict_t *self)
{
if (! self->delay)
self->delay = 1;
self->svflags = SVF_NOCLIENT;
self->think = target_crosslevel_target_think;
self->nextthink = level.time + self->delay;
}
//==========================================================
/*QUAKED target_laser (0 .5 .8) (-8 -8 -8) (8 8 8) START_ON RED GREEN BLUE YELLOW ORANGE FAT
When triggered, fires a laser. You can either set a target
or a direction.
*/
void target_laser_think (edict_t *self)
{
edict_t *ignore;
vec3_t start;
vec3_t end;
trace_t tr;
vec3_t point;
vec3_t last_movedir;
int count;
if (self->spawnflags & 0x80000000)
count = 8;
else
count = 4;
if (self->enemy)
{
VectorCopy (self->movedir, last_movedir);
VectorMA (self->enemy->absmin, 0.5, self->enemy->size, point);
VectorSubtract (point, self->s.origin, self->movedir);
VectorNormalize (self->movedir);
if (!VectorCompare(self->movedir, last_movedir))
self->spawnflags |= 0x80000000;
}
ignore = self;
VectorCopy (self->s.origin, start);
VectorMA (start, 2048, self->movedir, end);
while(1)
{
tr = gi.trace (start, NULL, NULL, end, ignore, CONTENTS_SOLID|CONTENTS_MONSTER|CONTENTS_DEADMONSTER);
if (!tr.ent)
break;
// hurt it if we can
if ((tr.ent->takedamage) && !(tr.ent->flags & FL_IMMUNE_LASER))
T_Damage (tr.ent, self, self->activator, self->movedir, tr.endpos, vec3_origin, self->dmg, 1, DAMAGE_ENERGY, MOD_TARGET_LASER);
// if we hit something that's not a monster or player or is immune to lasers, we're done
if (!(tr.ent->svflags & SVF_MONSTER) && (!tr.ent->client))
{
if (self->spawnflags & 0x80000000)
{
self->spawnflags &= ~0x80000000;
gi.WriteByte (svc_temp_entity);
gi.WriteByte (TE_LASER_SPARKS);
gi.WriteByte (count);
gi.WritePosition (tr.endpos);
gi.WriteDir (tr.plane.normal);
gi.WriteByte (self->s.skinnum);
gi.multicast (tr.endpos, MULTICAST_PVS);
}
break;
}
ignore = tr.ent;
VectorCopy (tr.endpos, start);
}
VectorCopy (tr.endpos, self->s.old_origin);
self->nextthink = level.time + FRAMETIME;
}
void target_laser_on (edict_t *self)
{
if (!self->activator)
self->activator = self;
self->spawnflags |= 0x80000001;
self->svflags &= ~SVF_NOCLIENT;
target_laser_think (self);
}
void target_laser_off (edict_t *self)
{
self->spawnflags &= ~1;
self->svflags |= SVF_NOCLIENT;
self->nextthink = 0;
}
void target_laser_use (edict_t *self, edict_t *other, edict_t *activator)
{
self->activator = activator;
if (self->spawnflags & 1)
target_laser_off (self);
else
target_laser_on (self);
}
void target_laser_start (edict_t *self)
{
edict_t *ent;
self->movetype = MOVETYPE_NONE;
self->solid = SOLID_NOT;
self->s.renderfx |= RF_BEAM|RF_TRANSLUCENT;
self->s.modelindex = 1; // must be non-zero
// set the beam diameter
if (self->spawnflags & 64)
self->s.frame = 16;
else
self->s.frame = 4;
// set the color
if (self->spawnflags & 2)
self->s.skinnum = 0xf2f2f0f0;
else if (self->spawnflags & 4)
self->s.skinnum = 0xd0d1d2d3;
else if (self->spawnflags & 8)
self->s.skinnum = 0xf3f3f1f1;
else if (self->spawnflags & 16)
self->s.skinnum = 0xdcdddedf;
else if (self->spawnflags & 32)
self->s.skinnum = 0xe0e1e2e3;
if (!self->enemy)
{
if (self->target)
{
ent = G_Find (NULL, FOFS(targetname), self->target);
if (!ent)
gi.dprintf ("%s at %s: %s is a bad target\n", self->classname, vtos(self->s.origin), self->target);
self->enemy = ent;
}
else
{
G_SetMovedir (self->s.angles, self->movedir);
}
}
self->use = target_laser_use;
self->think = target_laser_think;
if (!self->dmg)
self->dmg = 1;
VectorSet (self->mins, -8, -8, -8);
VectorSet (self->maxs, 8, 8, 8);
gi.linkentity (self);
if (self->spawnflags & 1)
target_laser_on (self);
else
target_laser_off (self);
}
void SP_target_laser (edict_t *self)
{
// let everything else get spawned before we start firing
self->think = target_laser_start;
self->nextthink = level.time + 1;
}
//==========================================================
/*QUAKED target_lightramp (0 .5 .8) (-8 -8 -8) (8 8 8) TOGGLE
speed How many seconds the ramping will take
message two letters; starting lightlevel and ending lightlevel
*/
void target_lightramp_think (edict_t *self)
{
char style[2];
style[0] = 'a' + self->movedir[0] + (level.time - self->timestamp) / FRAMETIME * self->movedir[2];
style[1] = 0;
gi.configstring (CS_LIGHTS+self->enemy->style, style);
if ((level.time - self->timestamp) < self->speed)
{
self->nextthink = level.time + FRAMETIME;
}
else if (self->spawnflags & 1)
{
char temp;
temp = self->movedir[0];
self->movedir[0] = self->movedir[1];
self->movedir[1] = temp;
self->movedir[2] *= -1;
}
}
void target_lightramp_use (edict_t *self, edict_t *other, edict_t *activator)
{
if (!self->enemy)
{
edict_t *e;
// check all the targets
e = NULL;
while (1)
{
e = G_Find (e, FOFS(targetname), self->target);
if (!e)
break;
if (strcmp(e->classname, "light") != 0)
{
gi.dprintf("%s at %s ", self->classname, vtos(self->s.origin));
gi.dprintf("target %s (%s at %s) is not a light\n", self->target, e->classname, vtos(e->s.origin));
}
else
{
self->enemy = e;
}
}
if (!self->enemy)
{
gi.dprintf("%s target %s not found at %s\n", self->classname, self->target, vtos(self->s.origin));
G_FreeEdict (self);
return;
}
}
self->timestamp = level.time;
target_lightramp_think (self);
}
void SP_target_lightramp (edict_t *self)
{
if (!self->message || strlen(self->message) != 2 || self->message[0] < 'a' || self->message[0] > 'z' || self->message[1] < 'a' || self->message[1] > 'z' || self->message[0] == self->message[1])
{
gi.dprintf("target_lightramp has bad ramp (%s) at %s\n", self->message, vtos(self->s.origin));
G_FreeEdict (self);
return;
}
if (deathmatch->value)
{
G_FreeEdict (self);
return;
}
if (!self->target)
{
gi.dprintf("%s with no target at %s\n", self->classname, vtos(self->s.origin));
G_FreeEdict (self);
return;
}
self->svflags |= SVF_NOCLIENT;
self->use = target_lightramp_use;
self->think = target_lightramp_think;
self->movedir[0] = self->message[0] - 'a';
self->movedir[1] = self->message[1] - 'a';
self->movedir[2] = (self->movedir[1] - self->movedir[0]) / (self->speed / FRAMETIME);
}
//==========================================================
/*QUAKED target_earthquake (1 0 0) (-8 -8 -8) (8 8 8)
When triggered, this initiates a level-wide earthquake.
All players and monsters are affected.
"speed" severity of the quake (default:200)
"count" duration of the quake (default:5)
*/
void target_earthquake_think (edict_t *self)
{
int i;
edict_t *e;
if (self->last_move_time < level.time)
{
gi.positioned_sound (self->s.origin, self, CHAN_AUTO, self->noise_index, 1.0, ATTN_NONE, 0);
self->last_move_time = level.time + 0.5;
}
for (i=1, e=g_edicts+i; i < globals.num_edicts; i++,e++)
{
if (!e->inuse)
continue;
if (!e->client)
continue;
if (!e->groundentity)
continue;
e->groundentity = NULL;
e->velocity[0] += crandom()* 150;
e->velocity[1] += crandom()* 150;
e->velocity[2] = self->speed * (100.0 / e->mass);
}
if (level.time < self->timestamp)
self->nextthink = level.time + FRAMETIME;
}
void target_earthquake_use (edict_t *self, edict_t *other, edict_t *activator)
{
self->timestamp = level.time + self->count;
self->nextthink = level.time + FRAMETIME;
self->activator = activator;
self->last_move_time = 0;
}
void SP_target_earthquake (edict_t *self)
{
if (!self->targetname)
gi.dprintf("untargeted %s at %s\n", self->classname, vtos(self->s.origin));
if (!self->count)
self->count = 5;
if (!self->speed)
self->speed = 200;
self->svflags |= SVF_NOCLIENT;
self->think = target_earthquake_think;
self->use = target_earthquake_use;
self->noise_index = gi.soundindex ("world/quake.wav");
}

598
game/g_trigger.c Normal file
View File

@ -0,0 +1,598 @@
/*
Copyright (C) 1997-2001 Id Software, Inc.
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 the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "g_local.h"
void InitTrigger (edict_t *self)
{
if (!VectorCompare (self->s.angles, vec3_origin))
G_SetMovedir (self->s.angles, self->movedir);
self->solid = SOLID_TRIGGER;
self->movetype = MOVETYPE_NONE;
gi.setmodel (self, self->model);
self->svflags = SVF_NOCLIENT;
}
// the wait time has passed, so set back up for another activation
void multi_wait (edict_t *ent)
{
ent->nextthink = 0;
}
// the trigger was just activated
// ent->activator 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 (edict_t *ent)
{
if (ent->nextthink)
return; // already been triggered
G_UseTargets (ent, ent->activator);
if (ent->wait > 0)
{
ent->think = multi_wait;
ent->nextthink = level.time + ent->wait;
}
else
{ // we can't just remove (self) here, because this is a touch function
// called while looping through area links...
ent->touch = NULL;
ent->nextthink = level.time + FRAMETIME;
ent->think = G_FreeEdict;
}
}
void Use_Multi (edict_t *ent, edict_t *other, edict_t *activator)
{
ent->activator = activator;
multi_trigger (ent);
}
void Touch_Multi (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
{
if(other->client)
{
if (self->spawnflags & 2)
return;
}
else if (other->svflags & SVF_MONSTER)
{
if (!(self->spawnflags & 1))
return;
}
else
return;
if (!VectorCompare(self->movedir, vec3_origin))
{
vec3_t forward;
AngleVectors(other->s.angles, forward, NULL, NULL);
if (_DotProduct(forward, self->movedir) < 0)
return;
}
self->activator = other;
multi_trigger (self);
}
/*QUAKED trigger_multiple (.5 .5 .5) ? MONSTER NOT_PLAYER TRIGGERED
Variable sized repeatable trigger. Must be targeted at one or more entities.
If "delay" is set, the trigger waits some time after activating before firing.
"wait" : Seconds between triggerings. (.2 default)
sounds
1) secret
2) beep beep
3) large switch
4)
set "message" to text string
*/
void trigger_enable (edict_t *self, edict_t *other, edict_t *activator)
{
self->solid = SOLID_TRIGGER;
self->use = Use_Multi;
gi.linkentity (self);
}
void SP_trigger_multiple (edict_t *ent)
{
if (ent->sounds == 1)
ent->noise_index = gi.soundindex ("misc/secret.wav");
else if (ent->sounds == 2)
ent->noise_index = gi.soundindex ("misc/talk.wav");
else if (ent->sounds == 3)
ent->noise_index = gi.soundindex ("misc/trigger1.wav");
if (!ent->wait)
ent->wait = 0.2;
ent->touch = Touch_Multi;
ent->movetype = MOVETYPE_NONE;
ent->svflags |= SVF_NOCLIENT;
if (ent->spawnflags & 4)
{
ent->solid = SOLID_NOT;
ent->use = trigger_enable;
}
else
{
ent->solid = SOLID_TRIGGER;
ent->use = Use_Multi;
}
if (!VectorCompare(ent->s.angles, vec3_origin))
G_SetMovedir (ent->s.angles, ent->movedir);
gi.setmodel (ent, ent->model);
gi.linkentity (ent);
}
/*QUAKED trigger_once (.5 .5 .5) ? x x TRIGGERED
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 TRIGGERED, this trigger must be triggered before it is live.
sounds
1) secret
2) beep beep
3) large switch
4)
"message" string to be displayed when triggered
*/
void SP_trigger_once(edict_t *ent)
{
// make old maps work because I messed up on flag assignments here
// triggered was on bit 1 when it should have been on bit 4
if (ent->spawnflags & 1)
{
vec3_t v;
VectorMA (ent->mins, 0.5, ent->size, v);
ent->spawnflags &= ~1;
ent->spawnflags |= 4;
gi.dprintf("fixed TRIGGERED flag on %s at %s\n", ent->classname, vtos(v));
}
ent->wait = -1;
SP_trigger_multiple (ent);
}
/*QUAKED trigger_relay (.5 .5 .5) (-8 -8 -8) (8 8 8)
This fixed size trigger cannot be touched, it can only be fired by other events.
*/
void trigger_relay_use (edict_t *self, edict_t *other, edict_t *activator)
{
G_UseTargets (self, activator);
}
void SP_trigger_relay (edict_t *self)
{
self->use = trigger_relay_use;
}
/*
==============================================================================
trigger_key
==============================================================================
*/
/*QUAKED trigger_key (.5 .5 .5) (-8 -8 -8) (8 8 8)
A relay trigger that only fires it's targets if player has the proper key.
Use "item" to specify the required key, for example "key_data_cd"
*/
void trigger_key_use (edict_t *self, edict_t *other, edict_t *activator)
{
int index;
if (!self->item)
return;
if (!activator->client)
return;
index = ITEM_INDEX(self->item);
if (!activator->client->pers.inventory[index])
{
if (level.time < self->touch_debounce_time)
return;
self->touch_debounce_time = level.time + 5.0;
gi.centerprintf (activator, "You need the %s", self->item->pickup_name);
gi.sound (activator, CHAN_AUTO, gi.soundindex ("misc/keytry.wav"), 1, ATTN_NORM, 0);
return;
}
gi.sound (activator, CHAN_AUTO, gi.soundindex ("misc/keyuse.wav"), 1, ATTN_NORM, 0);
if (coop->value)
{
int player;
edict_t *ent;
if (strcmp(self->item->classname, "key_power_cube") == 0)
{
int cube;
for (cube = 0; cube < 8; cube++)
if (activator->client->pers.power_cubes & (1 << cube))
break;
for (player = 1; player <= game.maxclients; player++)
{
ent = &g_edicts[player];
if (!ent->inuse)
continue;
if (!ent->client)
continue;
if (ent->client->pers.power_cubes & (1 << cube))
{
ent->client->pers.inventory[index]--;
ent->client->pers.power_cubes &= ~(1 << cube);
}
}
}
else
{
for (player = 1; player <= game.maxclients; player++)
{
ent = &g_edicts[player];
if (!ent->inuse)
continue;
if (!ent->client)
continue;
ent->client->pers.inventory[index] = 0;
}
}
}
else
{
activator->client->pers.inventory[index]--;
}
G_UseTargets (self, activator);
self->use = NULL;
}
void SP_trigger_key (edict_t *self)
{
if (!st.item)
{
gi.dprintf("no key item for trigger_key at %s\n", vtos(self->s.origin));
return;
}
self->item = FindItemByClassname (st.item);
if (!self->item)
{
gi.dprintf("item %s not found for trigger_key at %s\n", st.item, vtos(self->s.origin));
return;
}
if (!self->target)
{
gi.dprintf("%s at %s has no target\n", self->classname, vtos(self->s.origin));
return;
}
gi.soundindex ("misc/keytry.wav");
gi.soundindex ("misc/keyuse.wav");
self->use = trigger_key_use;
}
/*
==============================================================================
trigger_counter
==============================================================================
*/
/*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_use(edict_t *self, edict_t *other, edict_t *activator)
{
if (self->count == 0)
return;
self->count--;
if (self->count)
{
if (! (self->spawnflags & 1))
{
gi.centerprintf(activator, "%i more to go...", self->count);
gi.sound (activator, CHAN_AUTO, gi.soundindex ("misc/talk1.wav"), 1, ATTN_NORM, 0);
}
return;
}
if (! (self->spawnflags & 1))
{
gi.centerprintf(activator, "Sequence completed!");
gi.sound (activator, CHAN_AUTO, gi.soundindex ("misc/talk1.wav"), 1, ATTN_NORM, 0);
}
self->activator = activator;
multi_trigger (self);
}
void SP_trigger_counter (edict_t *self)
{
self->wait = -1;
if (!self->count)
self->count = 2;
self->use = trigger_counter_use;
}
/*
==============================================================================
trigger_always
==============================================================================
*/
/*QUAKED trigger_always (.5 .5 .5) (-8 -8 -8) (8 8 8)
This trigger will always fire. It is activated by the world.
*/
void SP_trigger_always (edict_t *ent)
{
// we must have some delay to make sure our use targets are present
if (ent->delay < 0.2)
ent->delay = 0.2;
G_UseTargets(ent, ent);
}
/*
==============================================================================
trigger_push
==============================================================================
*/
#define PUSH_ONCE 1
static int windsound;
void trigger_push_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
{
if (strcmp(other->classname, "grenade") == 0)
{
VectorScale (self->movedir, self->speed * 10, other->velocity);
}
else if (other->health > 0)
{
VectorScale (self->movedir, self->speed * 10, other->velocity);
if (other->client)
{
// don't take falling damage immediately from this
VectorCopy (other->velocity, other->client->oldvelocity);
if (other->fly_sound_debounce_time < level.time)
{
other->fly_sound_debounce_time = level.time + 1.5;
gi.sound (other, CHAN_AUTO, windsound, 1, ATTN_NORM, 0);
}
}
}
if (self->spawnflags & PUSH_ONCE)
G_FreeEdict (self);
}
/*QUAKED trigger_push (.5 .5 .5) ? PUSH_ONCE
Pushes the player
"speed" defaults to 1000
*/
void SP_trigger_push (edict_t *self)
{
InitTrigger (self);
windsound = gi.soundindex ("misc/windfly.wav");
self->touch = trigger_push_touch;
if (!self->speed)
self->speed = 1000;
gi.linkentity (self);
}
/*
==============================================================================
trigger_hurt
==============================================================================
*/
/*QUAKED trigger_hurt (.5 .5 .5) ? START_OFF TOGGLE SILENT NO_PROTECTION SLOW
Any entity that touches this will be hurt.
It does dmg points of damage each server frame
SILENT supresses playing the sound
SLOW changes the damage rate to once per second
NO_PROTECTION *nothing* stops the damage
"dmg" default 5 (whole numbers only)
*/
void hurt_use (edict_t *self, edict_t *other, edict_t *activator)
{
if (self->solid == SOLID_NOT)
self->solid = SOLID_TRIGGER;
else
self->solid = SOLID_NOT;
gi.linkentity (self);
if (!(self->spawnflags & 2))
self->use = NULL;
}
void hurt_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
{
int dflags;
if (!other->takedamage)
return;
if (self->timestamp > level.time)
return;
if (self->spawnflags & 16)
self->timestamp = level.time + 1;
else
self->timestamp = level.time + FRAMETIME;
if (!(self->spawnflags & 4))
{
if ((level.framenum % 10) == 0)
gi.sound (other, CHAN_AUTO, self->noise_index, 1, ATTN_NORM, 0);
}
if (self->spawnflags & 8)
dflags = DAMAGE_NO_PROTECTION;
else
dflags = 0;
T_Damage (other, self, self, vec3_origin, other->s.origin, vec3_origin, self->dmg, self->dmg, dflags, MOD_TRIGGER_HURT);
}
void SP_trigger_hurt (edict_t *self)
{
InitTrigger (self);
self->noise_index = gi.soundindex ("world/electro.wav");
self->touch = hurt_touch;
if (!self->dmg)
self->dmg = 5;
if (self->spawnflags & 1)
self->solid = SOLID_NOT;
else
self->solid = SOLID_TRIGGER;
if (self->spawnflags & 2)
self->use = hurt_use;
gi.linkentity (self);
}
/*
==============================================================================
trigger_gravity
==============================================================================
*/
/*QUAKED trigger_gravity (.5 .5 .5) ?
Changes the touching entites gravity to
the value of "gravity". 1.0 is standard
gravity for the level.
*/
void trigger_gravity_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
{
other->gravity = self->gravity;
}
void SP_trigger_gravity (edict_t *self)
{
if (st.gravity == 0)
{
gi.dprintf("trigger_gravity without gravity set at %s\n", vtos(self->s.origin));
G_FreeEdict (self);
return;
}
InitTrigger (self);
self->gravity = atoi(st.gravity);
self->touch = trigger_gravity_touch;
}
/*
==============================================================================
trigger_monsterjump
==============================================================================
*/
/*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_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
{
if (other->flags & (FL_FLY | FL_SWIM) )
return;
if (other->svflags & SVF_DEADMONSTER)
return;
if ( !(other->svflags & SVF_MONSTER))
return;
// set XY even if not on ground, so the jump will clear lips
other->velocity[0] = self->movedir[0] * self->speed;
other->velocity[1] = self->movedir[1] * self->speed;
if (!other->groundentity)
return;
other->groundentity = NULL;
other->velocity[2] = self->movedir[2];
}
void SP_trigger_monsterjump (edict_t *self)
{
if (!self->speed)
self->speed = 200;
if (!st.height)
st.height = 200;
if (self->s.angles[YAW] == 0)
self->s.angles[YAW] = 360;
InitTrigger (self);
self->touch = trigger_monsterjump_touch;
self->movedir[2] = st.height;
}

432
game/g_turret.c Normal file
View File

@ -0,0 +1,432 @@
/*
Copyright (C) 1997-2001 Id Software, Inc.
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 the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
// g_turret.c
#include "g_local.h"
void AnglesNormalize(vec3_t vec)
{
while(vec[0] > 360)
vec[0] -= 360;
while(vec[0] < 0)
vec[0] += 360;
while(vec[1] > 360)
vec[1] -= 360;
while(vec[1] < 0)
vec[1] += 360;
}
float SnapToEights(float x)
{
x *= 8.0;
if (x > 0.0)
x += 0.5;
else
x -= 0.5;
return 0.125 * (int)x;
}
void turret_blocked(edict_t *self, edict_t *other)
{
edict_t *attacker;
if (other->takedamage)
{
if (self->teammaster->owner)
attacker = self->teammaster->owner;
else
attacker = self->teammaster;
T_Damage (other, self, attacker, vec3_origin, other->s.origin, vec3_origin, self->teammaster->dmg, 10, 0, MOD_CRUSH);
}
}
/*QUAKED turret_breach (0 0 0) ?
This portion of the turret can change both pitch and yaw.
The model should be made with a flat pitch.
It (and the associated base) need to be oriented towards 0.
Use "angle" to set the starting angle.
"speed" default 50
"dmg" default 10
"angle" point this forward
"target" point this at an info_notnull at the muzzle tip
"minpitch" min acceptable pitch angle : default -30
"maxpitch" max acceptable pitch angle : default 30
"minyaw" min acceptable yaw angle : default 0
"maxyaw" max acceptable yaw angle : default 360
*/
void turret_breach_fire (edict_t *self)
{
vec3_t f, r, u;
vec3_t start;
int damage;
int speed;
AngleVectors (self->s.angles, f, r, u);
VectorMA (self->s.origin, self->move_origin[0], f, start);
VectorMA (start, self->move_origin[1], r, start);
VectorMA (start, self->move_origin[2], u, start);
damage = 100 + random() * 50;
speed = 550 + 50 * skill->value;
fire_rocket (self->teammaster->owner, start, f, damage, speed, 150, damage);
gi.positioned_sound (start, self, CHAN_WEAPON, gi.soundindex("weapons/rocklf1a.wav"), 1, ATTN_NORM, 0);
}
void turret_breach_think (edict_t *self)
{
edict_t *ent;
vec3_t current_angles;
vec3_t delta;
VectorCopy (self->s.angles, current_angles);
AnglesNormalize(current_angles);
AnglesNormalize(self->move_angles);
if (self->move_angles[PITCH] > 180)
self->move_angles[PITCH] -= 360;
// clamp angles to mins & maxs
if (self->move_angles[PITCH] > self->pos1[PITCH])
self->move_angles[PITCH] = self->pos1[PITCH];
else if (self->move_angles[PITCH] < self->pos2[PITCH])
self->move_angles[PITCH] = self->pos2[PITCH];
if ((self->move_angles[YAW] < self->pos1[YAW]) || (self->move_angles[YAW] > self->pos2[YAW]))
{
float dmin, dmax;
dmin = fabs(self->pos1[YAW] - self->move_angles[YAW]);
if (dmin < -180)
dmin += 360;
else if (dmin > 180)
dmin -= 360;
dmax = fabs(self->pos2[YAW] - self->move_angles[YAW]);
if (dmax < -180)
dmax += 360;
else if (dmax > 180)
dmax -= 360;
if (fabs(dmin) < fabs(dmax))
self->move_angles[YAW] = self->pos1[YAW];
else
self->move_angles[YAW] = self->pos2[YAW];
}
VectorSubtract (self->move_angles, current_angles, delta);
if (delta[0] < -180)
delta[0] += 360;
else if (delta[0] > 180)
delta[0] -= 360;
if (delta[1] < -180)
delta[1] += 360;
else if (delta[1] > 180)
delta[1] -= 360;
delta[2] = 0;
if (delta[0] > self->speed * FRAMETIME)
delta[0] = self->speed * FRAMETIME;
if (delta[0] < -1 * self->speed * FRAMETIME)
delta[0] = -1 * self->speed * FRAMETIME;
if (delta[1] > self->speed * FRAMETIME)
delta[1] = self->speed * FRAMETIME;
if (delta[1] < -1 * self->speed * FRAMETIME)
delta[1] = -1 * self->speed * FRAMETIME;
VectorScale (delta, 1.0/FRAMETIME, self->avelocity);
self->nextthink = level.time + FRAMETIME;
for (ent = self->teammaster; ent; ent = ent->teamchain)
ent->avelocity[1] = self->avelocity[1];
// if we have adriver, adjust his velocities
if (self->owner)
{
float angle;
float target_z;
float diff;
vec3_t target;
vec3_t dir;
// angular is easy, just copy ours
self->owner->avelocity[0] = self->avelocity[0];
self->owner->avelocity[1] = self->avelocity[1];
// x & y
angle = self->s.angles[1] + self->owner->move_origin[1];
angle *= (M_PI*2 / 360);
target[0] = SnapToEights(self->s.origin[0] + cos(angle) * self->owner->move_origin[0]);
target[1] = SnapToEights(self->s.origin[1] + sin(angle) * self->owner->move_origin[0]);
target[2] = self->owner->s.origin[2];
VectorSubtract (target, self->owner->s.origin, dir);
self->owner->velocity[0] = dir[0] * 1.0 / FRAMETIME;
self->owner->velocity[1] = dir[1] * 1.0 / FRAMETIME;
// z
angle = self->s.angles[PITCH] * (M_PI*2 / 360);
target_z = SnapToEights(self->s.origin[2] + self->owner->move_origin[0] * tan(angle) + self->owner->move_origin[2]);
diff = target_z - self->owner->s.origin[2];
self->owner->velocity[2] = diff * 1.0 / FRAMETIME;
if (self->spawnflags & 65536)
{
turret_breach_fire (self);
self->spawnflags &= ~65536;
}
}
}
void turret_breach_finish_init (edict_t *self)
{
// get and save info for muzzle location
if (!self->target)
{
gi.dprintf("%s at %s needs a target\n", self->classname, vtos(self->s.origin));
}
else
{
self->target_ent = G_PickTarget (self->target);
VectorSubtract (self->target_ent->s.origin, self->s.origin, self->move_origin);
G_FreeEdict(self->target_ent);
}
self->teammaster->dmg = self->dmg;
self->think = turret_breach_think;
self->think (self);
}
void SP_turret_breach (edict_t *self)
{
self->solid = SOLID_BSP;
self->movetype = MOVETYPE_PUSH;
gi.setmodel (self, self->model);
if (!self->speed)
self->speed = 50;
if (!self->dmg)
self->dmg = 10;
if (!st.minpitch)
st.minpitch = -30;
if (!st.maxpitch)
st.maxpitch = 30;
if (!st.maxyaw)
st.maxyaw = 360;
self->pos1[PITCH] = -1 * st.minpitch;
self->pos1[YAW] = st.minyaw;
self->pos2[PITCH] = -1 * st.maxpitch;
self->pos2[YAW] = st.maxyaw;
self->ideal_yaw = self->s.angles[YAW];
self->move_angles[YAW] = self->ideal_yaw;
self->blocked = turret_blocked;
self->think = turret_breach_finish_init;
self->nextthink = level.time + FRAMETIME;
gi.linkentity (self);
}
/*QUAKED turret_base (0 0 0) ?
This portion of the turret changes yaw only.
MUST be teamed with a turret_breach.
*/
void SP_turret_base (edict_t *self)
{
self->solid = SOLID_BSP;
self->movetype = MOVETYPE_PUSH;
gi.setmodel (self, self->model);
self->blocked = turret_blocked;
gi.linkentity (self);
}
/*QUAKED turret_driver (1 .5 0) (-16 -16 -24) (16 16 32)
Must NOT be on the team with the rest of the turret parts.
Instead it must target the turret_breach.
*/
void infantry_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage);
void infantry_stand (edict_t *self);
void monster_use (edict_t *self, edict_t *other, edict_t *activator);
void turret_driver_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
{
edict_t *ent;
// level the gun
self->target_ent->move_angles[0] = 0;
// remove the driver from the end of them team chain
for (ent = self->target_ent->teammaster; ent->teamchain != self; ent = ent->teamchain)
;
ent->teamchain = NULL;
self->teammaster = NULL;
self->flags &= ~FL_TEAMSLAVE;
self->target_ent->owner = NULL;
self->target_ent->teammaster->owner = NULL;
infantry_die (self, inflictor, attacker, damage);
}
qboolean FindTarget (edict_t *self);
void turret_driver_think (edict_t *self)
{
vec3_t target;
vec3_t dir;
float reaction_time;
self->nextthink = level.time + FRAMETIME;
if (self->enemy && (!self->enemy->inuse || self->enemy->health <= 0))
self->enemy = NULL;
if (!self->enemy)
{
if (!FindTarget (self))
return;
self->monsterinfo.trail_time = level.time;
self->monsterinfo.aiflags &= ~AI_LOST_SIGHT;
}
else
{
if (visible (self, self->enemy))
{
if (self->monsterinfo.aiflags & AI_LOST_SIGHT)
{
self->monsterinfo.trail_time = level.time;
self->monsterinfo.aiflags &= ~AI_LOST_SIGHT;
}
}
else
{
self->monsterinfo.aiflags |= AI_LOST_SIGHT;
return;
}
}
// let the turret know where we want it to aim
VectorCopy (self->enemy->s.origin, target);
target[2] += self->enemy->viewheight;
VectorSubtract (target, self->target_ent->s.origin, dir);
vectoangles (dir, self->target_ent->move_angles);
// decide if we should shoot
if (level.time < self->monsterinfo.attack_finished)
return;
reaction_time = (3 - skill->value) * 1.0;
if ((level.time - self->monsterinfo.trail_time) < reaction_time)
return;
self->monsterinfo.attack_finished = level.time + reaction_time + 1.0;
//FIXME how do we really want to pass this along?
self->target_ent->spawnflags |= 65536;
}
void turret_driver_link (edict_t *self)
{
vec3_t vec;
edict_t *ent;
self->think = turret_driver_think;
self->nextthink = level.time + FRAMETIME;
self->target_ent = G_PickTarget (self->target);
self->target_ent->owner = self;
self->target_ent->teammaster->owner = self;
VectorCopy (self->target_ent->s.angles, self->s.angles);
vec[0] = self->target_ent->s.origin[0] - self->s.origin[0];
vec[1] = self->target_ent->s.origin[1] - self->s.origin[1];
vec[2] = 0;
self->move_origin[0] = VectorLength(vec);
VectorSubtract (self->s.origin, self->target_ent->s.origin, vec);
vectoangles (vec, vec);
AnglesNormalize(vec);
self->move_origin[1] = vec[1];
self->move_origin[2] = self->s.origin[2] - self->target_ent->s.origin[2];
// add the driver to the end of them team chain
for (ent = self->target_ent->teammaster; ent->teamchain; ent = ent->teamchain)
;
ent->teamchain = self;
self->teammaster = self->target_ent->teammaster;
self->flags |= FL_TEAMSLAVE;
}
void SP_turret_driver (edict_t *self)
{
if (deathmatch->value)
{
G_FreeEdict (self);
return;
}
self->movetype = MOVETYPE_PUSH;
self->solid = SOLID_BBOX;
self->s.modelindex = gi.modelindex("models/monsters/infantry/tris.md2");
VectorSet (self->mins, -16, -16, -24);
VectorSet (self->maxs, 16, 16, 32);
self->health = 100;
self->gib_health = 0;
self->mass = 200;
self->viewheight = 24;
self->die = turret_driver_die;
self->monsterinfo.stand = infantry_stand;
self->flags |= FL_NO_KNOCKBACK;
level.total_monsters++;
self->svflags |= SVF_MONSTER;
self->s.renderfx |= RF_FRAMELERP;
self->takedamage = DAMAGE_AIM;
self->use = monster_use;
self->clipmask = MASK_MONSTERSOLID;
VectorCopy (self->s.origin, self->s.old_origin);
self->monsterinfo.aiflags |= AI_STAND_GROUND|AI_DUCKED;
if (st.item)
{
self->item = FindItemByClassname (st.item);
if (!self->item)
gi.dprintf("%s at %s has bad item: %s\n", self->classname, vtos(self->s.origin), st.item);
}
self->think = turret_driver_link;
self->nextthink = level.time + FRAMETIME;
gi.linkentity (self);
}

568
game/g_utils.c Normal file
View File

@ -0,0 +1,568 @@
/*
Copyright (C) 1997-2001 Id Software, Inc.
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 the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
// g_utils.c -- misc utility functions for game module
#include "g_local.h"
void G_ProjectSource (vec3_t point, vec3_t distance, vec3_t forward, vec3_t right, vec3_t result)
{
result[0] = point[0] + forward[0] * distance[0] + right[0] * distance[1];
result[1] = point[1] + forward[1] * distance[0] + right[1] * distance[1];
result[2] = point[2] + forward[2] * distance[0] + right[2] * distance[1] + distance[2];
}
/*
=============
G_Find
Searches all active entities for the next one that holds
the matching string at fieldofs (use the FOFS() macro) in the structure.
Searches beginning at the edict after from, or the beginning if NULL
NULL will be returned if the end of the list is reached.
=============
*/
edict_t *G_Find (edict_t *from, int fieldofs, char *match)
{
char *s;
if (!from)
from = g_edicts;
else
from++;
for ( ; from < &g_edicts[globals.num_edicts] ; from++)
{
if (!from->inuse)
continue;
s = *(char **) ((byte *)from + fieldofs);
if (!s)
continue;
if (!Q_stricmp (s, match))
return from;
}
return NULL;
}
/*
=================
findradius
Returns entities that have origins within a spherical area
findradius (origin, radius)
=================
*/
edict_t *findradius (edict_t *from, vec3_t org, float rad)
{
vec3_t eorg;
int j;
if (!from)
from = g_edicts;
else
from++;
for ( ; from < &g_edicts[globals.num_edicts]; from++)
{
if (!from->inuse)
continue;
if (from->solid == SOLID_NOT)
continue;
for (j=0 ; j<3 ; j++)
eorg[j] = org[j] - (from->s.origin[j] + (from->mins[j] + from->maxs[j])*0.5);
if (VectorLength(eorg) > rad)
continue;
return from;
}
return NULL;
}
/*
=============
G_PickTarget
Searches all active entities for the next one that holds
the matching string at fieldofs (use the FOFS() macro) in the structure.
Searches beginning at the edict after from, or the beginning if NULL
NULL will be returned if the end of the list is reached.
=============
*/
#define MAXCHOICES 8
edict_t *G_PickTarget (char *targetname)
{
edict_t *ent = NULL;
int num_choices = 0;
edict_t *choice[MAXCHOICES];
if (!targetname)
{
gi.dprintf("G_PickTarget called with NULL targetname\n");
return NULL;
}
while(1)
{
ent = G_Find (ent, FOFS(targetname), targetname);
if (!ent)
break;
choice[num_choices++] = ent;
if (num_choices == MAXCHOICES)
break;
}
if (!num_choices)
{
gi.dprintf("G_PickTarget: target %s not found\n", targetname);
return NULL;
}
return choice[rand() % num_choices];
}
void Think_Delay (edict_t *ent)
{
G_UseTargets (ent, ent->activator);
G_FreeEdict (ent);
}
/*
==============================
G_UseTargets
the global "activator" should be set to the entity that initiated the firing.
If self.delay is set, a DelayedUse entity will be created that will actually
do the SUB_UseTargets after that many seconds have passed.
Centerprints any self.message to the activator.
Search for (string)targetname in all entities that
match (string)self.target and call their .use function
==============================
*/
void G_UseTargets (edict_t *ent, edict_t *activator)
{
edict_t *t;
//
// check for a delay
//
if (ent->delay)
{
// create a temp object to fire at a later time
t = G_Spawn();
t->classname = "DelayedUse";
t->nextthink = level.time + ent->delay;
t->think = Think_Delay;
t->activator = activator;
if (!activator)
gi.dprintf ("Think_Delay with no activator\n");
t->message = ent->message;
t->target = ent->target;
t->killtarget = ent->killtarget;
return;
}
//
// print the message
//
if ((ent->message) && !(activator->svflags & SVF_MONSTER))
{
gi.centerprintf (activator, "%s", ent->message);
if (ent->noise_index)
gi.sound (activator, CHAN_AUTO, ent->noise_index, 1, ATTN_NORM, 0);
else
gi.sound (activator, CHAN_AUTO, gi.soundindex ("misc/talk1.wav"), 1, ATTN_NORM, 0);
}
//
// kill killtargets
//
if (ent->killtarget)
{
t = NULL;
while ((t = G_Find (t, FOFS(targetname), ent->killtarget)))
{
G_FreeEdict (t);
if (!ent->inuse)
{
gi.dprintf("entity was removed while using killtargets\n");
return;
}
}
}
//
// fire targets
//
if (ent->target)
{
t = NULL;
while ((t = G_Find (t, FOFS(targetname), ent->target)))
{
// doors fire area portals in a specific way
if (!Q_stricmp(t->classname, "func_areaportal") &&
(!Q_stricmp(ent->classname, "func_door") || !Q_stricmp(ent->classname, "func_door_rotating")))
continue;
if (t == ent)
{
gi.dprintf ("WARNING: Entity used itself.\n");
}
else
{
if (t->use)
t->use (t, ent, activator);
}
if (!ent->inuse)
{
gi.dprintf("entity was removed while using targets\n");
return;
}
}
}
}
/*
=============
TempVector
This is just a convenience function
for making temporary vectors for function calls
=============
*/
float *tv (float x, float y, float z)
{
static int index;
static vec3_t vecs[8];
float *v;
// use an array so that multiple tempvectors won't collide
// for a while
v = vecs[index];
index = (index + 1)&7;
v[0] = x;
v[1] = y;
v[2] = z;
return v;
}
/*
=============
VectorToString
This is just a convenience function
for printing vectors
=============
*/
char *vtos (vec3_t v)
{
static int index;
static char str[8][32];
char *s;
// use an array so that multiple vtos won't collide
s = str[index];
index = (index + 1)&7;
Com_sprintf (s, 32, "(%i %i %i)", (int)v[0], (int)v[1], (int)v[2]);
return s;
}
vec3_t VEC_UP = {0, -1, 0};
vec3_t MOVEDIR_UP = {0, 0, 1};
vec3_t VEC_DOWN = {0, -2, 0};
vec3_t MOVEDIR_DOWN = {0, 0, -1};
void G_SetMovedir (vec3_t angles, vec3_t movedir)
{
if (VectorCompare (angles, VEC_UP))
{
VectorCopy (MOVEDIR_UP, movedir);
}
else if (VectorCompare (angles, VEC_DOWN))
{
VectorCopy (MOVEDIR_DOWN, movedir);
}
else
{
AngleVectors (angles, movedir, NULL, NULL);
}
VectorClear (angles);
}
float vectoyaw (vec3_t vec)
{
float yaw;
if (/*vec[YAW] == 0 &&*/ vec[PITCH] == 0)
{
yaw = 0;
if (vec[YAW] > 0)
yaw = 90;
else if (vec[YAW] < 0)
yaw = -90;
}
else
{
yaw = (int) (atan2(vec[YAW], vec[PITCH]) * 180 / M_PI);
if (yaw < 0)
yaw += 360;
}
return yaw;
}
void vectoangles (vec3_t value1, vec3_t angles)
{
float forward;
float yaw, pitch;
if (value1[1] == 0 && value1[0] == 0)
{
yaw = 0;
if (value1[2] > 0)
pitch = 90;
else
pitch = 270;
}
else
{
if (value1[0])
yaw = (int) (atan2(value1[1], value1[0]) * 180 / M_PI);
else if (value1[1] > 0)
yaw = 90;
else
yaw = -90;
if (yaw < 0)
yaw += 360;
forward = sqrt (value1[0]*value1[0] + value1[1]*value1[1]);
pitch = (int) (atan2(value1[2], forward) * 180 / M_PI);
if (pitch < 0)
pitch += 360;
}
angles[PITCH] = -pitch;
angles[YAW] = yaw;
angles[ROLL] = 0;
}
char *G_CopyString (char *in)
{
char *out;
out = gi.TagMalloc (strlen(in)+1, TAG_LEVEL);
strcpy (out, in);
return out;
}
void G_InitEdict (edict_t *e)
{
e->inuse = true;
e->classname = "noclass";
e->gravity = 1.0;
e->s.number = e - g_edicts;
}
/*
=================
G_Spawn
Either finds a free edict, or allocates a new one.
Try to avoid reusing an entity that was recently freed, because it
can cause the client to think the entity morphed into something else
instead of being removed and recreated, which can cause interpolated
angles and bad trails.
=================
*/
edict_t *G_Spawn (void)
{
int i;
edict_t *e;
e = &g_edicts[(int)maxclients->value+1];
for ( i=maxclients->value+1 ; i<globals.num_edicts ; i++, e++)
{
// the first couple seconds of server time can involve a lot of
// freeing and allocating, so relax the replacement policy
if (!e->inuse && ( e->freetime < 2 || level.time - e->freetime > 0.5 ) )
{
G_InitEdict (e);
return e;
}
}
if (i == game.maxentities)
gi.error ("ED_Alloc: no free edicts");
globals.num_edicts++;
G_InitEdict (e);
return e;
}
/*
=================
G_FreeEdict
Marks the edict as free
=================
*/
void G_FreeEdict (edict_t *ed)
{
gi.unlinkentity (ed); // unlink from world
if ((ed - g_edicts) <= (maxclients->value + BODY_QUEUE_SIZE))
{
// gi.dprintf("tried to free special edict\n");
return;
}
memset (ed, 0, sizeof(*ed));
ed->classname = "freed";
ed->freetime = level.time;
ed->inuse = false;
}
/*
============
G_TouchTriggers
============
*/
void G_TouchTriggers (edict_t *ent)
{
int i, num;
edict_t *touch[MAX_EDICTS], *hit;
// dead things don't activate triggers!
if ((ent->client || (ent->svflags & SVF_MONSTER)) && (ent->health <= 0))
return;
num = gi.BoxEdicts (ent->absmin, ent->absmax, touch
, MAX_EDICTS, AREA_TRIGGERS);
// be careful, it is possible to have an entity in this
// list removed before we get to it (killtriggered)
for (i=0 ; i<num ; i++)
{
hit = touch[i];
if (!hit->inuse)
continue;
if (!hit->touch)
continue;
hit->touch (hit, ent, NULL, NULL);
}
}
/*
============
G_TouchSolids
Call after linking a new trigger in during gameplay
to force all entities it covers to immediately touch it
============
*/
void G_TouchSolids (edict_t *ent)
{
int i, num;
edict_t *touch[MAX_EDICTS], *hit;
num = gi.BoxEdicts (ent->absmin, ent->absmax, touch
, MAX_EDICTS, AREA_SOLID);
// be careful, it is possible to have an entity in this
// list removed before we get to it (killtriggered)
for (i=0 ; i<num ; i++)
{
hit = touch[i];
if (!hit->inuse)
continue;
if (ent->touch)
ent->touch (hit, ent, NULL, NULL);
if (!ent->inuse)
break;
}
}
/*
==============================================================================
Kill box
==============================================================================
*/
/*
=================
KillBox
Kills all entities that would touch the proposed new positioning
of ent. Ent should be unlinked before calling this!
=================
*/
qboolean KillBox (edict_t *ent)
{
trace_t tr;
while (1)
{
tr = gi.trace (ent->s.origin, ent->mins, ent->maxs, ent->s.origin, NULL, MASK_PLAYERSOLID);
if (!tr.ent)
break;
// nail it
T_Damage (tr.ent, ent, ent, vec3_origin, ent->s.origin, vec3_origin, 100000, 0, DAMAGE_NO_PROTECTION, MOD_TELEFRAG);
// if we didn't kill it, fail
if (tr.ent->solid)
return false;
}
return true; // all clear
}

916
game/g_weapon.c Normal file
View File

@ -0,0 +1,916 @@
/*
Copyright (C) 1997-2001 Id Software, Inc.
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 the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "g_local.h"
/*
=================
check_dodge
This is a support routine used when a client is firing
a non-instant attack weapon. It checks to see if a
monster's dodge function should be called.
=================
*/
static void check_dodge (edict_t *self, vec3_t start, vec3_t dir, int speed)
{
vec3_t end;
vec3_t v;
trace_t tr;
float eta;
// easy mode only ducks one quarter the time
if (skill->value == 0)
{
if (random() > 0.25)
return;
}
VectorMA (start, 8192, dir, end);
tr = gi.trace (start, NULL, NULL, end, self, MASK_SHOT);
if ((tr.ent) && (tr.ent->svflags & SVF_MONSTER) && (tr.ent->health > 0) && (tr.ent->monsterinfo.dodge) && infront(tr.ent, self))
{
VectorSubtract (tr.endpos, start, v);
eta = (VectorLength(v) - tr.ent->maxs[0]) / speed;
tr.ent->monsterinfo.dodge (tr.ent, self, eta);
}
}
/*
=================
fire_hit
Used for all impact (hit/punch/slash) attacks
=================
*/
qboolean fire_hit (edict_t *self, vec3_t aim, int damage, int kick)
{
trace_t tr;
vec3_t forward, right, up;
vec3_t v;
vec3_t point;
float range;
vec3_t dir;
//see if enemy is in range
VectorSubtract (self->enemy->s.origin, self->s.origin, dir);
range = VectorLength(dir);
if (range > aim[0])
return false;
if (aim[1] > self->mins[0] && aim[1] < self->maxs[0])
{
// the hit is straight on so back the range up to the edge of their bbox
range -= self->enemy->maxs[0];
}
else
{
// this is a side hit so adjust the "right" value out to the edge of their bbox
if (aim[1] < 0)
aim[1] = self->enemy->mins[0];
else
aim[1] = self->enemy->maxs[0];
}
VectorMA (self->s.origin, range, dir, point);
tr = gi.trace (self->s.origin, NULL, NULL, point, self, MASK_SHOT);
if (tr.fraction < 1)
{
if (!tr.ent->takedamage)
return false;
// if it will hit any client/monster then hit the one we wanted to hit
if ((tr.ent->svflags & SVF_MONSTER) || (tr.ent->client))
tr.ent = self->enemy;
}
AngleVectors(self->s.angles, forward, right, up);
VectorMA (self->s.origin, range, forward, point);
VectorMA (point, aim[1], right, point);
VectorMA (point, aim[2], up, point);
VectorSubtract (point, self->enemy->s.origin, dir);
// do the damage
T_Damage (tr.ent, self, self, dir, point, vec3_origin, damage, kick/2, DAMAGE_NO_KNOCKBACK, MOD_HIT);
if (!(tr.ent->svflags & SVF_MONSTER) && (!tr.ent->client))
return false;
// do our special form of knockback here
VectorMA (self->enemy->absmin, 0.5, self->enemy->size, v);
VectorSubtract (v, point, v);
VectorNormalize (v);
VectorMA (self->enemy->velocity, kick, v, self->enemy->velocity);
if (self->enemy->velocity[2] > 0)
self->enemy->groundentity = NULL;
return true;
}
/*
=================
fire_lead
This is an internal support routine used for bullet/pellet based weapons.
=================
*/
static void fire_lead (edict_t *self, vec3_t start, vec3_t aimdir, int damage, int kick, int te_impact, int hspread, int vspread, int mod)
{
trace_t tr;
vec3_t dir;
vec3_t forward, right, up;
vec3_t end;
float r;
float u;
vec3_t water_start;
qboolean water = false;
int content_mask = MASK_SHOT | MASK_WATER;
tr = gi.trace (self->s.origin, NULL, NULL, start, self, MASK_SHOT);
if (!(tr.fraction < 1.0))
{
vectoangles (aimdir, dir);
AngleVectors (dir, forward, right, up);
r = crandom()*hspread;
u = crandom()*vspread;
VectorMA (start, 8192, forward, end);
VectorMA (end, r, right, end);
VectorMA (end, u, up, end);
if (gi.pointcontents (start) & MASK_WATER)
{
water = true;
VectorCopy (start, water_start);
content_mask &= ~MASK_WATER;
}
tr = gi.trace (start, NULL, NULL, end, self, content_mask);
// see if we hit water
if (tr.contents & MASK_WATER)
{
int color;
water = true;
VectorCopy (tr.endpos, water_start);
if (!VectorCompare (start, tr.endpos))
{
if (tr.contents & CONTENTS_WATER)
{
if (strcmp(tr.surface->name, "*brwater") == 0)
color = SPLASH_BROWN_WATER;
else
color = SPLASH_BLUE_WATER;
}
else if (tr.contents & CONTENTS_SLIME)
color = SPLASH_SLIME;
else if (tr.contents & CONTENTS_LAVA)
color = SPLASH_LAVA;
else
color = SPLASH_UNKNOWN;
if (color != SPLASH_UNKNOWN)
{
gi.WriteByte (svc_temp_entity);
gi.WriteByte (TE_SPLASH);
gi.WriteByte (8);
gi.WritePosition (tr.endpos);
gi.WriteDir (tr.plane.normal);
gi.WriteByte (color);
gi.multicast (tr.endpos, MULTICAST_PVS);
}
// change bullet's course when it enters water
VectorSubtract (end, start, dir);
vectoangles (dir, dir);
AngleVectors (dir, forward, right, up);
r = crandom()*hspread*2;
u = crandom()*vspread*2;
VectorMA (water_start, 8192, forward, end);
VectorMA (end, r, right, end);
VectorMA (end, u, up, end);
}
// re-trace ignoring water this time
tr = gi.trace (water_start, NULL, NULL, end, self, MASK_SHOT);
}
}
// send gun puff / flash
if (!((tr.surface) && (tr.surface->flags & SURF_SKY)))
{
if (tr.fraction < 1.0)
{
if (tr.ent->takedamage)
{
T_Damage (tr.ent, self, self, aimdir, tr.endpos, tr.plane.normal, damage, kick, DAMAGE_BULLET, mod);
}
else
{
if (strncmp (tr.surface->name, "sky", 3) != 0)
{
gi.WriteByte (svc_temp_entity);
gi.WriteByte (te_impact);
gi.WritePosition (tr.endpos);
gi.WriteDir (tr.plane.normal);
gi.multicast (tr.endpos, MULTICAST_PVS);
if (self->client)
PlayerNoise(self, tr.endpos, PNOISE_IMPACT);
}
}
}
}
// if went through water, determine where the end and make a bubble trail
if (water)
{
vec3_t pos;
VectorSubtract (tr.endpos, water_start, dir);
VectorNormalize (dir);
VectorMA (tr.endpos, -2, dir, pos);
if (gi.pointcontents (pos) & MASK_WATER)
VectorCopy (pos, tr.endpos);
else
tr = gi.trace (pos, NULL, NULL, water_start, tr.ent, MASK_WATER);
VectorAdd (water_start, tr.endpos, pos);
VectorScale (pos, 0.5, pos);
gi.WriteByte (svc_temp_entity);
gi.WriteByte (TE_BUBBLETRAIL);
gi.WritePosition (water_start);
gi.WritePosition (tr.endpos);
gi.multicast (pos, MULTICAST_PVS);
}
}
/*
=================
fire_bullet
Fires a single round. Used for machinegun and chaingun. Would be fine for
pistols, rifles, etc....
=================
*/
void fire_bullet (edict_t *self, vec3_t start, vec3_t aimdir, int damage, int kick, int hspread, int vspread, int mod)
{
fire_lead (self, start, aimdir, damage, kick, TE_GUNSHOT, hspread, vspread, mod);
}
/*
=================
fire_shotgun
Shoots shotgun pellets. Used by shotgun and super shotgun.
=================
*/
void fire_shotgun (edict_t *self, vec3_t start, vec3_t aimdir, int damage, int kick, int hspread, int vspread, int count, int mod)
{
int i;
for (i = 0; i < count; i++)
fire_lead (self, start, aimdir, damage, kick, TE_SHOTGUN, hspread, vspread, mod);
}
/*
=================
fire_blaster
Fires a single blaster bolt. Used by the blaster and hyper blaster.
=================
*/
void blaster_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
{
int mod;
if (other == self->owner)
return;
if (surf && (surf->flags & SURF_SKY))
{
G_FreeEdict (self);
return;
}
if (self->owner->client)
PlayerNoise(self->owner, self->s.origin, PNOISE_IMPACT);
if (other->takedamage)
{
if (self->spawnflags & 1)
mod = MOD_HYPERBLASTER;
else
mod = MOD_BLASTER;
T_Damage (other, self, self->owner, self->velocity, self->s.origin, plane->normal, self->dmg, 1, DAMAGE_ENERGY, mod);
}
else
{
gi.WriteByte (svc_temp_entity);
gi.WriteByte (TE_BLASTER);
gi.WritePosition (self->s.origin);
if (!plane)
gi.WriteDir (vec3_origin);
else
gi.WriteDir (plane->normal);
gi.multicast (self->s.origin, MULTICAST_PVS);
}
G_FreeEdict (self);
}
void fire_blaster (edict_t *self, vec3_t start, vec3_t dir, int damage, int speed, int effect, qboolean hyper)
{
edict_t *bolt;
trace_t tr;
VectorNormalize (dir);
bolt = G_Spawn();
bolt->svflags = SVF_DEADMONSTER;
// yes, I know it looks weird that projectiles are deadmonsters
// what this means is that when prediction is used against the object
// (blaster/hyperblaster shots), the player won't be solid clipped against
// the object. Right now trying to run into a firing hyperblaster
// is very jerky since you are predicted 'against' the shots.
VectorCopy (start, bolt->s.origin);
VectorCopy (start, bolt->s.old_origin);
vectoangles (dir, bolt->s.angles);
VectorScale (dir, speed, bolt->velocity);
bolt->movetype = MOVETYPE_FLYMISSILE;
bolt->clipmask = MASK_SHOT;
bolt->solid = SOLID_BBOX;
bolt->s.effects |= effect;
VectorClear (bolt->mins);
VectorClear (bolt->maxs);
bolt->s.modelindex = gi.modelindex ("models/objects/laser/tris.md2");
bolt->s.sound = gi.soundindex ("misc/lasfly.wav");
bolt->owner = self;
bolt->touch = blaster_touch;
bolt->nextthink = level.time + 2;
bolt->think = G_FreeEdict;
bolt->dmg = damage;
bolt->classname = "bolt";
if (hyper)
bolt->spawnflags = 1;
gi.linkentity (bolt);
if (self->client)
check_dodge (self, bolt->s.origin, dir, speed);
tr = gi.trace (self->s.origin, NULL, NULL, bolt->s.origin, bolt, MASK_SHOT);
if (tr.fraction < 1.0)
{
VectorMA (bolt->s.origin, -10, dir, bolt->s.origin);
bolt->touch (bolt, tr.ent, NULL, NULL);
}
}
/*
=================
fire_grenade
=================
*/
static void Grenade_Explode (edict_t *ent)
{
vec3_t origin;
int mod;
if (ent->owner->client)
PlayerNoise(ent->owner, ent->s.origin, PNOISE_IMPACT);
//FIXME: if we are onground then raise our Z just a bit since we are a point?
if (ent->enemy)
{
float points;
vec3_t v;
vec3_t dir;
VectorAdd (ent->enemy->mins, ent->enemy->maxs, v);
VectorMA (ent->enemy->s.origin, 0.5, v, v);
VectorSubtract (ent->s.origin, v, v);
points = ent->dmg - 0.5 * VectorLength (v);
VectorSubtract (ent->enemy->s.origin, ent->s.origin, dir);
if (ent->spawnflags & 1)
mod = MOD_HANDGRENADE;
else
mod = MOD_GRENADE;
T_Damage (ent->enemy, ent, ent->owner, dir, ent->s.origin, vec3_origin, (int)points, (int)points, DAMAGE_RADIUS, mod);
}
if (ent->spawnflags & 2)
mod = MOD_HELD_GRENADE;
else if (ent->spawnflags & 1)
mod = MOD_HG_SPLASH;
else
mod = MOD_G_SPLASH;
T_RadiusDamage(ent, ent->owner, ent->dmg, ent->enemy, ent->dmg_radius, mod);
VectorMA (ent->s.origin, -0.02, ent->velocity, origin);
gi.WriteByte (svc_temp_entity);
if (ent->waterlevel)
{
if (ent->groundentity)
gi.WriteByte (TE_GRENADE_EXPLOSION_WATER);
else
gi.WriteByte (TE_ROCKET_EXPLOSION_WATER);
}
else
{
if (ent->groundentity)
gi.WriteByte (TE_GRENADE_EXPLOSION);
else
gi.WriteByte (TE_ROCKET_EXPLOSION);
}
gi.WritePosition (origin);
gi.multicast (ent->s.origin, MULTICAST_PHS);
G_FreeEdict (ent);
}
static void Grenade_Touch (edict_t *ent, edict_t *other, cplane_t *plane, csurface_t *surf)
{
if (other == ent->owner)
return;
if (surf && (surf->flags & SURF_SKY))
{
G_FreeEdict (ent);
return;
}
if (!other->takedamage)
{
if (ent->spawnflags & 1)
{
if (random() > 0.5)
gi.sound (ent, CHAN_VOICE, gi.soundindex ("weapons/hgrenb1a.wav"), 1, ATTN_NORM, 0);
else
gi.sound (ent, CHAN_VOICE, gi.soundindex ("weapons/hgrenb2a.wav"), 1, ATTN_NORM, 0);
}
else
{
gi.sound (ent, CHAN_VOICE, gi.soundindex ("weapons/grenlb1b.wav"), 1, ATTN_NORM, 0);
}
return;
}
ent->enemy = other;
Grenade_Explode (ent);
}
void fire_grenade (edict_t *self, vec3_t start, vec3_t aimdir, int damage, int speed, float timer, float damage_radius)
{
edict_t *grenade;
vec3_t dir;
vec3_t forward, right, up;
vectoangles (aimdir, dir);
AngleVectors (dir, forward, right, up);
grenade = G_Spawn();
VectorCopy (start, grenade->s.origin);
VectorScale (aimdir, speed, grenade->velocity);
VectorMA (grenade->velocity, 200 + crandom() * 10.0, up, grenade->velocity);
VectorMA (grenade->velocity, crandom() * 10.0, right, grenade->velocity);
VectorSet (grenade->avelocity, 300, 300, 300);
grenade->movetype = MOVETYPE_BOUNCE;
grenade->clipmask = MASK_SHOT;
grenade->solid = SOLID_BBOX;
grenade->s.effects |= EF_GRENADE;
VectorClear (grenade->mins);
VectorClear (grenade->maxs);
grenade->s.modelindex = gi.modelindex ("models/objects/grenade/tris.md2");
grenade->owner = self;
grenade->touch = Grenade_Touch;
grenade->nextthink = level.time + timer;
grenade->think = Grenade_Explode;
grenade->dmg = damage;
grenade->dmg_radius = damage_radius;
grenade->classname = "grenade";
gi.linkentity (grenade);
}
void fire_grenade2 (edict_t *self, vec3_t start, vec3_t aimdir, int damage, int speed, float timer, float damage_radius, qboolean held)
{
edict_t *grenade;
vec3_t dir;
vec3_t forward, right, up;
vectoangles (aimdir, dir);
AngleVectors (dir, forward, right, up);
grenade = G_Spawn();
VectorCopy (start, grenade->s.origin);
VectorScale (aimdir, speed, grenade->velocity);
VectorMA (grenade->velocity, 200 + crandom() * 10.0, up, grenade->velocity);
VectorMA (grenade->velocity, crandom() * 10.0, right, grenade->velocity);
VectorSet (grenade->avelocity, 300, 300, 300);
grenade->movetype = MOVETYPE_BOUNCE;
grenade->clipmask = MASK_SHOT;
grenade->solid = SOLID_BBOX;
grenade->s.effects |= EF_GRENADE;
VectorClear (grenade->mins);
VectorClear (grenade->maxs);
grenade->s.modelindex = gi.modelindex ("models/objects/grenade2/tris.md2");
grenade->owner = self;
grenade->touch = Grenade_Touch;
grenade->nextthink = level.time + timer;
grenade->think = Grenade_Explode;
grenade->dmg = damage;
grenade->dmg_radius = damage_radius;
grenade->classname = "hgrenade";
if (held)
grenade->spawnflags = 3;
else
grenade->spawnflags = 1;
grenade->s.sound = gi.soundindex("weapons/hgrenc1b.wav");
if (timer <= 0.0)
Grenade_Explode (grenade);
else
{
gi.sound (self, CHAN_WEAPON, gi.soundindex ("weapons/hgrent1a.wav"), 1, ATTN_NORM, 0);
gi.linkentity (grenade);
}
}
/*
=================
fire_rocket
=================
*/
void rocket_touch (edict_t *ent, edict_t *other, cplane_t *plane, csurface_t *surf)
{
vec3_t origin;
int n;
if (other == ent->owner)
return;
if (surf && (surf->flags & SURF_SKY))
{
G_FreeEdict (ent);
return;
}
if (ent->owner->client)
PlayerNoise(ent->owner, ent->s.origin, PNOISE_IMPACT);
// calculate position for the explosion entity
VectorMA (ent->s.origin, -0.02, ent->velocity, origin);
if (other->takedamage)
{
T_Damage (other, ent, ent->owner, ent->velocity, ent->s.origin, plane->normal, ent->dmg, 0, 0, MOD_ROCKET);
}
else
{
// don't throw any debris in net games
if (!deathmatch->value && !coop->value)
{
if ((surf) && !(surf->flags & (SURF_WARP|SURF_TRANS33|SURF_TRANS66|SURF_FLOWING)))
{
n = rand() % 5;
while(n--)
ThrowDebris (ent, "models/objects/debris2/tris.md2", 2, ent->s.origin);
}
}
}
T_RadiusDamage(ent, ent->owner, ent->radius_dmg, other, ent->dmg_radius, MOD_R_SPLASH);
gi.WriteByte (svc_temp_entity);
if (ent->waterlevel)
gi.WriteByte (TE_ROCKET_EXPLOSION_WATER);
else
gi.WriteByte (TE_ROCKET_EXPLOSION);
gi.WritePosition (origin);
gi.multicast (ent->s.origin, MULTICAST_PHS);
G_FreeEdict (ent);
}
void fire_rocket (edict_t *self, vec3_t start, vec3_t dir, int damage, int speed, float damage_radius, int radius_damage)
{
edict_t *rocket;
rocket = G_Spawn();
VectorCopy (start, rocket->s.origin);
VectorCopy (dir, rocket->movedir);
vectoangles (dir, rocket->s.angles);
VectorScale (dir, speed, rocket->velocity);
rocket->movetype = MOVETYPE_FLYMISSILE;
rocket->clipmask = MASK_SHOT;
rocket->solid = SOLID_BBOX;
rocket->s.effects |= EF_ROCKET;
VectorClear (rocket->mins);
VectorClear (rocket->maxs);
rocket->s.modelindex = gi.modelindex ("models/objects/rocket/tris.md2");
rocket->owner = self;
rocket->touch = rocket_touch;
rocket->nextthink = level.time + 8000/speed;
rocket->think = G_FreeEdict;
rocket->dmg = damage;
rocket->radius_dmg = radius_damage;
rocket->dmg_radius = damage_radius;
rocket->s.sound = gi.soundindex ("weapons/rockfly.wav");
rocket->classname = "rocket";
if (self->client)
check_dodge (self, rocket->s.origin, dir, speed);
gi.linkentity (rocket);
}
/*
=================
fire_rail
=================
*/
void fire_rail (edict_t *self, vec3_t start, vec3_t aimdir, int damage, int kick)
{
vec3_t from;
vec3_t end;
trace_t tr;
edict_t *ignore;
int mask;
qboolean water;
VectorMA (start, 8192, aimdir, end);
VectorCopy (start, from);
ignore = self;
water = false;
mask = MASK_SHOT|CONTENTS_SLIME|CONTENTS_LAVA;
while (ignore)
{
tr = gi.trace (from, NULL, NULL, end, ignore, mask);
if (tr.contents & (CONTENTS_SLIME|CONTENTS_LAVA))
{
mask &= ~(CONTENTS_SLIME|CONTENTS_LAVA);
water = true;
}
else
{
if ((tr.ent->svflags & SVF_MONSTER) || (tr.ent->client))
ignore = tr.ent;
else
ignore = NULL;
if ((tr.ent != self) && (tr.ent->takedamage))
T_Damage (tr.ent, self, self, aimdir, tr.endpos, tr.plane.normal, damage, kick, 0, MOD_RAILGUN);
}
VectorCopy (tr.endpos, from);
}
// send gun puff / flash
gi.WriteByte (svc_temp_entity);
gi.WriteByte (TE_RAILTRAIL);
gi.WritePosition (start);
gi.WritePosition (tr.endpos);
gi.multicast (self->s.origin, MULTICAST_PHS);
// gi.multicast (start, MULTICAST_PHS);
if (water)
{
gi.WriteByte (svc_temp_entity);
gi.WriteByte (TE_RAILTRAIL);
gi.WritePosition (start);
gi.WritePosition (tr.endpos);
gi.multicast (tr.endpos, MULTICAST_PHS);
}
if (self->client)
PlayerNoise(self, tr.endpos, PNOISE_IMPACT);
}
/*
=================
fire_bfg
=================
*/
void bfg_explode (edict_t *self)
{
edict_t *ent;
float points;
vec3_t v;
float dist;
if (self->s.frame == 0)
{
// the BFG effect
ent = NULL;
while ((ent = findradius(ent, self->s.origin, self->dmg_radius)) != NULL)
{
if (!ent->takedamage)
continue;
if (ent == self->owner)
continue;
if (!CanDamage (ent, self))
continue;
if (!CanDamage (ent, self->owner))
continue;
VectorAdd (ent->mins, ent->maxs, v);
VectorMA (ent->s.origin, 0.5, v, v);
VectorSubtract (self->s.origin, v, v);
dist = VectorLength(v);
points = self->radius_dmg * (1.0 - sqrt(dist/self->dmg_radius));
if (ent == self->owner)
points = points * 0.5;
gi.WriteByte (svc_temp_entity);
gi.WriteByte (TE_BFG_EXPLOSION);
gi.WritePosition (ent->s.origin);
gi.multicast (ent->s.origin, MULTICAST_PHS);
T_Damage (ent, self, self->owner, self->velocity, ent->s.origin, vec3_origin, (int)points, 0, DAMAGE_ENERGY, MOD_BFG_EFFECT);
}
}
self->nextthink = level.time + FRAMETIME;
self->s.frame++;
if (self->s.frame == 5)
self->think = G_FreeEdict;
}
void bfg_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
{
if (other == self->owner)
return;
if (surf && (surf->flags & SURF_SKY))
{
G_FreeEdict (self);
return;
}
if (self->owner->client)
PlayerNoise(self->owner, self->s.origin, PNOISE_IMPACT);
// core explosion - prevents firing it into the wall/floor
if (other->takedamage)
T_Damage (other, self, self->owner, self->velocity, self->s.origin, plane->normal, 200, 0, 0, MOD_BFG_BLAST);
T_RadiusDamage(self, self->owner, 200, other, 100, MOD_BFG_BLAST);
gi.sound (self, CHAN_VOICE, gi.soundindex ("weapons/bfg__x1b.wav"), 1, ATTN_NORM, 0);
self->solid = SOLID_NOT;
self->touch = NULL;
VectorMA (self->s.origin, -1 * FRAMETIME, self->velocity, self->s.origin);
VectorClear (self->velocity);
self->s.modelindex = gi.modelindex ("sprites/s_bfg3.sp2");
self->s.frame = 0;
self->s.sound = 0;
self->s.effects &= ~EF_ANIM_ALLFAST;
self->think = bfg_explode;
self->nextthink = level.time + FRAMETIME;
self->enemy = other;
gi.WriteByte (svc_temp_entity);
gi.WriteByte (TE_BFG_BIGEXPLOSION);
gi.WritePosition (self->s.origin);
gi.multicast (self->s.origin, MULTICAST_PVS);
}
void bfg_think (edict_t *self)
{
edict_t *ent;
edict_t *ignore;
vec3_t point;
vec3_t dir;
vec3_t start;
vec3_t end;
int dmg;
trace_t tr;
if (deathmatch->value)
dmg = 5;
else
dmg = 10;
ent = NULL;
while ((ent = findradius(ent, self->s.origin, 256)) != NULL)
{
if (ent == self)
continue;
if (ent == self->owner)
continue;
if (!ent->takedamage)
continue;
if (!(ent->svflags & SVF_MONSTER) && (!ent->client) && (strcmp(ent->classname, "misc_explobox") != 0))
continue;
VectorMA (ent->absmin, 0.5, ent->size, point);
VectorSubtract (point, self->s.origin, dir);
VectorNormalize (dir);
ignore = self;
VectorCopy (self->s.origin, start);
VectorMA (start, 2048, dir, end);
while(1)
{
tr = gi.trace (start, NULL, NULL, end, ignore, CONTENTS_SOLID|CONTENTS_MONSTER|CONTENTS_DEADMONSTER);
if (!tr.ent)
break;
// hurt it if we can
if ((tr.ent->takedamage) && !(tr.ent->flags & FL_IMMUNE_LASER) && (tr.ent != self->owner))
T_Damage (tr.ent, self, self->owner, dir, tr.endpos, vec3_origin, dmg, 1, DAMAGE_ENERGY, MOD_BFG_LASER);
// if we hit something that's not a monster or player we're done
if (!(tr.ent->svflags & SVF_MONSTER) && (!tr.ent->client))
{
gi.WriteByte (svc_temp_entity);
gi.WriteByte (TE_LASER_SPARKS);
gi.WriteByte (4);
gi.WritePosition (tr.endpos);
gi.WriteDir (tr.plane.normal);
gi.WriteByte (self->s.skinnum);
gi.multicast (tr.endpos, MULTICAST_PVS);
break;
}
ignore = tr.ent;
VectorCopy (tr.endpos, start);
}
gi.WriteByte (svc_temp_entity);
gi.WriteByte (TE_BFG_LASER);
gi.WritePosition (self->s.origin);
gi.WritePosition (tr.endpos);
gi.multicast (self->s.origin, MULTICAST_PHS);
}
self->nextthink = level.time + FRAMETIME;
}
void fire_bfg (edict_t *self, vec3_t start, vec3_t dir, int damage, int speed, float damage_radius)
{
edict_t *bfg;
bfg = G_Spawn();
VectorCopy (start, bfg->s.origin);
VectorCopy (dir, bfg->movedir);
vectoangles (dir, bfg->s.angles);
VectorScale (dir, speed, bfg->velocity);
bfg->movetype = MOVETYPE_FLYMISSILE;
bfg->clipmask = MASK_SHOT;
bfg->solid = SOLID_BBOX;
bfg->s.effects |= EF_BFG | EF_ANIM_ALLFAST;
VectorClear (bfg->mins);
VectorClear (bfg->maxs);
bfg->s.modelindex = gi.modelindex ("sprites/s_bfg1.sp2");
bfg->owner = self;
bfg->touch = bfg_touch;
bfg->nextthink = level.time + 8000/speed;
bfg->think = G_FreeEdict;
bfg->radius_dmg = damage;
bfg->dmg_radius = damage_radius;
bfg->classname = "bfg blast";
bfg->s.sound = gi.soundindex ("weapons/bfg__l1a.wav");
bfg->think = bfg_think;
bfg->nextthink = level.time + FRAMETIME;
bfg->teammaster = bfg;
bfg->teamchain = NULL;
if (self->client)
check_dodge (self, bfg->s.origin, dir, speed);
gi.linkentity (bfg);
}

1619
game/game.001 Normal file

File diff suppressed because it is too large Load Diff

2
game/game.def Normal file
View File

@ -0,0 +1,2 @@
EXPORTS
GetGameAPI

1618
game/game.dsp Normal file

File diff suppressed because it is too large Load Diff

254
game/game.h Normal file
View File

@ -0,0 +1,254 @@
/*
Copyright (C) 1997-2001 Id Software, Inc.
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 the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/*
Copyright (C) 1997-2001 Id Software, Inc.
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 the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
// game.h -- game dll information visible to server
#define GAME_API_VERSION 3
// edict->svflags
#define SVF_NOCLIENT 0x00000001 // don't send entity to clients, even if it has effects
#define SVF_DEADMONSTER 0x00000002 // treat as CONTENTS_DEADMONSTER for collision
#define SVF_MONSTER 0x00000004 // treat as CONTENTS_MONSTER for collision
// edict->solid values
typedef enum
{
SOLID_NOT, // no interaction with other objects
SOLID_TRIGGER, // only touch when inside, after moving
SOLID_BBOX, // touch on edge
SOLID_BSP // bsp clip, touch on edge
} solid_t;
//===============================================================
// link_t is only used for entity area links now
typedef struct link_s
{
struct link_s *prev, *next;
} link_t;
#define MAX_ENT_CLUSTERS 16
typedef struct edict_s edict_t;
typedef struct gclient_s gclient_t;
#ifndef GAME_INCLUDE
struct gclient_s
{
player_state_t ps; // communicated by server to clients
int ping;
// the game dll can add anything it wants after
// this point in the structure
};
struct edict_s
{
entity_state_t s;
struct gclient_s *client;
qboolean inuse;
int linkcount;
// FIXME: move these fields to a server private sv_entity_t
link_t area; // linked to a division node or leaf
int num_clusters; // if -1, use headnode instead
int clusternums[MAX_ENT_CLUSTERS];
int headnode; // unused if num_clusters != -1
int areanum, areanum2;
//================================
int svflags; // SVF_NOCLIENT, SVF_DEADMONSTER, SVF_MONSTER, etc
vec3_t mins, maxs;
vec3_t absmin, absmax, size;
solid_t solid;
int clipmask;
edict_t *owner;
// the game dll can add anything it wants after
// this point in the structure
};
#endif // GAME_INCLUDE
//===============================================================
//
// functions provided by the main engine
//
typedef struct
{
// special messages
void (*bprintf) (int printlevel, char *fmt, ...);
void (*dprintf) (char *fmt, ...);
void (*cprintf) (edict_t *ent, int printlevel, char *fmt, ...);
void (*centerprintf) (edict_t *ent, char *fmt, ...);
void (*sound) (edict_t *ent, int channel, int soundindex, float volume, float attenuation, float timeofs);
void (*positioned_sound) (vec3_t origin, edict_t *ent, int channel, int soundinedex, float volume, float attenuation, float timeofs);
// config strings hold all the index strings, the lightstyles,
// and misc data like the sky definition and cdtrack.
// All of the current configstrings are sent to clients when
// they connect, and changes are sent to all connected clients.
void (*configstring) (int num, char *string);
void (*error) (char *fmt, ...);
// the *index functions create configstrings and some internal server state
int (*modelindex) (char *name);
int (*soundindex) (char *name);
int (*imageindex) (char *name);
void (*setmodel) (edict_t *ent, char *name);
// collision detection
trace_t (*trace) (vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, edict_t *passent, int contentmask);
int (*pointcontents) (vec3_t point);
qboolean (*inPVS) (vec3_t p1, vec3_t p2);
qboolean (*inPHS) (vec3_t p1, vec3_t p2);
void (*SetAreaPortalState) (int portalnum, qboolean open);
qboolean (*AreasConnected) (int area1, int area2);
// an entity will never be sent to a client or used for collision
// if it is not passed to linkentity. If the size, position, or
// solidity changes, it must be relinked.
void (*linkentity) (edict_t *ent);
void (*unlinkentity) (edict_t *ent); // call before removing an interactive edict
int (*BoxEdicts) (vec3_t mins, vec3_t maxs, edict_t **list, int maxcount, int areatype);
void (*Pmove) (pmove_t *pmove); // player movement code common with client prediction
// network messaging
void (*multicast) (vec3_t origin, multicast_t to);
void (*unicast) (edict_t *ent, qboolean reliable);
void (*WriteChar) (int c);
void (*WriteByte) (int c);
void (*WriteShort) (int c);
void (*WriteLong) (int c);
void (*WriteFloat) (float f);
void (*WriteString) (char *s);
void (*WritePosition) (vec3_t pos); // some fractional bits
void (*WriteDir) (vec3_t pos); // single byte encoded, very coarse
void (*WriteAngle) (float f);
// managed memory allocation
void *(*TagMalloc) (int size, int tag);
void (*TagFree) (void *block);
void (*FreeTags) (int tag);
// console variable interaction
cvar_t *(*cvar) (char *var_name, char *value, int flags);
cvar_t *(*cvar_set) (char *var_name, char *value);
cvar_t *(*cvar_forceset) (char *var_name, char *value);
// ClientCommand and ServerCommand parameter access
int (*argc) (void);
char *(*argv) (int n);
char *(*args) (void); // concatenation of all argv >= 1
// add commands to the server console as if they were typed in
// for map changing, etc
void (*AddCommandString) (char *text);
void (*DebugGraph) (float value, int color);
} game_import_t;
//
// functions exported by the game subsystem
//
typedef struct
{
int apiversion;
// the init function will only be called when a game starts,
// not each time a level is loaded. Persistant data for clients
// and the server can be allocated in init
void (*Init) (void);
void (*Shutdown) (void);
// each new level entered will cause a call to SpawnEntities
void (*SpawnEntities) (char *mapname, char *entstring, char *spawnpoint);
// Read/Write Game is for storing persistant cross level information
// about the world state and the clients.
// WriteGame is called every time a level is exited.
// ReadGame is called on a loadgame.
void (*WriteGame) (char *filename, qboolean autosave);
void (*ReadGame) (char *filename);
// ReadLevel is called after the default map information has been
// loaded with SpawnEntities
void (*WriteLevel) (char *filename);
void (*ReadLevel) (char *filename);
qboolean (*ClientConnect) (edict_t *ent, char *userinfo);
void (*ClientBegin) (edict_t *ent);
void (*ClientUserinfoChanged) (edict_t *ent, char *userinfo);
void (*ClientDisconnect) (edict_t *ent);
void (*ClientCommand) (edict_t *ent);
void (*ClientThink) (edict_t *ent, usercmd_t *cmd);
void (*RunFrame) (void);
// ServerCommand will be called when an "sv <command>" command is issued on the
// server console.
// The game can issue gi.argc() / gi.argv() commands to get the rest
// of the parameters
void (*ServerCommand) (void);
//
// global variables shared between game and server
//
// The edict array is allocated in the game dll so it
// can vary in size from one game to another.
//
// The size will be fixed when ge->Init() is called
struct edict_s *edicts;
int edict_size;
int num_edicts; // current number, <= max_edicts
int max_edicts;
} game_export_t;
game_export_t *GetGameApi (game_import_t *import);

75
game/game.plg Normal file
View File

@ -0,0 +1,75 @@
--------------------Configuration: game - Win32 Release Alpha--------------------
Begining build with project "G:\quake2\code\game\game.dsp", at root.
Active configuration is Win32 (ALPHA) Dynamic-Link Library (based on Win32 (ALPHA) Dynamic-Link Library)
Project's tools are:
"OLE Type Library Maker" with flags "/nologo /D "NDEBUG" /mktyplib203 /o NUL /win32 "
"C/C++ Compiler for Alpha" with flags "/nologo /QA21164 /MT /Gt0 /W3 /GX /Zi /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "C_ONLY" /Fp".\ReleaseAXP/game.pch" /YX /Fo".\ReleaseAXP/" /Fd".\ReleaseAXP/" /FD /c "
"Win32 Resource Compiler" with flags "/l 0x409 /d "NDEBUG" "
"Browser Database Maker" with flags "/nologo /o"..\ReleaseAXP/game.bsc" "
"COFF Linker for Alpha" with flags "kernel32.lib user32.lib gdi32.lib /nologo /base:"0x20000000" /subsystem:windows /dll /incremental:no /pdb:"..\ReleaseAXP/gameaxp.pdb" /debug /machine:ALPHA /def:".\game.def" /out:"..\ReleaseAXP/gameaxp.dll" /implib:"..\ReleaseAXP/gameaxp.lib" "
"Custom Build" with flags ""
"<Component 0xa>" with flags ""
Creating temp file "C:\TEMP\RSPA6.tmp" with contents </nologo /QA21164 /MT /Gt0 /W3 /GX /Zi /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "C_ONLY" /Fp".\ReleaseAXP/game.pch" /YX /Fo".\ReleaseAXP/" /Fd".\ReleaseAXP/" /c
"G:\quake2\code\game\p_weapon.c"
>
Creating command line "cl.exe @C:\TEMP\RSPA6.tmp"
Creating temp file "C:\TEMP\RSPA7.tmp" with contents <kernel32.lib user32.lib gdi32.lib /nologo /base:"0x20000000" /subsystem:windows /dll /incremental:no /pdb:"..\ReleaseAXP/gameaxp.pdb" /debug /machine:ALPHA /def:".\game.def" /out:"..\ReleaseAXP/gameaxp.dll" /implib:"..\ReleaseAXP/gameaxp.lib"
.\ReleaseAXP\g_ai.obj
.\ReleaseAXP\g_chase.obj
.\ReleaseAXP\g_cmds.obj
.\ReleaseAXP\g_combat.obj
.\ReleaseAXP\g_func.obj
.\ReleaseAXP\g_items.obj
.\ReleaseAXP\g_main.obj
.\ReleaseAXP\g_misc.obj
.\ReleaseAXP\g_monster.obj
.\ReleaseAXP\g_phys.obj
.\ReleaseAXP\g_save.obj
.\ReleaseAXP\g_spawn.obj
.\ReleaseAXP\g_svcmds.obj
.\ReleaseAXP\g_target.obj
.\ReleaseAXP\g_trigger.obj
.\ReleaseAXP\g_turret.obj
.\ReleaseAXP\g_utils.obj
.\ReleaseAXP\g_weapon.obj
.\ReleaseAXP\m_actor.obj
.\ReleaseAXP\m_berserk.obj
.\ReleaseAXP\m_boss2.obj
.\ReleaseAXP\m_boss3.obj
.\ReleaseAXP\m_boss31.obj
.\ReleaseAXP\m_boss32.obj
.\ReleaseAXP\m_brain.obj
.\ReleaseAXP\m_chick.obj
.\ReleaseAXP\m_flash.obj
.\ReleaseAXP\m_flipper.obj
.\ReleaseAXP\m_float.obj
.\ReleaseAXP\m_flyer.obj
.\ReleaseAXP\m_gladiator.obj
.\ReleaseAXP\m_gunner.obj
.\ReleaseAXP\m_hover.obj
.\ReleaseAXP\m_infantry.obj
.\ReleaseAXP\m_insane.obj
.\ReleaseAXP\m_medic.obj
.\ReleaseAXP\m_move.obj
.\ReleaseAXP\m_mutant.obj
.\ReleaseAXP\m_parasite.obj
.\ReleaseAXP\m_soldier.obj
.\ReleaseAXP\m_supertank.obj
.\ReleaseAXP\m_tank.obj
.\ReleaseAXP\p_client.obj
.\ReleaseAXP\p_hud.obj
.\ReleaseAXP\p_trail.obj
.\ReleaseAXP\p_view.obj
.\ReleaseAXP\p_weapon.obj
.\ReleaseAXP\q_shared.obj>
Creating command line "link.exe @C:\TEMP\RSPA7.tmp"
Compiling...
p_weapon.c
Linking...
Creating library ..\ReleaseAXP/gameaxp.lib and object ..\ReleaseAXP/gameaxp.exp
gameaxp.dll - 0 error(s), 0 warning(s)

609
game/m_actor.c Normal file
View File

@ -0,0 +1,609 @@
/*
Copyright (C) 1997-2001 Id Software, Inc.
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 the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
// g_actor.c
#include "g_local.h"
#include "m_actor.h"
#define MAX_ACTOR_NAMES 8
char *actor_names[MAX_ACTOR_NAMES] =
{
"Hellrot",
"Tokay",
"Killme",
"Disruptor",
"Adrianator",
"Rambear",
"Titus",
"Bitterman"
};
mframe_t actor_frames_stand [] =
{
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL
};
mmove_t actor_move_stand = {FRAME_stand101, FRAME_stand140, actor_frames_stand, NULL};
void actor_stand (edict_t *self)
{
self->monsterinfo.currentmove = &actor_move_stand;
// randomize on startup
if (level.time < 1.0)
self->s.frame = self->monsterinfo.currentmove->firstframe + (rand() % (self->monsterinfo.currentmove->lastframe - self->monsterinfo.currentmove->firstframe + 1));
}
mframe_t actor_frames_walk [] =
{
ai_walk, 0, NULL,
ai_walk, 6, NULL,
ai_walk, 10, NULL,
ai_walk, 3, NULL,
ai_walk, 2, NULL,
ai_walk, 7, NULL,
ai_walk, 10, NULL,
ai_walk, 1, NULL,
ai_walk, 4, NULL,
ai_walk, 0, NULL,
ai_walk, 0, NULL
};
mmove_t actor_move_walk = {FRAME_walk01, FRAME_walk08, actor_frames_walk, NULL};
void actor_walk (edict_t *self)
{
self->monsterinfo.currentmove = &actor_move_walk;
}
mframe_t actor_frames_run [] =
{
ai_run, 4, NULL,
ai_run, 15, NULL,
ai_run, 15, NULL,
ai_run, 8, NULL,
ai_run, 20, NULL,
ai_run, 15, NULL,
ai_run, 8, NULL,
ai_run, 17, NULL,
ai_run, 12, NULL,
ai_run, -2, NULL,
ai_run, -2, NULL,
ai_run, -1, NULL
};
mmove_t actor_move_run = {FRAME_run02, FRAME_run07, actor_frames_run, NULL};
void actor_run (edict_t *self)
{
if ((level.time < self->pain_debounce_time) && (!self->enemy))
{
if (self->movetarget)
actor_walk(self);
else
actor_stand(self);
return;
}
if (self->monsterinfo.aiflags & AI_STAND_GROUND)
{
actor_stand(self);
return;
}
self->monsterinfo.currentmove = &actor_move_run;
}
mframe_t actor_frames_pain1 [] =
{
ai_move, -5, NULL,
ai_move, 4, NULL,
ai_move, 1, NULL
};
mmove_t actor_move_pain1 = {FRAME_pain101, FRAME_pain103, actor_frames_pain1, actor_run};
mframe_t actor_frames_pain2 [] =
{
ai_move, -4, NULL,
ai_move, 4, NULL,
ai_move, 0, NULL
};
mmove_t actor_move_pain2 = {FRAME_pain201, FRAME_pain203, actor_frames_pain2, actor_run};
mframe_t actor_frames_pain3 [] =
{
ai_move, -1, NULL,
ai_move, 1, NULL,
ai_move, 0, NULL
};
mmove_t actor_move_pain3 = {FRAME_pain301, FRAME_pain303, actor_frames_pain3, actor_run};
mframe_t actor_frames_flipoff [] =
{
ai_turn, 0, NULL,
ai_turn, 0, NULL,
ai_turn, 0, NULL,
ai_turn, 0, NULL,
ai_turn, 0, NULL,
ai_turn, 0, NULL,
ai_turn, 0, NULL,
ai_turn, 0, NULL,
ai_turn, 0, NULL,
ai_turn, 0, NULL,
ai_turn, 0, NULL,
ai_turn, 0, NULL,
ai_turn, 0, NULL,
ai_turn, 0, NULL
};
mmove_t actor_move_flipoff = {FRAME_flip01, FRAME_flip14, actor_frames_flipoff, actor_run};
mframe_t actor_frames_taunt [] =
{
ai_turn, 0, NULL,
ai_turn, 0, NULL,
ai_turn, 0, NULL,
ai_turn, 0, NULL,
ai_turn, 0, NULL,
ai_turn, 0, NULL,
ai_turn, 0, NULL,
ai_turn, 0, NULL,
ai_turn, 0, NULL,
ai_turn, 0, NULL,
ai_turn, 0, NULL,
ai_turn, 0, NULL,
ai_turn, 0, NULL,
ai_turn, 0, NULL,
ai_turn, 0, NULL,
ai_turn, 0, NULL,
ai_turn, 0, NULL
};
mmove_t actor_move_taunt = {FRAME_taunt01, FRAME_taunt17, actor_frames_taunt, actor_run};
char *messages[] =
{
"Watch it",
"#$@*&",
"Idiot",
"Check your targets"
};
void actor_pain (edict_t *self, edict_t *other, float kick, int damage)
{
int n;
if (self->health < (self->max_health / 2))
self->s.skinnum = 1;
if (level.time < self->pain_debounce_time)
return;
self->pain_debounce_time = level.time + 3;
// gi.sound (self, CHAN_VOICE, actor.sound_pain, 1, ATTN_NORM, 0);
if ((other->client) && (random() < 0.4))
{
vec3_t v;
char *name;
VectorSubtract (other->s.origin, self->s.origin, v);
self->ideal_yaw = vectoyaw (v);
if (random() < 0.5)
self->monsterinfo.currentmove = &actor_move_flipoff;
else
self->monsterinfo.currentmove = &actor_move_taunt;
name = actor_names[(self - g_edicts)%MAX_ACTOR_NAMES];
gi.cprintf (other, PRINT_CHAT, "%s: %s!\n", name, messages[rand()%3]);
return;
}
n = rand() % 3;
if (n == 0)
self->monsterinfo.currentmove = &actor_move_pain1;
else if (n == 1)
self->monsterinfo.currentmove = &actor_move_pain2;
else
self->monsterinfo.currentmove = &actor_move_pain3;
}
void actorMachineGun (edict_t *self)
{
vec3_t start, target;
vec3_t forward, right;
AngleVectors (self->s.angles, forward, right, NULL);
G_ProjectSource (self->s.origin, monster_flash_offset[MZ2_ACTOR_MACHINEGUN_1], forward, right, start);
if (self->enemy)
{
if (self->enemy->health > 0)
{
VectorMA (self->enemy->s.origin, -0.2, self->enemy->velocity, target);
target[2] += self->enemy->viewheight;
}
else
{
VectorCopy (self->enemy->absmin, target);
target[2] += (self->enemy->size[2] / 2);
}
VectorSubtract (target, start, forward);
VectorNormalize (forward);
}
else
{
AngleVectors (self->s.angles, forward, NULL, NULL);
}
monster_fire_bullet (self, start, forward, 3, 4, DEFAULT_BULLET_HSPREAD, DEFAULT_BULLET_VSPREAD, MZ2_ACTOR_MACHINEGUN_1);
}
void actor_dead (edict_t *self)
{
VectorSet (self->mins, -16, -16, -24);
VectorSet (self->maxs, 16, 16, -8);
self->movetype = MOVETYPE_TOSS;
self->svflags |= SVF_DEADMONSTER;
self->nextthink = 0;
gi.linkentity (self);
}
mframe_t actor_frames_death1 [] =
{
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, -13, NULL,
ai_move, 14, NULL,
ai_move, 3, NULL,
ai_move, -2, NULL,
ai_move, 1, NULL
};
mmove_t actor_move_death1 = {FRAME_death101, FRAME_death107, actor_frames_death1, actor_dead};
mframe_t actor_frames_death2 [] =
{
ai_move, 0, NULL,
ai_move, 7, NULL,
ai_move, -6, NULL,
ai_move, -5, NULL,
ai_move, 1, NULL,
ai_move, 0, NULL,
ai_move, -1, NULL,
ai_move, -2, NULL,
ai_move, -1, NULL,
ai_move, -9, NULL,
ai_move, -13, NULL,
ai_move, -13, NULL,
ai_move, 0, NULL
};
mmove_t actor_move_death2 = {FRAME_death201, FRAME_death213, actor_frames_death2, actor_dead};
void actor_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
{
int n;
// check for gib
if (self->health <= -80)
{
// gi.sound (self, CHAN_VOICE, actor.sound_gib, 1, ATTN_NORM, 0);
for (n= 0; n < 2; n++)
ThrowGib (self, "models/objects/gibs/bone/tris.md2", damage, GIB_ORGANIC);
for (n= 0; n < 4; n++)
ThrowGib (self, "models/objects/gibs/sm_meat/tris.md2", damage, GIB_ORGANIC);
ThrowHead (self, "models/objects/gibs/head2/tris.md2", damage, GIB_ORGANIC);
self->deadflag = DEAD_DEAD;
return;
}
if (self->deadflag == DEAD_DEAD)
return;
// regular death
// gi.sound (self, CHAN_VOICE, actor.sound_die, 1, ATTN_NORM, 0);
self->deadflag = DEAD_DEAD;
self->takedamage = DAMAGE_YES;
n = rand() % 2;
if (n == 0)
self->monsterinfo.currentmove = &actor_move_death1;
else
self->monsterinfo.currentmove = &actor_move_death2;
}
void actor_fire (edict_t *self)
{
actorMachineGun (self);
if (level.time >= self->monsterinfo.pausetime)
self->monsterinfo.aiflags &= ~AI_HOLD_FRAME;
else
self->monsterinfo.aiflags |= AI_HOLD_FRAME;
}
mframe_t actor_frames_attack [] =
{
ai_charge, -2, actor_fire,
ai_charge, -2, NULL,
ai_charge, 3, NULL,
ai_charge, 2, NULL
};
mmove_t actor_move_attack = {FRAME_attak01, FRAME_attak04, actor_frames_attack, actor_run};
void actor_attack(edict_t *self)
{
int n;
self->monsterinfo.currentmove = &actor_move_attack;
n = (rand() & 15) + 3 + 7;
self->monsterinfo.pausetime = level.time + n * FRAMETIME;
}
void actor_use (edict_t *self, edict_t *other, edict_t *activator)
{
vec3_t v;
self->goalentity = self->movetarget = G_PickTarget(self->target);
if ((!self->movetarget) || (strcmp(self->movetarget->classname, "target_actor") != 0))
{
gi.dprintf ("%s has bad target %s at %s\n", self->classname, self->target, vtos(self->s.origin));
self->target = NULL;
self->monsterinfo.pausetime = 100000000;
self->monsterinfo.stand (self);
return;
}
VectorSubtract (self->goalentity->s.origin, self->s.origin, v);
self->ideal_yaw = self->s.angles[YAW] = vectoyaw(v);
self->monsterinfo.walk (self);
self->target = NULL;
}
/*QUAKED misc_actor (1 .5 0) (-16 -16 -24) (16 16 32)
*/
void SP_misc_actor (edict_t *self)
{
if (deathmatch->value)
{
G_FreeEdict (self);
return;
}
if (!self->targetname)
{
gi.dprintf("untargeted %s at %s\n", self->classname, vtos(self->s.origin));
G_FreeEdict (self);
return;
}
if (!self->target)
{
gi.dprintf("%s with no target at %s\n", self->classname, vtos(self->s.origin));
G_FreeEdict (self);
return;
}
self->movetype = MOVETYPE_STEP;
self->solid = SOLID_BBOX;
self->s.modelindex = gi.modelindex("players/male/tris.md2");
VectorSet (self->mins, -16, -16, -24);
VectorSet (self->maxs, 16, 16, 32);
if (!self->health)
self->health = 100;
self->mass = 200;
self->pain = actor_pain;
self->die = actor_die;
self->monsterinfo.stand = actor_stand;
self->monsterinfo.walk = actor_walk;
self->monsterinfo.run = actor_run;
self->monsterinfo.attack = actor_attack;
self->monsterinfo.melee = NULL;
self->monsterinfo.sight = NULL;
self->monsterinfo.aiflags |= AI_GOOD_GUY;
gi.linkentity (self);
self->monsterinfo.currentmove = &actor_move_stand;
self->monsterinfo.scale = MODEL_SCALE;
walkmonster_start (self);
// actors always start in a dormant state, they *must* be used to get going
self->use = actor_use;
}
/*QUAKED target_actor (.5 .3 0) (-8 -8 -8) (8 8 8) JUMP SHOOT ATTACK x HOLD BRUTAL
JUMP jump in set direction upon reaching this target
SHOOT take a single shot at the pathtarget
ATTACK attack pathtarget until it or actor is dead
"target" next target_actor
"pathtarget" target of any action to be taken at this point
"wait" amount of time actor should pause at this point
"message" actor will "say" this to the player
for JUMP only:
"speed" speed thrown forward (default 200)
"height" speed thrown upwards (default 200)
*/
void target_actor_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
{
vec3_t v;
if (other->movetarget != self)
return;
if (other->enemy)
return;
other->goalentity = other->movetarget = NULL;
if (self->message)
{
int n;
edict_t *ent;
for (n = 1; n <= game.maxclients; n++)
{
ent = &g_edicts[n];
if (!ent->inuse)
continue;
gi.cprintf (ent, PRINT_CHAT, "%s: %s\n", actor_names[(other - g_edicts)%MAX_ACTOR_NAMES], self->message);
}
}
if (self->spawnflags & 1) //jump
{
other->velocity[0] = self->movedir[0] * self->speed;
other->velocity[1] = self->movedir[1] * self->speed;
if (other->groundentity)
{
other->groundentity = NULL;
other->velocity[2] = self->movedir[2];
gi.sound(other, CHAN_VOICE, gi.soundindex("player/male/jump1.wav"), 1, ATTN_NORM, 0);
}
}
if (self->spawnflags & 2) //shoot
{
}
else if (self->spawnflags & 4) //attack
{
other->enemy = G_PickTarget(self->pathtarget);
if (other->enemy)
{
other->goalentity = other->enemy;
if (self->spawnflags & 32)
other->monsterinfo.aiflags |= AI_BRUTAL;
if (self->spawnflags & 16)
{
other->monsterinfo.aiflags |= AI_STAND_GROUND;
actor_stand (other);
}
else
{
actor_run (other);
}
}
}
if (!(self->spawnflags & 6) && (self->pathtarget))
{
char *savetarget;
savetarget = self->target;
self->target = self->pathtarget;
G_UseTargets (self, other);
self->target = savetarget;
}
other->movetarget = G_PickTarget(self->target);
if (!other->goalentity)
other->goalentity = other->movetarget;
if (!other->movetarget && !other->enemy)
{
other->monsterinfo.pausetime = level.time + 100000000;
other->monsterinfo.stand (other);
}
else if (other->movetarget == other->goalentity)
{
VectorSubtract (other->movetarget->s.origin, other->s.origin, v);
other->ideal_yaw = vectoyaw (v);
}
}
void SP_target_actor (edict_t *self)
{
if (!self->targetname)
gi.dprintf ("%s with no targetname at %s\n", self->classname, vtos(self->s.origin));
self->solid = SOLID_TRIGGER;
self->touch = target_actor_touch;
VectorSet (self->mins, -8, -8, -8);
VectorSet (self->maxs, 8, 8, 8);
self->svflags = SVF_NOCLIENT;
if (self->spawnflags & 1)
{
if (!self->speed)
self->speed = 200;
if (!st.height)
st.height = 200;
if (self->s.angles[YAW] == 0)
self->s.angles[YAW] = 360;
G_SetMovedir (self->s.angles, self->movedir);
self->movedir[2] = st.height;
}
gi.linkentity (self);
}

506
game/m_actor.h Normal file
View File

@ -0,0 +1,506 @@
/*
Copyright (C) 1997-2001 Id Software, Inc.
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 the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
// G:\quake2\baseq2\models/player_y
// This file generated by ModelGen - Do NOT Modify
#define FRAME_attak01 0
#define FRAME_attak02 1
#define FRAME_attak03 2
#define FRAME_attak04 3
#define FRAME_death101 4
#define FRAME_death102 5
#define FRAME_death103 6
#define FRAME_death104 7
#define FRAME_death105 8
#define FRAME_death106 9
#define FRAME_death107 10
#define FRAME_death201 11
#define FRAME_death202 12
#define FRAME_death203 13
#define FRAME_death204 14
#define FRAME_death205 15
#define FRAME_death206 16
#define FRAME_death207 17
#define FRAME_death208 18
#define FRAME_death209 19
#define FRAME_death210 20
#define FRAME_death211 21
#define FRAME_death212 22
#define FRAME_death213 23
#define FRAME_death301 24
#define FRAME_death302 25
#define FRAME_death303 26
#define FRAME_death304 27
#define FRAME_death305 28
#define FRAME_death306 29
#define FRAME_death307 30
#define FRAME_death308 31
#define FRAME_death309 32
#define FRAME_death310 33
#define FRAME_death311 34
#define FRAME_death312 35
#define FRAME_death313 36
#define FRAME_death314 37
#define FRAME_death315 38
#define FRAME_flip01 39
#define FRAME_flip02 40
#define FRAME_flip03 41
#define FRAME_flip04 42
#define FRAME_flip05 43
#define FRAME_flip06 44
#define FRAME_flip07 45
#define FRAME_flip08 46
#define FRAME_flip09 47
#define FRAME_flip10 48
#define FRAME_flip11 49
#define FRAME_flip12 50
#define FRAME_flip13 51
#define FRAME_flip14 52
#define FRAME_grenad01 53
#define FRAME_grenad02 54
#define FRAME_grenad03 55
#define FRAME_grenad04 56
#define FRAME_grenad05 57
#define FRAME_grenad06 58
#define FRAME_grenad07 59
#define FRAME_grenad08 60
#define FRAME_grenad09 61
#define FRAME_grenad10 62
#define FRAME_grenad11 63
#define FRAME_grenad12 64
#define FRAME_grenad13 65
#define FRAME_grenad14 66
#define FRAME_grenad15 67
#define FRAME_jump01 68
#define FRAME_jump02 69
#define FRAME_jump03 70
#define FRAME_jump04 71
#define FRAME_jump05 72
#define FRAME_jump06 73
#define FRAME_pain101 74
#define FRAME_pain102 75
#define FRAME_pain103 76
#define FRAME_pain201 77
#define FRAME_pain202 78
#define FRAME_pain203 79
#define FRAME_pain301 80
#define FRAME_pain302 81
#define FRAME_pain303 82
#define FRAME_push01 83
#define FRAME_push02 84
#define FRAME_push03 85
#define FRAME_push04 86
#define FRAME_push05 87
#define FRAME_push06 88
#define FRAME_push07 89
#define FRAME_push08 90
#define FRAME_push09 91
#define FRAME_run01 92
#define FRAME_run02 93
#define FRAME_run03 94
#define FRAME_run04 95
#define FRAME_run05 96
#define FRAME_run06 97
#define FRAME_run07 98
#define FRAME_run08 99
#define FRAME_run09 100
#define FRAME_run10 101
#define FRAME_run11 102
#define FRAME_run12 103
#define FRAME_runs01 104
#define FRAME_runs02 105
#define FRAME_runs03 106
#define FRAME_runs04 107
#define FRAME_runs05 108
#define FRAME_runs06 109
#define FRAME_runs07 110
#define FRAME_runs08 111
#define FRAME_runs09 112
#define FRAME_runs10 113
#define FRAME_runs11 114
#define FRAME_runs12 115
#define FRAME_salute01 116
#define FRAME_salute02 117
#define FRAME_salute03 118
#define FRAME_salute04 119
#define FRAME_salute05 120
#define FRAME_salute06 121
#define FRAME_salute07 122
#define FRAME_salute08 123
#define FRAME_salute09 124
#define FRAME_salute10 125
#define FRAME_salute11 126
#define FRAME_salute12 127
#define FRAME_stand101 128
#define FRAME_stand102 129
#define FRAME_stand103 130
#define FRAME_stand104 131
#define FRAME_stand105 132
#define FRAME_stand106 133
#define FRAME_stand107 134
#define FRAME_stand108 135
#define FRAME_stand109 136
#define FRAME_stand110 137
#define FRAME_stand111 138
#define FRAME_stand112 139
#define FRAME_stand113 140
#define FRAME_stand114 141
#define FRAME_stand115 142
#define FRAME_stand116 143
#define FRAME_stand117 144
#define FRAME_stand118 145
#define FRAME_stand119 146
#define FRAME_stand120 147
#define FRAME_stand121 148
#define FRAME_stand122 149
#define FRAME_stand123 150
#define FRAME_stand124 151
#define FRAME_stand125 152
#define FRAME_stand126 153
#define FRAME_stand127 154
#define FRAME_stand128 155
#define FRAME_stand129 156
#define FRAME_stand130 157
#define FRAME_stand131 158
#define FRAME_stand132 159
#define FRAME_stand133 160
#define FRAME_stand134 161
#define FRAME_stand135 162
#define FRAME_stand136 163
#define FRAME_stand137 164
#define FRAME_stand138 165
#define FRAME_stand139 166
#define FRAME_stand140 167
#define FRAME_stand201 168
#define FRAME_stand202 169
#define FRAME_stand203 170
#define FRAME_stand204 171
#define FRAME_stand205 172
#define FRAME_stand206 173
#define FRAME_stand207 174
#define FRAME_stand208 175
#define FRAME_stand209 176
#define FRAME_stand210 177
#define FRAME_stand211 178
#define FRAME_stand212 179
#define FRAME_stand213 180
#define FRAME_stand214 181
#define FRAME_stand215 182
#define FRAME_stand216 183
#define FRAME_stand217 184
#define FRAME_stand218 185
#define FRAME_stand219 186
#define FRAME_stand220 187
#define FRAME_stand221 188
#define FRAME_stand222 189
#define FRAME_stand223 190
#define FRAME_swim01 191
#define FRAME_swim02 192
#define FRAME_swim03 193
#define FRAME_swim04 194
#define FRAME_swim05 195
#define FRAME_swim06 196
#define FRAME_swim07 197
#define FRAME_swim08 198
#define FRAME_swim09 199
#define FRAME_swim10 200
#define FRAME_swim11 201
#define FRAME_swim12 202
#define FRAME_sw_atk01 203
#define FRAME_sw_atk02 204
#define FRAME_sw_atk03 205
#define FRAME_sw_atk04 206
#define FRAME_sw_atk05 207
#define FRAME_sw_atk06 208
#define FRAME_sw_pan01 209
#define FRAME_sw_pan02 210
#define FRAME_sw_pan03 211
#define FRAME_sw_pan04 212
#define FRAME_sw_pan05 213
#define FRAME_sw_std01 214
#define FRAME_sw_std02 215
#define FRAME_sw_std03 216
#define FRAME_sw_std04 217
#define FRAME_sw_std05 218
#define FRAME_sw_std06 219
#define FRAME_sw_std07 220
#define FRAME_sw_std08 221
#define FRAME_sw_std09 222
#define FRAME_sw_std10 223
#define FRAME_sw_std11 224
#define FRAME_sw_std12 225
#define FRAME_sw_std13 226
#define FRAME_sw_std14 227
#define FRAME_sw_std15 228
#define FRAME_sw_std16 229
#define FRAME_sw_std17 230
#define FRAME_sw_std18 231
#define FRAME_sw_std19 232
#define FRAME_sw_std20 233
#define FRAME_taunt01 234
#define FRAME_taunt02 235
#define FRAME_taunt03 236
#define FRAME_taunt04 237
#define FRAME_taunt05 238
#define FRAME_taunt06 239
#define FRAME_taunt07 240
#define FRAME_taunt08 241
#define FRAME_taunt09 242
#define FRAME_taunt10 243
#define FRAME_taunt11 244
#define FRAME_taunt12 245
#define FRAME_taunt13 246
#define FRAME_taunt14 247
#define FRAME_taunt15 248
#define FRAME_taunt16 249
#define FRAME_taunt17 250
#define FRAME_walk01 251
#define FRAME_walk02 252
#define FRAME_walk03 253
#define FRAME_walk04 254
#define FRAME_walk05 255
#define FRAME_walk06 256
#define FRAME_walk07 257
#define FRAME_walk08 258
#define FRAME_walk09 259
#define FRAME_walk10 260
#define FRAME_walk11 261
#define FRAME_wave01 262
#define FRAME_wave02 263
#define FRAME_wave03 264
#define FRAME_wave04 265
#define FRAME_wave05 266
#define FRAME_wave06 267
#define FRAME_wave07 268
#define FRAME_wave08 269
#define FRAME_wave09 270
#define FRAME_wave10 271
#define FRAME_wave11 272
#define FRAME_wave12 273
#define FRAME_wave13 274
#define FRAME_wave14 275
#define FRAME_wave15 276
#define FRAME_wave16 277
#define FRAME_wave17 278
#define FRAME_wave18 279
#define FRAME_wave19 280
#define FRAME_wave20 281
#define FRAME_wave21 282
#define FRAME_bl_atk01 283
#define FRAME_bl_atk02 284
#define FRAME_bl_atk03 285
#define FRAME_bl_atk04 286
#define FRAME_bl_atk05 287
#define FRAME_bl_atk06 288
#define FRAME_bl_flp01 289
#define FRAME_bl_flp02 290
#define FRAME_bl_flp13 291
#define FRAME_bl_flp14 292
#define FRAME_bl_flp15 293
#define FRAME_bl_jmp01 294
#define FRAME_bl_jmp02 295
#define FRAME_bl_jmp03 296
#define FRAME_bl_jmp04 297
#define FRAME_bl_jmp05 298
#define FRAME_bl_jmp06 299
#define FRAME_bl_pn101 300
#define FRAME_bl_pn102 301
#define FRAME_bl_pn103 302
#define FRAME_bl_pn201 303
#define FRAME_bl_pn202 304
#define FRAME_bl_pn203 305
#define FRAME_bl_pn301 306
#define FRAME_bl_pn302 307
#define FRAME_bl_pn303 308
#define FRAME_bl_psh08 309
#define FRAME_bl_psh09 310
#define FRAME_bl_run01 311
#define FRAME_bl_run02 312
#define FRAME_bl_run03 313
#define FRAME_bl_run04 314
#define FRAME_bl_run05 315
#define FRAME_bl_run06 316
#define FRAME_bl_run07 317
#define FRAME_bl_run08 318
#define FRAME_bl_run09 319
#define FRAME_bl_run10 320
#define FRAME_bl_run11 321
#define FRAME_bl_run12 322
#define FRAME_bl_rns03 323
#define FRAME_bl_rns04 324
#define FRAME_bl_rns05 325
#define FRAME_bl_rns06 326
#define FRAME_bl_rns07 327
#define FRAME_bl_rns08 328
#define FRAME_bl_rns09 329
#define FRAME_bl_sal10 330
#define FRAME_bl_sal11 331
#define FRAME_bl_sal12 332
#define FRAME_bl_std01 333
#define FRAME_bl_std02 334
#define FRAME_bl_std03 335
#define FRAME_bl_std04 336
#define FRAME_bl_std05 337
#define FRAME_bl_std06 338
#define FRAME_bl_std07 339
#define FRAME_bl_std08 340
#define FRAME_bl_std09 341
#define FRAME_bl_std10 342
#define FRAME_bl_std11 343
#define FRAME_bl_std12 344
#define FRAME_bl_std13 345
#define FRAME_bl_std14 346
#define FRAME_bl_std15 347
#define FRAME_bl_std16 348
#define FRAME_bl_std17 349
#define FRAME_bl_std18 350
#define FRAME_bl_std19 351
#define FRAME_bl_std20 352
#define FRAME_bl_std21 353
#define FRAME_bl_std22 354
#define FRAME_bl_std23 355
#define FRAME_bl_std24 356
#define FRAME_bl_std25 357
#define FRAME_bl_std26 358
#define FRAME_bl_std27 359
#define FRAME_bl_std28 360
#define FRAME_bl_std29 361
#define FRAME_bl_std30 362
#define FRAME_bl_std31 363
#define FRAME_bl_std32 364
#define FRAME_bl_std33 365
#define FRAME_bl_std34 366
#define FRAME_bl_std35 367
#define FRAME_bl_std36 368
#define FRAME_bl_std37 369
#define FRAME_bl_std38 370
#define FRAME_bl_std39 371
#define FRAME_bl_std40 372
#define FRAME_bl_swm01 373
#define FRAME_bl_swm02 374
#define FRAME_bl_swm03 375
#define FRAME_bl_swm04 376
#define FRAME_bl_swm05 377
#define FRAME_bl_swm06 378
#define FRAME_bl_swm07 379
#define FRAME_bl_swm08 380
#define FRAME_bl_swm09 381
#define FRAME_bl_swm10 382
#define FRAME_bl_swm11 383
#define FRAME_bl_swm12 384
#define FRAME_bl_swk01 385
#define FRAME_bl_swk02 386
#define FRAME_bl_swk03 387
#define FRAME_bl_swk04 388
#define FRAME_bl_swk05 389
#define FRAME_bl_swk06 390
#define FRAME_bl_swp01 391
#define FRAME_bl_swp02 392
#define FRAME_bl_swp03 393
#define FRAME_bl_swp04 394
#define FRAME_bl_swp05 395
#define FRAME_bl_sws01 396
#define FRAME_bl_sws02 397
#define FRAME_bl_sws03 398
#define FRAME_bl_sws04 399
#define FRAME_bl_sws05 400
#define FRAME_bl_sws06 401
#define FRAME_bl_sws07 402
#define FRAME_bl_sws08 403
#define FRAME_bl_sws09 404
#define FRAME_bl_sws10 405
#define FRAME_bl_sws11 406
#define FRAME_bl_sws12 407
#define FRAME_bl_sws13 408
#define FRAME_bl_sws14 409
#define FRAME_bl_tau14 410
#define FRAME_bl_tau15 411
#define FRAME_bl_tau16 412
#define FRAME_bl_tau17 413
#define FRAME_bl_wlk01 414
#define FRAME_bl_wlk02 415
#define FRAME_bl_wlk03 416
#define FRAME_bl_wlk04 417
#define FRAME_bl_wlk05 418
#define FRAME_bl_wlk06 419
#define FRAME_bl_wlk07 420
#define FRAME_bl_wlk08 421
#define FRAME_bl_wlk09 422
#define FRAME_bl_wlk10 423
#define FRAME_bl_wlk11 424
#define FRAME_bl_wav19 425
#define FRAME_bl_wav20 426
#define FRAME_bl_wav21 427
#define FRAME_cr_atk01 428
#define FRAME_cr_atk02 429
#define FRAME_cr_atk03 430
#define FRAME_cr_atk04 431
#define FRAME_cr_atk05 432
#define FRAME_cr_atk06 433
#define FRAME_cr_atk07 434
#define FRAME_cr_atk08 435
#define FRAME_cr_pan01 436
#define FRAME_cr_pan02 437
#define FRAME_cr_pan03 438
#define FRAME_cr_pan04 439
#define FRAME_cr_std01 440
#define FRAME_cr_std02 441
#define FRAME_cr_std03 442
#define FRAME_cr_std04 443
#define FRAME_cr_std05 444
#define FRAME_cr_std06 445
#define FRAME_cr_std07 446
#define FRAME_cr_std08 447
#define FRAME_cr_wlk01 448
#define FRAME_cr_wlk02 449
#define FRAME_cr_wlk03 450
#define FRAME_cr_wlk04 451
#define FRAME_cr_wlk05 452
#define FRAME_cr_wlk06 453
#define FRAME_cr_wlk07 454
#define FRAME_crbl_a01 455
#define FRAME_crbl_a02 456
#define FRAME_crbl_a03 457
#define FRAME_crbl_a04 458
#define FRAME_crbl_a05 459
#define FRAME_crbl_a06 460
#define FRAME_crbl_a07 461
#define FRAME_crbl_p01 462
#define FRAME_crbl_p02 463
#define FRAME_crbl_p03 464
#define FRAME_crbl_p04 465
#define FRAME_crbl_s01 466
#define FRAME_crbl_s02 467
#define FRAME_crbl_s03 468
#define FRAME_crbl_s04 469
#define FRAME_crbl_s05 470
#define FRAME_crbl_s06 471
#define FRAME_crbl_s07 472
#define FRAME_crbl_s08 473
#define FRAME_crbl_w01 474
#define FRAME_crbl_w02 475
#define FRAME_crbl_w03 476
#define FRAME_crbl_w04 477
#define FRAME_crbl_w05 478
#define FRAME_crbl_w06 479
#define FRAME_crbl_w07 480
#define MODEL_SCALE 1.000000

457
game/m_berserk.c Normal file
View File

@ -0,0 +1,457 @@
/*
Copyright (C) 1997-2001 Id Software, Inc.
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 the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/*
==============================================================================
BERSERK
==============================================================================
*/
#include "g_local.h"
#include "m_berserk.h"
static int sound_pain;
static int sound_die;
static int sound_idle;
static int sound_punch;
static int sound_sight;
static int sound_search;
void berserk_sight (edict_t *self, edict_t *other)
{
gi.sound (self, CHAN_VOICE, sound_sight, 1, ATTN_NORM, 0);
}
void berserk_search (edict_t *self)
{
gi.sound (self, CHAN_VOICE, sound_search, 1, ATTN_NORM, 0);
}
void berserk_fidget (edict_t *self);
mframe_t berserk_frames_stand [] =
{
ai_stand, 0, berserk_fidget,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL
};
mmove_t berserk_move_stand = {FRAME_stand1, FRAME_stand5, berserk_frames_stand, NULL};
void berserk_stand (edict_t *self)
{
self->monsterinfo.currentmove = &berserk_move_stand;
}
mframe_t berserk_frames_stand_fidget [] =
{
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL
};
mmove_t berserk_move_stand_fidget = {FRAME_standb1, FRAME_standb20, berserk_frames_stand_fidget, berserk_stand};
void berserk_fidget (edict_t *self)
{
if (self->monsterinfo.aiflags & AI_STAND_GROUND)
return;
if (random() > 0.15)
return;
self->monsterinfo.currentmove = &berserk_move_stand_fidget;
gi.sound (self, CHAN_WEAPON, sound_idle, 1, ATTN_IDLE, 0);
}
mframe_t berserk_frames_walk [] =
{
ai_walk, 9.1, NULL,
ai_walk, 6.3, NULL,
ai_walk, 4.9, NULL,
ai_walk, 6.7, NULL,
ai_walk, 6.0, NULL,
ai_walk, 8.2, NULL,
ai_walk, 7.2, NULL,
ai_walk, 6.1, NULL,
ai_walk, 4.9, NULL,
ai_walk, 4.7, NULL,
ai_walk, 4.7, NULL,
ai_walk, 4.8, NULL
};
mmove_t berserk_move_walk = {FRAME_walkc1, FRAME_walkc11, berserk_frames_walk, NULL};
void berserk_walk (edict_t *self)
{
self->monsterinfo.currentmove = &berserk_move_walk;
}
/*
*****************************
SKIPPED THIS FOR NOW!
*****************************
Running -> Arm raised in air
void() berserk_runb1 =[ $r_att1 , berserk_runb2 ] {ai_run(21);};
void() berserk_runb2 =[ $r_att2 , berserk_runb3 ] {ai_run(11);};
void() berserk_runb3 =[ $r_att3 , berserk_runb4 ] {ai_run(21);};
void() berserk_runb4 =[ $r_att4 , berserk_runb5 ] {ai_run(25);};
void() berserk_runb5 =[ $r_att5 , berserk_runb6 ] {ai_run(18);};
void() berserk_runb6 =[ $r_att6 , berserk_runb7 ] {ai_run(19);};
// running with arm in air : start loop
void() berserk_runb7 =[ $r_att7 , berserk_runb8 ] {ai_run(21);};
void() berserk_runb8 =[ $r_att8 , berserk_runb9 ] {ai_run(11);};
void() berserk_runb9 =[ $r_att9 , berserk_runb10 ] {ai_run(21);};
void() berserk_runb10 =[ $r_att10 , berserk_runb11 ] {ai_run(25);};
void() berserk_runb11 =[ $r_att11 , berserk_runb12 ] {ai_run(18);};
void() berserk_runb12 =[ $r_att12 , berserk_runb7 ] {ai_run(19);};
// running with arm in air : end loop
*/
mframe_t berserk_frames_run1 [] =
{
ai_run, 21, NULL,
ai_run, 11, NULL,
ai_run, 21, NULL,
ai_run, 25, NULL,
ai_run, 18, NULL,
ai_run, 19, NULL
};
mmove_t berserk_move_run1 = {FRAME_run1, FRAME_run6, berserk_frames_run1, NULL};
void berserk_run (edict_t *self)
{
if (self->monsterinfo.aiflags & AI_STAND_GROUND)
self->monsterinfo.currentmove = &berserk_move_stand;
else
self->monsterinfo.currentmove = &berserk_move_run1;
}
void berserk_attack_spike (edict_t *self)
{
static vec3_t aim = {MELEE_DISTANCE, 0, -24};
fire_hit (self, aim, (15 + (rand() % 6)), 400); // Faster attack -- upwards and backwards
}
void berserk_swing (edict_t *self)
{
gi.sound (self, CHAN_WEAPON, sound_punch, 1, ATTN_NORM, 0);
}
mframe_t berserk_frames_attack_spike [] =
{
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, berserk_swing,
ai_charge, 0, berserk_attack_spike,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL
};
mmove_t berserk_move_attack_spike = {FRAME_att_c1, FRAME_att_c8, berserk_frames_attack_spike, berserk_run};
void berserk_attack_club (edict_t *self)
{
vec3_t aim;
VectorSet (aim, MELEE_DISTANCE, self->mins[0], -4);
fire_hit (self, aim, (5 + (rand() % 6)), 400); // Slower attack
}
mframe_t berserk_frames_attack_club [] =
{
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, berserk_swing,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, berserk_attack_club,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL
};
mmove_t berserk_move_attack_club = {FRAME_att_c9, FRAME_att_c20, berserk_frames_attack_club, berserk_run};
void berserk_strike (edict_t *self)
{
//FIXME play impact sound
}
mframe_t berserk_frames_attack_strike [] =
{
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, berserk_swing,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, berserk_strike,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 9.7, NULL,
ai_move, 13.6, NULL
};
mmove_t berserk_move_attack_strike = {FRAME_att_c21, FRAME_att_c34, berserk_frames_attack_strike, berserk_run};
void berserk_melee (edict_t *self)
{
if ((rand() % 2) == 0)
self->monsterinfo.currentmove = &berserk_move_attack_spike;
else
self->monsterinfo.currentmove = &berserk_move_attack_club;
}
/*
void() berserk_atke1 =[ $r_attb1, berserk_atke2 ] {ai_run(9);};
void() berserk_atke2 =[ $r_attb2, berserk_atke3 ] {ai_run(6);};
void() berserk_atke3 =[ $r_attb3, berserk_atke4 ] {ai_run(18.4);};
void() berserk_atke4 =[ $r_attb4, berserk_atke5 ] {ai_run(25);};
void() berserk_atke5 =[ $r_attb5, berserk_atke6 ] {ai_run(14);};
void() berserk_atke6 =[ $r_attb6, berserk_atke7 ] {ai_run(20);};
void() berserk_atke7 =[ $r_attb7, berserk_atke8 ] {ai_run(8.5);};
void() berserk_atke8 =[ $r_attb8, berserk_atke9 ] {ai_run(3);};
void() berserk_atke9 =[ $r_attb9, berserk_atke10 ] {ai_run(17.5);};
void() berserk_atke10 =[ $r_attb10, berserk_atke11 ] {ai_run(17);};
void() berserk_atke11 =[ $r_attb11, berserk_atke12 ] {ai_run(9);};
void() berserk_atke12 =[ $r_attb12, berserk_atke13 ] {ai_run(25);};
void() berserk_atke13 =[ $r_attb13, berserk_atke14 ] {ai_run(3.7);};
void() berserk_atke14 =[ $r_attb14, berserk_atke15 ] {ai_run(2.6);};
void() berserk_atke15 =[ $r_attb15, berserk_atke16 ] {ai_run(19);};
void() berserk_atke16 =[ $r_attb16, berserk_atke17 ] {ai_run(25);};
void() berserk_atke17 =[ $r_attb17, berserk_atke18 ] {ai_run(19.6);};
void() berserk_atke18 =[ $r_attb18, berserk_run1 ] {ai_run(7.8);};
*/
mframe_t berserk_frames_pain1 [] =
{
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL
};
mmove_t berserk_move_pain1 = {FRAME_painc1, FRAME_painc4, berserk_frames_pain1, berserk_run};
mframe_t berserk_frames_pain2 [] =
{
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL
};
mmove_t berserk_move_pain2 = {FRAME_painb1, FRAME_painb20, berserk_frames_pain2, berserk_run};
void berserk_pain (edict_t *self, edict_t *other, float kick, int damage)
{
if (self->health < (self->max_health / 2))
self->s.skinnum = 1;
if (level.time < self->pain_debounce_time)
return;
self->pain_debounce_time = level.time + 3;
gi.sound (self, CHAN_VOICE, sound_pain, 1, ATTN_NORM, 0);
if (skill->value == 3)
return; // no pain anims in nightmare
if ((damage < 20) || (random() < 0.5))
self->monsterinfo.currentmove = &berserk_move_pain1;
else
self->monsterinfo.currentmove = &berserk_move_pain2;
}
void berserk_dead (edict_t *self)
{
VectorSet (self->mins, -16, -16, -24);
VectorSet (self->maxs, 16, 16, -8);
self->movetype = MOVETYPE_TOSS;
self->svflags |= SVF_DEADMONSTER;
self->nextthink = 0;
gi.linkentity (self);
}
mframe_t berserk_frames_death1 [] =
{
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL
};
mmove_t berserk_move_death1 = {FRAME_death1, FRAME_death13, berserk_frames_death1, berserk_dead};
mframe_t berserk_frames_death2 [] =
{
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL
};
mmove_t berserk_move_death2 = {FRAME_deathc1, FRAME_deathc8, berserk_frames_death2, berserk_dead};
void berserk_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
{
int n;
if (self->health <= self->gib_health)
{
gi.sound (self, CHAN_VOICE, gi.soundindex ("misc/udeath.wav"), 1, ATTN_NORM, 0);
for (n= 0; n < 2; n++)
ThrowGib (self, "models/objects/gibs/bone/tris.md2", damage, GIB_ORGANIC);
for (n= 0; n < 4; n++)
ThrowGib (self, "models/objects/gibs/sm_meat/tris.md2", damage, GIB_ORGANIC);
ThrowHead (self, "models/objects/gibs/head2/tris.md2", damage, GIB_ORGANIC);
self->deadflag = DEAD_DEAD;
return;
}
if (self->deadflag == DEAD_DEAD)
return;
gi.sound (self, CHAN_VOICE, sound_die, 1, ATTN_NORM, 0);
self->deadflag = DEAD_DEAD;
self->takedamage = DAMAGE_YES;
if (damage >= 50)
self->monsterinfo.currentmove = &berserk_move_death1;
else
self->monsterinfo.currentmove = &berserk_move_death2;
}
/*QUAKED monster_berserk (1 .5 0) (-16 -16 -24) (16 16 32) Ambush Trigger_Spawn Sight
*/
void SP_monster_berserk (edict_t *self)
{
if (deathmatch->value)
{
G_FreeEdict (self);
return;
}
// pre-caches
sound_pain = gi.soundindex ("berserk/berpain2.wav");
sound_die = gi.soundindex ("berserk/berdeth2.wav");
sound_idle = gi.soundindex ("berserk/beridle1.wav");
sound_punch = gi.soundindex ("berserk/attack.wav");
sound_search = gi.soundindex ("berserk/bersrch1.wav");
sound_sight = gi.soundindex ("berserk/sight.wav");
self->s.modelindex = gi.modelindex("models/monsters/berserk/tris.md2");
VectorSet (self->mins, -16, -16, -24);
VectorSet (self->maxs, 16, 16, 32);
self->movetype = MOVETYPE_STEP;
self->solid = SOLID_BBOX;
self->health = 240;
self->gib_health = -60;
self->mass = 250;
self->pain = berserk_pain;
self->die = berserk_die;
self->monsterinfo.stand = berserk_stand;
self->monsterinfo.walk = berserk_walk;
self->monsterinfo.run = berserk_run;
self->monsterinfo.dodge = NULL;
self->monsterinfo.attack = NULL;
self->monsterinfo.melee = berserk_melee;
self->monsterinfo.sight = berserk_sight;
self->monsterinfo.search = berserk_search;
self->monsterinfo.currentmove = &berserk_move_stand;
self->monsterinfo.scale = MODEL_SCALE;
gi.linkentity (self);
walkmonster_start (self);
}

269
game/m_berserk.h Normal file
View File

@ -0,0 +1,269 @@
/*
Copyright (C) 1997-2001 Id Software, Inc.
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 the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
// G:\quake2\baseq2\models/monsters/berserk
// This file generated by ModelGen - Do NOT Modify
#define FRAME_stand1 0
#define FRAME_stand2 1
#define FRAME_stand3 2
#define FRAME_stand4 3
#define FRAME_stand5 4
#define FRAME_standb1 5
#define FRAME_standb2 6
#define FRAME_standb3 7
#define FRAME_standb4 8
#define FRAME_standb5 9
#define FRAME_standb6 10
#define FRAME_standb7 11
#define FRAME_standb8 12
#define FRAME_standb9 13
#define FRAME_standb10 14
#define FRAME_standb11 15
#define FRAME_standb12 16
#define FRAME_standb13 17
#define FRAME_standb14 18
#define FRAME_standb15 19
#define FRAME_standb16 20
#define FRAME_standb17 21
#define FRAME_standb18 22
#define FRAME_standb19 23
#define FRAME_standb20 24
#define FRAME_walkc1 25
#define FRAME_walkc2 26
#define FRAME_walkc3 27
#define FRAME_walkc4 28
#define FRAME_walkc5 29
#define FRAME_walkc6 30
#define FRAME_walkc7 31
#define FRAME_walkc8 32
#define FRAME_walkc9 33
#define FRAME_walkc10 34
#define FRAME_walkc11 35
#define FRAME_run1 36
#define FRAME_run2 37
#define FRAME_run3 38
#define FRAME_run4 39
#define FRAME_run5 40
#define FRAME_run6 41
#define FRAME_att_a1 42
#define FRAME_att_a2 43
#define FRAME_att_a3 44
#define FRAME_att_a4 45
#define FRAME_att_a5 46
#define FRAME_att_a6 47
#define FRAME_att_a7 48
#define FRAME_att_a8 49
#define FRAME_att_a9 50
#define FRAME_att_a10 51
#define FRAME_att_a11 52
#define FRAME_att_a12 53
#define FRAME_att_a13 54
#define FRAME_att_b1 55
#define FRAME_att_b2 56
#define FRAME_att_b3 57
#define FRAME_att_b4 58
#define FRAME_att_b5 59
#define FRAME_att_b6 60
#define FRAME_att_b7 61
#define FRAME_att_b8 62
#define FRAME_att_b9 63
#define FRAME_att_b10 64
#define FRAME_att_b11 65
#define FRAME_att_b12 66
#define FRAME_att_b13 67
#define FRAME_att_b14 68
#define FRAME_att_b15 69
#define FRAME_att_b16 70
#define FRAME_att_b17 71
#define FRAME_att_b18 72
#define FRAME_att_b19 73
#define FRAME_att_b20 74
#define FRAME_att_b21 75
#define FRAME_att_c1 76
#define FRAME_att_c2 77
#define FRAME_att_c3 78
#define FRAME_att_c4 79
#define FRAME_att_c5 80
#define FRAME_att_c6 81
#define FRAME_att_c7 82
#define FRAME_att_c8 83
#define FRAME_att_c9 84
#define FRAME_att_c10 85
#define FRAME_att_c11 86
#define FRAME_att_c12 87
#define FRAME_att_c13 88
#define FRAME_att_c14 89
#define FRAME_att_c15 90
#define FRAME_att_c16 91
#define FRAME_att_c17 92
#define FRAME_att_c18 93
#define FRAME_att_c19 94
#define FRAME_att_c20 95
#define FRAME_att_c21 96
#define FRAME_att_c22 97
#define FRAME_att_c23 98
#define FRAME_att_c24 99
#define FRAME_att_c25 100
#define FRAME_att_c26 101
#define FRAME_att_c27 102
#define FRAME_att_c28 103
#define FRAME_att_c29 104
#define FRAME_att_c30 105
#define FRAME_att_c31 106
#define FRAME_att_c32 107
#define FRAME_att_c33 108
#define FRAME_att_c34 109
#define FRAME_r_att1 110
#define FRAME_r_att2 111
#define FRAME_r_att3 112
#define FRAME_r_att4 113
#define FRAME_r_att5 114
#define FRAME_r_att6 115
#define FRAME_r_att7 116
#define FRAME_r_att8 117
#define FRAME_r_att9 118
#define FRAME_r_att10 119
#define FRAME_r_att11 120
#define FRAME_r_att12 121
#define FRAME_r_att13 122
#define FRAME_r_att14 123
#define FRAME_r_att15 124
#define FRAME_r_att16 125
#define FRAME_r_att17 126
#define FRAME_r_att18 127
#define FRAME_r_attb1 128
#define FRAME_r_attb2 129
#define FRAME_r_attb3 130
#define FRAME_r_attb4 131
#define FRAME_r_attb5 132
#define FRAME_r_attb6 133
#define FRAME_r_attb7 134
#define FRAME_r_attb8 135
#define FRAME_r_attb9 136
#define FRAME_r_attb10 137
#define FRAME_r_attb11 138
#define FRAME_r_attb12 139
#define FRAME_r_attb13 140
#define FRAME_r_attb14 141
#define FRAME_r_attb15 142
#define FRAME_r_attb16 143
#define FRAME_r_attb17 144
#define FRAME_r_attb18 145
#define FRAME_slam1 146
#define FRAME_slam2 147
#define FRAME_slam3 148
#define FRAME_slam4 149
#define FRAME_slam5 150
#define FRAME_slam6 151
#define FRAME_slam7 152
#define FRAME_slam8 153
#define FRAME_slam9 154
#define FRAME_slam10 155
#define FRAME_slam11 156
#define FRAME_slam12 157
#define FRAME_slam13 158
#define FRAME_slam14 159
#define FRAME_slam15 160
#define FRAME_slam16 161
#define FRAME_slam17 162
#define FRAME_slam18 163
#define FRAME_slam19 164
#define FRAME_slam20 165
#define FRAME_slam21 166
#define FRAME_slam22 167
#define FRAME_slam23 168
#define FRAME_duck1 169
#define FRAME_duck2 170
#define FRAME_duck3 171
#define FRAME_duck4 172
#define FRAME_duck5 173
#define FRAME_duck6 174
#define FRAME_duck7 175
#define FRAME_duck8 176
#define FRAME_duck9 177
#define FRAME_duck10 178
#define FRAME_fall1 179
#define FRAME_fall2 180
#define FRAME_fall3 181
#define FRAME_fall4 182
#define FRAME_fall5 183
#define FRAME_fall6 184
#define FRAME_fall7 185
#define FRAME_fall8 186
#define FRAME_fall9 187
#define FRAME_fall10 188
#define FRAME_fall11 189
#define FRAME_fall12 190
#define FRAME_fall13 191
#define FRAME_fall14 192
#define FRAME_fall15 193
#define FRAME_fall16 194
#define FRAME_fall17 195
#define FRAME_fall18 196
#define FRAME_fall19 197
#define FRAME_fall20 198
#define FRAME_painc1 199
#define FRAME_painc2 200
#define FRAME_painc3 201
#define FRAME_painc4 202
#define FRAME_painb1 203
#define FRAME_painb2 204
#define FRAME_painb3 205
#define FRAME_painb4 206
#define FRAME_painb5 207
#define FRAME_painb6 208
#define FRAME_painb7 209
#define FRAME_painb8 210
#define FRAME_painb9 211
#define FRAME_painb10 212
#define FRAME_painb11 213
#define FRAME_painb12 214
#define FRAME_painb13 215
#define FRAME_painb14 216
#define FRAME_painb15 217
#define FRAME_painb16 218
#define FRAME_painb17 219
#define FRAME_painb18 220
#define FRAME_painb19 221
#define FRAME_painb20 222
#define FRAME_death1 223
#define FRAME_death2 224
#define FRAME_death3 225
#define FRAME_death4 226
#define FRAME_death5 227
#define FRAME_death6 228
#define FRAME_death7 229
#define FRAME_death8 230
#define FRAME_death9 231
#define FRAME_death10 232
#define FRAME_death11 233
#define FRAME_death12 234
#define FRAME_death13 235
#define FRAME_deathc1 236
#define FRAME_deathc2 237
#define FRAME_deathc3 238
#define FRAME_deathc4 239
#define FRAME_deathc5 240
#define FRAME_deathc6 241
#define FRAME_deathc7 242
#define FRAME_deathc8 243
#define MODEL_SCALE 1.000000

679
game/m_boss2.c Normal file
View File

@ -0,0 +1,679 @@
/*
Copyright (C) 1997-2001 Id Software, Inc.
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 the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/*
==============================================================================
boss2
==============================================================================
*/
#include "g_local.h"
#include "m_boss2.h"
void BossExplode (edict_t *self);
qboolean infront (edict_t *self, edict_t *other);
static int sound_pain1;
static int sound_pain2;
static int sound_pain3;
static int sound_death;
static int sound_search1;
void boss2_search (edict_t *self)
{
if (random() < 0.5)
gi.sound (self, CHAN_VOICE, sound_search1, 1, ATTN_NONE, 0);
}
void boss2_run (edict_t *self);
void boss2_stand (edict_t *self);
void boss2_dead (edict_t *self);
void boss2_attack (edict_t *self);
void boss2_attack_mg (edict_t *self);
void boss2_reattack_mg (edict_t *self);
void boss2_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point);
void Boss2Rocket (edict_t *self)
{
vec3_t forward, right;
vec3_t start;
vec3_t dir;
vec3_t vec;
AngleVectors (self->s.angles, forward, right, NULL);
//1
G_ProjectSource (self->s.origin, monster_flash_offset[MZ2_BOSS2_ROCKET_1], forward, right, start);
VectorCopy (self->enemy->s.origin, vec);
vec[2] += self->enemy->viewheight;
VectorSubtract (vec, start, dir);
VectorNormalize (dir);
monster_fire_rocket (self, start, dir, 50, 500, MZ2_BOSS2_ROCKET_1);
//2
G_ProjectSource (self->s.origin, monster_flash_offset[MZ2_BOSS2_ROCKET_2], forward, right, start);
VectorCopy (self->enemy->s.origin, vec);
vec[2] += self->enemy->viewheight;
VectorSubtract (vec, start, dir);
VectorNormalize (dir);
monster_fire_rocket (self, start, dir, 50, 500, MZ2_BOSS2_ROCKET_2);
//3
G_ProjectSource (self->s.origin, monster_flash_offset[MZ2_BOSS2_ROCKET_3], forward, right, start);
VectorCopy (self->enemy->s.origin, vec);
vec[2] += self->enemy->viewheight;
VectorSubtract (vec, start, dir);
VectorNormalize (dir);
monster_fire_rocket (self, start, dir, 50, 500, MZ2_BOSS2_ROCKET_3);
//4
G_ProjectSource (self->s.origin, monster_flash_offset[MZ2_BOSS2_ROCKET_4], forward, right, start);
VectorCopy (self->enemy->s.origin, vec);
vec[2] += self->enemy->viewheight;
VectorSubtract (vec, start, dir);
VectorNormalize (dir);
monster_fire_rocket (self, start, dir, 50, 500, MZ2_BOSS2_ROCKET_4);
}
void boss2_firebullet_right (edict_t *self)
{
vec3_t forward, right, target;
vec3_t start;
AngleVectors (self->s.angles, forward, right, NULL);
G_ProjectSource (self->s.origin, monster_flash_offset[MZ2_BOSS2_MACHINEGUN_R1], forward, right, start);
VectorMA (self->enemy->s.origin, -0.2, self->enemy->velocity, target);
target[2] += self->enemy->viewheight;
VectorSubtract (target, start, forward);
VectorNormalize (forward);
monster_fire_bullet (self, start, forward, 6, 4, DEFAULT_BULLET_HSPREAD, DEFAULT_BULLET_VSPREAD, MZ2_BOSS2_MACHINEGUN_R1);
}
void boss2_firebullet_left (edict_t *self)
{
vec3_t forward, right, target;
vec3_t start;
AngleVectors (self->s.angles, forward, right, NULL);
G_ProjectSource (self->s.origin, monster_flash_offset[MZ2_BOSS2_MACHINEGUN_L1], forward, right, start);
VectorMA (self->enemy->s.origin, -0.2, self->enemy->velocity, target);
target[2] += self->enemy->viewheight;
VectorSubtract (target, start, forward);
VectorNormalize (forward);
monster_fire_bullet (self, start, forward, 6, 4, DEFAULT_BULLET_HSPREAD, DEFAULT_BULLET_VSPREAD, MZ2_BOSS2_MACHINEGUN_L1);
}
void Boss2MachineGun (edict_t *self)
{
/* vec3_t forward, right;
vec3_t start;
vec3_t dir;
vec3_t vec;
int flash_number;
AngleVectors (self->s.angles, forward, right, NULL);
flash_number = MZ2_BOSS2_MACHINEGUN_1 + (self->s.frame - FRAME_attack10);
G_ProjectSource (self->s.origin, monster_flash_offset[flash_number], forward, right, start);
VectorCopy (self->enemy->s.origin, vec);
vec[2] += self->enemy->viewheight;
VectorSubtract (vec, start, dir);
VectorNormalize (dir);
monster_fire_bullet (self, start, dir, 3, 4, DEFAULT_BULLET_HSPREAD, DEFAULT_BULLET_VSPREAD, flash_number);
*/
boss2_firebullet_left(self);
boss2_firebullet_right(self);
}
mframe_t boss2_frames_stand [] =
{
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL
};
mmove_t boss2_move_stand = {FRAME_stand30, FRAME_stand50, boss2_frames_stand, NULL};
mframe_t boss2_frames_fidget [] =
{
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL
};
mmove_t boss2_move_fidget = {FRAME_stand1, FRAME_stand30, boss2_frames_fidget, NULL};
mframe_t boss2_frames_walk [] =
{
ai_walk, 8, NULL,
ai_walk, 8, NULL,
ai_walk, 8, NULL,
ai_walk, 8, NULL,
ai_walk, 8, NULL,
ai_walk, 8, NULL,
ai_walk, 8, NULL,
ai_walk, 8, NULL,
ai_walk, 8, NULL,
ai_walk, 8, NULL,
ai_walk, 8, NULL,
ai_walk, 8, NULL,
ai_walk, 8, NULL,
ai_walk, 8, NULL,
ai_walk, 8, NULL,
ai_walk, 8, NULL,
ai_walk, 8, NULL,
ai_walk, 8, NULL,
ai_walk, 8, NULL,
ai_walk, 8, NULL
};
mmove_t boss2_move_walk = {FRAME_walk1, FRAME_walk20, boss2_frames_walk, NULL};
mframe_t boss2_frames_run [] =
{
ai_run, 8, NULL,
ai_run, 8, NULL,
ai_run, 8, NULL,
ai_run, 8, NULL,
ai_run, 8, NULL,
ai_run, 8, NULL,
ai_run, 8, NULL,
ai_run, 8, NULL,
ai_run, 8, NULL,
ai_run, 8, NULL,
ai_run, 8, NULL,
ai_run, 8, NULL,
ai_run, 8, NULL,
ai_run, 8, NULL,
ai_run, 8, NULL,
ai_run, 8, NULL,
ai_run, 8, NULL,
ai_run, 8, NULL,
ai_run, 8, NULL,
ai_run, 8, NULL
};
mmove_t boss2_move_run = {FRAME_walk1, FRAME_walk20, boss2_frames_run, NULL};
mframe_t boss2_frames_attack_pre_mg [] =
{
ai_charge, 1, NULL,
ai_charge, 1, NULL,
ai_charge, 1, NULL,
ai_charge, 1, NULL,
ai_charge, 1, NULL,
ai_charge, 1, NULL,
ai_charge, 1, NULL,
ai_charge, 1, NULL,
ai_charge, 1, boss2_attack_mg
};
mmove_t boss2_move_attack_pre_mg = {FRAME_attack1, FRAME_attack9, boss2_frames_attack_pre_mg, NULL};
// Loop this
mframe_t boss2_frames_attack_mg [] =
{
ai_charge, 1, Boss2MachineGun,
ai_charge, 1, Boss2MachineGun,
ai_charge, 1, Boss2MachineGun,
ai_charge, 1, Boss2MachineGun,
ai_charge, 1, Boss2MachineGun,
ai_charge, 1, boss2_reattack_mg
};
mmove_t boss2_move_attack_mg = {FRAME_attack10, FRAME_attack15, boss2_frames_attack_mg, NULL};
mframe_t boss2_frames_attack_post_mg [] =
{
ai_charge, 1, NULL,
ai_charge, 1, NULL,
ai_charge, 1, NULL,
ai_charge, 1, NULL
};
mmove_t boss2_move_attack_post_mg = {FRAME_attack16, FRAME_attack19, boss2_frames_attack_post_mg, boss2_run};
mframe_t boss2_frames_attack_rocket [] =
{
ai_charge, 1, NULL,
ai_charge, 1, NULL,
ai_charge, 1, NULL,
ai_charge, 1, NULL,
ai_charge, 1, NULL,
ai_charge, 1, NULL,
ai_charge, 1, NULL,
ai_charge, 1, NULL,
ai_charge, 1, NULL,
ai_charge, 1, NULL,
ai_charge, 1, NULL,
ai_charge, 1, NULL,
ai_move, -20, Boss2Rocket,
ai_charge, 1, NULL,
ai_charge, 1, NULL,
ai_charge, 1, NULL,
ai_charge, 1, NULL,
ai_charge, 1, NULL,
ai_charge, 1, NULL,
ai_charge, 1, NULL,
ai_charge, 1, NULL
};
mmove_t boss2_move_attack_rocket = {FRAME_attack20, FRAME_attack40, boss2_frames_attack_rocket, boss2_run};
mframe_t boss2_frames_pain_heavy [] =
{
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL
};
mmove_t boss2_move_pain_heavy = {FRAME_pain2, FRAME_pain19, boss2_frames_pain_heavy, boss2_run};
mframe_t boss2_frames_pain_light [] =
{
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL
};
mmove_t boss2_move_pain_light = {FRAME_pain20, FRAME_pain23, boss2_frames_pain_light, boss2_run};
mframe_t boss2_frames_death [] =
{
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, BossExplode
};
mmove_t boss2_move_death = {FRAME_death2, FRAME_death50, boss2_frames_death, boss2_dead};
void boss2_stand (edict_t *self)
{
self->monsterinfo.currentmove = &boss2_move_stand;
}
void boss2_run (edict_t *self)
{
if (self->monsterinfo.aiflags & AI_STAND_GROUND)
self->monsterinfo.currentmove = &boss2_move_stand;
else
self->monsterinfo.currentmove = &boss2_move_run;
}
void boss2_walk (edict_t *self)
{
self->monsterinfo.currentmove = &boss2_move_walk;
}
void boss2_attack (edict_t *self)
{
vec3_t vec;
float range;
VectorSubtract (self->enemy->s.origin, self->s.origin, vec);
range = VectorLength (vec);
if (range <= 125)
{
self->monsterinfo.currentmove = &boss2_move_attack_pre_mg;
}
else
{
if (random() <= 0.6)
self->monsterinfo.currentmove = &boss2_move_attack_pre_mg;
else
self->monsterinfo.currentmove = &boss2_move_attack_rocket;
}
}
void boss2_attack_mg (edict_t *self)
{
self->monsterinfo.currentmove = &boss2_move_attack_mg;
}
void boss2_reattack_mg (edict_t *self)
{
if ( infront(self, self->enemy) )
if (random() <= 0.7)
self->monsterinfo.currentmove = &boss2_move_attack_mg;
else
self->monsterinfo.currentmove = &boss2_move_attack_post_mg;
else
self->monsterinfo.currentmove = &boss2_move_attack_post_mg;
}
void boss2_pain (edict_t *self, edict_t *other, float kick, int damage)
{
if (self->health < (self->max_health / 2))
self->s.skinnum = 1;
if (level.time < self->pain_debounce_time)
return;
self->pain_debounce_time = level.time + 3;
// American wanted these at no attenuation
if (damage < 10)
{
gi.sound (self, CHAN_VOICE, sound_pain3, 1, ATTN_NONE, 0);
self->monsterinfo.currentmove = &boss2_move_pain_light;
}
else if (damage < 30)
{
gi.sound (self, CHAN_VOICE, sound_pain1, 1, ATTN_NONE, 0);
self->monsterinfo.currentmove = &boss2_move_pain_light;
}
else
{
gi.sound (self, CHAN_VOICE, sound_pain2, 1, ATTN_NONE, 0);
self->monsterinfo.currentmove = &boss2_move_pain_heavy;
}
}
void boss2_dead (edict_t *self)
{
VectorSet (self->mins, -56, -56, 0);
VectorSet (self->maxs, 56, 56, 80);
self->movetype = MOVETYPE_TOSS;
self->svflags |= SVF_DEADMONSTER;
self->nextthink = 0;
gi.linkentity (self);
}
void boss2_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
{
gi.sound (self, CHAN_VOICE, sound_death, 1, ATTN_NONE, 0);
self->deadflag = DEAD_DEAD;
self->takedamage = DAMAGE_NO;
self->count = 0;
self->monsterinfo.currentmove = &boss2_move_death;
#if 0
int n;
self->s.sound = 0;
// check for gib
if (self->health <= self->gib_health)
{
gi.sound (self, CHAN_VOICE, gi.soundindex ("misc/udeath.wav"), 1, ATTN_NORM, 0);
for (n= 0; n < 2; n++)
ThrowGib (self, "models/objects/gibs/bone/tris.md2", damage, GIB_ORGANIC);
for (n= 0; n < 4; n++)
ThrowGib (self, "models/objects/gibs/sm_meat/tris.md2", damage, GIB_ORGANIC);
ThrowHead (self, "models/objects/gibs/head2/tris.md2", damage, GIB_ORGANIC);
self->deadflag = DEAD_DEAD;
return;
}
if (self->deadflag == DEAD_DEAD)
return;
self->deadflag = DEAD_DEAD;
self->takedamage = DAMAGE_YES;
self->monsterinfo.currentmove = &boss2_move_death;
#endif
}
qboolean Boss2_CheckAttack (edict_t *self)
{
vec3_t spot1, spot2;
vec3_t temp;
float chance;
trace_t tr;
qboolean enemy_infront;
int enemy_range;
float enemy_yaw;
if (self->enemy->health > 0)
{
// see if any entities are in the way of the shot
VectorCopy (self->s.origin, spot1);
spot1[2] += self->viewheight;
VectorCopy (self->enemy->s.origin, spot2);
spot2[2] += self->enemy->viewheight;
tr = gi.trace (spot1, NULL, NULL, spot2, self, CONTENTS_SOLID|CONTENTS_MONSTER|CONTENTS_SLIME|CONTENTS_LAVA);
// do we have a clear shot?
if (tr.ent != self->enemy)
return false;
}
enemy_infront = infront(self, self->enemy);
enemy_range = range(self, self->enemy);
VectorSubtract (self->enemy->s.origin, self->s.origin, temp);
enemy_yaw = vectoyaw(temp);
self->ideal_yaw = enemy_yaw;
// melee attack
if (enemy_range == RANGE_MELEE)
{
if (self->monsterinfo.melee)
self->monsterinfo.attack_state = AS_MELEE;
else
self->monsterinfo.attack_state = AS_MISSILE;
return true;
}
// missile attack
if (!self->monsterinfo.attack)
return false;
if (level.time < self->monsterinfo.attack_finished)
return false;
if (enemy_range == RANGE_FAR)
return false;
if (self->monsterinfo.aiflags & AI_STAND_GROUND)
{
chance = 0.4;
}
else if (enemy_range == RANGE_MELEE)
{
chance = 0.8;
}
else if (enemy_range == RANGE_NEAR)
{
chance = 0.8;
}
else if (enemy_range == RANGE_MID)
{
chance = 0.8;
}
else
{
return false;
}
if (random () < chance)
{
self->monsterinfo.attack_state = AS_MISSILE;
self->monsterinfo.attack_finished = level.time + 2*random();
return true;
}
if (self->flags & FL_FLY)
{
if (random() < 0.3)
self->monsterinfo.attack_state = AS_SLIDING;
else
self->monsterinfo.attack_state = AS_STRAIGHT;
}
return false;
}
/*QUAKED monster_boss2 (1 .5 0) (-56 -56 0) (56 56 80) Ambush Trigger_Spawn Sight
*/
void SP_monster_boss2 (edict_t *self)
{
if (deathmatch->value)
{
G_FreeEdict (self);
return;
}
sound_pain1 = gi.soundindex ("bosshovr/bhvpain1.wav");
sound_pain2 = gi.soundindex ("bosshovr/bhvpain2.wav");
sound_pain3 = gi.soundindex ("bosshovr/bhvpain3.wav");
sound_death = gi.soundindex ("bosshovr/bhvdeth1.wav");
sound_search1 = gi.soundindex ("bosshovr/bhvunqv1.wav");
self->s.sound = gi.soundindex ("bosshovr/bhvengn1.wav");
self->movetype = MOVETYPE_STEP;
self->solid = SOLID_BBOX;
self->s.modelindex = gi.modelindex ("models/monsters/boss2/tris.md2");
VectorSet (self->mins, -56, -56, 0);
VectorSet (self->maxs, 56, 56, 80);
self->health = 2000;
self->gib_health = -200;
self->mass = 1000;
self->flags |= FL_IMMUNE_LASER;
self->pain = boss2_pain;
self->die = boss2_die;
self->monsterinfo.stand = boss2_stand;
self->monsterinfo.walk = boss2_walk;
self->monsterinfo.run = boss2_run;
self->monsterinfo.attack = boss2_attack;
self->monsterinfo.search = boss2_search;
self->monsterinfo.checkattack = Boss2_CheckAttack;
gi.linkentity (self);
self->monsterinfo.currentmove = &boss2_move_stand;
self->monsterinfo.scale = MODEL_SCALE;
flymonster_start (self);
}

206
game/m_boss2.h Normal file
View File

@ -0,0 +1,206 @@
/*
Copyright (C) 1997-2001 Id Software, Inc.
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 the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
// G:\quake2\baseq2\models/monsters/boss2
// This file generated by ModelGen - Do NOT Modify
#define FRAME_stand30 0
#define FRAME_stand31 1
#define FRAME_stand32 2
#define FRAME_stand33 3
#define FRAME_stand34 4
#define FRAME_stand35 5
#define FRAME_stand36 6
#define FRAME_stand37 7
#define FRAME_stand38 8
#define FRAME_stand39 9
#define FRAME_stand40 10
#define FRAME_stand41 11
#define FRAME_stand42 12
#define FRAME_stand43 13
#define FRAME_stand44 14
#define FRAME_stand45 15
#define FRAME_stand46 16
#define FRAME_stand47 17
#define FRAME_stand48 18
#define FRAME_stand49 19
#define FRAME_stand50 20
#define FRAME_stand1 21
#define FRAME_stand2 22
#define FRAME_stand3 23
#define FRAME_stand4 24
#define FRAME_stand5 25
#define FRAME_stand6 26
#define FRAME_stand7 27
#define FRAME_stand8 28
#define FRAME_stand9 29
#define FRAME_stand10 30
#define FRAME_stand11 31
#define FRAME_stand12 32
#define FRAME_stand13 33
#define FRAME_stand14 34
#define FRAME_stand15 35
#define FRAME_stand16 36
#define FRAME_stand17 37
#define FRAME_stand18 38
#define FRAME_stand19 39
#define FRAME_stand20 40
#define FRAME_stand21 41
#define FRAME_stand22 42
#define FRAME_stand23 43
#define FRAME_stand24 44
#define FRAME_stand25 45
#define FRAME_stand26 46
#define FRAME_stand27 47
#define FRAME_stand28 48
#define FRAME_stand29 49
#define FRAME_walk1 50
#define FRAME_walk2 51
#define FRAME_walk3 52
#define FRAME_walk4 53
#define FRAME_walk5 54
#define FRAME_walk6 55
#define FRAME_walk7 56
#define FRAME_walk8 57
#define FRAME_walk9 58
#define FRAME_walk10 59
#define FRAME_walk11 60
#define FRAME_walk12 61
#define FRAME_walk13 62
#define FRAME_walk14 63
#define FRAME_walk15 64
#define FRAME_walk16 65
#define FRAME_walk17 66
#define FRAME_walk18 67
#define FRAME_walk19 68
#define FRAME_walk20 69
#define FRAME_attack1 70
#define FRAME_attack2 71
#define FRAME_attack3 72
#define FRAME_attack4 73
#define FRAME_attack5 74
#define FRAME_attack6 75
#define FRAME_attack7 76
#define FRAME_attack8 77
#define FRAME_attack9 78
#define FRAME_attack10 79
#define FRAME_attack11 80
#define FRAME_attack12 81
#define FRAME_attack13 82
#define FRAME_attack14 83
#define FRAME_attack15 84
#define FRAME_attack16 85
#define FRAME_attack17 86
#define FRAME_attack18 87
#define FRAME_attack19 88
#define FRAME_attack20 89
#define FRAME_attack21 90
#define FRAME_attack22 91
#define FRAME_attack23 92
#define FRAME_attack24 93
#define FRAME_attack25 94
#define FRAME_attack26 95
#define FRAME_attack27 96
#define FRAME_attack28 97
#define FRAME_attack29 98
#define FRAME_attack30 99
#define FRAME_attack31 100
#define FRAME_attack32 101
#define FRAME_attack33 102
#define FRAME_attack34 103
#define FRAME_attack35 104
#define FRAME_attack36 105
#define FRAME_attack37 106
#define FRAME_attack38 107
#define FRAME_attack39 108
#define FRAME_attack40 109
#define FRAME_pain2 110
#define FRAME_pain3 111
#define FRAME_pain4 112
#define FRAME_pain5 113
#define FRAME_pain6 114
#define FRAME_pain7 115
#define FRAME_pain8 116
#define FRAME_pain9 117
#define FRAME_pain10 118
#define FRAME_pain11 119
#define FRAME_pain12 120
#define FRAME_pain13 121
#define FRAME_pain14 122
#define FRAME_pain15 123
#define FRAME_pain16 124
#define FRAME_pain17 125
#define FRAME_pain18 126
#define FRAME_pain19 127
#define FRAME_pain20 128
#define FRAME_pain21 129
#define FRAME_pain22 130
#define FRAME_pain23 131
#define FRAME_death2 132
#define FRAME_death3 133
#define FRAME_death4 134
#define FRAME_death5 135
#define FRAME_death6 136
#define FRAME_death7 137
#define FRAME_death8 138
#define FRAME_death9 139
#define FRAME_death10 140
#define FRAME_death11 141
#define FRAME_death12 142
#define FRAME_death13 143
#define FRAME_death14 144
#define FRAME_death15 145
#define FRAME_death16 146
#define FRAME_death17 147
#define FRAME_death18 148
#define FRAME_death19 149
#define FRAME_death20 150
#define FRAME_death21 151
#define FRAME_death22 152
#define FRAME_death23 153
#define FRAME_death24 154
#define FRAME_death25 155
#define FRAME_death26 156
#define FRAME_death27 157
#define FRAME_death28 158
#define FRAME_death29 159
#define FRAME_death30 160
#define FRAME_death31 161
#define FRAME_death32 162
#define FRAME_death33 163
#define FRAME_death34 164
#define FRAME_death35 165
#define FRAME_death36 166
#define FRAME_death37 167
#define FRAME_death38 168
#define FRAME_death39 169
#define FRAME_death40 170
#define FRAME_death41 171
#define FRAME_death42 172
#define FRAME_death43 173
#define FRAME_death44 174
#define FRAME_death45 175
#define FRAME_death46 176
#define FRAME_death47 177
#define FRAME_death48 178
#define FRAME_death49 179
#define FRAME_death50 180
#define MODEL_SCALE 1.000000

76
game/m_boss3.c Normal file
View File

@ -0,0 +1,76 @@
/*
Copyright (C) 1997-2001 Id Software, Inc.
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 the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/*
==============================================================================
boss3
==============================================================================
*/
#include "g_local.h"
#include "m_boss32.h"
void Use_Boss3 (edict_t *ent, edict_t *other, edict_t *activator)
{
gi.WriteByte (svc_temp_entity);
gi.WriteByte (TE_BOSSTPORT);
gi.WritePosition (ent->s.origin);
gi.multicast (ent->s.origin, MULTICAST_PVS);
G_FreeEdict (ent);
}
void Think_Boss3Stand (edict_t *ent)
{
if (ent->s.frame == FRAME_stand260)
ent->s.frame = FRAME_stand201;
else
ent->s.frame++;
ent->nextthink = level.time + FRAMETIME;
}
/*QUAKED monster_boss3_stand (1 .5 0) (-32 -32 0) (32 32 90)
Just stands and cycles in one place until targeted, then teleports away.
*/
void SP_monster_boss3_stand (edict_t *self)
{
if (deathmatch->value)
{
G_FreeEdict (self);
return;
}
self->movetype = MOVETYPE_STEP;
self->solid = SOLID_BBOX;
self->model = "models/monsters/boss3/rider/tris.md2";
self->s.modelindex = gi.modelindex (self->model);
self->s.frame = FRAME_stand201;
gi.soundindex ("misc/bigtele.wav");
VectorSet (self->mins, -32, -32, 0);
VectorSet (self->maxs, 32, 32, 90);
self->use = Use_Boss3;
self->think = Think_Boss3Stand;
self->nextthink = level.time + FRAMETIME;
gi.linkentity (self);
}

749
game/m_boss31.c Normal file
View File

@ -0,0 +1,749 @@
/*
Copyright (C) 1997-2001 Id Software, Inc.
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 the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/*
==============================================================================
jorg
==============================================================================
*/
#include "g_local.h"
#include "m_boss31.h"
extern SP_monster_makron (edict_t *self);
qboolean visible (edict_t *self, edict_t *other);
static int sound_pain1;
static int sound_pain2;
static int sound_pain3;
static int sound_idle;
static int sound_death;
static int sound_search1;
static int sound_search2;
static int sound_search3;
static int sound_attack1;
static int sound_attack2;
static int sound_firegun;
static int sound_step_left;
static int sound_step_right;
static int sound_death_hit;
void BossExplode (edict_t *self);
void MakronToss (edict_t *self);
void jorg_search (edict_t *self)
{
float r;
r = random();
if (r <= 0.3)
gi.sound (self, CHAN_VOICE, sound_search1, 1, ATTN_NORM, 0);
else if (r <= 0.6)
gi.sound (self, CHAN_VOICE, sound_search2, 1, ATTN_NORM, 0);
else
gi.sound (self, CHAN_VOICE, sound_search3, 1, ATTN_NORM, 0);
}
void jorg_dead (edict_t *self);
void jorgBFG (edict_t *self);
void jorgMachineGun (edict_t *self);
void jorg_firebullet (edict_t *self);
void jorg_reattack1(edict_t *self);
void jorg_attack1(edict_t *self);
void jorg_idle(edict_t *self);
void jorg_step_left(edict_t *self);
void jorg_step_right(edict_t *self);
void jorg_death_hit(edict_t *self);
//
// stand
//
mframe_t jorg_frames_stand []=
{
ai_stand, 0, jorg_idle,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL, // 10
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL, // 20
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL, // 30
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 19, NULL,
ai_stand, 11, jorg_step_left,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 6, NULL,
ai_stand, 9, jorg_step_right,
ai_stand, 0, NULL, // 40
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, -2, NULL,
ai_stand, -17, jorg_step_left,
ai_stand, 0, NULL,
ai_stand, -12, NULL, // 50
ai_stand, -14, jorg_step_right // 51
};
mmove_t jorg_move_stand = {FRAME_stand01, FRAME_stand51, jorg_frames_stand, NULL};
void jorg_idle (edict_t *self)
{
gi.sound (self, CHAN_VOICE, sound_idle, 1, ATTN_NORM,0);
}
void jorg_death_hit (edict_t *self)
{
gi.sound (self, CHAN_BODY, sound_death_hit, 1, ATTN_NORM,0);
}
void jorg_step_left (edict_t *self)
{
gi.sound (self, CHAN_BODY, sound_step_left, 1, ATTN_NORM,0);
}
void jorg_step_right (edict_t *self)
{
gi.sound (self, CHAN_BODY, sound_step_right, 1, ATTN_NORM,0);
}
void jorg_stand (edict_t *self)
{
self->monsterinfo.currentmove = &jorg_move_stand;
}
mframe_t jorg_frames_run [] =
{
ai_run, 17, jorg_step_left,
ai_run, 0, NULL,
ai_run, 0, NULL,
ai_run, 0, NULL,
ai_run, 12, NULL,
ai_run, 8, NULL,
ai_run, 10, NULL,
ai_run, 33, jorg_step_right,
ai_run, 0, NULL,
ai_run, 0, NULL,
ai_run, 0, NULL,
ai_run, 9, NULL,
ai_run, 9, NULL,
ai_run, 9, NULL
};
mmove_t jorg_move_run = {FRAME_walk06, FRAME_walk19, jorg_frames_run, NULL};
//
// walk
//
mframe_t jorg_frames_start_walk [] =
{
ai_walk, 5, NULL,
ai_walk, 6, NULL,
ai_walk, 7, NULL,
ai_walk, 9, NULL,
ai_walk, 15, NULL
};
mmove_t jorg_move_start_walk = {FRAME_walk01, FRAME_walk05, jorg_frames_start_walk, NULL};
mframe_t jorg_frames_walk [] =
{
ai_walk, 17, NULL,
ai_walk, 0, NULL,
ai_walk, 0, NULL,
ai_walk, 0, NULL,
ai_walk, 12, NULL,
ai_walk, 8, NULL,
ai_walk, 10, NULL,
ai_walk, 33, NULL,
ai_walk, 0, NULL,
ai_walk, 0, NULL,
ai_walk, 0, NULL,
ai_walk, 9, NULL,
ai_walk, 9, NULL,
ai_walk, 9, NULL
};
mmove_t jorg_move_walk = {FRAME_walk06, FRAME_walk19, jorg_frames_walk, NULL};
mframe_t jorg_frames_end_walk [] =
{
ai_walk, 11, NULL,
ai_walk, 0, NULL,
ai_walk, 0, NULL,
ai_walk, 0, NULL,
ai_walk, 8, NULL,
ai_walk, -8, NULL
};
mmove_t jorg_move_end_walk = {FRAME_walk20, FRAME_walk25, jorg_frames_end_walk, NULL};
void jorg_walk (edict_t *self)
{
self->monsterinfo.currentmove = &jorg_move_walk;
}
void jorg_run (edict_t *self)
{
if (self->monsterinfo.aiflags & AI_STAND_GROUND)
self->monsterinfo.currentmove = &jorg_move_stand;
else
self->monsterinfo.currentmove = &jorg_move_run;
}
mframe_t jorg_frames_pain3 [] =
{
ai_move, -28, NULL,
ai_move, -6, NULL,
ai_move, -3, jorg_step_left,
ai_move, -9, NULL,
ai_move, 0, jorg_step_right,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, -7, NULL,
ai_move, 1, NULL,
ai_move, -11, NULL,
ai_move, -4, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 10, NULL,
ai_move, 11, NULL,
ai_move, 0, NULL,
ai_move, 10, NULL,
ai_move, 3, NULL,
ai_move, 10, NULL,
ai_move, 7, jorg_step_left,
ai_move, 17, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, jorg_step_right
};
mmove_t jorg_move_pain3 = {FRAME_pain301, FRAME_pain325, jorg_frames_pain3, jorg_run};
mframe_t jorg_frames_pain2 [] =
{
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL
};
mmove_t jorg_move_pain2 = {FRAME_pain201, FRAME_pain203, jorg_frames_pain2, jorg_run};
mframe_t jorg_frames_pain1 [] =
{
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL
};
mmove_t jorg_move_pain1 = {FRAME_pain101, FRAME_pain103, jorg_frames_pain1, jorg_run};
mframe_t jorg_frames_death1 [] =
{
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL, // 10
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL, // 20
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL, // 30
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL, // 40
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, MakronToss,
ai_move, 0, BossExplode // 50
};
mmove_t jorg_move_death = {FRAME_death01, FRAME_death50, jorg_frames_death1, jorg_dead};
mframe_t jorg_frames_attack2 []=
{
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, jorgBFG,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL
};
mmove_t jorg_move_attack2 = {FRAME_attak201, FRAME_attak213, jorg_frames_attack2, jorg_run};
mframe_t jorg_frames_start_attack1 [] =
{
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL
};
mmove_t jorg_move_start_attack1 = {FRAME_attak101, FRAME_attak108, jorg_frames_start_attack1, jorg_attack1};
mframe_t jorg_frames_attack1[]=
{
ai_charge, 0, jorg_firebullet,
ai_charge, 0, jorg_firebullet,
ai_charge, 0, jorg_firebullet,
ai_charge, 0, jorg_firebullet,
ai_charge, 0, jorg_firebullet,
ai_charge, 0, jorg_firebullet
};
mmove_t jorg_move_attack1 = {FRAME_attak109, FRAME_attak114, jorg_frames_attack1, jorg_reattack1};
mframe_t jorg_frames_end_attack1[]=
{
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL
};
mmove_t jorg_move_end_attack1 = {FRAME_attak115, FRAME_attak118, jorg_frames_end_attack1, jorg_run};
void jorg_reattack1(edict_t *self)
{
if (visible(self, self->enemy))
if (random() < 0.9)
self->monsterinfo.currentmove = &jorg_move_attack1;
else
{
self->s.sound = 0;
self->monsterinfo.currentmove = &jorg_move_end_attack1;
}
else
{
self->s.sound = 0;
self->monsterinfo.currentmove = &jorg_move_end_attack1;
}
}
void jorg_attack1(edict_t *self)
{
self->monsterinfo.currentmove = &jorg_move_attack1;
}
void jorg_pain (edict_t *self, edict_t *other, float kick, int damage)
{
if (self->health < (self->max_health / 2))
self->s.skinnum = 1;
self->s.sound = 0;
if (level.time < self->pain_debounce_time)
return;
// Lessen the chance of him going into his pain frames if he takes little damage
if (damage <= 40)
if (random()<=0.6)
return;
/*
If he's entering his attack1 or using attack1, lessen the chance of him
going into pain
*/
if ( (self->s.frame >= FRAME_attak101) && (self->s.frame <= FRAME_attak108) )
if (random() <= 0.005)
return;
if ( (self->s.frame >= FRAME_attak109) && (self->s.frame <= FRAME_attak114) )
if (random() <= 0.00005)
return;
if ( (self->s.frame >= FRAME_attak201) && (self->s.frame <= FRAME_attak208) )
if (random() <= 0.005)
return;
self->pain_debounce_time = level.time + 3;
if (skill->value == 3)
return; // no pain anims in nightmare
if (damage <= 50)
{
gi.sound (self, CHAN_VOICE, sound_pain1, 1, ATTN_NORM,0);
self->monsterinfo.currentmove = &jorg_move_pain1;
}
else if (damage <= 100)
{
gi.sound (self, CHAN_VOICE, sound_pain2, 1, ATTN_NORM,0);
self->monsterinfo.currentmove = &jorg_move_pain2;
}
else
{
if (random() <= 0.3)
{
gi.sound (self, CHAN_VOICE, sound_pain3, 1, ATTN_NORM,0);
self->monsterinfo.currentmove = &jorg_move_pain3;
}
}
};
void jorgBFG (edict_t *self)
{
vec3_t forward, right;
vec3_t start;
vec3_t dir;
vec3_t vec;
AngleVectors (self->s.angles, forward, right, NULL);
G_ProjectSource (self->s.origin, monster_flash_offset[MZ2_JORG_BFG_1], forward, right, start);
VectorCopy (self->enemy->s.origin, vec);
vec[2] += self->enemy->viewheight;
VectorSubtract (vec, start, dir);
VectorNormalize (dir);
gi.sound (self, CHAN_VOICE, sound_attack2, 1, ATTN_NORM, 0);
/*void monster_fire_bfg (edict_t *self,
vec3_t start,
vec3_t aimdir,
int damage,
int speed,
int kick,
float damage_radius,
int flashtype)*/
monster_fire_bfg (self, start, dir, 50, 300, 100, 200, MZ2_JORG_BFG_1);
}
void jorg_firebullet_right (edict_t *self)
{
vec3_t forward, right, target;
vec3_t start;
AngleVectors (self->s.angles, forward, right, NULL);
G_ProjectSource (self->s.origin, monster_flash_offset[MZ2_JORG_MACHINEGUN_R1], forward, right, start);
VectorMA (self->enemy->s.origin, -0.2, self->enemy->velocity, target);
target[2] += self->enemy->viewheight;
VectorSubtract (target, start, forward);
VectorNormalize (forward);
monster_fire_bullet (self, start, forward, 6, 4, DEFAULT_BULLET_HSPREAD, DEFAULT_BULLET_VSPREAD, MZ2_JORG_MACHINEGUN_R1);
}
void jorg_firebullet_left (edict_t *self)
{
vec3_t forward, right, target;
vec3_t start;
AngleVectors (self->s.angles, forward, right, NULL);
G_ProjectSource (self->s.origin, monster_flash_offset[MZ2_JORG_MACHINEGUN_L1], forward, right, start);
VectorMA (self->enemy->s.origin, -0.2, self->enemy->velocity, target);
target[2] += self->enemy->viewheight;
VectorSubtract (target, start, forward);
VectorNormalize (forward);
monster_fire_bullet (self, start, forward, 6, 4, DEFAULT_BULLET_HSPREAD, DEFAULT_BULLET_VSPREAD, MZ2_JORG_MACHINEGUN_L1);
}
void jorg_firebullet (edict_t *self)
{
jorg_firebullet_left(self);
jorg_firebullet_right(self);
};
void jorg_attack(edict_t *self)
{
vec3_t vec;
float range;
VectorSubtract (self->enemy->s.origin, self->s.origin, vec);
range = VectorLength (vec);
if (random() <= 0.75)
{
gi.sound (self, CHAN_VOICE, sound_attack1, 1, ATTN_NORM,0);
self->s.sound = gi.soundindex ("boss3/w_loop.wav");
self->monsterinfo.currentmove = &jorg_move_start_attack1;
}
else
{
gi.sound (self, CHAN_VOICE, sound_attack2, 1, ATTN_NORM,0);
self->monsterinfo.currentmove = &jorg_move_attack2;
}
}
void jorg_dead (edict_t *self)
{
#if 0
edict_t *tempent;
/*
VectorSet (self->mins, -16, -16, -24);
VectorSet (self->maxs, 16, 16, -8);
*/
// Jorg is on modelindex2. Do not clear him.
VectorSet (self->mins, -60, -60, 0);
VectorSet (self->maxs, 60, 60, 72);
self->movetype = MOVETYPE_TOSS;
self->nextthink = 0;
gi.linkentity (self);
tempent = G_Spawn();
VectorCopy (self->s.origin, tempent->s.origin);
VectorCopy (self->s.angles, tempent->s.angles);
tempent->killtarget = self->killtarget;
tempent->target = self->target;
tempent->activator = self->enemy;
self->killtarget = 0;
self->target = 0;
SP_monster_makron (tempent);
#endif
}
void jorg_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
{
gi.sound (self, CHAN_VOICE, sound_death, 1, ATTN_NORM, 0);
self->deadflag = DEAD_DEAD;
self->takedamage = DAMAGE_NO;
self->s.sound = 0;
self->count = 0;
self->monsterinfo.currentmove = &jorg_move_death;
}
qboolean Jorg_CheckAttack (edict_t *self)
{
vec3_t spot1, spot2;
vec3_t temp;
float chance;
trace_t tr;
qboolean enemy_infront;
int enemy_range;
float enemy_yaw;
if (self->enemy->health > 0)
{
// see if any entities are in the way of the shot
VectorCopy (self->s.origin, spot1);
spot1[2] += self->viewheight;
VectorCopy (self->enemy->s.origin, spot2);
spot2[2] += self->enemy->viewheight;
tr = gi.trace (spot1, NULL, NULL, spot2, self, CONTENTS_SOLID|CONTENTS_MONSTER|CONTENTS_SLIME|CONTENTS_LAVA);
// do we have a clear shot?
if (tr.ent != self->enemy)
return false;
}
enemy_infront = infront(self, self->enemy);
enemy_range = range(self, self->enemy);
VectorSubtract (self->enemy->s.origin, self->s.origin, temp);
enemy_yaw = vectoyaw(temp);
self->ideal_yaw = enemy_yaw;
// melee attack
if (enemy_range == RANGE_MELEE)
{
if (self->monsterinfo.melee)
self->monsterinfo.attack_state = AS_MELEE;
else
self->monsterinfo.attack_state = AS_MISSILE;
return true;
}
// missile attack
if (!self->monsterinfo.attack)
return false;
if (level.time < self->monsterinfo.attack_finished)
return false;
if (enemy_range == RANGE_FAR)
return false;
if (self->monsterinfo.aiflags & AI_STAND_GROUND)
{
chance = 0.4;
}
else if (enemy_range == RANGE_MELEE)
{
chance = 0.8;
}
else if (enemy_range == RANGE_NEAR)
{
chance = 0.4;
}
else if (enemy_range == RANGE_MID)
{
chance = 0.2;
}
else
{
return false;
}
if (random () < chance)
{
self->monsterinfo.attack_state = AS_MISSILE;
self->monsterinfo.attack_finished = level.time + 2*random();
return true;
}
if (self->flags & FL_FLY)
{
if (random() < 0.3)
self->monsterinfo.attack_state = AS_SLIDING;
else
self->monsterinfo.attack_state = AS_STRAIGHT;
}
return false;
}
void MakronPrecache (void);
/*QUAKED monster_jorg (1 .5 0) (-80 -80 0) (90 90 140) Ambush Trigger_Spawn Sight
*/
void SP_monster_jorg (edict_t *self)
{
if (deathmatch->value)
{
G_FreeEdict (self);
return;
}
sound_pain1 = gi.soundindex ("boss3/bs3pain1.wav");
sound_pain2 = gi.soundindex ("boss3/bs3pain2.wav");
sound_pain3 = gi.soundindex ("boss3/bs3pain3.wav");
sound_death = gi.soundindex ("boss3/bs3deth1.wav");
sound_attack1 = gi.soundindex ("boss3/bs3atck1.wav");
sound_attack2 = gi.soundindex ("boss3/bs3atck2.wav");
sound_search1 = gi.soundindex ("boss3/bs3srch1.wav");
sound_search2 = gi.soundindex ("boss3/bs3srch2.wav");
sound_search3 = gi.soundindex ("boss3/bs3srch3.wav");
sound_idle = gi.soundindex ("boss3/bs3idle1.wav");
sound_step_left = gi.soundindex ("boss3/step1.wav");
sound_step_right = gi.soundindex ("boss3/step2.wav");
sound_firegun = gi.soundindex ("boss3/xfire.wav");
sound_death_hit = gi.soundindex ("boss3/d_hit.wav");
MakronPrecache ();
self->movetype = MOVETYPE_STEP;
self->solid = SOLID_BBOX;
self->s.modelindex = gi.modelindex ("models/monsters/boss3/rider/tris.md2");
self->s.modelindex2 = gi.modelindex ("models/monsters/boss3/jorg/tris.md2");
VectorSet (self->mins, -80, -80, 0);
VectorSet (self->maxs, 80, 80, 140);
self->health = 3000;
self->gib_health = -2000;
self->mass = 1000;
self->pain = jorg_pain;
self->die = jorg_die;
self->monsterinfo.stand = jorg_stand;
self->monsterinfo.walk = jorg_walk;
self->monsterinfo.run = jorg_run;
self->monsterinfo.dodge = NULL;
self->monsterinfo.attack = jorg_attack;
self->monsterinfo.search = jorg_search;
self->monsterinfo.melee = NULL;
self->monsterinfo.sight = NULL;
self->monsterinfo.checkattack = Jorg_CheckAttack;
gi.linkentity (self);
self->monsterinfo.currentmove = &jorg_move_stand;
self->monsterinfo.scale = MODEL_SCALE;
walkmonster_start(self);
}

213
game/m_boss31.h Normal file
View File

@ -0,0 +1,213 @@
/*
Copyright (C) 1997-2001 Id Software, Inc.
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 the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
// G:\quake2\baseq2\models/monsters/boss3/jorg
// This file generated by ModelGen - Do NOT Modify
#define FRAME_attak101 0
#define FRAME_attak102 1
#define FRAME_attak103 2
#define FRAME_attak104 3
#define FRAME_attak105 4
#define FRAME_attak106 5
#define FRAME_attak107 6
#define FRAME_attak108 7
#define FRAME_attak109 8
#define FRAME_attak110 9
#define FRAME_attak111 10
#define FRAME_attak112 11
#define FRAME_attak113 12
#define FRAME_attak114 13
#define FRAME_attak115 14
#define FRAME_attak116 15
#define FRAME_attak117 16
#define FRAME_attak118 17
#define FRAME_attak201 18
#define FRAME_attak202 19
#define FRAME_attak203 20
#define FRAME_attak204 21
#define FRAME_attak205 22
#define FRAME_attak206 23
#define FRAME_attak207 24
#define FRAME_attak208 25
#define FRAME_attak209 26
#define FRAME_attak210 27
#define FRAME_attak211 28
#define FRAME_attak212 29
#define FRAME_attak213 30
#define FRAME_death01 31
#define FRAME_death02 32
#define FRAME_death03 33
#define FRAME_death04 34
#define FRAME_death05 35
#define FRAME_death06 36
#define FRAME_death07 37
#define FRAME_death08 38
#define FRAME_death09 39
#define FRAME_death10 40
#define FRAME_death11 41
#define FRAME_death12 42
#define FRAME_death13 43
#define FRAME_death14 44
#define FRAME_death15 45
#define FRAME_death16 46
#define FRAME_death17 47
#define FRAME_death18 48
#define FRAME_death19 49
#define FRAME_death20 50
#define FRAME_death21 51
#define FRAME_death22 52
#define FRAME_death23 53
#define FRAME_death24 54
#define FRAME_death25 55
#define FRAME_death26 56
#define FRAME_death27 57
#define FRAME_death28 58
#define FRAME_death29 59
#define FRAME_death30 60
#define FRAME_death31 61
#define FRAME_death32 62
#define FRAME_death33 63
#define FRAME_death34 64
#define FRAME_death35 65
#define FRAME_death36 66
#define FRAME_death37 67
#define FRAME_death38 68
#define FRAME_death39 69
#define FRAME_death40 70
#define FRAME_death41 71
#define FRAME_death42 72
#define FRAME_death43 73
#define FRAME_death44 74
#define FRAME_death45 75
#define FRAME_death46 76
#define FRAME_death47 77
#define FRAME_death48 78
#define FRAME_death49 79
#define FRAME_death50 80
#define FRAME_pain101 81
#define FRAME_pain102 82
#define FRAME_pain103 83
#define FRAME_pain201 84
#define FRAME_pain202 85
#define FRAME_pain203 86
#define FRAME_pain301 87
#define FRAME_pain302 88
#define FRAME_pain303 89
#define FRAME_pain304 90
#define FRAME_pain305 91
#define FRAME_pain306 92
#define FRAME_pain307 93
#define FRAME_pain308 94
#define FRAME_pain309 95
#define FRAME_pain310 96
#define FRAME_pain311 97
#define FRAME_pain312 98
#define FRAME_pain313 99
#define FRAME_pain314 100
#define FRAME_pain315 101
#define FRAME_pain316 102
#define FRAME_pain317 103
#define FRAME_pain318 104
#define FRAME_pain319 105
#define FRAME_pain320 106
#define FRAME_pain321 107
#define FRAME_pain322 108
#define FRAME_pain323 109
#define FRAME_pain324 110
#define FRAME_pain325 111
#define FRAME_stand01 112
#define FRAME_stand02 113
#define FRAME_stand03 114
#define FRAME_stand04 115
#define FRAME_stand05 116
#define FRAME_stand06 117
#define FRAME_stand07 118
#define FRAME_stand08 119
#define FRAME_stand09 120
#define FRAME_stand10 121
#define FRAME_stand11 122
#define FRAME_stand12 123
#define FRAME_stand13 124
#define FRAME_stand14 125
#define FRAME_stand15 126
#define FRAME_stand16 127
#define FRAME_stand17 128
#define FRAME_stand18 129
#define FRAME_stand19 130
#define FRAME_stand20 131
#define FRAME_stand21 132
#define FRAME_stand22 133
#define FRAME_stand23 134
#define FRAME_stand24 135
#define FRAME_stand25 136
#define FRAME_stand26 137
#define FRAME_stand27 138
#define FRAME_stand28 139
#define FRAME_stand29 140
#define FRAME_stand30 141
#define FRAME_stand31 142
#define FRAME_stand32 143
#define FRAME_stand33 144
#define FRAME_stand34 145
#define FRAME_stand35 146
#define FRAME_stand36 147
#define FRAME_stand37 148
#define FRAME_stand38 149
#define FRAME_stand39 150
#define FRAME_stand40 151
#define FRAME_stand41 152
#define FRAME_stand42 153
#define FRAME_stand43 154
#define FRAME_stand44 155
#define FRAME_stand45 156
#define FRAME_stand46 157
#define FRAME_stand47 158
#define FRAME_stand48 159
#define FRAME_stand49 160
#define FRAME_stand50 161
#define FRAME_stand51 162
#define FRAME_walk01 163
#define FRAME_walk02 164
#define FRAME_walk03 165
#define FRAME_walk04 166
#define FRAME_walk05 167
#define FRAME_walk06 168
#define FRAME_walk07 169
#define FRAME_walk08 170
#define FRAME_walk09 171
#define FRAME_walk10 172
#define FRAME_walk11 173
#define FRAME_walk12 174
#define FRAME_walk13 175
#define FRAME_walk14 176
#define FRAME_walk15 177
#define FRAME_walk16 178
#define FRAME_walk17 179
#define FRAME_walk18 180
#define FRAME_walk19 181
#define FRAME_walk20 182
#define FRAME_walk21 183
#define FRAME_walk22 184
#define FRAME_walk23 185
#define FRAME_walk24 186
#define FRAME_walk25 187
#define MODEL_SCALE 1.000000

913
game/m_boss32.c Normal file
View File

@ -0,0 +1,913 @@
/*
Copyright (C) 1997-2001 Id Software, Inc.
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 the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/*
==============================================================================
Makron -- Final Boss
==============================================================================
*/
#include "g_local.h"
#include "m_boss32.h"
qboolean visible (edict_t *self, edict_t *other);
void MakronRailgun (edict_t *self);
void MakronSaveloc (edict_t *self);
void MakronHyperblaster (edict_t *self);
void makron_step_left (edict_t *self);
void makron_step_right (edict_t *self);
void makronBFG (edict_t *self);
void makron_dead (edict_t *self);
static int sound_pain4;
static int sound_pain5;
static int sound_pain6;
static int sound_death;
static int sound_step_left;
static int sound_step_right;
static int sound_attack_bfg;
static int sound_brainsplorch;
static int sound_prerailgun;
static int sound_popup;
static int sound_taunt1;
static int sound_taunt2;
static int sound_taunt3;
static int sound_hit;
void makron_taunt (edict_t *self)
{
float r;
r=random();
if (r <= 0.3)
gi.sound (self, CHAN_AUTO, sound_taunt1, 1, ATTN_NONE, 0);
else if (r <= 0.6)
gi.sound (self, CHAN_AUTO, sound_taunt2, 1, ATTN_NONE, 0);
else
gi.sound (self, CHAN_AUTO, sound_taunt3, 1, ATTN_NONE, 0);
}
//
// stand
//
mframe_t makron_frames_stand []=
{
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL, // 10
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL, // 20
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL, // 30
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL, // 40
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL, // 50
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL // 60
};
mmove_t makron_move_stand = {FRAME_stand201, FRAME_stand260, makron_frames_stand, NULL};
void makron_stand (edict_t *self)
{
self->monsterinfo.currentmove = &makron_move_stand;
}
mframe_t makron_frames_run [] =
{
ai_run, 3, makron_step_left,
ai_run, 12, NULL,
ai_run, 8, NULL,
ai_run, 8, NULL,
ai_run, 8, makron_step_right,
ai_run, 6, NULL,
ai_run, 12, NULL,
ai_run, 9, NULL,
ai_run, 6, NULL,
ai_run, 12, NULL
};
mmove_t makron_move_run = {FRAME_walk204, FRAME_walk213, makron_frames_run, NULL};
void makron_hit (edict_t *self)
{
gi.sound (self, CHAN_AUTO, sound_hit, 1, ATTN_NONE,0);
}
void makron_popup (edict_t *self)
{
gi.sound (self, CHAN_BODY, sound_popup, 1, ATTN_NONE,0);
}
void makron_step_left (edict_t *self)
{
gi.sound (self, CHAN_BODY, sound_step_left, 1, ATTN_NORM,0);
}
void makron_step_right (edict_t *self)
{
gi.sound (self, CHAN_BODY, sound_step_right, 1, ATTN_NORM,0);
}
void makron_brainsplorch (edict_t *self)
{
gi.sound (self, CHAN_VOICE, sound_brainsplorch, 1, ATTN_NORM,0);
}
void makron_prerailgun (edict_t *self)
{
gi.sound (self, CHAN_WEAPON, sound_prerailgun, 1, ATTN_NORM,0);
}
mframe_t makron_frames_walk [] =
{
ai_walk, 3, makron_step_left,
ai_walk, 12, NULL,
ai_walk, 8, NULL,
ai_walk, 8, NULL,
ai_walk, 8, makron_step_right,
ai_walk, 6, NULL,
ai_walk, 12, NULL,
ai_walk, 9, NULL,
ai_walk, 6, NULL,
ai_walk, 12, NULL
};
mmove_t makron_move_walk = {FRAME_walk204, FRAME_walk213, makron_frames_run, NULL};
void makron_walk (edict_t *self)
{
self->monsterinfo.currentmove = &makron_move_walk;
}
void makron_run (edict_t *self)
{
if (self->monsterinfo.aiflags & AI_STAND_GROUND)
self->monsterinfo.currentmove = &makron_move_stand;
else
self->monsterinfo.currentmove = &makron_move_run;
}
mframe_t makron_frames_pain6 [] =
{
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL, // 10
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, makron_popup,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL, // 20
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, makron_taunt,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL
};
mmove_t makron_move_pain6 = {FRAME_pain601, FRAME_pain627, makron_frames_pain6, makron_run};
mframe_t makron_frames_pain5 [] =
{
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL
};
mmove_t makron_move_pain5 = {FRAME_pain501, FRAME_pain504, makron_frames_pain5, makron_run};
mframe_t makron_frames_pain4 [] =
{
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL
};
mmove_t makron_move_pain4 = {FRAME_pain401, FRAME_pain404, makron_frames_pain4, makron_run};
mframe_t makron_frames_death2 [] =
{
ai_move, -15, NULL,
ai_move, 3, NULL,
ai_move, -12, NULL,
ai_move, 0, makron_step_left,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL, // 10
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 11, NULL,
ai_move, 12, NULL,
ai_move, 11, makron_step_right,
ai_move, 0, NULL,
ai_move, 0, NULL, // 20
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL, // 30
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 5, NULL,
ai_move, 7, NULL,
ai_move, 6, makron_step_left,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, -1, NULL,
ai_move, 2, NULL, // 40
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL, // 50
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, -6, NULL,
ai_move, -4, NULL,
ai_move, -6, makron_step_right,
ai_move, -4, NULL,
ai_move, -4, makron_step_left,
ai_move, 0, NULL,
ai_move, 0, NULL, // 60
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, -2, NULL,
ai_move, -5, NULL,
ai_move, -3, makron_step_right,
ai_move, -8, NULL,
ai_move, -3, makron_step_left,
ai_move, -7, NULL,
ai_move, -4, NULL,
ai_move, -4, makron_step_right, // 70
ai_move, -6, NULL,
ai_move, -7, NULL,
ai_move, 0, makron_step_left,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL, // 80
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, -2, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 2, NULL,
ai_move, 0, NULL, // 90
ai_move, 27, makron_hit,
ai_move, 26, NULL,
ai_move, 0, makron_brainsplorch,
ai_move, 0, NULL,
ai_move, 0, NULL // 95
};
mmove_t makron_move_death2 = {FRAME_death201, FRAME_death295, makron_frames_death2, makron_dead};
mframe_t makron_frames_death3 [] =
{
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL
};
mmove_t makron_move_death3 = {FRAME_death301, FRAME_death320, makron_frames_death3, NULL};
mframe_t makron_frames_sight [] =
{
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL
};
mmove_t makron_move_sight= {FRAME_active01, FRAME_active13, makron_frames_sight, makron_run};
void makronBFG (edict_t *self)
{
vec3_t forward, right;
vec3_t start;
vec3_t dir;
vec3_t vec;
AngleVectors (self->s.angles, forward, right, NULL);
G_ProjectSource (self->s.origin, monster_flash_offset[MZ2_MAKRON_BFG], forward, right, start);
VectorCopy (self->enemy->s.origin, vec);
vec[2] += self->enemy->viewheight;
VectorSubtract (vec, start, dir);
VectorNormalize (dir);
gi.sound (self, CHAN_VOICE, sound_attack_bfg, 1, ATTN_NORM, 0);
monster_fire_bfg (self, start, dir, 50, 300, 100, 300, MZ2_MAKRON_BFG);
}
mframe_t makron_frames_attack3 []=
{
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, makronBFG, // FIXME: BFG Attack here
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL
};
mmove_t makron_move_attack3 = {FRAME_attak301, FRAME_attak308, makron_frames_attack3, makron_run};
mframe_t makron_frames_attack4[]=
{
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_move, 0, MakronHyperblaster, // fire
ai_move, 0, MakronHyperblaster, // fire
ai_move, 0, MakronHyperblaster, // fire
ai_move, 0, MakronHyperblaster, // fire
ai_move, 0, MakronHyperblaster, // fire
ai_move, 0, MakronHyperblaster, // fire
ai_move, 0, MakronHyperblaster, // fire
ai_move, 0, MakronHyperblaster, // fire
ai_move, 0, MakronHyperblaster, // fire
ai_move, 0, MakronHyperblaster, // fire
ai_move, 0, MakronHyperblaster, // fire
ai_move, 0, MakronHyperblaster, // fire
ai_move, 0, MakronHyperblaster, // fire
ai_move, 0, MakronHyperblaster, // fire
ai_move, 0, MakronHyperblaster, // fire
ai_move, 0, MakronHyperblaster, // fire
ai_move, 0, MakronHyperblaster, // fire
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL
};
mmove_t makron_move_attack4 = {FRAME_attak401, FRAME_attak426, makron_frames_attack4, makron_run};
mframe_t makron_frames_attack5[]=
{
ai_charge, 0, makron_prerailgun,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, MakronSaveloc,
ai_move, 0, MakronRailgun, // Fire railgun
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL
};
mmove_t makron_move_attack5 = {FRAME_attak501, FRAME_attak516, makron_frames_attack5, makron_run};
void MakronSaveloc (edict_t *self)
{
VectorCopy (self->enemy->s.origin, self->pos1); //save for aiming the shot
self->pos1[2] += self->enemy->viewheight;
};
// FIXME: He's not firing from the proper Z
void MakronRailgun (edict_t *self)
{
vec3_t start;
vec3_t dir;
vec3_t forward, right;
AngleVectors (self->s.angles, forward, right, NULL);
G_ProjectSource (self->s.origin, monster_flash_offset[MZ2_MAKRON_RAILGUN_1], forward, right, start);
// calc direction to where we targted
VectorSubtract (self->pos1, start, dir);
VectorNormalize (dir);
monster_fire_railgun (self, start, dir, 50, 100, MZ2_MAKRON_RAILGUN_1);
}
// FIXME: This is all wrong. He's not firing at the proper angles.
void MakronHyperblaster (edict_t *self)
{
vec3_t dir;
vec3_t vec;
vec3_t start;
vec3_t forward, right;
int flash_number;
flash_number = MZ2_MAKRON_BLASTER_1 + (self->s.frame - FRAME_attak405);
AngleVectors (self->s.angles, forward, right, NULL);
G_ProjectSource (self->s.origin, monster_flash_offset[flash_number], forward, right, start);
if (self->enemy)
{
VectorCopy (self->enemy->s.origin, vec);
vec[2] += self->enemy->viewheight;
VectorSubtract (vec, start, vec);
vectoangles (vec, vec);
dir[0] = vec[0];
}
else
{
dir[0] = 0;
}
if (self->s.frame <= FRAME_attak413)
dir[1] = self->s.angles[1] - 10 * (self->s.frame - FRAME_attak413);
else
dir[1] = self->s.angles[1] + 10 * (self->s.frame - FRAME_attak421);
dir[2] = 0;
AngleVectors (dir, forward, NULL, NULL);
monster_fire_blaster (self, start, forward, 15, 1000, MZ2_MAKRON_BLASTER_1, EF_BLASTER);
}
void makron_pain (edict_t *self, edict_t *other, float kick, int damage)
{
if (self->health < (self->max_health / 2))
self->s.skinnum = 1;
if (level.time < self->pain_debounce_time)
return;
// Lessen the chance of him going into his pain frames
if (damage <=25)
if (random()<0.2)
return;
self->pain_debounce_time = level.time + 3;
if (skill->value == 3)
return; // no pain anims in nightmare
if (damage <= 40)
{
gi.sound (self, CHAN_VOICE, sound_pain4, 1, ATTN_NONE,0);
self->monsterinfo.currentmove = &makron_move_pain4;
}
else if (damage <= 110)
{
gi.sound (self, CHAN_VOICE, sound_pain5, 1, ATTN_NONE,0);
self->monsterinfo.currentmove = &makron_move_pain5;
}
else
{
if (damage <= 150)
if (random() <= 0.45)
{
gi.sound (self, CHAN_VOICE, sound_pain6, 1, ATTN_NONE,0);
self->monsterinfo.currentmove = &makron_move_pain6;
}
else
if (random() <= 0.35)
{
gi.sound (self, CHAN_VOICE, sound_pain6, 1, ATTN_NONE,0);
self->monsterinfo.currentmove = &makron_move_pain6;
}
}
};
void makron_sight(edict_t *self, edict_t *other)
{
self->monsterinfo.currentmove = &makron_move_sight;
};
void makron_attack(edict_t *self)
{
vec3_t vec;
float range;
float r;
r = random();
VectorSubtract (self->enemy->s.origin, self->s.origin, vec);
range = VectorLength (vec);
if (r <= 0.3)
self->monsterinfo.currentmove = &makron_move_attack3;
else if (r <= 0.6)
self->monsterinfo.currentmove = &makron_move_attack4;
else
self->monsterinfo.currentmove = &makron_move_attack5;
}
/*
---
Makron Torso. This needs to be spawned in
---
*/
void makron_torso_think (edict_t *self)
{
if (++self->s.frame < 365)
self->nextthink = level.time + FRAMETIME;
else
{
self->s.frame = 346;
self->nextthink = level.time + FRAMETIME;
}
}
void makron_torso (edict_t *ent)
{
ent->movetype = MOVETYPE_NONE;
ent->solid = SOLID_NOT;
VectorSet (ent->mins, -8, -8, 0);
VectorSet (ent->maxs, 8, 8, 8);
ent->s.frame = 346;
ent->s.modelindex = gi.modelindex ("models/monsters/boss3/rider/tris.md2");
ent->think = makron_torso_think;
ent->nextthink = level.time + 2 * FRAMETIME;
ent->s.sound = gi.soundindex ("makron/spine.wav");
gi.linkentity (ent);
}
//
// death
//
void makron_dead (edict_t *self)
{
VectorSet (self->mins, -60, -60, 0);
VectorSet (self->maxs, 60, 60, 72);
self->movetype = MOVETYPE_TOSS;
self->svflags |= SVF_DEADMONSTER;
self->nextthink = 0;
gi.linkentity (self);
}
void makron_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
{
edict_t *tempent;
int n;
self->s.sound = 0;
// check for gib
if (self->health <= self->gib_health)
{
gi.sound (self, CHAN_VOICE, gi.soundindex ("misc/udeath.wav"), 1, ATTN_NORM, 0);
for (n= 0; n < 1 /*4*/; n++)
ThrowGib (self, "models/objects/gibs/sm_meat/tris.md2", damage, GIB_ORGANIC);
for (n= 0; n < 4; n++)
ThrowGib (self, "models/objects/gibs/sm_metal/tris.md2", damage, GIB_METALLIC);
ThrowHead (self, "models/objects/gibs/gear/tris.md2", damage, GIB_METALLIC);
self->deadflag = DEAD_DEAD;
return;
}
if (self->deadflag == DEAD_DEAD)
return;
// regular death
gi.sound (self, CHAN_VOICE, sound_death, 1, ATTN_NONE, 0);
self->deadflag = DEAD_DEAD;
self->takedamage = DAMAGE_YES;
tempent = G_Spawn();
VectorCopy (self->s.origin, tempent->s.origin);
VectorCopy (self->s.angles, tempent->s.angles);
tempent->s.origin[1] -= 84;
makron_torso (tempent);
self->monsterinfo.currentmove = &makron_move_death2;
}
qboolean Makron_CheckAttack (edict_t *self)
{
vec3_t spot1, spot2;
vec3_t temp;
float chance;
trace_t tr;
qboolean enemy_infront;
int enemy_range;
float enemy_yaw;
if (self->enemy->health > 0)
{
// see if any entities are in the way of the shot
VectorCopy (self->s.origin, spot1);
spot1[2] += self->viewheight;
VectorCopy (self->enemy->s.origin, spot2);
spot2[2] += self->enemy->viewheight;
tr = gi.trace (spot1, NULL, NULL, spot2, self, CONTENTS_SOLID|CONTENTS_MONSTER|CONTENTS_SLIME|CONTENTS_LAVA);
// do we have a clear shot?
if (tr.ent != self->enemy)
return false;
}
enemy_infront = infront(self, self->enemy);
enemy_range = range(self, self->enemy);
VectorSubtract (self->enemy->s.origin, self->s.origin, temp);
enemy_yaw = vectoyaw(temp);
self->ideal_yaw = enemy_yaw;
// melee attack
if (enemy_range == RANGE_MELEE)
{
if (self->monsterinfo.melee)
self->monsterinfo.attack_state = AS_MELEE;
else
self->monsterinfo.attack_state = AS_MISSILE;
return true;
}
// missile attack
if (!self->monsterinfo.attack)
return false;
if (level.time < self->monsterinfo.attack_finished)
return false;
if (enemy_range == RANGE_FAR)
return false;
if (self->monsterinfo.aiflags & AI_STAND_GROUND)
{
chance = 0.4;
}
else if (enemy_range == RANGE_MELEE)
{
chance = 0.8;
}
else if (enemy_range == RANGE_NEAR)
{
chance = 0.4;
}
else if (enemy_range == RANGE_MID)
{
chance = 0.2;
}
else
{
return false;
}
if (random () < chance)
{
self->monsterinfo.attack_state = AS_MISSILE;
self->monsterinfo.attack_finished = level.time + 2*random();
return true;
}
if (self->flags & FL_FLY)
{
if (random() < 0.3)
self->monsterinfo.attack_state = AS_SLIDING;
else
self->monsterinfo.attack_state = AS_STRAIGHT;
}
return false;
}
//
// monster_makron
//
void MakronPrecache (void)
{
sound_pain4 = gi.soundindex ("makron/pain3.wav");
sound_pain5 = gi.soundindex ("makron/pain2.wav");
sound_pain6 = gi.soundindex ("makron/pain1.wav");
sound_death = gi.soundindex ("makron/death.wav");
sound_step_left = gi.soundindex ("makron/step1.wav");
sound_step_right = gi.soundindex ("makron/step2.wav");
sound_attack_bfg = gi.soundindex ("makron/bfg_fire.wav");
sound_brainsplorch = gi.soundindex ("makron/brain1.wav");
sound_prerailgun = gi.soundindex ("makron/rail_up.wav");
sound_popup = gi.soundindex ("makron/popup.wav");
sound_taunt1 = gi.soundindex ("makron/voice4.wav");
sound_taunt2 = gi.soundindex ("makron/voice3.wav");
sound_taunt3 = gi.soundindex ("makron/voice.wav");
sound_hit = gi.soundindex ("makron/bhit.wav");
gi.modelindex ("models/monsters/boss3/rider/tris.md2");
}
/*QUAKED monster_makron (1 .5 0) (-30 -30 0) (30 30 90) Ambush Trigger_Spawn Sight
*/
void SP_monster_makron (edict_t *self)
{
if (deathmatch->value)
{
G_FreeEdict (self);
return;
}
MakronPrecache ();
self->movetype = MOVETYPE_STEP;
self->solid = SOLID_BBOX;
self->s.modelindex = gi.modelindex ("models/monsters/boss3/rider/tris.md2");
VectorSet (self->mins, -30, -30, 0);
VectorSet (self->maxs, 30, 30, 90);
self->health = 3000;
self->gib_health = -2000;
self->mass = 500;
self->pain = makron_pain;
self->die = makron_die;
self->monsterinfo.stand = makron_stand;
self->monsterinfo.walk = makron_walk;
self->monsterinfo.run = makron_run;
self->monsterinfo.dodge = NULL;
self->monsterinfo.attack = makron_attack;
self->monsterinfo.melee = NULL;
self->monsterinfo.sight = makron_sight;
self->monsterinfo.checkattack = Makron_CheckAttack;
gi.linkentity (self);
// self->monsterinfo.currentmove = &makron_move_stand;
self->monsterinfo.currentmove = &makron_move_sight;
self->monsterinfo.scale = MODEL_SCALE;
walkmonster_start(self);
}
/*
=================
MakronSpawn
=================
*/
void MakronSpawn (edict_t *self)
{
vec3_t vec;
edict_t *player;
SP_monster_makron (self);
// jump at player
player = level.sight_client;
if (!player)
return;
VectorSubtract (player->s.origin, self->s.origin, vec);
self->s.angles[YAW] = vectoyaw(vec);
VectorNormalize (vec);
VectorMA (vec3_origin, 400, vec, self->velocity);
self->velocity[2] = 200;
self->groundentity = NULL;
}
/*
=================
MakronToss
Jorg is just about dead, so set up to launch Makron out
=================
*/
void MakronToss (edict_t *self)
{
edict_t *ent;
ent = G_Spawn ();
ent->nextthink = level.time + 0.8;
ent->think = MakronSpawn;
ent->target = self->target;
VectorCopy (self->s.origin, ent->s.origin);
}

516
game/m_boss32.h Normal file
View File

@ -0,0 +1,516 @@
/*
Copyright (C) 1997-2001 Id Software, Inc.
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 the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
// G:\quake2\baseq2\models/monsters/boss3/rider
// This file generated by ModelGen - Do NOT Modify
#define FRAME_attak101 0
#define FRAME_attak102 1
#define FRAME_attak103 2
#define FRAME_attak104 3
#define FRAME_attak105 4
#define FRAME_attak106 5
#define FRAME_attak107 6
#define FRAME_attak108 7
#define FRAME_attak109 8
#define FRAME_attak110 9
#define FRAME_attak111 10
#define FRAME_attak112 11
#define FRAME_attak113 12
#define FRAME_attak114 13
#define FRAME_attak115 14
#define FRAME_attak116 15
#define FRAME_attak117 16
#define FRAME_attak118 17
#define FRAME_attak201 18
#define FRAME_attak202 19
#define FRAME_attak203 20
#define FRAME_attak204 21
#define FRAME_attak205 22
#define FRAME_attak206 23
#define FRAME_attak207 24
#define FRAME_attak208 25
#define FRAME_attak209 26
#define FRAME_attak210 27
#define FRAME_attak211 28
#define FRAME_attak212 29
#define FRAME_attak213 30
#define FRAME_death01 31
#define FRAME_death02 32
#define FRAME_death03 33
#define FRAME_death04 34
#define FRAME_death05 35
#define FRAME_death06 36
#define FRAME_death07 37
#define FRAME_death08 38
#define FRAME_death09 39
#define FRAME_death10 40
#define FRAME_death11 41
#define FRAME_death12 42
#define FRAME_death13 43
#define FRAME_death14 44
#define FRAME_death15 45
#define FRAME_death16 46
#define FRAME_death17 47
#define FRAME_death18 48
#define FRAME_death19 49
#define FRAME_death20 50
#define FRAME_death21 51
#define FRAME_death22 52
#define FRAME_death23 53
#define FRAME_death24 54
#define FRAME_death25 55
#define FRAME_death26 56
#define FRAME_death27 57
#define FRAME_death28 58
#define FRAME_death29 59
#define FRAME_death30 60
#define FRAME_death31 61
#define FRAME_death32 62
#define FRAME_death33 63
#define FRAME_death34 64
#define FRAME_death35 65
#define FRAME_death36 66
#define FRAME_death37 67
#define FRAME_death38 68
#define FRAME_death39 69
#define FRAME_death40 70
#define FRAME_death41 71
#define FRAME_death42 72
#define FRAME_death43 73
#define FRAME_death44 74
#define FRAME_death45 75
#define FRAME_death46 76
#define FRAME_death47 77
#define FRAME_death48 78
#define FRAME_death49 79
#define FRAME_death50 80
#define FRAME_pain101 81
#define FRAME_pain102 82
#define FRAME_pain103 83
#define FRAME_pain201 84
#define FRAME_pain202 85
#define FRAME_pain203 86
#define FRAME_pain301 87
#define FRAME_pain302 88
#define FRAME_pain303 89
#define FRAME_pain304 90
#define FRAME_pain305 91
#define FRAME_pain306 92
#define FRAME_pain307 93
#define FRAME_pain308 94
#define FRAME_pain309 95
#define FRAME_pain310 96
#define FRAME_pain311 97
#define FRAME_pain312 98
#define FRAME_pain313 99
#define FRAME_pain314 100
#define FRAME_pain315 101
#define FRAME_pain316 102
#define FRAME_pain317 103
#define FRAME_pain318 104
#define FRAME_pain319 105
#define FRAME_pain320 106
#define FRAME_pain321 107
#define FRAME_pain322 108
#define FRAME_pain323 109
#define FRAME_pain324 110
#define FRAME_pain325 111
#define FRAME_stand01 112
#define FRAME_stand02 113
#define FRAME_stand03 114
#define FRAME_stand04 115
#define FRAME_stand05 116
#define FRAME_stand06 117
#define FRAME_stand07 118
#define FRAME_stand08 119
#define FRAME_stand09 120
#define FRAME_stand10 121
#define FRAME_stand11 122
#define FRAME_stand12 123
#define FRAME_stand13 124
#define FRAME_stand14 125
#define FRAME_stand15 126
#define FRAME_stand16 127
#define FRAME_stand17 128
#define FRAME_stand18 129
#define FRAME_stand19 130
#define FRAME_stand20 131
#define FRAME_stand21 132
#define FRAME_stand22 133
#define FRAME_stand23 134
#define FRAME_stand24 135
#define FRAME_stand25 136
#define FRAME_stand26 137
#define FRAME_stand27 138
#define FRAME_stand28 139
#define FRAME_stand29 140
#define FRAME_stand30 141
#define FRAME_stand31 142
#define FRAME_stand32 143
#define FRAME_stand33 144
#define FRAME_stand34 145
#define FRAME_stand35 146
#define FRAME_stand36 147
#define FRAME_stand37 148
#define FRAME_stand38 149
#define FRAME_stand39 150
#define FRAME_stand40 151
#define FRAME_stand41 152
#define FRAME_stand42 153
#define FRAME_stand43 154
#define FRAME_stand44 155
#define FRAME_stand45 156
#define FRAME_stand46 157
#define FRAME_stand47 158
#define FRAME_stand48 159
#define FRAME_stand49 160
#define FRAME_stand50 161
#define FRAME_stand51 162
#define FRAME_walk01 163
#define FRAME_walk02 164
#define FRAME_walk03 165
#define FRAME_walk04 166
#define FRAME_walk05 167
#define FRAME_walk06 168
#define FRAME_walk07 169
#define FRAME_walk08 170
#define FRAME_walk09 171
#define FRAME_walk10 172
#define FRAME_walk11 173
#define FRAME_walk12 174
#define FRAME_walk13 175
#define FRAME_walk14 176
#define FRAME_walk15 177
#define FRAME_walk16 178
#define FRAME_walk17 179
#define FRAME_walk18 180
#define FRAME_walk19 181
#define FRAME_walk20 182
#define FRAME_walk21 183
#define FRAME_walk22 184
#define FRAME_walk23 185
#define FRAME_walk24 186
#define FRAME_walk25 187
#define FRAME_active01 188
#define FRAME_active02 189
#define FRAME_active03 190
#define FRAME_active04 191
#define FRAME_active05 192
#define FRAME_active06 193
#define FRAME_active07 194
#define FRAME_active08 195
#define FRAME_active09 196
#define FRAME_active10 197
#define FRAME_active11 198
#define FRAME_active12 199
#define FRAME_active13 200
#define FRAME_attak301 201
#define FRAME_attak302 202
#define FRAME_attak303 203
#define FRAME_attak304 204
#define FRAME_attak305 205
#define FRAME_attak306 206
#define FRAME_attak307 207
#define FRAME_attak308 208
#define FRAME_attak401 209
#define FRAME_attak402 210
#define FRAME_attak403 211
#define FRAME_attak404 212
#define FRAME_attak405 213
#define FRAME_attak406 214
#define FRAME_attak407 215
#define FRAME_attak408 216
#define FRAME_attak409 217
#define FRAME_attak410 218
#define FRAME_attak411 219
#define FRAME_attak412 220
#define FRAME_attak413 221
#define FRAME_attak414 222
#define FRAME_attak415 223
#define FRAME_attak416 224
#define FRAME_attak417 225
#define FRAME_attak418 226
#define FRAME_attak419 227
#define FRAME_attak420 228
#define FRAME_attak421 229
#define FRAME_attak422 230
#define FRAME_attak423 231
#define FRAME_attak424 232
#define FRAME_attak425 233
#define FRAME_attak426 234
#define FRAME_attak501 235
#define FRAME_attak502 236
#define FRAME_attak503 237
#define FRAME_attak504 238
#define FRAME_attak505 239
#define FRAME_attak506 240
#define FRAME_attak507 241
#define FRAME_attak508 242
#define FRAME_attak509 243
#define FRAME_attak510 244
#define FRAME_attak511 245
#define FRAME_attak512 246
#define FRAME_attak513 247
#define FRAME_attak514 248
#define FRAME_attak515 249
#define FRAME_attak516 250
#define FRAME_death201 251
#define FRAME_death202 252
#define FRAME_death203 253
#define FRAME_death204 254
#define FRAME_death205 255
#define FRAME_death206 256
#define FRAME_death207 257
#define FRAME_death208 258
#define FRAME_death209 259
#define FRAME_death210 260
#define FRAME_death211 261
#define FRAME_death212 262
#define FRAME_death213 263
#define FRAME_death214 264
#define FRAME_death215 265
#define FRAME_death216 266
#define FRAME_death217 267
#define FRAME_death218 268
#define FRAME_death219 269
#define FRAME_death220 270
#define FRAME_death221 271
#define FRAME_death222 272
#define FRAME_death223 273
#define FRAME_death224 274
#define FRAME_death225 275
#define FRAME_death226 276
#define FRAME_death227 277
#define FRAME_death228 278
#define FRAME_death229 279
#define FRAME_death230 280
#define FRAME_death231 281
#define FRAME_death232 282
#define FRAME_death233 283
#define FRAME_death234 284
#define FRAME_death235 285
#define FRAME_death236 286
#define FRAME_death237 287
#define FRAME_death238 288
#define FRAME_death239 289
#define FRAME_death240 290
#define FRAME_death241 291
#define FRAME_death242 292
#define FRAME_death243 293
#define FRAME_death244 294
#define FRAME_death245 295
#define FRAME_death246 296
#define FRAME_death247 297
#define FRAME_death248 298
#define FRAME_death249 299
#define FRAME_death250 300
#define FRAME_death251 301
#define FRAME_death252 302
#define FRAME_death253 303
#define FRAME_death254 304
#define FRAME_death255 305
#define FRAME_death256 306
#define FRAME_death257 307
#define FRAME_death258 308
#define FRAME_death259 309
#define FRAME_death260 310
#define FRAME_death261 311
#define FRAME_death262 312
#define FRAME_death263 313
#define FRAME_death264 314
#define FRAME_death265 315
#define FRAME_death266 316
#define FRAME_death267 317
#define FRAME_death268 318
#define FRAME_death269 319
#define FRAME_death270 320
#define FRAME_death271 321
#define FRAME_death272 322
#define FRAME_death273 323
#define FRAME_death274 324
#define FRAME_death275 325
#define FRAME_death276 326
#define FRAME_death277 327
#define FRAME_death278 328
#define FRAME_death279 329
#define FRAME_death280 330
#define FRAME_death281 331
#define FRAME_death282 332
#define FRAME_death283 333
#define FRAME_death284 334
#define FRAME_death285 335
#define FRAME_death286 336
#define FRAME_death287 337
#define FRAME_death288 338
#define FRAME_death289 339
#define FRAME_death290 340
#define FRAME_death291 341
#define FRAME_death292 342
#define FRAME_death293 343
#define FRAME_death294 344
#define FRAME_death295 345
#define FRAME_death301 346
#define FRAME_death302 347
#define FRAME_death303 348
#define FRAME_death304 349
#define FRAME_death305 350
#define FRAME_death306 351
#define FRAME_death307 352
#define FRAME_death308 353
#define FRAME_death309 354
#define FRAME_death310 355
#define FRAME_death311 356
#define FRAME_death312 357
#define FRAME_death313 358
#define FRAME_death314 359
#define FRAME_death315 360
#define FRAME_death316 361
#define FRAME_death317 362
#define FRAME_death318 363
#define FRAME_death319 364
#define FRAME_death320 365
#define FRAME_jump01 366
#define FRAME_jump02 367
#define FRAME_jump03 368
#define FRAME_jump04 369
#define FRAME_jump05 370
#define FRAME_jump06 371
#define FRAME_jump07 372
#define FRAME_jump08 373
#define FRAME_jump09 374
#define FRAME_jump10 375
#define FRAME_jump11 376
#define FRAME_jump12 377
#define FRAME_jump13 378
#define FRAME_pain401 379
#define FRAME_pain402 380
#define FRAME_pain403 381
#define FRAME_pain404 382
#define FRAME_pain501 383
#define FRAME_pain502 384
#define FRAME_pain503 385
#define FRAME_pain504 386
#define FRAME_pain601 387
#define FRAME_pain602 388
#define FRAME_pain603 389
#define FRAME_pain604 390
#define FRAME_pain605 391
#define FRAME_pain606 392
#define FRAME_pain607 393
#define FRAME_pain608 394
#define FRAME_pain609 395
#define FRAME_pain610 396
#define FRAME_pain611 397
#define FRAME_pain612 398
#define FRAME_pain613 399
#define FRAME_pain614 400
#define FRAME_pain615 401
#define FRAME_pain616 402
#define FRAME_pain617 403
#define FRAME_pain618 404
#define FRAME_pain619 405
#define FRAME_pain620 406
#define FRAME_pain621 407
#define FRAME_pain622 408
#define FRAME_pain623 409
#define FRAME_pain624 410
#define FRAME_pain625 411
#define FRAME_pain626 412
#define FRAME_pain627 413
#define FRAME_stand201 414
#define FRAME_stand202 415
#define FRAME_stand203 416
#define FRAME_stand204 417
#define FRAME_stand205 418
#define FRAME_stand206 419
#define FRAME_stand207 420
#define FRAME_stand208 421
#define FRAME_stand209 422
#define FRAME_stand210 423
#define FRAME_stand211 424
#define FRAME_stand212 425
#define FRAME_stand213 426
#define FRAME_stand214 427
#define FRAME_stand215 428
#define FRAME_stand216 429
#define FRAME_stand217 430
#define FRAME_stand218 431
#define FRAME_stand219 432
#define FRAME_stand220 433
#define FRAME_stand221 434
#define FRAME_stand222 435
#define FRAME_stand223 436
#define FRAME_stand224 437
#define FRAME_stand225 438
#define FRAME_stand226 439
#define FRAME_stand227 440
#define FRAME_stand228 441
#define FRAME_stand229 442
#define FRAME_stand230 443
#define FRAME_stand231 444
#define FRAME_stand232 445
#define FRAME_stand233 446
#define FRAME_stand234 447
#define FRAME_stand235 448
#define FRAME_stand236 449
#define FRAME_stand237 450
#define FRAME_stand238 451
#define FRAME_stand239 452
#define FRAME_stand240 453
#define FRAME_stand241 454
#define FRAME_stand242 455
#define FRAME_stand243 456
#define FRAME_stand244 457
#define FRAME_stand245 458
#define FRAME_stand246 459
#define FRAME_stand247 460
#define FRAME_stand248 461
#define FRAME_stand249 462
#define FRAME_stand250 463
#define FRAME_stand251 464
#define FRAME_stand252 465
#define FRAME_stand253 466
#define FRAME_stand254 467
#define FRAME_stand255 468
#define FRAME_stand256 469
#define FRAME_stand257 470
#define FRAME_stand258 471
#define FRAME_stand259 472
#define FRAME_stand260 473
#define FRAME_walk201 474
#define FRAME_walk202 475
#define FRAME_walk203 476
#define FRAME_walk204 477
#define FRAME_walk205 478
#define FRAME_walk206 479
#define FRAME_walk207 480
#define FRAME_walk208 481
#define FRAME_walk209 482
#define FRAME_walk210 483
#define FRAME_walk211 484
#define FRAME_walk212 485
#define FRAME_walk213 486
#define FRAME_walk214 487
#define FRAME_walk215 488
#define FRAME_walk216 489
#define FRAME_walk217 490
#define MODEL_SCALE 1.000000

676
game/m_brain.c Normal file
View File

@ -0,0 +1,676 @@
/*
Copyright (C) 1997-2001 Id Software, Inc.
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 the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/*
==============================================================================
brain
==============================================================================
*/
#include "g_local.h"
#include "m_brain.h"
static int sound_chest_open;
static int sound_tentacles_extend;
static int sound_tentacles_retract;
static int sound_death;
static int sound_idle1;
static int sound_idle2;
static int sound_idle3;
static int sound_pain1;
static int sound_pain2;
static int sound_sight;
static int sound_search;
static int sound_melee1;
static int sound_melee2;
static int sound_melee3;
void brain_sight (edict_t *self, edict_t *other)
{
gi.sound (self, CHAN_VOICE, sound_sight, 1, ATTN_NORM, 0);
}
void brain_search (edict_t *self)
{
gi.sound (self, CHAN_VOICE, sound_search, 1, ATTN_NORM, 0);
}
void brain_run (edict_t *self);
void brain_dead (edict_t *self);
//
// STAND
//
mframe_t brain_frames_stand [] =
{
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL
};
mmove_t brain_move_stand = {FRAME_stand01, FRAME_stand30, brain_frames_stand, NULL};
void brain_stand (edict_t *self)
{
self->monsterinfo.currentmove = &brain_move_stand;
}
//
// IDLE
//
mframe_t brain_frames_idle [] =
{
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL
};
mmove_t brain_move_idle = {FRAME_stand31, FRAME_stand60, brain_frames_idle, brain_stand};
void brain_idle (edict_t *self)
{
gi.sound (self, CHAN_AUTO, sound_idle3, 1, ATTN_IDLE, 0);
self->monsterinfo.currentmove = &brain_move_idle;
}
//
// WALK
//
mframe_t brain_frames_walk1 [] =
{
ai_walk, 7, NULL,
ai_walk, 2, NULL,
ai_walk, 3, NULL,
ai_walk, 3, NULL,
ai_walk, 1, NULL,
ai_walk, 0, NULL,
ai_walk, 0, NULL,
ai_walk, 9, NULL,
ai_walk, -4, NULL,
ai_walk, -1, NULL,
ai_walk, 2, NULL
};
mmove_t brain_move_walk1 = {FRAME_walk101, FRAME_walk111, brain_frames_walk1, NULL};
// walk2 is FUBAR, do not use
#if 0
void brain_walk2_cycle (edict_t *self)
{
if (random() > 0.1)
self->monsterinfo.nextframe = FRAME_walk220;
}
mframe_t brain_frames_walk2 [] =
{
ai_walk, 3, NULL,
ai_walk, -2, NULL,
ai_walk, -4, NULL,
ai_walk, -3, NULL,
ai_walk, 0, NULL,
ai_walk, 1, NULL,
ai_walk, 12, NULL,
ai_walk, 0, NULL,
ai_walk, -3, NULL,
ai_walk, 0, NULL,
ai_walk, -2, NULL,
ai_walk, 0, NULL,
ai_walk, 0, NULL,
ai_walk, 1, NULL,
ai_walk, 0, NULL,
ai_walk, 0, NULL,
ai_walk, 0, NULL,
ai_walk, 0, NULL,
ai_walk, 0, NULL,
ai_walk, 10, NULL, // Cycle Start
ai_walk, -1, NULL,
ai_walk, 7, NULL,
ai_walk, 0, NULL,
ai_walk, 3, NULL,
ai_walk, -3, NULL,
ai_walk, 2, NULL,
ai_walk, 4, NULL,
ai_walk, -3, NULL,
ai_walk, 2, NULL,
ai_walk, 0, NULL,
ai_walk, 4, brain_walk2_cycle,
ai_walk, -1, NULL,
ai_walk, -1, NULL,
ai_walk, -8, NULL,
ai_walk, 0, NULL,
ai_walk, 1, NULL,
ai_walk, 5, NULL,
ai_walk, 2, NULL,
ai_walk, -1, NULL,
ai_walk, -5, NULL
};
mmove_t brain_move_walk2 = {FRAME_walk201, FRAME_walk240, brain_frames_walk2, NULL};
#endif
void brain_walk (edict_t *self)
{
// if (random() <= 0.5)
self->monsterinfo.currentmove = &brain_move_walk1;
// else
// self->monsterinfo.currentmove = &brain_move_walk2;
}
mframe_t brain_frames_defense [] =
{
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL
};
mmove_t brain_move_defense = {FRAME_defens01, FRAME_defens08, brain_frames_defense, NULL};
mframe_t brain_frames_pain3 [] =
{
ai_move, -2, NULL,
ai_move, 2, NULL,
ai_move, 1, NULL,
ai_move, 3, NULL,
ai_move, 0, NULL,
ai_move, -4, NULL
};
mmove_t brain_move_pain3 = {FRAME_pain301, FRAME_pain306, brain_frames_pain3, brain_run};
mframe_t brain_frames_pain2 [] =
{
ai_move, -2, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 3, NULL,
ai_move, 1, NULL,
ai_move, -2, NULL
};
mmove_t brain_move_pain2 = {FRAME_pain201, FRAME_pain208, brain_frames_pain2, brain_run};
mframe_t brain_frames_pain1 [] =
{
ai_move, -6, NULL,
ai_move, -2, NULL,
ai_move, -6, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 2, NULL,
ai_move, 0, NULL,
ai_move, 2, NULL,
ai_move, 1, NULL,
ai_move, 7, NULL,
ai_move, 0, NULL,
ai_move, 3, NULL,
ai_move, -1, NULL
};
mmove_t brain_move_pain1 = {FRAME_pain101, FRAME_pain121, brain_frames_pain1, brain_run};
//
// DUCK
//
void brain_duck_down (edict_t *self)
{
if (self->monsterinfo.aiflags & AI_DUCKED)
return;
self->monsterinfo.aiflags |= AI_DUCKED;
self->maxs[2] -= 32;
self->takedamage = DAMAGE_YES;
gi.linkentity (self);
}
void brain_duck_hold (edict_t *self)
{
if (level.time >= self->monsterinfo.pausetime)
self->monsterinfo.aiflags &= ~AI_HOLD_FRAME;
else
self->monsterinfo.aiflags |= AI_HOLD_FRAME;
}
void brain_duck_up (edict_t *self)
{
self->monsterinfo.aiflags &= ~AI_DUCKED;
self->maxs[2] += 32;
self->takedamage = DAMAGE_AIM;
gi.linkentity (self);
}
mframe_t brain_frames_duck [] =
{
ai_move, 0, NULL,
ai_move, -2, brain_duck_down,
ai_move, 17, brain_duck_hold,
ai_move, -3, NULL,
ai_move, -1, brain_duck_up,
ai_move, -5, NULL,
ai_move, -6, NULL,
ai_move, -6, NULL
};
mmove_t brain_move_duck = {FRAME_duck01, FRAME_duck08, brain_frames_duck, brain_run};
void brain_dodge (edict_t *self, edict_t *attacker, float eta)
{
if (random() > 0.25)
return;
if (!self->enemy)
self->enemy = attacker;
self->monsterinfo.pausetime = level.time + eta + 0.5;
self->monsterinfo.currentmove = &brain_move_duck;
}
mframe_t brain_frames_death2 [] =
{
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 9, NULL,
ai_move, 0, NULL
};
mmove_t brain_move_death2 = {FRAME_death201, FRAME_death205, brain_frames_death2, brain_dead};
mframe_t brain_frames_death1 [] =
{
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, -2, NULL,
ai_move, 9, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL
};
mmove_t brain_move_death1 = {FRAME_death101, FRAME_death118, brain_frames_death1, brain_dead};
//
// MELEE
//
void brain_swing_right (edict_t *self)
{
gi.sound (self, CHAN_BODY, sound_melee1, 1, ATTN_NORM, 0);
}
void brain_hit_right (edict_t *self)
{
vec3_t aim;
VectorSet (aim, MELEE_DISTANCE, self->maxs[0], 8);
if (fire_hit (self, aim, (15 + (rand() %5)), 40))
gi.sound (self, CHAN_WEAPON, sound_melee3, 1, ATTN_NORM, 0);
}
void brain_swing_left (edict_t *self)
{
gi.sound (self, CHAN_BODY, sound_melee2, 1, ATTN_NORM, 0);
}
void brain_hit_left (edict_t *self)
{
vec3_t aim;
VectorSet (aim, MELEE_DISTANCE, self->mins[0], 8);
if (fire_hit (self, aim, (15 + (rand() %5)), 40))
gi.sound (self, CHAN_WEAPON, sound_melee3, 1, ATTN_NORM, 0);
}
mframe_t brain_frames_attack1 [] =
{
ai_charge, 8, NULL,
ai_charge, 3, NULL,
ai_charge, 5, NULL,
ai_charge, 0, NULL,
ai_charge, -3, brain_swing_right,
ai_charge, 0, NULL,
ai_charge, -5, NULL,
ai_charge, -7, brain_hit_right,
ai_charge, 0, NULL,
ai_charge, 6, brain_swing_left,
ai_charge, 1, NULL,
ai_charge, 2, brain_hit_left,
ai_charge, -3, NULL,
ai_charge, 6, NULL,
ai_charge, -1, NULL,
ai_charge, -3, NULL,
ai_charge, 2, NULL,
ai_charge, -11,NULL
};
mmove_t brain_move_attack1 = {FRAME_attak101, FRAME_attak118, brain_frames_attack1, brain_run};
void brain_chest_open (edict_t *self)
{
self->spawnflags &= ~65536;
self->monsterinfo.power_armor_type = POWER_ARMOR_NONE;
gi.sound (self, CHAN_BODY, sound_chest_open, 1, ATTN_NORM, 0);
}
void brain_tentacle_attack (edict_t *self)
{
vec3_t aim;
VectorSet (aim, MELEE_DISTANCE, 0, 8);
if (fire_hit (self, aim, (10 + (rand() %5)), -600) && skill->value > 0)
self->spawnflags |= 65536;
gi.sound (self, CHAN_WEAPON, sound_tentacles_retract, 1, ATTN_NORM, 0);
}
void brain_chest_closed (edict_t *self)
{
self->monsterinfo.power_armor_type = POWER_ARMOR_SCREEN;
if (self->spawnflags & 65536)
{
self->spawnflags &= ~65536;
self->monsterinfo.currentmove = &brain_move_attack1;
}
}
mframe_t brain_frames_attack2 [] =
{
ai_charge, 5, NULL,
ai_charge, -4, NULL,
ai_charge, -4, NULL,
ai_charge, -3, NULL,
ai_charge, 0, brain_chest_open,
ai_charge, 0, NULL,
ai_charge, 13, brain_tentacle_attack,
ai_charge, 0, NULL,
ai_charge, 2, NULL,
ai_charge, 0, NULL,
ai_charge, -9, brain_chest_closed,
ai_charge, 0, NULL,
ai_charge, 4, NULL,
ai_charge, 3, NULL,
ai_charge, 2, NULL,
ai_charge, -3, NULL,
ai_charge, -6, NULL
};
mmove_t brain_move_attack2 = {FRAME_attak201, FRAME_attak217, brain_frames_attack2, brain_run};
void brain_melee(edict_t *self)
{
if (random() <= 0.5)
self->monsterinfo.currentmove = &brain_move_attack1;
else
self->monsterinfo.currentmove = &brain_move_attack2;
}
//
// RUN
//
mframe_t brain_frames_run [] =
{
ai_run, 9, NULL,
ai_run, 2, NULL,
ai_run, 3, NULL,
ai_run, 3, NULL,
ai_run, 1, NULL,
ai_run, 0, NULL,
ai_run, 0, NULL,
ai_run, 10, NULL,
ai_run, -4, NULL,
ai_run, -1, NULL,
ai_run, 2, NULL
};
mmove_t brain_move_run = {FRAME_walk101, FRAME_walk111, brain_frames_run, NULL};
void brain_run (edict_t *self)
{
self->monsterinfo.power_armor_type = POWER_ARMOR_SCREEN;
if (self->monsterinfo.aiflags & AI_STAND_GROUND)
self->monsterinfo.currentmove = &brain_move_stand;
else
self->monsterinfo.currentmove = &brain_move_run;
}
void brain_pain (edict_t *self, edict_t *other, float kick, int damage)
{
float r;
if (self->health < (self->max_health / 2))
self->s.skinnum = 1;
if (level.time < self->pain_debounce_time)
return;
self->pain_debounce_time = level.time + 3;
if (skill->value == 3)
return; // no pain anims in nightmare
r = random();
if (r < 0.33)
{
gi.sound (self, CHAN_VOICE, sound_pain1, 1, ATTN_NORM, 0);
self->monsterinfo.currentmove = &brain_move_pain1;
}
else if (r < 0.66)
{
gi.sound (self, CHAN_VOICE, sound_pain2, 1, ATTN_NORM, 0);
self->monsterinfo.currentmove = &brain_move_pain2;
}
else
{
gi.sound (self, CHAN_VOICE, sound_pain1, 1, ATTN_NORM, 0);
self->monsterinfo.currentmove = &brain_move_pain3;
}
}
void brain_dead (edict_t *self)
{
VectorSet (self->mins, -16, -16, -24);
VectorSet (self->maxs, 16, 16, -8);
self->movetype = MOVETYPE_TOSS;
self->svflags |= SVF_DEADMONSTER;
self->nextthink = 0;
gi.linkentity (self);
}
void brain_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
{
int n;
self->s.effects = 0;
self->monsterinfo.power_armor_type = POWER_ARMOR_NONE;
// check for gib
if (self->health <= self->gib_health)
{
gi.sound (self, CHAN_VOICE, gi.soundindex ("misc/udeath.wav"), 1, ATTN_NORM, 0);
for (n= 0; n < 2; n++)
ThrowGib (self, "models/objects/gibs/bone/tris.md2", damage, GIB_ORGANIC);
for (n= 0; n < 4; n++)
ThrowGib (self, "models/objects/gibs/sm_meat/tris.md2", damage, GIB_ORGANIC);
ThrowHead (self, "models/objects/gibs/head2/tris.md2", damage, GIB_ORGANIC);
self->deadflag = DEAD_DEAD;
return;
}
if (self->deadflag == DEAD_DEAD)
return;
// regular death
gi.sound (self, CHAN_VOICE, sound_death, 1, ATTN_NORM, 0);
self->deadflag = DEAD_DEAD;
self->takedamage = DAMAGE_YES;
if (random() <= 0.5)
self->monsterinfo.currentmove = &brain_move_death1;
else
self->monsterinfo.currentmove = &brain_move_death2;
}
/*QUAKED monster_brain (1 .5 0) (-16 -16 -24) (16 16 32) Ambush Trigger_Spawn Sight
*/
void SP_monster_brain (edict_t *self)
{
if (deathmatch->value)
{
G_FreeEdict (self);
return;
}
sound_chest_open = gi.soundindex ("brain/brnatck1.wav");
sound_tentacles_extend = gi.soundindex ("brain/brnatck2.wav");
sound_tentacles_retract = gi.soundindex ("brain/brnatck3.wav");
sound_death = gi.soundindex ("brain/brndeth1.wav");
sound_idle1 = gi.soundindex ("brain/brnidle1.wav");
sound_idle2 = gi.soundindex ("brain/brnidle2.wav");
sound_idle3 = gi.soundindex ("brain/brnlens1.wav");
sound_pain1 = gi.soundindex ("brain/brnpain1.wav");
sound_pain2 = gi.soundindex ("brain/brnpain2.wav");
sound_sight = gi.soundindex ("brain/brnsght1.wav");
sound_search = gi.soundindex ("brain/brnsrch1.wav");
sound_melee1 = gi.soundindex ("brain/melee1.wav");
sound_melee2 = gi.soundindex ("brain/melee2.wav");
sound_melee3 = gi.soundindex ("brain/melee3.wav");
self->movetype = MOVETYPE_STEP;
self->solid = SOLID_BBOX;
self->s.modelindex = gi.modelindex ("models/monsters/brain/tris.md2");
VectorSet (self->mins, -16, -16, -24);
VectorSet (self->maxs, 16, 16, 32);
self->health = 300;
self->gib_health = -150;
self->mass = 400;
self->pain = brain_pain;
self->die = brain_die;
self->monsterinfo.stand = brain_stand;
self->monsterinfo.walk = brain_walk;
self->monsterinfo.run = brain_run;
self->monsterinfo.dodge = brain_dodge;
// self->monsterinfo.attack = brain_attack;
self->monsterinfo.melee = brain_melee;
self->monsterinfo.sight = brain_sight;
self->monsterinfo.search = brain_search;
self->monsterinfo.idle = brain_idle;
self->monsterinfo.power_armor_type = POWER_ARMOR_SCREEN;
self->monsterinfo.power_armor_power = 100;
gi.linkentity (self);
self->monsterinfo.currentmove = &brain_move_stand;
self->monsterinfo.scale = MODEL_SCALE;
walkmonster_start (self);
}

247
game/m_brain.h Normal file
View File

@ -0,0 +1,247 @@
/*
Copyright (C) 1997-2001 Id Software, Inc.
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 the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
// G:\quake2\baseq2\models/monsters/brain
// This file generated by ModelGen - Do NOT Modify
#define FRAME_walk101 0
#define FRAME_walk102 1
#define FRAME_walk103 2
#define FRAME_walk104 3
#define FRAME_walk105 4
#define FRAME_walk106 5
#define FRAME_walk107 6
#define FRAME_walk108 7
#define FRAME_walk109 8
#define FRAME_walk110 9
#define FRAME_walk111 10
#define FRAME_walk112 11
#define FRAME_walk113 12
#define FRAME_walk201 13
#define FRAME_walk202 14
#define FRAME_walk203 15
#define FRAME_walk204 16
#define FRAME_walk205 17
#define FRAME_walk206 18
#define FRAME_walk207 19
#define FRAME_walk208 20
#define FRAME_walk209 21
#define FRAME_walk210 22
#define FRAME_walk211 23
#define FRAME_walk212 24
#define FRAME_walk213 25
#define FRAME_walk214 26
#define FRAME_walk215 27
#define FRAME_walk216 28
#define FRAME_walk217 29
#define FRAME_walk218 30
#define FRAME_walk219 31
#define FRAME_walk220 32
#define FRAME_walk221 33
#define FRAME_walk222 34
#define FRAME_walk223 35
#define FRAME_walk224 36
#define FRAME_walk225 37
#define FRAME_walk226 38
#define FRAME_walk227 39
#define FRAME_walk228 40
#define FRAME_walk229 41
#define FRAME_walk230 42
#define FRAME_walk231 43
#define FRAME_walk232 44
#define FRAME_walk233 45
#define FRAME_walk234 46
#define FRAME_walk235 47
#define FRAME_walk236 48
#define FRAME_walk237 49
#define FRAME_walk238 50
#define FRAME_walk239 51
#define FRAME_walk240 52
#define FRAME_attak101 53
#define FRAME_attak102 54
#define FRAME_attak103 55
#define FRAME_attak104 56
#define FRAME_attak105 57
#define FRAME_attak106 58
#define FRAME_attak107 59
#define FRAME_attak108 60
#define FRAME_attak109 61
#define FRAME_attak110 62
#define FRAME_attak111 63
#define FRAME_attak112 64
#define FRAME_attak113 65
#define FRAME_attak114 66
#define FRAME_attak115 67
#define FRAME_attak116 68
#define FRAME_attak117 69
#define FRAME_attak118 70
#define FRAME_attak201 71
#define FRAME_attak202 72
#define FRAME_attak203 73
#define FRAME_attak204 74
#define FRAME_attak205 75
#define FRAME_attak206 76
#define FRAME_attak207 77
#define FRAME_attak208 78
#define FRAME_attak209 79
#define FRAME_attak210 80
#define FRAME_attak211 81
#define FRAME_attak212 82
#define FRAME_attak213 83
#define FRAME_attak214 84
#define FRAME_attak215 85
#define FRAME_attak216 86
#define FRAME_attak217 87
#define FRAME_pain101 88
#define FRAME_pain102 89
#define FRAME_pain103 90
#define FRAME_pain104 91
#define FRAME_pain105 92
#define FRAME_pain106 93
#define FRAME_pain107 94
#define FRAME_pain108 95
#define FRAME_pain109 96
#define FRAME_pain110 97
#define FRAME_pain111 98
#define FRAME_pain112 99
#define FRAME_pain113 100
#define FRAME_pain114 101
#define FRAME_pain115 102
#define FRAME_pain116 103
#define FRAME_pain117 104
#define FRAME_pain118 105
#define FRAME_pain119 106
#define FRAME_pain120 107
#define FRAME_pain121 108
#define FRAME_pain201 109
#define FRAME_pain202 110
#define FRAME_pain203 111
#define FRAME_pain204 112
#define FRAME_pain205 113
#define FRAME_pain206 114
#define FRAME_pain207 115
#define FRAME_pain208 116
#define FRAME_pain301 117
#define FRAME_pain302 118
#define FRAME_pain303 119
#define FRAME_pain304 120
#define FRAME_pain305 121
#define FRAME_pain306 122
#define FRAME_death101 123
#define FRAME_death102 124
#define FRAME_death103 125
#define FRAME_death104 126
#define FRAME_death105 127
#define FRAME_death106 128
#define FRAME_death107 129
#define FRAME_death108 130
#define FRAME_death109 131
#define FRAME_death110 132
#define FRAME_death111 133
#define FRAME_death112 134
#define FRAME_death113 135
#define FRAME_death114 136
#define FRAME_death115 137
#define FRAME_death116 138
#define FRAME_death117 139
#define FRAME_death118 140
#define FRAME_death201 141
#define FRAME_death202 142
#define FRAME_death203 143
#define FRAME_death204 144
#define FRAME_death205 145
#define FRAME_duck01 146
#define FRAME_duck02 147
#define FRAME_duck03 148
#define FRAME_duck04 149
#define FRAME_duck05 150
#define FRAME_duck06 151
#define FRAME_duck07 152
#define FRAME_duck08 153
#define FRAME_defens01 154
#define FRAME_defens02 155
#define FRAME_defens03 156
#define FRAME_defens04 157
#define FRAME_defens05 158
#define FRAME_defens06 159
#define FRAME_defens07 160
#define FRAME_defens08 161
#define FRAME_stand01 162
#define FRAME_stand02 163
#define FRAME_stand03 164
#define FRAME_stand04 165
#define FRAME_stand05 166
#define FRAME_stand06 167
#define FRAME_stand07 168
#define FRAME_stand08 169
#define FRAME_stand09 170
#define FRAME_stand10 171
#define FRAME_stand11 172
#define FRAME_stand12 173
#define FRAME_stand13 174
#define FRAME_stand14 175
#define FRAME_stand15 176
#define FRAME_stand16 177
#define FRAME_stand17 178
#define FRAME_stand18 179
#define FRAME_stand19 180
#define FRAME_stand20 181
#define FRAME_stand21 182
#define FRAME_stand22 183
#define FRAME_stand23 184
#define FRAME_stand24 185
#define FRAME_stand25 186
#define FRAME_stand26 187
#define FRAME_stand27 188
#define FRAME_stand28 189
#define FRAME_stand29 190
#define FRAME_stand30 191
#define FRAME_stand31 192
#define FRAME_stand32 193
#define FRAME_stand33 194
#define FRAME_stand34 195
#define FRAME_stand35 196
#define FRAME_stand36 197
#define FRAME_stand37 198
#define FRAME_stand38 199
#define FRAME_stand39 200
#define FRAME_stand40 201
#define FRAME_stand41 202
#define FRAME_stand42 203
#define FRAME_stand43 204
#define FRAME_stand44 205
#define FRAME_stand45 206
#define FRAME_stand46 207
#define FRAME_stand47 208
#define FRAME_stand48 209
#define FRAME_stand49 210
#define FRAME_stand50 211
#define FRAME_stand51 212
#define FRAME_stand52 213
#define FRAME_stand53 214
#define FRAME_stand54 215
#define FRAME_stand55 216
#define FRAME_stand56 217
#define FRAME_stand57 218
#define FRAME_stand58 219
#define FRAME_stand59 220
#define FRAME_stand60 221
#define MODEL_SCALE 1.000000

677
game/m_chick.c Normal file
View File

@ -0,0 +1,677 @@
/*
Copyright (C) 1997-2001 Id Software, Inc.
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 the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/*
==============================================================================
chick
==============================================================================
*/
#include "g_local.h"
#include "m_chick.h"
qboolean visible (edict_t *self, edict_t *other);
void chick_stand (edict_t *self);
void chick_run (edict_t *self);
void chick_reslash(edict_t *self);
void chick_rerocket(edict_t *self);
void chick_attack1(edict_t *self);
static int sound_missile_prelaunch;
static int sound_missile_launch;
static int sound_melee_swing;
static int sound_melee_hit;
static int sound_missile_reload;
static int sound_death1;
static int sound_death2;
static int sound_fall_down;
static int sound_idle1;
static int sound_idle2;
static int sound_pain1;
static int sound_pain2;
static int sound_pain3;
static int sound_sight;
static int sound_search;
void ChickMoan (edict_t *self)
{
if (random() < 0.5)
gi.sound (self, CHAN_VOICE, sound_idle1, 1, ATTN_IDLE, 0);
else
gi.sound (self, CHAN_VOICE, sound_idle2, 1, ATTN_IDLE, 0);
}
mframe_t chick_frames_fidget [] =
{
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, ChickMoan,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL
};
mmove_t chick_move_fidget = {FRAME_stand201, FRAME_stand230, chick_frames_fidget, chick_stand};
void chick_fidget (edict_t *self)
{
if (self->monsterinfo.aiflags & AI_STAND_GROUND)
return;
if (random() <= 0.3)
self->monsterinfo.currentmove = &chick_move_fidget;
}
mframe_t chick_frames_stand [] =
{
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, chick_fidget,
};
mmove_t chick_move_stand = {FRAME_stand101, FRAME_stand130, chick_frames_stand, NULL};
void chick_stand (edict_t *self)
{
self->monsterinfo.currentmove = &chick_move_stand;
}
mframe_t chick_frames_start_run [] =
{
ai_run, 1, NULL,
ai_run, 0, NULL,
ai_run, 0, NULL,
ai_run, -1, NULL,
ai_run, -1, NULL,
ai_run, 0, NULL,
ai_run, 1, NULL,
ai_run, 3, NULL,
ai_run, 6, NULL,
ai_run, 3, NULL
};
mmove_t chick_move_start_run = {FRAME_walk01, FRAME_walk10, chick_frames_start_run, chick_run};
mframe_t chick_frames_run [] =
{
ai_run, 6, NULL,
ai_run, 8, NULL,
ai_run, 13, NULL,
ai_run, 5, NULL,
ai_run, 7, NULL,
ai_run, 4, NULL,
ai_run, 11, NULL,
ai_run, 5, NULL,
ai_run, 9, NULL,
ai_run, 7, NULL
};
mmove_t chick_move_run = {FRAME_walk11, FRAME_walk20, chick_frames_run, NULL};
mframe_t chick_frames_walk [] =
{
ai_walk, 6, NULL,
ai_walk, 8, NULL,
ai_walk, 13, NULL,
ai_walk, 5, NULL,
ai_walk, 7, NULL,
ai_walk, 4, NULL,
ai_walk, 11, NULL,
ai_walk, 5, NULL,
ai_walk, 9, NULL,
ai_walk, 7, NULL
};
mmove_t chick_move_walk = {FRAME_walk11, FRAME_walk20, chick_frames_walk, NULL};
void chick_walk (edict_t *self)
{
self->monsterinfo.currentmove = &chick_move_walk;
}
void chick_run (edict_t *self)
{
if (self->monsterinfo.aiflags & AI_STAND_GROUND)
{
self->monsterinfo.currentmove = &chick_move_stand;
return;
}
if (self->monsterinfo.currentmove == &chick_move_walk ||
self->monsterinfo.currentmove == &chick_move_start_run)
{
self->monsterinfo.currentmove = &chick_move_run;
}
else
{
self->monsterinfo.currentmove = &chick_move_start_run;
}
}
mframe_t chick_frames_pain1 [] =
{
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL
};
mmove_t chick_move_pain1 = {FRAME_pain101, FRAME_pain105, chick_frames_pain1, chick_run};
mframe_t chick_frames_pain2 [] =
{
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL
};
mmove_t chick_move_pain2 = {FRAME_pain201, FRAME_pain205, chick_frames_pain2, chick_run};
mframe_t chick_frames_pain3 [] =
{
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, -6, NULL,
ai_move, 3, NULL,
ai_move, 11, NULL,
ai_move, 3, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 4, NULL,
ai_move, 1, NULL,
ai_move, 0, NULL,
ai_move, -3, NULL,
ai_move, -4, NULL,
ai_move, 5, NULL,
ai_move, 7, NULL,
ai_move, -2, NULL,
ai_move, 3, NULL,
ai_move, -5, NULL,
ai_move, -2, NULL,
ai_move, -8, NULL,
ai_move, 2, NULL
};
mmove_t chick_move_pain3 = {FRAME_pain301, FRAME_pain321, chick_frames_pain3, chick_run};
void chick_pain (edict_t *self, edict_t *other, float kick, int damage)
{
float r;
if (self->health < (self->max_health / 2))
self->s.skinnum = 1;
if (level.time < self->pain_debounce_time)
return;
self->pain_debounce_time = level.time + 3;
r = random();
if (r < 0.33)
gi.sound (self, CHAN_VOICE, sound_pain1, 1, ATTN_NORM, 0);
else if (r < 0.66)
gi.sound (self, CHAN_VOICE, sound_pain2, 1, ATTN_NORM, 0);
else
gi.sound (self, CHAN_VOICE, sound_pain3, 1, ATTN_NORM, 0);
if (skill->value == 3)
return; // no pain anims in nightmare
if (damage <= 10)
self->monsterinfo.currentmove = &chick_move_pain1;
else if (damage <= 25)
self->monsterinfo.currentmove = &chick_move_pain2;
else
self->monsterinfo.currentmove = &chick_move_pain3;
}
void chick_dead (edict_t *self)
{
VectorSet (self->mins, -16, -16, 0);
VectorSet (self->maxs, 16, 16, 16);
self->movetype = MOVETYPE_TOSS;
self->svflags |= SVF_DEADMONSTER;
self->nextthink = 0;
gi.linkentity (self);
}
mframe_t chick_frames_death2 [] =
{
ai_move, -6, NULL,
ai_move, 0, NULL,
ai_move, -1, NULL,
ai_move, -5, NULL,
ai_move, 0, NULL,
ai_move, -1, NULL,
ai_move, -2, NULL,
ai_move, 1, NULL,
ai_move, 10, NULL,
ai_move, 2, NULL,
ai_move, 3, NULL,
ai_move, 1, NULL,
ai_move, 2, NULL,
ai_move, 0, NULL,
ai_move, 3, NULL,
ai_move, 3, NULL,
ai_move, 1, NULL,
ai_move, -3, NULL,
ai_move, -5, NULL,
ai_move, 4, NULL,
ai_move, 15, NULL,
ai_move, 14, NULL,
ai_move, 1, NULL
};
mmove_t chick_move_death2 = {FRAME_death201, FRAME_death223, chick_frames_death2, chick_dead};
mframe_t chick_frames_death1 [] =
{
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, -7, NULL,
ai_move, 4, NULL,
ai_move, 11, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL
};
mmove_t chick_move_death1 = {FRAME_death101, FRAME_death112, chick_frames_death1, chick_dead};
void chick_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
{
int n;
// check for gib
if (self->health <= self->gib_health)
{
gi.sound (self, CHAN_VOICE, gi.soundindex ("misc/udeath.wav"), 1, ATTN_NORM, 0);
for (n= 0; n < 2; n++)
ThrowGib (self, "models/objects/gibs/bone/tris.md2", damage, GIB_ORGANIC);
for (n= 0; n < 4; n++)
ThrowGib (self, "models/objects/gibs/sm_meat/tris.md2", damage, GIB_ORGANIC);
ThrowHead (self, "models/objects/gibs/head2/tris.md2", damage, GIB_ORGANIC);
self->deadflag = DEAD_DEAD;
return;
}
if (self->deadflag == DEAD_DEAD)
return;
// regular death
self->deadflag = DEAD_DEAD;
self->takedamage = DAMAGE_YES;
n = rand() % 2;
if (n == 0)
{
self->monsterinfo.currentmove = &chick_move_death1;
gi.sound (self, CHAN_VOICE, sound_death1, 1, ATTN_NORM, 0);
}
else
{
self->monsterinfo.currentmove = &chick_move_death2;
gi.sound (self, CHAN_VOICE, sound_death2, 1, ATTN_NORM, 0);
}
}
void chick_duck_down (edict_t *self)
{
if (self->monsterinfo.aiflags & AI_DUCKED)
return;
self->monsterinfo.aiflags |= AI_DUCKED;
self->maxs[2] -= 32;
self->takedamage = DAMAGE_YES;
self->monsterinfo.pausetime = level.time + 1;
gi.linkentity (self);
}
void chick_duck_hold (edict_t *self)
{
if (level.time >= self->monsterinfo.pausetime)
self->monsterinfo.aiflags &= ~AI_HOLD_FRAME;
else
self->monsterinfo.aiflags |= AI_HOLD_FRAME;
}
void chick_duck_up (edict_t *self)
{
self->monsterinfo.aiflags &= ~AI_DUCKED;
self->maxs[2] += 32;
self->takedamage = DAMAGE_AIM;
gi.linkentity (self);
}
mframe_t chick_frames_duck [] =
{
ai_move, 0, chick_duck_down,
ai_move, 1, NULL,
ai_move, 4, chick_duck_hold,
ai_move, -4, NULL,
ai_move, -5, chick_duck_up,
ai_move, 3, NULL,
ai_move, 1, NULL
};
mmove_t chick_move_duck = {FRAME_duck01, FRAME_duck07, chick_frames_duck, chick_run};
void chick_dodge (edict_t *self, edict_t *attacker, float eta)
{
if (random() > 0.25)
return;
if (!self->enemy)
self->enemy = attacker;
self->monsterinfo.currentmove = &chick_move_duck;
}
void ChickSlash (edict_t *self)
{
vec3_t aim;
VectorSet (aim, MELEE_DISTANCE, self->mins[0], 10);
gi.sound (self, CHAN_WEAPON, sound_melee_swing, 1, ATTN_NORM, 0);
fire_hit (self, aim, (10 + (rand() %6)), 100);
}
void ChickRocket (edict_t *self)
{
vec3_t forward, right;
vec3_t start;
vec3_t dir;
vec3_t vec;
AngleVectors (self->s.angles, forward, right, NULL);
G_ProjectSource (self->s.origin, monster_flash_offset[MZ2_CHICK_ROCKET_1], forward, right, start);
VectorCopy (self->enemy->s.origin, vec);
vec[2] += self->enemy->viewheight;
VectorSubtract (vec, start, dir);
VectorNormalize (dir);
monster_fire_rocket (self, start, dir, 50, 500, MZ2_CHICK_ROCKET_1);
}
void Chick_PreAttack1 (edict_t *self)
{
gi.sound (self, CHAN_VOICE, sound_missile_prelaunch, 1, ATTN_NORM, 0);
}
void ChickReload (edict_t *self)
{
gi.sound (self, CHAN_VOICE, sound_missile_reload, 1, ATTN_NORM, 0);
}
mframe_t chick_frames_start_attack1 [] =
{
ai_charge, 0, Chick_PreAttack1,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 4, NULL,
ai_charge, 0, NULL,
ai_charge, -3, NULL,
ai_charge, 3, NULL,
ai_charge, 5, NULL,
ai_charge, 7, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, chick_attack1
};
mmove_t chick_move_start_attack1 = {FRAME_attak101, FRAME_attak113, chick_frames_start_attack1, NULL};
mframe_t chick_frames_attack1 [] =
{
ai_charge, 19, ChickRocket,
ai_charge, -6, NULL,
ai_charge, -5, NULL,
ai_charge, -2, NULL,
ai_charge, -7, NULL,
ai_charge, 0, NULL,
ai_charge, 1, NULL,
ai_charge, 10, ChickReload,
ai_charge, 4, NULL,
ai_charge, 5, NULL,
ai_charge, 6, NULL,
ai_charge, 6, NULL,
ai_charge, 4, NULL,
ai_charge, 3, chick_rerocket
};
mmove_t chick_move_attack1 = {FRAME_attak114, FRAME_attak127, chick_frames_attack1, NULL};
mframe_t chick_frames_end_attack1 [] =
{
ai_charge, -3, NULL,
ai_charge, 0, NULL,
ai_charge, -6, NULL,
ai_charge, -4, NULL,
ai_charge, -2, NULL
};
mmove_t chick_move_end_attack1 = {FRAME_attak128, FRAME_attak132, chick_frames_end_attack1, chick_run};
void chick_rerocket(edict_t *self)
{
if (self->enemy->health > 0)
{
if (range (self, self->enemy) > RANGE_MELEE)
if ( visible (self, self->enemy) )
if (random() <= 0.6)
{
self->monsterinfo.currentmove = &chick_move_attack1;
return;
}
}
self->monsterinfo.currentmove = &chick_move_end_attack1;
}
void chick_attack1(edict_t *self)
{
self->monsterinfo.currentmove = &chick_move_attack1;
}
mframe_t chick_frames_slash [] =
{
ai_charge, 1, NULL,
ai_charge, 7, ChickSlash,
ai_charge, -7, NULL,
ai_charge, 1, NULL,
ai_charge, -1, NULL,
ai_charge, 1, NULL,
ai_charge, 0, NULL,
ai_charge, 1, NULL,
ai_charge, -2, chick_reslash
};
mmove_t chick_move_slash = {FRAME_attak204, FRAME_attak212, chick_frames_slash, NULL};
mframe_t chick_frames_end_slash [] =
{
ai_charge, -6, NULL,
ai_charge, -1, NULL,
ai_charge, -6, NULL,
ai_charge, 0, NULL
};
mmove_t chick_move_end_slash = {FRAME_attak213, FRAME_attak216, chick_frames_end_slash, chick_run};
void chick_reslash(edict_t *self)
{
if (self->enemy->health > 0)
{
if (range (self, self->enemy) == RANGE_MELEE)
if (random() <= 0.9)
{
self->monsterinfo.currentmove = &chick_move_slash;
return;
}
else
{
self->monsterinfo.currentmove = &chick_move_end_slash;
return;
}
}
self->monsterinfo.currentmove = &chick_move_end_slash;
}
void chick_slash(edict_t *self)
{
self->monsterinfo.currentmove = &chick_move_slash;
}
mframe_t chick_frames_start_slash [] =
{
ai_charge, 1, NULL,
ai_charge, 8, NULL,
ai_charge, 3, NULL
};
mmove_t chick_move_start_slash = {FRAME_attak201, FRAME_attak203, chick_frames_start_slash, chick_slash};
void chick_melee(edict_t *self)
{
self->monsterinfo.currentmove = &chick_move_start_slash;
}
void chick_attack(edict_t *self)
{
self->monsterinfo.currentmove = &chick_move_start_attack1;
}
void chick_sight(edict_t *self, edict_t *other)
{
gi.sound (self, CHAN_VOICE, sound_sight, 1, ATTN_NORM, 0);
}
/*QUAKED monster_chick (1 .5 0) (-16 -16 -24) (16 16 32) Ambush Trigger_Spawn Sight
*/
void SP_monster_chick (edict_t *self)
{
if (deathmatch->value)
{
G_FreeEdict (self);
return;
}
sound_missile_prelaunch = gi.soundindex ("chick/chkatck1.wav");
sound_missile_launch = gi.soundindex ("chick/chkatck2.wav");
sound_melee_swing = gi.soundindex ("chick/chkatck3.wav");
sound_melee_hit = gi.soundindex ("chick/chkatck4.wav");
sound_missile_reload = gi.soundindex ("chick/chkatck5.wav");
sound_death1 = gi.soundindex ("chick/chkdeth1.wav");
sound_death2 = gi.soundindex ("chick/chkdeth2.wav");
sound_fall_down = gi.soundindex ("chick/chkfall1.wav");
sound_idle1 = gi.soundindex ("chick/chkidle1.wav");
sound_idle2 = gi.soundindex ("chick/chkidle2.wav");
sound_pain1 = gi.soundindex ("chick/chkpain1.wav");
sound_pain2 = gi.soundindex ("chick/chkpain2.wav");
sound_pain3 = gi.soundindex ("chick/chkpain3.wav");
sound_sight = gi.soundindex ("chick/chksght1.wav");
sound_search = gi.soundindex ("chick/chksrch1.wav");
self->movetype = MOVETYPE_STEP;
self->solid = SOLID_BBOX;
self->s.modelindex = gi.modelindex ("models/monsters/bitch/tris.md2");
VectorSet (self->mins, -16, -16, 0);
VectorSet (self->maxs, 16, 16, 56);
self->health = 175;
self->gib_health = -70;
self->mass = 200;
self->pain = chick_pain;
self->die = chick_die;
self->monsterinfo.stand = chick_stand;
self->monsterinfo.walk = chick_walk;
self->monsterinfo.run = chick_run;
self->monsterinfo.dodge = chick_dodge;
self->monsterinfo.attack = chick_attack;
self->monsterinfo.melee = chick_melee;
self->monsterinfo.sight = chick_sight;
gi.linkentity (self);
self->monsterinfo.currentmove = &chick_move_stand;
self->monsterinfo.scale = MODEL_SCALE;
walkmonster_start (self);
}

313
game/m_chick.h Normal file
View File

@ -0,0 +1,313 @@
/*
Copyright (C) 1997-2001 Id Software, Inc.
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 the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
// G:\quake2\baseq2\models/monsters/bitch
// This file generated by qdata - Do NOT Modify
#define FRAME_attak101 0
#define FRAME_attak102 1
#define FRAME_attak103 2
#define FRAME_attak104 3
#define FRAME_attak105 4
#define FRAME_attak106 5
#define FRAME_attak107 6
#define FRAME_attak108 7
#define FRAME_attak109 8
#define FRAME_attak110 9
#define FRAME_attak111 10
#define FRAME_attak112 11
#define FRAME_attak113 12
#define FRAME_attak114 13
#define FRAME_attak115 14
#define FRAME_attak116 15
#define FRAME_attak117 16
#define FRAME_attak118 17
#define FRAME_attak119 18
#define FRAME_attak120 19
#define FRAME_attak121 20
#define FRAME_attak122 21
#define FRAME_attak123 22
#define FRAME_attak124 23
#define FRAME_attak125 24
#define FRAME_attak126 25
#define FRAME_attak127 26
#define FRAME_attak128 27
#define FRAME_attak129 28
#define FRAME_attak130 29
#define FRAME_attak131 30
#define FRAME_attak132 31
#define FRAME_attak201 32
#define FRAME_attak202 33
#define FRAME_attak203 34
#define FRAME_attak204 35
#define FRAME_attak205 36
#define FRAME_attak206 37
#define FRAME_attak207 38
#define FRAME_attak208 39
#define FRAME_attak209 40
#define FRAME_attak210 41
#define FRAME_attak211 42
#define FRAME_attak212 43
#define FRAME_attak213 44
#define FRAME_attak214 45
#define FRAME_attak215 46
#define FRAME_attak216 47
#define FRAME_death101 48
#define FRAME_death102 49
#define FRAME_death103 50
#define FRAME_death104 51
#define FRAME_death105 52
#define FRAME_death106 53
#define FRAME_death107 54
#define FRAME_death108 55
#define FRAME_death109 56
#define FRAME_death110 57
#define FRAME_death111 58
#define FRAME_death112 59
#define FRAME_death201 60
#define FRAME_death202 61
#define FRAME_death203 62
#define FRAME_death204 63
#define FRAME_death205 64
#define FRAME_death206 65
#define FRAME_death207 66
#define FRAME_death208 67
#define FRAME_death209 68
#define FRAME_death210 69
#define FRAME_death211 70
#define FRAME_death212 71
#define FRAME_death213 72
#define FRAME_death214 73
#define FRAME_death215 74
#define FRAME_death216 75
#define FRAME_death217 76
#define FRAME_death218 77
#define FRAME_death219 78
#define FRAME_death220 79
#define FRAME_death221 80
#define FRAME_death222 81
#define FRAME_death223 82
#define FRAME_duck01 83
#define FRAME_duck02 84
#define FRAME_duck03 85
#define FRAME_duck04 86
#define FRAME_duck05 87
#define FRAME_duck06 88
#define FRAME_duck07 89
#define FRAME_pain101 90
#define FRAME_pain102 91
#define FRAME_pain103 92
#define FRAME_pain104 93
#define FRAME_pain105 94
#define FRAME_pain201 95
#define FRAME_pain202 96
#define FRAME_pain203 97
#define FRAME_pain204 98
#define FRAME_pain205 99
#define FRAME_pain301 100
#define FRAME_pain302 101
#define FRAME_pain303 102
#define FRAME_pain304 103
#define FRAME_pain305 104
#define FRAME_pain306 105
#define FRAME_pain307 106
#define FRAME_pain308 107
#define FRAME_pain309 108
#define FRAME_pain310 109
#define FRAME_pain311 110
#define FRAME_pain312 111
#define FRAME_pain313 112
#define FRAME_pain314 113
#define FRAME_pain315 114
#define FRAME_pain316 115
#define FRAME_pain317 116
#define FRAME_pain318 117
#define FRAME_pain319 118
#define FRAME_pain320 119
#define FRAME_pain321 120
#define FRAME_stand101 121
#define FRAME_stand102 122
#define FRAME_stand103 123
#define FRAME_stand104 124
#define FRAME_stand105 125
#define FRAME_stand106 126
#define FRAME_stand107 127
#define FRAME_stand108 128
#define FRAME_stand109 129
#define FRAME_stand110 130
#define FRAME_stand111 131
#define FRAME_stand112 132
#define FRAME_stand113 133
#define FRAME_stand114 134
#define FRAME_stand115 135
#define FRAME_stand116 136
#define FRAME_stand117 137
#define FRAME_stand118 138
#define FRAME_stand119 139
#define FRAME_stand120 140
#define FRAME_stand121 141
#define FRAME_stand122 142
#define FRAME_stand123 143
#define FRAME_stand124 144
#define FRAME_stand125 145
#define FRAME_stand126 146
#define FRAME_stand127 147
#define FRAME_stand128 148
#define FRAME_stand129 149
#define FRAME_stand130 150
#define FRAME_stand201 151
#define FRAME_stand202 152
#define FRAME_stand203 153
#define FRAME_stand204 154
#define FRAME_stand205 155
#define FRAME_stand206 156
#define FRAME_stand207 157
#define FRAME_stand208 158
#define FRAME_stand209 159
#define FRAME_stand210 160
#define FRAME_stand211 161
#define FRAME_stand212 162
#define FRAME_stand213 163
#define FRAME_stand214 164
#define FRAME_stand215 165
#define FRAME_stand216 166
#define FRAME_stand217 167
#define FRAME_stand218 168
#define FRAME_stand219 169
#define FRAME_stand220 170
#define FRAME_stand221 171
#define FRAME_stand222 172
#define FRAME_stand223 173
#define FRAME_stand224 174
#define FRAME_stand225 175
#define FRAME_stand226 176
#define FRAME_stand227 177
#define FRAME_stand228 178
#define FRAME_stand229 179
#define FRAME_stand230 180
#define FRAME_walk01 181
#define FRAME_walk02 182
#define FRAME_walk03 183
#define FRAME_walk04 184
#define FRAME_walk05 185
#define FRAME_walk06 186
#define FRAME_walk07 187
#define FRAME_walk08 188
#define FRAME_walk09 189
#define FRAME_walk10 190
#define FRAME_walk11 191
#define FRAME_walk12 192
#define FRAME_walk13 193
#define FRAME_walk14 194
#define FRAME_walk15 195
#define FRAME_walk16 196
#define FRAME_walk17 197
#define FRAME_walk18 198
#define FRAME_walk19 199
#define FRAME_walk20 200
#define FRAME_walk21 201
#define FRAME_walk22 202
#define FRAME_walk23 203
#define FRAME_walk24 204
#define FRAME_walk25 205
#define FRAME_walk26 206
#define FRAME_walk27 207
#define FRAME_recln201 208
#define FRAME_recln202 209
#define FRAME_recln203 210
#define FRAME_recln204 211
#define FRAME_recln205 212
#define FRAME_recln206 213
#define FRAME_recln207 214
#define FRAME_recln208 215
#define FRAME_recln209 216
#define FRAME_recln210 217
#define FRAME_recln211 218
#define FRAME_recln212 219
#define FRAME_recln213 220
#define FRAME_recln214 221
#define FRAME_recln215 222
#define FRAME_recln216 223
#define FRAME_recln217 224
#define FRAME_recln218 225
#define FRAME_recln219 226
#define FRAME_recln220 227
#define FRAME_recln221 228
#define FRAME_recln222 229
#define FRAME_recln223 230
#define FRAME_recln224 231
#define FRAME_recln225 232
#define FRAME_recln226 233
#define FRAME_recln227 234
#define FRAME_recln228 235
#define FRAME_recln229 236
#define FRAME_recln230 237
#define FRAME_recln231 238
#define FRAME_recln232 239
#define FRAME_recln233 240
#define FRAME_recln234 241
#define FRAME_recln235 242
#define FRAME_recln236 243
#define FRAME_recln237 244
#define FRAME_recln238 245
#define FRAME_recln239 246
#define FRAME_recln240 247
#define FRAME_recln101 248
#define FRAME_recln102 249
#define FRAME_recln103 250
#define FRAME_recln104 251
#define FRAME_recln105 252
#define FRAME_recln106 253
#define FRAME_recln107 254
#define FRAME_recln108 255
#define FRAME_recln109 256
#define FRAME_recln110 257
#define FRAME_recln111 258
#define FRAME_recln112 259
#define FRAME_recln113 260
#define FRAME_recln114 261
#define FRAME_recln115 262
#define FRAME_recln116 263
#define FRAME_recln117 264
#define FRAME_recln118 265
#define FRAME_recln119 266
#define FRAME_recln120 267
#define FRAME_recln121 268
#define FRAME_recln122 269
#define FRAME_recln123 270
#define FRAME_recln124 271
#define FRAME_recln125 272
#define FRAME_recln126 273
#define FRAME_recln127 274
#define FRAME_recln128 275
#define FRAME_recln129 276
#define FRAME_recln130 277
#define FRAME_recln131 278
#define FRAME_recln132 279
#define FRAME_recln133 280
#define FRAME_recln134 281
#define FRAME_recln135 282
#define FRAME_recln136 283
#define FRAME_recln137 284
#define FRAME_recln138 285
#define FRAME_recln139 286
#define FRAME_recln140 287
#define MODEL_SCALE 1.000000

488
game/m_flash.c Normal file
View File

@ -0,0 +1,488 @@
/*
Copyright (C) 1997-2001 Id Software, Inc.
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 the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
// m_flash.c
#include "q_shared.h"
// this file is included in both the game dll and quake2,
// the game needs it to source shot locations, the client
// needs it to position muzzle flashes
vec3_t monster_flash_offset [] =
{
// flash 0 is not used
0.0, 0.0, 0.0,
// MZ2_TANK_BLASTER_1 1
20.7, -18.5, 28.7,
// MZ2_TANK_BLASTER_2 2
16.6, -21.5, 30.1,
// MZ2_TANK_BLASTER_3 3
11.8, -23.9, 32.1,
// MZ2_TANK_MACHINEGUN_1 4
22.9, -0.7, 25.3,
// MZ2_TANK_MACHINEGUN_2 5
22.2, 6.2, 22.3,
// MZ2_TANK_MACHINEGUN_3 6
19.4, 13.1, 18.6,
// MZ2_TANK_MACHINEGUN_4 7
19.4, 18.8, 18.6,
// MZ2_TANK_MACHINEGUN_5 8
17.9, 25.0, 18.6,
// MZ2_TANK_MACHINEGUN_6 9
14.1, 30.5, 20.6,
// MZ2_TANK_MACHINEGUN_7 10
9.3, 35.3, 22.1,
// MZ2_TANK_MACHINEGUN_8 11
4.7, 38.4, 22.1,
// MZ2_TANK_MACHINEGUN_9 12
-1.1, 40.4, 24.1,
// MZ2_TANK_MACHINEGUN_10 13
-6.5, 41.2, 24.1,
// MZ2_TANK_MACHINEGUN_11 14
3.2, 40.1, 24.7,
// MZ2_TANK_MACHINEGUN_12 15
11.7, 36.7, 26.0,
// MZ2_TANK_MACHINEGUN_13 16
18.9, 31.3, 26.0,
// MZ2_TANK_MACHINEGUN_14 17
24.4, 24.4, 26.4,
// MZ2_TANK_MACHINEGUN_15 18
27.1, 17.1, 27.2,
// MZ2_TANK_MACHINEGUN_16 19
28.5, 9.1, 28.0,
// MZ2_TANK_MACHINEGUN_17 20
27.1, 2.2, 28.0,
// MZ2_TANK_MACHINEGUN_18 21
24.9, -2.8, 28.0,
// MZ2_TANK_MACHINEGUN_19 22
21.6, -7.0, 26.4,
// MZ2_TANK_ROCKET_1 23
6.2, 29.1, 49.1,
// MZ2_TANK_ROCKET_2 24
6.9, 23.8, 49.1,
// MZ2_TANK_ROCKET_3 25
8.3, 17.8, 49.5,
// MZ2_INFANTRY_MACHINEGUN_1 26
26.6, 7.1, 13.1,
// MZ2_INFANTRY_MACHINEGUN_2 27
18.2, 7.5, 15.4,
// MZ2_INFANTRY_MACHINEGUN_3 28
17.2, 10.3, 17.9,
// MZ2_INFANTRY_MACHINEGUN_4 29
17.0, 12.8, 20.1,
// MZ2_INFANTRY_MACHINEGUN_5 30
15.1, 14.1, 21.8,
// MZ2_INFANTRY_MACHINEGUN_6 31
11.8, 17.2, 23.1,
// MZ2_INFANTRY_MACHINEGUN_7 32
11.4, 20.2, 21.0,
// MZ2_INFANTRY_MACHINEGUN_8 33
9.0, 23.0, 18.9,
// MZ2_INFANTRY_MACHINEGUN_9 34
13.9, 18.6, 17.7,
// MZ2_INFANTRY_MACHINEGUN_10 35
15.4, 15.6, 15.8,
// MZ2_INFANTRY_MACHINEGUN_11 36
10.2, 15.2, 25.1,
// MZ2_INFANTRY_MACHINEGUN_12 37
-1.9, 15.1, 28.2,
// MZ2_INFANTRY_MACHINEGUN_13 38
-12.4, 13.0, 20.2,
// MZ2_SOLDIER_BLASTER_1 39
10.6 * 1.2, 7.7 * 1.2, 7.8 * 1.2,
// MZ2_SOLDIER_BLASTER_2 40
21.1 * 1.2, 3.6 * 1.2, 19.0 * 1.2,
// MZ2_SOLDIER_SHOTGUN_1 41
10.6 * 1.2, 7.7 * 1.2, 7.8 * 1.2,
// MZ2_SOLDIER_SHOTGUN_2 42
21.1 * 1.2, 3.6 * 1.2, 19.0 * 1.2,
// MZ2_SOLDIER_MACHINEGUN_1 43
10.6 * 1.2, 7.7 * 1.2, 7.8 * 1.2,
// MZ2_SOLDIER_MACHINEGUN_2 44
21.1 * 1.2, 3.6 * 1.2, 19.0 * 1.2,
// MZ2_GUNNER_MACHINEGUN_1 45
30.1 * 1.15, 3.9 * 1.15, 19.6 * 1.15,
// MZ2_GUNNER_MACHINEGUN_2 46
29.1 * 1.15, 2.5 * 1.15, 20.7 * 1.15,
// MZ2_GUNNER_MACHINEGUN_3 47
28.2 * 1.15, 2.5 * 1.15, 22.2 * 1.15,
// MZ2_GUNNER_MACHINEGUN_4 48
28.2 * 1.15, 3.6 * 1.15, 22.0 * 1.15,
// MZ2_GUNNER_MACHINEGUN_5 49
26.9 * 1.15, 2.0 * 1.15, 23.4 * 1.15,
// MZ2_GUNNER_MACHINEGUN_6 50
26.5 * 1.15, 0.6 * 1.15, 20.8 * 1.15,
// MZ2_GUNNER_MACHINEGUN_7 51
26.9 * 1.15, 0.5 * 1.15, 21.5 * 1.15,
// MZ2_GUNNER_MACHINEGUN_8 52
29.0 * 1.15, 2.4 * 1.15, 19.5 * 1.15,
// MZ2_GUNNER_GRENADE_1 53
4.6 * 1.15, -16.8 * 1.15, 7.3 * 1.15,
// MZ2_GUNNER_GRENADE_2 54
4.6 * 1.15, -16.8 * 1.15, 7.3 * 1.15,
// MZ2_GUNNER_GRENADE_3 55
4.6 * 1.15, -16.8 * 1.15, 7.3 * 1.15,
// MZ2_GUNNER_GRENADE_4 56
4.6 * 1.15, -16.8 * 1.15, 7.3 * 1.15,
// MZ2_CHICK_ROCKET_1 57
// -24.8, -9.0, 39.0,
24.8, -9.0, 39.0, // PGM - this was incorrect in Q2
// MZ2_FLYER_BLASTER_1 58
12.1, 13.4, -14.5,
// MZ2_FLYER_BLASTER_2 59
12.1, -7.4, -14.5,
// MZ2_MEDIC_BLASTER_1 60
12.1, 5.4, 16.5,
// MZ2_GLADIATOR_RAILGUN_1 61
30.0, 18.0, 28.0,
// MZ2_HOVER_BLASTER_1 62
32.5, -0.8, 10.0,
// MZ2_ACTOR_MACHINEGUN_1 63
18.4, 7.4, 9.6,
// MZ2_SUPERTANK_MACHINEGUN_1 64
30.0, 30.0, 88.5,
// MZ2_SUPERTANK_MACHINEGUN_2 65
30.0, 30.0, 88.5,
// MZ2_SUPERTANK_MACHINEGUN_3 66
30.0, 30.0, 88.5,
// MZ2_SUPERTANK_MACHINEGUN_4 67
30.0, 30.0, 88.5,
// MZ2_SUPERTANK_MACHINEGUN_5 68
30.0, 30.0, 88.5,
// MZ2_SUPERTANK_MACHINEGUN_6 69
30.0, 30.0, 88.5,
// MZ2_SUPERTANK_ROCKET_1 70
16.0, -22.5, 91.2,
// MZ2_SUPERTANK_ROCKET_2 71
16.0, -33.4, 86.7,
// MZ2_SUPERTANK_ROCKET_3 72
16.0, -42.8, 83.3,
// --- Start Xian Stuff ---
// MZ2_BOSS2_MACHINEGUN_L1 73
32, -40, 70,
// MZ2_BOSS2_MACHINEGUN_L2 74
32, -40, 70,
// MZ2_BOSS2_MACHINEGUN_L3 75
32, -40, 70,
// MZ2_BOSS2_MACHINEGUN_L4 76
32, -40, 70,
// MZ2_BOSS2_MACHINEGUN_L5 77
32, -40, 70,
// --- End Xian Stuff
// MZ2_BOSS2_ROCKET_1 78
22.0, 16.0, 10.0,
// MZ2_BOSS2_ROCKET_2 79
22.0, 8.0, 10.0,
// MZ2_BOSS2_ROCKET_3 80
22.0, -8.0, 10.0,
// MZ2_BOSS2_ROCKET_4 81
22.0, -16.0, 10.0,
// MZ2_FLOAT_BLASTER_1 82
32.5, -0.8, 10,
// MZ2_SOLDIER_BLASTER_3 83
20.8 * 1.2, 10.1 * 1.2, -2.7 * 1.2,
// MZ2_SOLDIER_SHOTGUN_3 84
20.8 * 1.2, 10.1 * 1.2, -2.7 * 1.2,
// MZ2_SOLDIER_MACHINEGUN_3 85
20.8 * 1.2, 10.1 * 1.2, -2.7 * 1.2,
// MZ2_SOLDIER_BLASTER_4 86
7.6 * 1.2, 9.3 * 1.2, 0.8 * 1.2,
// MZ2_SOLDIER_SHOTGUN_4 87
7.6 * 1.2, 9.3 * 1.2, 0.8 * 1.2,
// MZ2_SOLDIER_MACHINEGUN_4 88
7.6 * 1.2, 9.3 * 1.2, 0.8 * 1.2,
// MZ2_SOLDIER_BLASTER_5 89
30.5 * 1.2, 9.9 * 1.2, -18.7 * 1.2,
// MZ2_SOLDIER_SHOTGUN_5 90
30.5 * 1.2, 9.9 * 1.2, -18.7 * 1.2,
// MZ2_SOLDIER_MACHINEGUN_5 91
30.5 * 1.2, 9.9 * 1.2, -18.7 * 1.2,
// MZ2_SOLDIER_BLASTER_6 92
27.6 * 1.2, 3.4 * 1.2, -10.4 * 1.2,
// MZ2_SOLDIER_SHOTGUN_6 93
27.6 * 1.2, 3.4 * 1.2, -10.4 * 1.2,
// MZ2_SOLDIER_MACHINEGUN_6 94
27.6 * 1.2, 3.4 * 1.2, -10.4 * 1.2,
// MZ2_SOLDIER_BLASTER_7 95
28.9 * 1.2, 4.6 * 1.2, -8.1 * 1.2,
// MZ2_SOLDIER_SHOTGUN_7 96
28.9 * 1.2, 4.6 * 1.2, -8.1 * 1.2,
// MZ2_SOLDIER_MACHINEGUN_7 97
28.9 * 1.2, 4.6 * 1.2, -8.1 * 1.2,
// MZ2_SOLDIER_BLASTER_8 98
// 34.5 * 1.2, 9.6 * 1.2, 6.1 * 1.2,
31.5 * 1.2, 9.6 * 1.2, 10.1 * 1.2,
// MZ2_SOLDIER_SHOTGUN_8 99
34.5 * 1.2, 9.6 * 1.2, 6.1 * 1.2,
// MZ2_SOLDIER_MACHINEGUN_8 100
34.5 * 1.2, 9.6 * 1.2, 6.1 * 1.2,
// --- Xian shit below ---
// MZ2_MAKRON_BFG 101
17, -19.5, 62.9,
// MZ2_MAKRON_BLASTER_1 102
-3.6, -24.1, 59.5,
// MZ2_MAKRON_BLASTER_2 103
-1.6, -19.3, 59.5,
// MZ2_MAKRON_BLASTER_3 104
-0.1, -14.4, 59.5,
// MZ2_MAKRON_BLASTER_4 105
2.0, -7.6, 59.5,
// MZ2_MAKRON_BLASTER_5 106
3.4, 1.3, 59.5,
// MZ2_MAKRON_BLASTER_6 107
3.7, 11.1, 59.5,
// MZ2_MAKRON_BLASTER_7 108
-0.3, 22.3, 59.5,
// MZ2_MAKRON_BLASTER_8 109
-6, 33, 59.5,
// MZ2_MAKRON_BLASTER_9 110
-9.3, 36.4, 59.5,
// MZ2_MAKRON_BLASTER_10 111
-7, 35, 59.5,
// MZ2_MAKRON_BLASTER_11 112
-2.1, 29, 59.5,
// MZ2_MAKRON_BLASTER_12 113
3.9, 17.3, 59.5,
// MZ2_MAKRON_BLASTER_13 114
6.1, 5.8, 59.5,
// MZ2_MAKRON_BLASTER_14 115
5.9, -4.4, 59.5,
// MZ2_MAKRON_BLASTER_15 116
4.2, -14.1, 59.5,
// MZ2_MAKRON_BLASTER_16 117
2.4, -18.8, 59.5,
// MZ2_MAKRON_BLASTER_17 118
-1.8, -25.5, 59.5,
// MZ2_MAKRON_RAILGUN_1 119
-17.3, 7.8, 72.4,
// MZ2_JORG_MACHINEGUN_L1 120
78.5, -47.1, 96,
// MZ2_JORG_MACHINEGUN_L2 121
78.5, -47.1, 96,
// MZ2_JORG_MACHINEGUN_L3 122
78.5, -47.1, 96,
// MZ2_JORG_MACHINEGUN_L4 123
78.5, -47.1, 96,
// MZ2_JORG_MACHINEGUN_L5 124
78.5, -47.1, 96,
// MZ2_JORG_MACHINEGUN_L6 125
78.5, -47.1, 96,
// MZ2_JORG_MACHINEGUN_R1 126
78.5, 46.7, 96,
// MZ2_JORG_MACHINEGUN_R2 127
78.5, 46.7, 96,
// MZ2_JORG_MACHINEGUN_R3 128
78.5, 46.7, 96,
// MZ2_JORG_MACHINEGUN_R4 129
78.5, 46.7, 96,
// MZ2_JORG_MACHINEGUN_R5 130
78.5, 46.7, 96,
// MZ2_JORG_MACHINEGUN_R6 131
78.5, 46.7, 96,
// MZ2_JORG_BFG_1 132
6.3, -9, 111.2,
// MZ2_BOSS2_MACHINEGUN_R1 73
32, 40, 70,
// MZ2_BOSS2_MACHINEGUN_R2 74
32, 40, 70,
// MZ2_BOSS2_MACHINEGUN_R3 75
32, 40, 70,
// MZ2_BOSS2_MACHINEGUN_R4 76
32, 40, 70,
// MZ2_BOSS2_MACHINEGUN_R5 77
32, 40, 70,
// --- End Xian Shit ---
// ROGUE
// note that the above really ends at 137
// carrier machineguns
// MZ2_CARRIER_MACHINEGUN_L1
56, -32, 32,
// MZ2_CARRIER_MACHINEGUN_R1
56, 32, 32,
// MZ2_CARRIER_GRENADE
42, 24, 50,
// MZ2_TURRET_MACHINEGUN 141
16, 0, 0,
// MZ2_TURRET_ROCKET 142
16, 0, 0,
// MZ2_TURRET_BLASTER 143
16, 0, 0,
// MZ2_STALKER_BLASTER 144
24, 0, 6,
// MZ2_DAEDALUS_BLASTER 145
32.5, -0.8, 10.0,
// MZ2_MEDIC_BLASTER_2 146
12.1, 5.4, 16.5,
// MZ2_CARRIER_RAILGUN 147
32, 0, 6,
// MZ2_WIDOW_DISRUPTOR 148
57.72, 14.50, 88.81,
// MZ2_WIDOW_BLASTER 149
56, 32, 32,
// MZ2_WIDOW_RAIL 150
62, -20, 84,
// MZ2_WIDOW_PLASMABEAM 151 // PMM - not used!
32, 0, 6,
// MZ2_CARRIER_MACHINEGUN_L2 152
61, -32, 12,
// MZ2_CARRIER_MACHINEGUN_R2 153
61, 32, 12,
// MZ2_WIDOW_RAIL_LEFT 154
17, -62, 91,
// MZ2_WIDOW_RAIL_RIGHT 155
68, 12, 86,
// MZ2_WIDOW_BLASTER_SWEEP1 156 pmm - the sweeps need to be in sequential order
47.5, 56, 89,
// MZ2_WIDOW_BLASTER_SWEEP2 157
54, 52, 91,
// MZ2_WIDOW_BLASTER_SWEEP3 158
58, 40, 91,
// MZ2_WIDOW_BLASTER_SWEEP4 159
68, 30, 88,
// MZ2_WIDOW_BLASTER_SWEEP5 160
74, 20, 88,
// MZ2_WIDOW_BLASTER_SWEEP6 161
73, 11, 87,
// MZ2_WIDOW_BLASTER_SWEEP7 162
73, 3, 87,
// MZ2_WIDOW_BLASTER_SWEEP8 163
70, -12, 87,
// MZ2_WIDOW_BLASTER_SWEEP9 164
67, -20, 90,
// MZ2_WIDOW_BLASTER_100 165
-20, 76, 90,
// MZ2_WIDOW_BLASTER_90 166
-8, 74, 90,
// MZ2_WIDOW_BLASTER_80 167
0, 72, 90,
// MZ2_WIDOW_BLASTER_70 168 d06
10, 71, 89,
// MZ2_WIDOW_BLASTER_60 169 d07
23, 70, 87,
// MZ2_WIDOW_BLASTER_50 170 d08
32, 64, 85,
// MZ2_WIDOW_BLASTER_40 171
40, 58, 84,
// MZ2_WIDOW_BLASTER_30 172 d10
48, 50, 83,
// MZ2_WIDOW_BLASTER_20 173
54, 42, 82,
// MZ2_WIDOW_BLASTER_10 174 d12
56, 34, 82,
// MZ2_WIDOW_BLASTER_0 175
58, 26, 82,
// MZ2_WIDOW_BLASTER_10L 176 d14
60, 16, 82,
// MZ2_WIDOW_BLASTER_20L 177
59, 6, 81,
// MZ2_WIDOW_BLASTER_30L 178 d16
58, -2, 80,
// MZ2_WIDOW_BLASTER_40L 179
57, -10, 79,
// MZ2_WIDOW_BLASTER_50L 180 d18
54, -18, 78,
// MZ2_WIDOW_BLASTER_60L 181
42, -32, 80,
// MZ2_WIDOW_BLASTER_70L 182 d20
36, -40, 78,
// MZ2_WIDOW_RUN_1 183
68.4, 10.88, 82.08,
// MZ2_WIDOW_RUN_2 184
68.51, 8.64, 85.14,
// MZ2_WIDOW_RUN_3 185
68.66, 6.38, 88.78,
// MZ2_WIDOW_RUN_4 186
68.73, 5.1, 84.47,
// MZ2_WIDOW_RUN_5 187
68.82, 4.79, 80.52,
// MZ2_WIDOW_RUN_6 188
68.77, 6.11, 85.37,
// MZ2_WIDOW_RUN_7 189
68.67, 7.99, 90.24,
// MZ2_WIDOW_RUN_8 190
68.55, 9.54, 87.36,
// MZ2_CARRIER_ROCKET_1 191
0, 0, -5,
// MZ2_CARRIER_ROCKET_2 192
0, 0, -5,
// MZ2_CARRIER_ROCKET_3 193
0, 0, -5,
// MZ2_CARRIER_ROCKET_4 194
0, 0, -5,
// MZ2_WIDOW2_BEAMER_1 195
// 72.13, -17.63, 93.77,
69.00, -17.63, 93.77,
// MZ2_WIDOW2_BEAMER_2 196
// 71.46, -17.08, 89.82,
69.00, -17.08, 89.82,
// MZ2_WIDOW2_BEAMER_3 197
// 71.47, -18.40, 90.70,
69.00, -18.40, 90.70,
// MZ2_WIDOW2_BEAMER_4 198
// 71.96, -18.34, 94.32,
69.00, -18.34, 94.32,
// MZ2_WIDOW2_BEAMER_5 199
// 72.25, -18.30, 97.98,
69.00, -18.30, 97.98,
// MZ2_WIDOW2_BEAM_SWEEP_1 200
45.04, -59.02, 92.24,
// MZ2_WIDOW2_BEAM_SWEEP_2 201
50.68, -54.70, 91.96,
// MZ2_WIDOW2_BEAM_SWEEP_3 202
56.57, -47.72, 91.65,
// MZ2_WIDOW2_BEAM_SWEEP_4 203
61.75, -38.75, 91.38,
// MZ2_WIDOW2_BEAM_SWEEP_5 204
65.55, -28.76, 91.24,
// MZ2_WIDOW2_BEAM_SWEEP_6 205
67.79, -18.90, 91.22,
// MZ2_WIDOW2_BEAM_SWEEP_7 206
68.60, -9.52, 91.23,
// MZ2_WIDOW2_BEAM_SWEEP_8 207
68.08, 0.18, 91.32,
// MZ2_WIDOW2_BEAM_SWEEP_9 208
66.14, 9.79, 91.44,
// MZ2_WIDOW2_BEAM_SWEEP_10 209
62.77, 18.91, 91.65,
// MZ2_WIDOW2_BEAM_SWEEP_11 210
58.29, 27.11, 92.00,
// end of table
0.0, 0.0, 0.0
};

403
game/m_flipper.c Normal file
View File

@ -0,0 +1,403 @@
/*
Copyright (C) 1997-2001 Id Software, Inc.
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 the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/*
==============================================================================
FLIPPER
==============================================================================
*/
#include "g_local.h"
#include "m_flipper.h"
static int sound_chomp;
static int sound_attack;
static int sound_pain1;
static int sound_pain2;
static int sound_death;
static int sound_idle;
static int sound_search;
static int sound_sight;
void flipper_stand (edict_t *self);
mframe_t flipper_frames_stand [] =
{
ai_stand, 0, NULL
};
mmove_t flipper_move_stand = {FRAME_flphor01, FRAME_flphor01, flipper_frames_stand, NULL};
void flipper_stand (edict_t *self)
{
self->monsterinfo.currentmove = &flipper_move_stand;
}
#define FLIPPER_RUN_SPEED 24
mframe_t flipper_frames_run [] =
{
ai_run, FLIPPER_RUN_SPEED, NULL, // 6
ai_run, FLIPPER_RUN_SPEED, NULL,
ai_run, FLIPPER_RUN_SPEED, NULL,
ai_run, FLIPPER_RUN_SPEED, NULL,
ai_run, FLIPPER_RUN_SPEED, NULL, // 10
ai_run, FLIPPER_RUN_SPEED, NULL,
ai_run, FLIPPER_RUN_SPEED, NULL,
ai_run, FLIPPER_RUN_SPEED, NULL,
ai_run, FLIPPER_RUN_SPEED, NULL,
ai_run, FLIPPER_RUN_SPEED, NULL,
ai_run, FLIPPER_RUN_SPEED, NULL,
ai_run, FLIPPER_RUN_SPEED, NULL,
ai_run, FLIPPER_RUN_SPEED, NULL,
ai_run, FLIPPER_RUN_SPEED, NULL,
ai_run, FLIPPER_RUN_SPEED, NULL, // 20
ai_run, FLIPPER_RUN_SPEED, NULL,
ai_run, FLIPPER_RUN_SPEED, NULL,
ai_run, FLIPPER_RUN_SPEED, NULL,
ai_run, FLIPPER_RUN_SPEED, NULL,
ai_run, FLIPPER_RUN_SPEED, NULL,
ai_run, FLIPPER_RUN_SPEED, NULL,
ai_run, FLIPPER_RUN_SPEED, NULL,
ai_run, FLIPPER_RUN_SPEED, NULL,
ai_run, FLIPPER_RUN_SPEED, NULL // 29
};
mmove_t flipper_move_run_loop = {FRAME_flpver06, FRAME_flpver29, flipper_frames_run, NULL};
void flipper_run_loop (edict_t *self)
{
self->monsterinfo.currentmove = &flipper_move_run_loop;
}
mframe_t flipper_frames_run_start [] =
{
ai_run, 8, NULL,
ai_run, 8, NULL,
ai_run, 8, NULL,
ai_run, 8, NULL,
ai_run, 8, NULL,
ai_run, 8, NULL
};
mmove_t flipper_move_run_start = {FRAME_flpver01, FRAME_flpver06, flipper_frames_run_start, flipper_run_loop};
void flipper_run (edict_t *self)
{
self->monsterinfo.currentmove = &flipper_move_run_start;
}
/* Standard Swimming */
mframe_t flipper_frames_walk [] =
{
ai_walk, 4, NULL,
ai_walk, 4, NULL,
ai_walk, 4, NULL,
ai_walk, 4, NULL,
ai_walk, 4, NULL,
ai_walk, 4, NULL,
ai_walk, 4, NULL,
ai_walk, 4, NULL,
ai_walk, 4, NULL,
ai_walk, 4, NULL,
ai_walk, 4, NULL,
ai_walk, 4, NULL,
ai_walk, 4, NULL,
ai_walk, 4, NULL,
ai_walk, 4, NULL,
ai_walk, 4, NULL,
ai_walk, 4, NULL,
ai_walk, 4, NULL,
ai_walk, 4, NULL,
ai_walk, 4, NULL,
ai_walk, 4, NULL,
ai_walk, 4, NULL,
ai_walk, 4, NULL,
ai_walk, 4, NULL
};
mmove_t flipper_move_walk = {FRAME_flphor01, FRAME_flphor24, flipper_frames_walk, NULL};
void flipper_walk (edict_t *self)
{
self->monsterinfo.currentmove = &flipper_move_walk;
}
mframe_t flipper_frames_start_run [] =
{
ai_run, 8, NULL,
ai_run, 8, NULL,
ai_run, 8, NULL,
ai_run, 8, NULL,
ai_run, 8, flipper_run
};
mmove_t flipper_move_start_run = {FRAME_flphor01, FRAME_flphor05, flipper_frames_start_run, NULL};
void flipper_start_run (edict_t *self)
{
self->monsterinfo.currentmove = &flipper_move_start_run;
}
mframe_t flipper_frames_pain2 [] =
{
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL
};
mmove_t flipper_move_pain2 = {FRAME_flppn101, FRAME_flppn105, flipper_frames_pain2, flipper_run};
mframe_t flipper_frames_pain1 [] =
{
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL
};
mmove_t flipper_move_pain1 = {FRAME_flppn201, FRAME_flppn205, flipper_frames_pain1, flipper_run};
void flipper_bite (edict_t *self)
{
vec3_t aim;
VectorSet (aim, MELEE_DISTANCE, 0, 0);
fire_hit (self, aim, 5, 0);
}
void flipper_preattack (edict_t *self)
{
gi.sound (self, CHAN_WEAPON, sound_chomp, 1, ATTN_NORM, 0);
}
mframe_t flipper_frames_attack [] =
{
ai_charge, 0, flipper_preattack,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, flipper_bite,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, flipper_bite,
ai_charge, 0, NULL
};
mmove_t flipper_move_attack = {FRAME_flpbit01, FRAME_flpbit20, flipper_frames_attack, flipper_run};
void flipper_melee(edict_t *self)
{
self->monsterinfo.currentmove = &flipper_move_attack;
}
void flipper_pain (edict_t *self, edict_t *other, float kick, int damage)
{
int n;
if (self->health < (self->max_health / 2))
self->s.skinnum = 1;
if (level.time < self->pain_debounce_time)
return;
self->pain_debounce_time = level.time + 3;
if (skill->value == 3)
return; // no pain anims in nightmare
n = (rand() + 1) % 2;
if (n == 0)
{
gi.sound (self, CHAN_VOICE, sound_pain1, 1, ATTN_NORM, 0);
self->monsterinfo.currentmove = &flipper_move_pain1;
}
else
{
gi.sound (self, CHAN_VOICE, sound_pain2, 1, ATTN_NORM, 0);
self->monsterinfo.currentmove = &flipper_move_pain2;
}
}
void flipper_dead (edict_t *self)
{
VectorSet (self->mins, -16, -16, -24);
VectorSet (self->maxs, 16, 16, -8);
self->movetype = MOVETYPE_TOSS;
self->svflags |= SVF_DEADMONSTER;
self->nextthink = 0;
gi.linkentity (self);
}
mframe_t flipper_frames_death [] =
{
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL
};
mmove_t flipper_move_death = {FRAME_flpdth01, FRAME_flpdth56, flipper_frames_death, flipper_dead};
void flipper_sight (edict_t *self, edict_t *other)
{
gi.sound (self, CHAN_VOICE, sound_sight, 1, ATTN_NORM, 0);
}
void flipper_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
{
int n;
// check for gib
if (self->health <= self->gib_health)
{
gi.sound (self, CHAN_VOICE, gi.soundindex ("misc/udeath.wav"), 1, ATTN_NORM, 0);
for (n= 0; n < 2; n++)
ThrowGib (self, "models/objects/gibs/bone/tris.md2", damage, GIB_ORGANIC);
for (n= 0; n < 2; n++)
ThrowGib (self, "models/objects/gibs/sm_meat/tris.md2", damage, GIB_ORGANIC);
ThrowHead (self, "models/objects/gibs/sm_meat/tris.md2", damage, GIB_ORGANIC);
self->deadflag = DEAD_DEAD;
return;
}
if (self->deadflag == DEAD_DEAD)
return;
// regular death
gi.sound (self, CHAN_VOICE, sound_death, 1, ATTN_NORM, 0);
self->deadflag = DEAD_DEAD;
self->takedamage = DAMAGE_YES;
self->monsterinfo.currentmove = &flipper_move_death;
}
/*QUAKED monster_flipper (1 .5 0) (-16 -16 -24) (16 16 32) Ambush Trigger_Spawn Sight
*/
void SP_monster_flipper (edict_t *self)
{
if (deathmatch->value)
{
G_FreeEdict (self);
return;
}
sound_pain1 = gi.soundindex ("flipper/flppain1.wav");
sound_pain2 = gi.soundindex ("flipper/flppain2.wav");
sound_death = gi.soundindex ("flipper/flpdeth1.wav");
sound_chomp = gi.soundindex ("flipper/flpatck1.wav");
sound_attack = gi.soundindex ("flipper/flpatck2.wav");
sound_idle = gi.soundindex ("flipper/flpidle1.wav");
sound_search = gi.soundindex ("flipper/flpsrch1.wav");
sound_sight = gi.soundindex ("flipper/flpsght1.wav");
self->movetype = MOVETYPE_STEP;
self->solid = SOLID_BBOX;
self->s.modelindex = gi.modelindex ("models/monsters/flipper/tris.md2");
VectorSet (self->mins, -16, -16, 0);
VectorSet (self->maxs, 16, 16, 32);
self->health = 50;
self->gib_health = -30;
self->mass = 100;
self->pain = flipper_pain;
self->die = flipper_die;
self->monsterinfo.stand = flipper_stand;
self->monsterinfo.walk = flipper_walk;
self->monsterinfo.run = flipper_start_run;
self->monsterinfo.melee = flipper_melee;
self->monsterinfo.sight = flipper_sight;
gi.linkentity (self);
self->monsterinfo.currentmove = &flipper_move_stand;
self->monsterinfo.scale = MODEL_SCALE;
swimmonster_start (self);
}

185
game/m_flipper.h Normal file
View File

@ -0,0 +1,185 @@
/*
Copyright (C) 1997-2001 Id Software, Inc.
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 the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
// G:\quake2\baseq2\models/monsters/flipper
// This file generated by ModelGen - Do NOT Modify
#define FRAME_flpbit01 0
#define FRAME_flpbit02 1
#define FRAME_flpbit03 2
#define FRAME_flpbit04 3
#define FRAME_flpbit05 4
#define FRAME_flpbit06 5
#define FRAME_flpbit07 6
#define FRAME_flpbit08 7
#define FRAME_flpbit09 8
#define FRAME_flpbit10 9
#define FRAME_flpbit11 10
#define FRAME_flpbit12 11
#define FRAME_flpbit13 12
#define FRAME_flpbit14 13
#define FRAME_flpbit15 14
#define FRAME_flpbit16 15
#define FRAME_flpbit17 16
#define FRAME_flpbit18 17
#define FRAME_flpbit19 18
#define FRAME_flpbit20 19
#define FRAME_flptal01 20
#define FRAME_flptal02 21
#define FRAME_flptal03 22
#define FRAME_flptal04 23
#define FRAME_flptal05 24
#define FRAME_flptal06 25
#define FRAME_flptal07 26
#define FRAME_flptal08 27
#define FRAME_flptal09 28
#define FRAME_flptal10 29
#define FRAME_flptal11 30
#define FRAME_flptal12 31
#define FRAME_flptal13 32
#define FRAME_flptal14 33
#define FRAME_flptal15 34
#define FRAME_flptal16 35
#define FRAME_flptal17 36
#define FRAME_flptal18 37
#define FRAME_flptal19 38
#define FRAME_flptal20 39
#define FRAME_flptal21 40
#define FRAME_flphor01 41
#define FRAME_flphor02 42
#define FRAME_flphor03 43
#define FRAME_flphor04 44
#define FRAME_flphor05 45
#define FRAME_flphor06 46
#define FRAME_flphor07 47
#define FRAME_flphor08 48
#define FRAME_flphor09 49
#define FRAME_flphor10 50
#define FRAME_flphor11 51
#define FRAME_flphor12 52
#define FRAME_flphor13 53
#define FRAME_flphor14 54
#define FRAME_flphor15 55
#define FRAME_flphor16 56
#define FRAME_flphor17 57
#define FRAME_flphor18 58
#define FRAME_flphor19 59
#define FRAME_flphor20 60
#define FRAME_flphor21 61
#define FRAME_flphor22 62
#define FRAME_flphor23 63
#define FRAME_flphor24 64
#define FRAME_flpver01 65
#define FRAME_flpver02 66
#define FRAME_flpver03 67
#define FRAME_flpver04 68
#define FRAME_flpver05 69
#define FRAME_flpver06 70
#define FRAME_flpver07 71
#define FRAME_flpver08 72
#define FRAME_flpver09 73
#define FRAME_flpver10 74
#define FRAME_flpver11 75
#define FRAME_flpver12 76
#define FRAME_flpver13 77
#define FRAME_flpver14 78
#define FRAME_flpver15 79
#define FRAME_flpver16 80
#define FRAME_flpver17 81
#define FRAME_flpver18 82
#define FRAME_flpver19 83
#define FRAME_flpver20 84
#define FRAME_flpver21 85
#define FRAME_flpver22 86
#define FRAME_flpver23 87
#define FRAME_flpver24 88
#define FRAME_flpver25 89
#define FRAME_flpver26 90
#define FRAME_flpver27 91
#define FRAME_flpver28 92
#define FRAME_flpver29 93
#define FRAME_flppn101 94
#define FRAME_flppn102 95
#define FRAME_flppn103 96
#define FRAME_flppn104 97
#define FRAME_flppn105 98
#define FRAME_flppn201 99
#define FRAME_flppn202 100
#define FRAME_flppn203 101
#define FRAME_flppn204 102
#define FRAME_flppn205 103
#define FRAME_flpdth01 104
#define FRAME_flpdth02 105
#define FRAME_flpdth03 106
#define FRAME_flpdth04 107
#define FRAME_flpdth05 108
#define FRAME_flpdth06 109
#define FRAME_flpdth07 110
#define FRAME_flpdth08 111
#define FRAME_flpdth09 112
#define FRAME_flpdth10 113
#define FRAME_flpdth11 114
#define FRAME_flpdth12 115
#define FRAME_flpdth13 116
#define FRAME_flpdth14 117
#define FRAME_flpdth15 118
#define FRAME_flpdth16 119
#define FRAME_flpdth17 120
#define FRAME_flpdth18 121
#define FRAME_flpdth19 122
#define FRAME_flpdth20 123
#define FRAME_flpdth21 124
#define FRAME_flpdth22 125
#define FRAME_flpdth23 126
#define FRAME_flpdth24 127
#define FRAME_flpdth25 128
#define FRAME_flpdth26 129
#define FRAME_flpdth27 130
#define FRAME_flpdth28 131
#define FRAME_flpdth29 132
#define FRAME_flpdth30 133
#define FRAME_flpdth31 134
#define FRAME_flpdth32 135
#define FRAME_flpdth33 136
#define FRAME_flpdth34 137
#define FRAME_flpdth35 138
#define FRAME_flpdth36 139
#define FRAME_flpdth37 140
#define FRAME_flpdth38 141
#define FRAME_flpdth39 142
#define FRAME_flpdth40 143
#define FRAME_flpdth41 144
#define FRAME_flpdth42 145
#define FRAME_flpdth43 146
#define FRAME_flpdth44 147
#define FRAME_flpdth45 148
#define FRAME_flpdth46 149
#define FRAME_flpdth47 150
#define FRAME_flpdth48 151
#define FRAME_flpdth49 152
#define FRAME_flpdth50 153
#define FRAME_flpdth51 154
#define FRAME_flpdth52 155
#define FRAME_flpdth53 156
#define FRAME_flpdth54 157
#define FRAME_flpdth55 158
#define FRAME_flpdth56 159
#define MODEL_SCALE 1.000000

663
game/m_float.c Normal file
View File

@ -0,0 +1,663 @@
/*
Copyright (C) 1997-2001 Id Software, Inc.
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 the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/*
==============================================================================
floater
==============================================================================
*/
#include "g_local.h"
#include "m_float.h"
static int sound_attack2;
static int sound_attack3;
static int sound_death1;
static int sound_idle;
static int sound_pain1;
static int sound_pain2;
static int sound_sight;
void floater_sight (edict_t *self, edict_t *other)
{
gi.sound (self, CHAN_VOICE, sound_sight, 1, ATTN_NORM, 0);
}
void floater_idle (edict_t *self)
{
gi.sound (self, CHAN_VOICE, sound_idle, 1, ATTN_IDLE, 0);
}
//void floater_stand1 (edict_t *self);
void floater_dead (edict_t *self);
void floater_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point);
void floater_run (edict_t *self);
void floater_wham (edict_t *self);
void floater_zap (edict_t *self);
void floater_fire_blaster (edict_t *self)
{
vec3_t start;
vec3_t forward, right;
vec3_t end;
vec3_t dir;
int effect;
if ((self->s.frame == FRAME_attak104) || (self->s.frame == FRAME_attak107))
effect = EF_HYPERBLASTER;
else
effect = 0;
AngleVectors (self->s.angles, forward, right, NULL);
G_ProjectSource (self->s.origin, monster_flash_offset[MZ2_FLOAT_BLASTER_1], forward, right, start);
VectorCopy (self->enemy->s.origin, end);
end[2] += self->enemy->viewheight;
VectorSubtract (end, start, dir);
monster_fire_blaster (self, start, dir, 1, 1000, MZ2_FLOAT_BLASTER_1, effect);
}
mframe_t floater_frames_stand1 [] =
{
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL
};
mmove_t floater_move_stand1 = {FRAME_stand101, FRAME_stand152, floater_frames_stand1, NULL};
mframe_t floater_frames_stand2 [] =
{
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL
};
mmove_t floater_move_stand2 = {FRAME_stand201, FRAME_stand252, floater_frames_stand2, NULL};
void floater_stand (edict_t *self)
{
if (random() <= 0.5)
self->monsterinfo.currentmove = &floater_move_stand1;
else
self->monsterinfo.currentmove = &floater_move_stand2;
}
mframe_t floater_frames_activate [] =
{
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL
};
mmove_t floater_move_activate = {FRAME_actvat01, FRAME_actvat31, floater_frames_activate, NULL};
mframe_t floater_frames_attack1 [] =
{
ai_charge, 0, NULL, // Blaster attack
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, floater_fire_blaster, // BOOM (0, -25.8, 32.5) -- LOOP Starts
ai_charge, 0, floater_fire_blaster,
ai_charge, 0, floater_fire_blaster,
ai_charge, 0, floater_fire_blaster,
ai_charge, 0, floater_fire_blaster,
ai_charge, 0, floater_fire_blaster,
ai_charge, 0, floater_fire_blaster,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL // -- LOOP Ends
};
mmove_t floater_move_attack1 = {FRAME_attak101, FRAME_attak114, floater_frames_attack1, floater_run};
mframe_t floater_frames_attack2 [] =
{
ai_charge, 0, NULL, // Claws
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, floater_wham, // WHAM (0, -45, 29.6) -- LOOP Starts
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL, // -- LOOP Ends
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL
};
mmove_t floater_move_attack2 = {FRAME_attak201, FRAME_attak225, floater_frames_attack2, floater_run};
mframe_t floater_frames_attack3 [] =
{
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, floater_zap, // -- LOOP Starts
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL, // -- LOOP Ends
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL
};
mmove_t floater_move_attack3 = {FRAME_attak301, FRAME_attak334, floater_frames_attack3, floater_run};
mframe_t floater_frames_death [] =
{
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL
};
mmove_t floater_move_death = {FRAME_death01, FRAME_death13, floater_frames_death, floater_dead};
mframe_t floater_frames_pain1 [] =
{
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL
};
mmove_t floater_move_pain1 = {FRAME_pain101, FRAME_pain107, floater_frames_pain1, floater_run};
mframe_t floater_frames_pain2 [] =
{
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL
};
mmove_t floater_move_pain2 = {FRAME_pain201, FRAME_pain208, floater_frames_pain2, floater_run};
mframe_t floater_frames_pain3 [] =
{
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL
};
mmove_t floater_move_pain3 = {FRAME_pain301, FRAME_pain312, floater_frames_pain3, floater_run};
mframe_t floater_frames_walk [] =
{
ai_walk, 5, NULL,
ai_walk, 5, NULL,
ai_walk, 5, NULL,
ai_walk, 5, NULL,
ai_walk, 5, NULL,
ai_walk, 5, NULL,
ai_walk, 5, NULL,
ai_walk, 5, NULL,
ai_walk, 5, NULL,
ai_walk, 5, NULL,
ai_walk, 5, NULL,
ai_walk, 5, NULL,
ai_walk, 5, NULL,
ai_walk, 5, NULL,
ai_walk, 5, NULL,
ai_walk, 5, NULL,
ai_walk, 5, NULL,
ai_walk, 5, NULL,
ai_walk, 5, NULL,
ai_walk, 5, NULL,
ai_walk, 5, NULL,
ai_walk, 5, NULL,
ai_walk, 5, NULL,
ai_walk, 5, NULL,
ai_walk, 5, NULL,
ai_walk, 5, NULL,
ai_walk, 5, NULL,
ai_walk, 5, NULL,
ai_walk, 5, NULL,
ai_walk, 5, NULL,
ai_walk, 5, NULL,
ai_walk, 5, NULL,
ai_walk, 5, NULL,
ai_walk, 5, NULL,
ai_walk, 5, NULL,
ai_walk, 5, NULL,
ai_walk, 5, NULL,
ai_walk, 5, NULL,
ai_walk, 5, NULL,
ai_walk, 5, NULL,
ai_walk, 5, NULL,
ai_walk, 5, NULL,
ai_walk, 5, NULL,
ai_walk, 5, NULL,
ai_walk, 5, NULL,
ai_walk, 5, NULL,
ai_walk, 5, NULL,
ai_walk, 5, NULL,
ai_walk, 5, NULL,
ai_walk, 5, NULL,
ai_walk, 5, NULL,
ai_walk, 5, NULL
};
mmove_t floater_move_walk = {FRAME_stand101, FRAME_stand152, floater_frames_walk, NULL};
mframe_t floater_frames_run [] =
{
ai_run, 13, NULL,
ai_run, 13, NULL,
ai_run, 13, NULL,
ai_run, 13, NULL,
ai_run, 13, NULL,
ai_run, 13, NULL,
ai_run, 13, NULL,
ai_run, 13, NULL,
ai_run, 13, NULL,
ai_run, 13, NULL,
ai_run, 13, NULL,
ai_run, 13, NULL,
ai_run, 13, NULL,
ai_run, 13, NULL,
ai_run, 13, NULL,
ai_run, 13, NULL,
ai_run, 13, NULL,
ai_run, 13, NULL,
ai_run, 13, NULL,
ai_run, 13, NULL,
ai_run, 13, NULL,
ai_run, 13, NULL,
ai_run, 13, NULL,
ai_run, 13, NULL,
ai_run, 13, NULL,
ai_run, 13, NULL,
ai_run, 13, NULL,
ai_run, 13, NULL,
ai_run, 13, NULL,
ai_run, 13, NULL,
ai_run, 13, NULL,
ai_run, 13, NULL,
ai_run, 13, NULL,
ai_run, 13, NULL,
ai_run, 13, NULL,
ai_run, 13, NULL,
ai_run, 13, NULL,
ai_run, 13, NULL,
ai_run, 13, NULL,
ai_run, 13, NULL,
ai_run, 13, NULL,
ai_run, 13, NULL,
ai_run, 13, NULL,
ai_run, 13, NULL,
ai_run, 13, NULL,
ai_run, 13, NULL,
ai_run, 13, NULL,
ai_run, 13, NULL,
ai_run, 13, NULL,
ai_run, 13, NULL,
ai_run, 13, NULL,
ai_run, 13, NULL
};
mmove_t floater_move_run = {FRAME_stand101, FRAME_stand152, floater_frames_run, NULL};
void floater_run (edict_t *self)
{
if (self->monsterinfo.aiflags & AI_STAND_GROUND)
self->monsterinfo.currentmove = &floater_move_stand1;
else
self->monsterinfo.currentmove = &floater_move_run;
}
void floater_walk (edict_t *self)
{
self->monsterinfo.currentmove = &floater_move_walk;
}
void floater_wham (edict_t *self)
{
static vec3_t aim = {MELEE_DISTANCE, 0, 0};
gi.sound (self, CHAN_WEAPON, sound_attack3, 1, ATTN_NORM, 0);
fire_hit (self, aim, 5 + rand() % 6, -50);
}
void floater_zap (edict_t *self)
{
vec3_t forward, right;
vec3_t origin;
vec3_t dir;
vec3_t offset;
VectorSubtract (self->enemy->s.origin, self->s.origin, dir);
AngleVectors (self->s.angles, forward, right, NULL);
//FIXME use a flash and replace these two lines with the commented one
VectorSet (offset, 18.5, -0.9, 10);
G_ProjectSource (self->s.origin, offset, forward, right, origin);
// G_ProjectSource (self->s.origin, monster_flash_offset[flash_number], forward, right, origin);
gi.sound (self, CHAN_WEAPON, sound_attack2, 1, ATTN_NORM, 0);
//FIXME use the flash, Luke
gi.WriteByte (svc_temp_entity);
gi.WriteByte (TE_SPLASH);
gi.WriteByte (32);
gi.WritePosition (origin);
gi.WriteDir (dir);
gi.WriteByte (1); //sparks
gi.multicast (origin, MULTICAST_PVS);
T_Damage (self->enemy, self, self, dir, self->enemy->s.origin, vec3_origin, 5 + rand() % 6, -10, DAMAGE_ENERGY, MOD_UNKNOWN);
}
void floater_attack(edict_t *self)
{
self->monsterinfo.currentmove = &floater_move_attack1;
}
void floater_melee(edict_t *self)
{
if (random() < 0.5)
self->monsterinfo.currentmove = &floater_move_attack3;
else
self->monsterinfo.currentmove = &floater_move_attack2;
}
void floater_pain (edict_t *self, edict_t *other, float kick, int damage)
{
int n;
if (self->health < (self->max_health / 2))
self->s.skinnum = 1;
if (level.time < self->pain_debounce_time)
return;
self->pain_debounce_time = level.time + 3;
if (skill->value == 3)
return; // no pain anims in nightmare
n = (rand() + 1) % 3;
if (n == 0)
{
gi.sound (self, CHAN_VOICE, sound_pain1, 1, ATTN_NORM, 0);
self->monsterinfo.currentmove = &floater_move_pain1;
}
else
{
gi.sound (self, CHAN_VOICE, sound_pain2, 1, ATTN_NORM, 0);
self->monsterinfo.currentmove = &floater_move_pain2;
}
}
void floater_dead (edict_t *self)
{
VectorSet (self->mins, -16, -16, -24);
VectorSet (self->maxs, 16, 16, -8);
self->movetype = MOVETYPE_TOSS;
self->svflags |= SVF_DEADMONSTER;
self->nextthink = 0;
gi.linkentity (self);
}
void floater_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
{
gi.sound (self, CHAN_VOICE, sound_death1, 1, ATTN_NORM, 0);
BecomeExplosion1(self);
}
/*QUAKED monster_floater (1 .5 0) (-16 -16 -24) (16 16 32) Ambush Trigger_Spawn Sight
*/
void SP_monster_floater (edict_t *self)
{
if (deathmatch->value)
{
G_FreeEdict (self);
return;
}
sound_attack2 = gi.soundindex ("floater/fltatck2.wav");
sound_attack3 = gi.soundindex ("floater/fltatck3.wav");
sound_death1 = gi.soundindex ("floater/fltdeth1.wav");
sound_idle = gi.soundindex ("floater/fltidle1.wav");
sound_pain1 = gi.soundindex ("floater/fltpain1.wav");
sound_pain2 = gi.soundindex ("floater/fltpain2.wav");
sound_sight = gi.soundindex ("floater/fltsght1.wav");
gi.soundindex ("floater/fltatck1.wav");
self->s.sound = gi.soundindex ("floater/fltsrch1.wav");
self->movetype = MOVETYPE_STEP;
self->solid = SOLID_BBOX;
self->s.modelindex = gi.modelindex ("models/monsters/float/tris.md2");
VectorSet (self->mins, -24, -24, -24);
VectorSet (self->maxs, 24, 24, 32);
self->health = 200;
self->gib_health = -80;
self->mass = 300;
self->pain = floater_pain;
self->die = floater_die;
self->monsterinfo.stand = floater_stand;
self->monsterinfo.walk = floater_walk;
self->monsterinfo.run = floater_run;
// self->monsterinfo.dodge = floater_dodge;
self->monsterinfo.attack = floater_attack;
self->monsterinfo.melee = floater_melee;
self->monsterinfo.sight = floater_sight;
self->monsterinfo.idle = floater_idle;
gi.linkentity (self);
if (random() <= 0.5)
self->monsterinfo.currentmove = &floater_move_stand1;
else
self->monsterinfo.currentmove = &floater_move_stand2;
self->monsterinfo.scale = MODEL_SCALE;
flymonster_start (self);
}

273
game/m_float.h Normal file
View File

@ -0,0 +1,273 @@
/*
Copyright (C) 1997-2001 Id Software, Inc.
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 the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
// G:\quake2\baseq2\models/monsters/float
// This file generated by ModelGen - Do NOT Modify
#define FRAME_actvat01 0
#define FRAME_actvat02 1
#define FRAME_actvat03 2
#define FRAME_actvat04 3
#define FRAME_actvat05 4
#define FRAME_actvat06 5
#define FRAME_actvat07 6
#define FRAME_actvat08 7
#define FRAME_actvat09 8
#define FRAME_actvat10 9
#define FRAME_actvat11 10
#define FRAME_actvat12 11
#define FRAME_actvat13 12
#define FRAME_actvat14 13
#define FRAME_actvat15 14
#define FRAME_actvat16 15
#define FRAME_actvat17 16
#define FRAME_actvat18 17
#define FRAME_actvat19 18
#define FRAME_actvat20 19
#define FRAME_actvat21 20
#define FRAME_actvat22 21
#define FRAME_actvat23 22
#define FRAME_actvat24 23
#define FRAME_actvat25 24
#define FRAME_actvat26 25
#define FRAME_actvat27 26
#define FRAME_actvat28 27
#define FRAME_actvat29 28
#define FRAME_actvat30 29
#define FRAME_actvat31 30
#define FRAME_attak101 31
#define FRAME_attak102 32
#define FRAME_attak103 33
#define FRAME_attak104 34
#define FRAME_attak105 35
#define FRAME_attak106 36
#define FRAME_attak107 37
#define FRAME_attak108 38
#define FRAME_attak109 39
#define FRAME_attak110 40
#define FRAME_attak111 41
#define FRAME_attak112 42
#define FRAME_attak113 43
#define FRAME_attak114 44
#define FRAME_attak201 45
#define FRAME_attak202 46
#define FRAME_attak203 47
#define FRAME_attak204 48
#define FRAME_attak205 49
#define FRAME_attak206 50
#define FRAME_attak207 51
#define FRAME_attak208 52
#define FRAME_attak209 53
#define FRAME_attak210 54
#define FRAME_attak211 55
#define FRAME_attak212 56
#define FRAME_attak213 57
#define FRAME_attak214 58
#define FRAME_attak215 59
#define FRAME_attak216 60
#define FRAME_attak217 61
#define FRAME_attak218 62
#define FRAME_attak219 63
#define FRAME_attak220 64
#define FRAME_attak221 65
#define FRAME_attak222 66
#define FRAME_attak223 67
#define FRAME_attak224 68
#define FRAME_attak225 69
#define FRAME_attak301 70
#define FRAME_attak302 71
#define FRAME_attak303 72
#define FRAME_attak304 73
#define FRAME_attak305 74
#define FRAME_attak306 75
#define FRAME_attak307 76
#define FRAME_attak308 77
#define FRAME_attak309 78
#define FRAME_attak310 79
#define FRAME_attak311 80
#define FRAME_attak312 81
#define FRAME_attak313 82
#define FRAME_attak314 83
#define FRAME_attak315 84
#define FRAME_attak316 85
#define FRAME_attak317 86
#define FRAME_attak318 87
#define FRAME_attak319 88
#define FRAME_attak320 89
#define FRAME_attak321 90
#define FRAME_attak322 91
#define FRAME_attak323 92
#define FRAME_attak324 93
#define FRAME_attak325 94
#define FRAME_attak326 95
#define FRAME_attak327 96
#define FRAME_attak328 97
#define FRAME_attak329 98
#define FRAME_attak330 99
#define FRAME_attak331 100
#define FRAME_attak332 101
#define FRAME_attak333 102
#define FRAME_attak334 103
#define FRAME_death01 104
#define FRAME_death02 105
#define FRAME_death03 106
#define FRAME_death04 107
#define FRAME_death05 108
#define FRAME_death06 109
#define FRAME_death07 110
#define FRAME_death08 111
#define FRAME_death09 112
#define FRAME_death10 113
#define FRAME_death11 114
#define FRAME_death12 115
#define FRAME_death13 116
#define FRAME_pain101 117
#define FRAME_pain102 118
#define FRAME_pain103 119
#define FRAME_pain104 120
#define FRAME_pain105 121
#define FRAME_pain106 122
#define FRAME_pain107 123
#define FRAME_pain201 124
#define FRAME_pain202 125
#define FRAME_pain203 126
#define FRAME_pain204 127
#define FRAME_pain205 128
#define FRAME_pain206 129
#define FRAME_pain207 130
#define FRAME_pain208 131
#define FRAME_pain301 132
#define FRAME_pain302 133
#define FRAME_pain303 134
#define FRAME_pain304 135
#define FRAME_pain305 136
#define FRAME_pain306 137
#define FRAME_pain307 138
#define FRAME_pain308 139
#define FRAME_pain309 140
#define FRAME_pain310 141
#define FRAME_pain311 142
#define FRAME_pain312 143
#define FRAME_stand101 144
#define FRAME_stand102 145
#define FRAME_stand103 146
#define FRAME_stand104 147
#define FRAME_stand105 148
#define FRAME_stand106 149
#define FRAME_stand107 150
#define FRAME_stand108 151
#define FRAME_stand109 152
#define FRAME_stand110 153
#define FRAME_stand111 154
#define FRAME_stand112 155
#define FRAME_stand113 156
#define FRAME_stand114 157
#define FRAME_stand115 158
#define FRAME_stand116 159
#define FRAME_stand117 160
#define FRAME_stand118 161
#define FRAME_stand119 162
#define FRAME_stand120 163
#define FRAME_stand121 164
#define FRAME_stand122 165
#define FRAME_stand123 166
#define FRAME_stand124 167
#define FRAME_stand125 168
#define FRAME_stand126 169
#define FRAME_stand127 170
#define FRAME_stand128 171
#define FRAME_stand129 172
#define FRAME_stand130 173
#define FRAME_stand131 174
#define FRAME_stand132 175
#define FRAME_stand133 176
#define FRAME_stand134 177
#define FRAME_stand135 178
#define FRAME_stand136 179
#define FRAME_stand137 180
#define FRAME_stand138 181
#define FRAME_stand139 182
#define FRAME_stand140 183
#define FRAME_stand141 184
#define FRAME_stand142 185
#define FRAME_stand143 186
#define FRAME_stand144 187
#define FRAME_stand145 188
#define FRAME_stand146 189
#define FRAME_stand147 190
#define FRAME_stand148 191
#define FRAME_stand149 192
#define FRAME_stand150 193
#define FRAME_stand151 194
#define FRAME_stand152 195
#define FRAME_stand201 196
#define FRAME_stand202 197
#define FRAME_stand203 198
#define FRAME_stand204 199
#define FRAME_stand205 200
#define FRAME_stand206 201
#define FRAME_stand207 202
#define FRAME_stand208 203
#define FRAME_stand209 204
#define FRAME_stand210 205
#define FRAME_stand211 206
#define FRAME_stand212 207
#define FRAME_stand213 208
#define FRAME_stand214 209
#define FRAME_stand215 210
#define FRAME_stand216 211
#define FRAME_stand217 212
#define FRAME_stand218 213
#define FRAME_stand219 214
#define FRAME_stand220 215
#define FRAME_stand221 216
#define FRAME_stand222 217
#define FRAME_stand223 218
#define FRAME_stand224 219
#define FRAME_stand225 220
#define FRAME_stand226 221
#define FRAME_stand227 222
#define FRAME_stand228 223
#define FRAME_stand229 224
#define FRAME_stand230 225
#define FRAME_stand231 226
#define FRAME_stand232 227
#define FRAME_stand233 228
#define FRAME_stand234 229
#define FRAME_stand235 230
#define FRAME_stand236 231
#define FRAME_stand237 232
#define FRAME_stand238 233
#define FRAME_stand239 234
#define FRAME_stand240 235
#define FRAME_stand241 236
#define FRAME_stand242 237
#define FRAME_stand243 238
#define FRAME_stand244 239
#define FRAME_stand245 240
#define FRAME_stand246 241
#define FRAME_stand247 242
#define FRAME_stand248 243
#define FRAME_stand249 244
#define FRAME_stand250 245
#define FRAME_stand251 246
#define FRAME_stand252 247
#define MODEL_SCALE 1.000000

626
game/m_flyer.c Normal file
View File

@ -0,0 +1,626 @@
/*
Copyright (C) 1997-2001 Id Software, Inc.
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 the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/*
==============================================================================
flyer
==============================================================================
*/
#include "g_local.h"
#include "m_flyer.h"
qboolean visible (edict_t *self, edict_t *other);
static int nextmove; // Used for start/stop frames
static int sound_sight;
static int sound_idle;
static int sound_pain1;
static int sound_pain2;
static int sound_slash;
static int sound_sproing;
static int sound_die;
void flyer_check_melee(edict_t *self);
void flyer_loop_melee (edict_t *self);
void flyer_melee (edict_t *self);
void flyer_setstart (edict_t *self);
void flyer_stand (edict_t *self);
void flyer_nextmove (edict_t *self);
void flyer_sight (edict_t *self, edict_t *other)
{
gi.sound (self, CHAN_VOICE, sound_sight, 1, ATTN_NORM, 0);
}
void flyer_idle (edict_t *self)
{
gi.sound (self, CHAN_VOICE, sound_idle, 1, ATTN_IDLE, 0);
}
void flyer_pop_blades (edict_t *self)
{
gi.sound (self, CHAN_VOICE, sound_sproing, 1, ATTN_NORM, 0);
}
mframe_t flyer_frames_stand [] =
{
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL
};
mmove_t flyer_move_stand = {FRAME_stand01, FRAME_stand45, flyer_frames_stand, NULL};
mframe_t flyer_frames_walk [] =
{
ai_walk, 5, NULL,
ai_walk, 5, NULL,
ai_walk, 5, NULL,
ai_walk, 5, NULL,
ai_walk, 5, NULL,
ai_walk, 5, NULL,
ai_walk, 5, NULL,
ai_walk, 5, NULL,
ai_walk, 5, NULL,
ai_walk, 5, NULL,
ai_walk, 5, NULL,
ai_walk, 5, NULL,
ai_walk, 5, NULL,
ai_walk, 5, NULL,
ai_walk, 5, NULL,
ai_walk, 5, NULL,
ai_walk, 5, NULL,
ai_walk, 5, NULL,
ai_walk, 5, NULL,
ai_walk, 5, NULL,
ai_walk, 5, NULL,
ai_walk, 5, NULL,
ai_walk, 5, NULL,
ai_walk, 5, NULL,
ai_walk, 5, NULL,
ai_walk, 5, NULL,
ai_walk, 5, NULL,
ai_walk, 5, NULL,
ai_walk, 5, NULL,
ai_walk, 5, NULL,
ai_walk, 5, NULL,
ai_walk, 5, NULL,
ai_walk, 5, NULL,
ai_walk, 5, NULL,
ai_walk, 5, NULL,
ai_walk, 5, NULL,
ai_walk, 5, NULL,
ai_walk, 5, NULL,
ai_walk, 5, NULL,
ai_walk, 5, NULL,
ai_walk, 5, NULL,
ai_walk, 5, NULL,
ai_walk, 5, NULL,
ai_walk, 5, NULL,
ai_walk, 5, NULL
};
mmove_t flyer_move_walk = {FRAME_stand01, FRAME_stand45, flyer_frames_walk, NULL};
mframe_t flyer_frames_run [] =
{
ai_run, 10, NULL,
ai_run, 10, NULL,
ai_run, 10, NULL,
ai_run, 10, NULL,
ai_run, 10, NULL,
ai_run, 10, NULL,
ai_run, 10, NULL,
ai_run, 10, NULL,
ai_run, 10, NULL,
ai_run, 10, NULL,
ai_run, 10, NULL,
ai_run, 10, NULL,
ai_run, 10, NULL,
ai_run, 10, NULL,
ai_run, 10, NULL,
ai_run, 10, NULL,
ai_run, 10, NULL,
ai_run, 10, NULL,
ai_run, 10, NULL,
ai_run, 10, NULL,
ai_run, 10, NULL,
ai_run, 10, NULL,
ai_run, 10, NULL,
ai_run, 10, NULL,
ai_run, 10, NULL,
ai_run, 10, NULL,
ai_run, 10, NULL,
ai_run, 10, NULL,
ai_run, 10, NULL,
ai_run, 10, NULL,
ai_run, 10, NULL,
ai_run, 10, NULL,
ai_run, 10, NULL,
ai_run, 10, NULL,
ai_run, 10, NULL,
ai_run, 10, NULL,
ai_run, 10, NULL,
ai_run, 10, NULL,
ai_run, 10, NULL,
ai_run, 10, NULL,
ai_run, 10, NULL,
ai_run, 10, NULL,
ai_run, 10, NULL,
ai_run, 10, NULL,
ai_run, 10, NULL
};
mmove_t flyer_move_run = {FRAME_stand01, FRAME_stand45, flyer_frames_run, NULL};
void flyer_run (edict_t *self)
{
if (self->monsterinfo.aiflags & AI_STAND_GROUND)
self->monsterinfo.currentmove = &flyer_move_stand;
else
self->monsterinfo.currentmove = &flyer_move_run;
}
void flyer_walk (edict_t *self)
{
self->monsterinfo.currentmove = &flyer_move_walk;
}
void flyer_stand (edict_t *self)
{
self->monsterinfo.currentmove = &flyer_move_stand;
}
mframe_t flyer_frames_start [] =
{
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, flyer_nextmove
};
mmove_t flyer_move_start = {FRAME_start01, FRAME_start06, flyer_frames_start, NULL};
mframe_t flyer_frames_stop [] =
{
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, flyer_nextmove
};
mmove_t flyer_move_stop = {FRAME_stop01, FRAME_stop07, flyer_frames_stop, NULL};
void flyer_stop (edict_t *self)
{
self->monsterinfo.currentmove = &flyer_move_stop;
}
void flyer_start (edict_t *self)
{
self->monsterinfo.currentmove = &flyer_move_start;
}
mframe_t flyer_frames_rollright [] =
{
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL
};
mmove_t flyer_move_rollright = {FRAME_rollr01, FRAME_rollr09, flyer_frames_rollright, NULL};
mframe_t flyer_frames_rollleft [] =
{
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL
};
mmove_t flyer_move_rollleft = {FRAME_rollf01, FRAME_rollf09, flyer_frames_rollleft, NULL};
mframe_t flyer_frames_pain3 [] =
{
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL
};
mmove_t flyer_move_pain3 = {FRAME_pain301, FRAME_pain304, flyer_frames_pain3, flyer_run};
mframe_t flyer_frames_pain2 [] =
{
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL
};
mmove_t flyer_move_pain2 = {FRAME_pain201, FRAME_pain204, flyer_frames_pain2, flyer_run};
mframe_t flyer_frames_pain1 [] =
{
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL
};
mmove_t flyer_move_pain1 = {FRAME_pain101, FRAME_pain109, flyer_frames_pain1, flyer_run};
mframe_t flyer_frames_defense [] =
{
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL, // Hold this frame
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL
};
mmove_t flyer_move_defense = {FRAME_defens01, FRAME_defens06, flyer_frames_defense, NULL};
mframe_t flyer_frames_bankright [] =
{
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL
};
mmove_t flyer_move_bankright = {FRAME_bankr01, FRAME_bankr07, flyer_frames_bankright, NULL};
mframe_t flyer_frames_bankleft [] =
{
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL
};
mmove_t flyer_move_bankleft = {FRAME_bankl01, FRAME_bankl07, flyer_frames_bankleft, NULL};
void flyer_fire (edict_t *self, int flash_number)
{
vec3_t start;
vec3_t forward, right;
vec3_t end;
vec3_t dir;
int effect;
if ((self->s.frame == FRAME_attak204) || (self->s.frame == FRAME_attak207) || (self->s.frame == FRAME_attak210))
effect = EF_HYPERBLASTER;
else
effect = 0;
AngleVectors (self->s.angles, forward, right, NULL);
G_ProjectSource (self->s.origin, monster_flash_offset[flash_number], forward, right, start);
VectorCopy (self->enemy->s.origin, end);
end[2] += self->enemy->viewheight;
VectorSubtract (end, start, dir);
monster_fire_blaster (self, start, dir, 1, 1000, flash_number, effect);
}
void flyer_fireleft (edict_t *self)
{
flyer_fire (self, MZ2_FLYER_BLASTER_1);
}
void flyer_fireright (edict_t *self)
{
flyer_fire (self, MZ2_FLYER_BLASTER_2);
}
mframe_t flyer_frames_attack2 [] =
{
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, -10, flyer_fireleft, // left gun
ai_charge, -10, flyer_fireright, // right gun
ai_charge, -10, flyer_fireleft, // left gun
ai_charge, -10, flyer_fireright, // right gun
ai_charge, -10, flyer_fireleft, // left gun
ai_charge, -10, flyer_fireright, // right gun
ai_charge, -10, flyer_fireleft, // left gun
ai_charge, -10, flyer_fireright, // right gun
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL
};
mmove_t flyer_move_attack2 = {FRAME_attak201, FRAME_attak217, flyer_frames_attack2, flyer_run};
void flyer_slash_left (edict_t *self)
{
vec3_t aim;
VectorSet (aim, MELEE_DISTANCE, self->mins[0], 0);
fire_hit (self, aim, 5, 0);
gi.sound (self, CHAN_WEAPON, sound_slash, 1, ATTN_NORM, 0);
}
void flyer_slash_right (edict_t *self)
{
vec3_t aim;
VectorSet (aim, MELEE_DISTANCE, self->maxs[0], 0);
fire_hit (self, aim, 5, 0);
gi.sound (self, CHAN_WEAPON, sound_slash, 1, ATTN_NORM, 0);
}
mframe_t flyer_frames_start_melee [] =
{
ai_charge, 0, flyer_pop_blades,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL
};
mmove_t flyer_move_start_melee = {FRAME_attak101, FRAME_attak106, flyer_frames_start_melee, flyer_loop_melee};
mframe_t flyer_frames_end_melee [] =
{
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL
};
mmove_t flyer_move_end_melee = {FRAME_attak119, FRAME_attak121, flyer_frames_end_melee, flyer_run};
mframe_t flyer_frames_loop_melee [] =
{
ai_charge, 0, NULL, // Loop Start
ai_charge, 0, NULL,
ai_charge, 0, flyer_slash_left, // Left Wing Strike
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, flyer_slash_right, // Right Wing Strike
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL // Loop Ends
};
mmove_t flyer_move_loop_melee = {FRAME_attak107, FRAME_attak118, flyer_frames_loop_melee, flyer_check_melee};
void flyer_loop_melee (edict_t *self)
{
/* if (random() <= 0.5)
self->monsterinfo.currentmove = &flyer_move_attack1;
else */
self->monsterinfo.currentmove = &flyer_move_loop_melee;
}
void flyer_attack (edict_t *self)
{
/* if (random() <= 0.5)
self->monsterinfo.currentmove = &flyer_move_attack1;
else */
self->monsterinfo.currentmove = &flyer_move_attack2;
}
void flyer_setstart (edict_t *self)
{
nextmove = ACTION_run;
self->monsterinfo.currentmove = &flyer_move_start;
}
void flyer_nextmove (edict_t *self)
{
if (nextmove == ACTION_attack1)
self->monsterinfo.currentmove = &flyer_move_start_melee;
else if (nextmove == ACTION_attack2)
self->monsterinfo.currentmove = &flyer_move_attack2;
else if (nextmove == ACTION_run)
self->monsterinfo.currentmove = &flyer_move_run;
}
void flyer_melee (edict_t *self)
{
// flyer.nextmove = ACTION_attack1;
// self->monsterinfo.currentmove = &flyer_move_stop;
self->monsterinfo.currentmove = &flyer_move_start_melee;
}
void flyer_check_melee(edict_t *self)
{
if (range (self, self->enemy) == RANGE_MELEE)
if (random() <= 0.8)
self->monsterinfo.currentmove = &flyer_move_loop_melee;
else
self->monsterinfo.currentmove = &flyer_move_end_melee;
else
self->monsterinfo.currentmove = &flyer_move_end_melee;
}
void flyer_pain (edict_t *self, edict_t *other, float kick, int damage)
{
int n;
if (self->health < (self->max_health / 2))
self->s.skinnum = 1;
if (level.time < self->pain_debounce_time)
return;
self->pain_debounce_time = level.time + 3;
if (skill->value == 3)
return; // no pain anims in nightmare
n = rand() % 3;
if (n == 0)
{
gi.sound (self, CHAN_VOICE, sound_pain1, 1, ATTN_NORM, 0);
self->monsterinfo.currentmove = &flyer_move_pain1;
}
else if (n == 1)
{
gi.sound (self, CHAN_VOICE, sound_pain2, 1, ATTN_NORM, 0);
self->monsterinfo.currentmove = &flyer_move_pain2;
}
else
{
gi.sound (self, CHAN_VOICE, sound_pain1, 1, ATTN_NORM, 0);
self->monsterinfo.currentmove = &flyer_move_pain3;
}
}
void flyer_die(edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
{
gi.sound (self, CHAN_VOICE, sound_die, 1, ATTN_NORM, 0);
BecomeExplosion1(self);
}
/*QUAKED monster_flyer (1 .5 0) (-16 -16 -24) (16 16 32) Ambush Trigger_Spawn Sight
*/
void SP_monster_flyer (edict_t *self)
{
if (deathmatch->value)
{
G_FreeEdict (self);
return;
}
// fix a map bug in jail5.bsp
if (!Q_stricmp(level.mapname, "jail5") && (self->s.origin[2] == -104))
{
self->targetname = self->target;
self->target = NULL;
}
sound_sight = gi.soundindex ("flyer/flysght1.wav");
sound_idle = gi.soundindex ("flyer/flysrch1.wav");
sound_pain1 = gi.soundindex ("flyer/flypain1.wav");
sound_pain2 = gi.soundindex ("flyer/flypain2.wav");
sound_slash = gi.soundindex ("flyer/flyatck2.wav");
sound_sproing = gi.soundindex ("flyer/flyatck1.wav");
sound_die = gi.soundindex ("flyer/flydeth1.wav");
gi.soundindex ("flyer/flyatck3.wav");
self->s.modelindex = gi.modelindex ("models/monsters/flyer/tris.md2");
VectorSet (self->mins, -16, -16, -24);
VectorSet (self->maxs, 16, 16, 32);
self->movetype = MOVETYPE_STEP;
self->solid = SOLID_BBOX;
self->s.sound = gi.soundindex ("flyer/flyidle1.wav");
self->health = 50;
self->mass = 50;
self->pain = flyer_pain;
self->die = flyer_die;
self->monsterinfo.stand = flyer_stand;
self->monsterinfo.walk = flyer_walk;
self->monsterinfo.run = flyer_run;
self->monsterinfo.attack = flyer_attack;
self->monsterinfo.melee = flyer_melee;
self->monsterinfo.sight = flyer_sight;
self->monsterinfo.idle = flyer_idle;
gi.linkentity (self);
self->monsterinfo.currentmove = &flyer_move_stand;
self->monsterinfo.scale = MODEL_SCALE;
flymonster_start (self);
}

182
game/m_flyer.h Normal file
View File

@ -0,0 +1,182 @@
/*
Copyright (C) 1997-2001 Id Software, Inc.
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 the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
// G:\quake2\baseq2\models/monsters/flyer
// This file generated by ModelGen - Do NOT Modify
#define ACTION_nothing 0
#define ACTION_attack1 1
#define ACTION_attack2 2
#define ACTION_run 3
#define ACTION_walk 4
#define FRAME_start01 0
#define FRAME_start02 1
#define FRAME_start03 2
#define FRAME_start04 3
#define FRAME_start05 4
#define FRAME_start06 5
#define FRAME_stop01 6
#define FRAME_stop02 7
#define FRAME_stop03 8
#define FRAME_stop04 9
#define FRAME_stop05 10
#define FRAME_stop06 11
#define FRAME_stop07 12
#define FRAME_stand01 13
#define FRAME_stand02 14
#define FRAME_stand03 15
#define FRAME_stand04 16
#define FRAME_stand05 17
#define FRAME_stand06 18
#define FRAME_stand07 19
#define FRAME_stand08 20
#define FRAME_stand09 21
#define FRAME_stand10 22
#define FRAME_stand11 23
#define FRAME_stand12 24
#define FRAME_stand13 25
#define FRAME_stand14 26
#define FRAME_stand15 27
#define FRAME_stand16 28
#define FRAME_stand17 29
#define FRAME_stand18 30
#define FRAME_stand19 31
#define FRAME_stand20 32
#define FRAME_stand21 33
#define FRAME_stand22 34
#define FRAME_stand23 35
#define FRAME_stand24 36
#define FRAME_stand25 37
#define FRAME_stand26 38
#define FRAME_stand27 39
#define FRAME_stand28 40
#define FRAME_stand29 41
#define FRAME_stand30 42
#define FRAME_stand31 43
#define FRAME_stand32 44
#define FRAME_stand33 45
#define FRAME_stand34 46
#define FRAME_stand35 47
#define FRAME_stand36 48
#define FRAME_stand37 49
#define FRAME_stand38 50
#define FRAME_stand39 51
#define FRAME_stand40 52
#define FRAME_stand41 53
#define FRAME_stand42 54
#define FRAME_stand43 55
#define FRAME_stand44 56
#define FRAME_stand45 57
#define FRAME_attak101 58
#define FRAME_attak102 59
#define FRAME_attak103 60
#define FRAME_attak104 61
#define FRAME_attak105 62
#define FRAME_attak106 63
#define FRAME_attak107 64
#define FRAME_attak108 65
#define FRAME_attak109 66
#define FRAME_attak110 67
#define FRAME_attak111 68
#define FRAME_attak112 69
#define FRAME_attak113 70
#define FRAME_attak114 71
#define FRAME_attak115 72
#define FRAME_attak116 73
#define FRAME_attak117 74
#define FRAME_attak118 75
#define FRAME_attak119 76
#define FRAME_attak120 77
#define FRAME_attak121 78
#define FRAME_attak201 79
#define FRAME_attak202 80
#define FRAME_attak203 81
#define FRAME_attak204 82
#define FRAME_attak205 83
#define FRAME_attak206 84
#define FRAME_attak207 85
#define FRAME_attak208 86
#define FRAME_attak209 87
#define FRAME_attak210 88
#define FRAME_attak211 89
#define FRAME_attak212 90
#define FRAME_attak213 91
#define FRAME_attak214 92
#define FRAME_attak215 93
#define FRAME_attak216 94
#define FRAME_attak217 95
#define FRAME_bankl01 96
#define FRAME_bankl02 97
#define FRAME_bankl03 98
#define FRAME_bankl04 99
#define FRAME_bankl05 100
#define FRAME_bankl06 101
#define FRAME_bankl07 102
#define FRAME_bankr01 103
#define FRAME_bankr02 104
#define FRAME_bankr03 105
#define FRAME_bankr04 106
#define FRAME_bankr05 107
#define FRAME_bankr06 108
#define FRAME_bankr07 109
#define FRAME_rollf01 110
#define FRAME_rollf02 111
#define FRAME_rollf03 112
#define FRAME_rollf04 113
#define FRAME_rollf05 114
#define FRAME_rollf06 115
#define FRAME_rollf07 116
#define FRAME_rollf08 117
#define FRAME_rollf09 118
#define FRAME_rollr01 119
#define FRAME_rollr02 120
#define FRAME_rollr03 121
#define FRAME_rollr04 122
#define FRAME_rollr05 123
#define FRAME_rollr06 124
#define FRAME_rollr07 125
#define FRAME_rollr08 126
#define FRAME_rollr09 127
#define FRAME_defens01 128
#define FRAME_defens02 129
#define FRAME_defens03 130
#define FRAME_defens04 131
#define FRAME_defens05 132
#define FRAME_defens06 133
#define FRAME_pain101 134
#define FRAME_pain102 135
#define FRAME_pain103 136
#define FRAME_pain104 137
#define FRAME_pain105 138
#define FRAME_pain106 139
#define FRAME_pain107 140
#define FRAME_pain108 141
#define FRAME_pain109 142
#define FRAME_pain201 143
#define FRAME_pain202 144
#define FRAME_pain203 145
#define FRAME_pain204 146
#define FRAME_pain301 147
#define FRAME_pain302 148
#define FRAME_pain303 149
#define FRAME_pain304 150
#define MODEL_SCALE 1.000000

387
game/m_gladiator.c Normal file
View File

@ -0,0 +1,387 @@
/*
Copyright (C) 1997-2001 Id Software, Inc.
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 the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/*
==============================================================================
GLADIATOR
==============================================================================
*/
#include "g_local.h"
#include "m_gladiator.h"
static int sound_pain1;
static int sound_pain2;
static int sound_die;
static int sound_gun;
static int sound_cleaver_swing;
static int sound_cleaver_hit;
static int sound_cleaver_miss;
static int sound_idle;
static int sound_search;
static int sound_sight;
void gladiator_idle (edict_t *self)
{
gi.sound (self, CHAN_VOICE, sound_idle, 1, ATTN_IDLE, 0);
}
void gladiator_sight (edict_t *self, edict_t *other)
{
gi.sound (self, CHAN_VOICE, sound_sight, 1, ATTN_NORM, 0);
}
void gladiator_search (edict_t *self)
{
gi.sound (self, CHAN_VOICE, sound_search, 1, ATTN_NORM, 0);
}
void gladiator_cleaver_swing (edict_t *self)
{
gi.sound (self, CHAN_WEAPON, sound_cleaver_swing, 1, ATTN_NORM, 0);
}
mframe_t gladiator_frames_stand [] =
{
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL
};
mmove_t gladiator_move_stand = {FRAME_stand1, FRAME_stand7, gladiator_frames_stand, NULL};
void gladiator_stand (edict_t *self)
{
self->monsterinfo.currentmove = &gladiator_move_stand;
}
mframe_t gladiator_frames_walk [] =
{
ai_walk, 15, NULL,
ai_walk, 7, NULL,
ai_walk, 6, NULL,
ai_walk, 5, NULL,
ai_walk, 2, NULL,
ai_walk, 0, NULL,
ai_walk, 2, NULL,
ai_walk, 8, NULL,
ai_walk, 12, NULL,
ai_walk, 8, NULL,
ai_walk, 5, NULL,
ai_walk, 5, NULL,
ai_walk, 2, NULL,
ai_walk, 2, NULL,
ai_walk, 1, NULL,
ai_walk, 8, NULL
};
mmove_t gladiator_move_walk = {FRAME_walk1, FRAME_walk16, gladiator_frames_walk, NULL};
void gladiator_walk (edict_t *self)
{
self->monsterinfo.currentmove = &gladiator_move_walk;
}
mframe_t gladiator_frames_run [] =
{
ai_run, 23, NULL,
ai_run, 14, NULL,
ai_run, 14, NULL,
ai_run, 21, NULL,
ai_run, 12, NULL,
ai_run, 13, NULL
};
mmove_t gladiator_move_run = {FRAME_run1, FRAME_run6, gladiator_frames_run, NULL};
void gladiator_run (edict_t *self)
{
if (self->monsterinfo.aiflags & AI_STAND_GROUND)
self->monsterinfo.currentmove = &gladiator_move_stand;
else
self->monsterinfo.currentmove = &gladiator_move_run;
}
void GaldiatorMelee (edict_t *self)
{
vec3_t aim;
VectorSet (aim, MELEE_DISTANCE, self->mins[0], -4);
if (fire_hit (self, aim, (20 + (rand() %5)), 300))
gi.sound (self, CHAN_AUTO, sound_cleaver_hit, 1, ATTN_NORM, 0);
else
gi.sound (self, CHAN_AUTO, sound_cleaver_miss, 1, ATTN_NORM, 0);
}
mframe_t gladiator_frames_attack_melee [] =
{
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, gladiator_cleaver_swing,
ai_charge, 0, NULL,
ai_charge, 0, GaldiatorMelee,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, gladiator_cleaver_swing,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, GaldiatorMelee,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL
};
mmove_t gladiator_move_attack_melee = {FRAME_melee1, FRAME_melee17, gladiator_frames_attack_melee, gladiator_run};
void gladiator_melee(edict_t *self)
{
self->monsterinfo.currentmove = &gladiator_move_attack_melee;
}
void GladiatorGun (edict_t *self)
{
vec3_t start;
vec3_t dir;
vec3_t forward, right;
AngleVectors (self->s.angles, forward, right, NULL);
G_ProjectSource (self->s.origin, monster_flash_offset[MZ2_GLADIATOR_RAILGUN_1], forward, right, start);
// calc direction to where we targted
VectorSubtract (self->pos1, start, dir);
VectorNormalize (dir);
monster_fire_railgun (self, start, dir, 50, 100, MZ2_GLADIATOR_RAILGUN_1);
}
mframe_t gladiator_frames_attack_gun [] =
{
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, GladiatorGun,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL
};
mmove_t gladiator_move_attack_gun = {FRAME_attack1, FRAME_attack9, gladiator_frames_attack_gun, gladiator_run};
void gladiator_attack(edict_t *self)
{
float range;
vec3_t v;
// a small safe zone
VectorSubtract (self->s.origin, self->enemy->s.origin, v);
range = VectorLength(v);
if (range <= (MELEE_DISTANCE + 32))
return;
// charge up the railgun
gi.sound (self, CHAN_WEAPON, sound_gun, 1, ATTN_NORM, 0);
VectorCopy (self->enemy->s.origin, self->pos1); //save for aiming the shot
self->pos1[2] += self->enemy->viewheight;
self->monsterinfo.currentmove = &gladiator_move_attack_gun;
}
mframe_t gladiator_frames_pain [] =
{
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL
};
mmove_t gladiator_move_pain = {FRAME_pain1, FRAME_pain6, gladiator_frames_pain, gladiator_run};
mframe_t gladiator_frames_pain_air [] =
{
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL
};
mmove_t gladiator_move_pain_air = {FRAME_painup1, FRAME_painup7, gladiator_frames_pain_air, gladiator_run};
void gladiator_pain (edict_t *self, edict_t *other, float kick, int damage)
{
if (self->health < (self->max_health / 2))
self->s.skinnum = 1;
if (level.time < self->pain_debounce_time)
{
if ((self->velocity[2] > 100) && (self->monsterinfo.currentmove == &gladiator_move_pain))
self->monsterinfo.currentmove = &gladiator_move_pain_air;
return;
}
self->pain_debounce_time = level.time + 3;
if (random() < 0.5)
gi.sound (self, CHAN_VOICE, sound_pain1, 1, ATTN_NORM, 0);
else
gi.sound (self, CHAN_VOICE, sound_pain2, 1, ATTN_NORM, 0);
if (skill->value == 3)
return; // no pain anims in nightmare
if (self->velocity[2] > 100)
self->monsterinfo.currentmove = &gladiator_move_pain_air;
else
self->monsterinfo.currentmove = &gladiator_move_pain;
}
void gladiator_dead (edict_t *self)
{
VectorSet (self->mins, -16, -16, -24);
VectorSet (self->maxs, 16, 16, -8);
self->movetype = MOVETYPE_TOSS;
self->svflags |= SVF_DEADMONSTER;
self->nextthink = 0;
gi.linkentity (self);
}
mframe_t gladiator_frames_death [] =
{
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL
};
mmove_t gladiator_move_death = {FRAME_death1, FRAME_death22, gladiator_frames_death, gladiator_dead};
void gladiator_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
{
int n;
// check for gib
if (self->health <= self->gib_health)
{
gi.sound (self, CHAN_VOICE, gi.soundindex ("misc/udeath.wav"), 1, ATTN_NORM, 0);
for (n= 0; n < 2; n++)
ThrowGib (self, "models/objects/gibs/bone/tris.md2", damage, GIB_ORGANIC);
for (n= 0; n < 4; n++)
ThrowGib (self, "models/objects/gibs/sm_meat/tris.md2", damage, GIB_ORGANIC);
ThrowHead (self, "models/objects/gibs/head2/tris.md2", damage, GIB_ORGANIC);
self->deadflag = DEAD_DEAD;
return;
}
if (self->deadflag == DEAD_DEAD)
return;
// regular death
gi.sound (self, CHAN_VOICE, sound_die, 1, ATTN_NORM, 0);
self->deadflag = DEAD_DEAD;
self->takedamage = DAMAGE_YES;
self->monsterinfo.currentmove = &gladiator_move_death;
}
/*QUAKED monster_gladiator (1 .5 0) (-32 -32 -24) (32 32 64) Ambush Trigger_Spawn Sight
*/
void SP_monster_gladiator (edict_t *self)
{
if (deathmatch->value)
{
G_FreeEdict (self);
return;
}
sound_pain1 = gi.soundindex ("gladiator/pain.wav");
sound_pain2 = gi.soundindex ("gladiator/gldpain2.wav");
sound_die = gi.soundindex ("gladiator/glddeth2.wav");
sound_gun = gi.soundindex ("gladiator/railgun.wav");
sound_cleaver_swing = gi.soundindex ("gladiator/melee1.wav");
sound_cleaver_hit = gi.soundindex ("gladiator/melee2.wav");
sound_cleaver_miss = gi.soundindex ("gladiator/melee3.wav");
sound_idle = gi.soundindex ("gladiator/gldidle1.wav");
sound_search = gi.soundindex ("gladiator/gldsrch1.wav");
sound_sight = gi.soundindex ("gladiator/sight.wav");
self->movetype = MOVETYPE_STEP;
self->solid = SOLID_BBOX;
self->s.modelindex = gi.modelindex ("models/monsters/gladiatr/tris.md2");
VectorSet (self->mins, -32, -32, -24);
VectorSet (self->maxs, 32, 32, 64);
self->health = 400;
self->gib_health = -175;
self->mass = 400;
self->pain = gladiator_pain;
self->die = gladiator_die;
self->monsterinfo.stand = gladiator_stand;
self->monsterinfo.walk = gladiator_walk;
self->monsterinfo.run = gladiator_run;
self->monsterinfo.dodge = NULL;
self->monsterinfo.attack = gladiator_attack;
self->monsterinfo.melee = gladiator_melee;
self->monsterinfo.sight = gladiator_sight;
self->monsterinfo.idle = gladiator_idle;
self->monsterinfo.search = gladiator_search;
gi.linkentity (self);
self->monsterinfo.currentmove = &gladiator_move_stand;
self->monsterinfo.scale = MODEL_SCALE;
walkmonster_start (self);
}

115
game/m_gladiator.h Normal file
View File

@ -0,0 +1,115 @@
/*
Copyright (C) 1997-2001 Id Software, Inc.
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 the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
// G:\quake2\baseq2\models/monsters/gladiatr
// This file generated by ModelGen - Do NOT Modify
#define FRAME_stand1 0
#define FRAME_stand2 1
#define FRAME_stand3 2
#define FRAME_stand4 3
#define FRAME_stand5 4
#define FRAME_stand6 5
#define FRAME_stand7 6
#define FRAME_walk1 7
#define FRAME_walk2 8
#define FRAME_walk3 9
#define FRAME_walk4 10
#define FRAME_walk5 11
#define FRAME_walk6 12
#define FRAME_walk7 13
#define FRAME_walk8 14
#define FRAME_walk9 15
#define FRAME_walk10 16
#define FRAME_walk11 17
#define FRAME_walk12 18
#define FRAME_walk13 19
#define FRAME_walk14 20
#define FRAME_walk15 21
#define FRAME_walk16 22
#define FRAME_run1 23
#define FRAME_run2 24
#define FRAME_run3 25
#define FRAME_run4 26
#define FRAME_run5 27
#define FRAME_run6 28
#define FRAME_melee1 29
#define FRAME_melee2 30
#define FRAME_melee3 31
#define FRAME_melee4 32
#define FRAME_melee5 33
#define FRAME_melee6 34
#define FRAME_melee7 35
#define FRAME_melee8 36
#define FRAME_melee9 37
#define FRAME_melee10 38
#define FRAME_melee11 39
#define FRAME_melee12 40
#define FRAME_melee13 41
#define FRAME_melee14 42
#define FRAME_melee15 43
#define FRAME_melee16 44
#define FRAME_melee17 45
#define FRAME_attack1 46
#define FRAME_attack2 47
#define FRAME_attack3 48
#define FRAME_attack4 49
#define FRAME_attack5 50
#define FRAME_attack6 51
#define FRAME_attack7 52
#define FRAME_attack8 53
#define FRAME_attack9 54
#define FRAME_pain1 55
#define FRAME_pain2 56
#define FRAME_pain3 57
#define FRAME_pain4 58
#define FRAME_pain5 59
#define FRAME_pain6 60
#define FRAME_death1 61
#define FRAME_death2 62
#define FRAME_death3 63
#define FRAME_death4 64
#define FRAME_death5 65
#define FRAME_death6 66
#define FRAME_death7 67
#define FRAME_death8 68
#define FRAME_death9 69
#define FRAME_death10 70
#define FRAME_death11 71
#define FRAME_death12 72
#define FRAME_death13 73
#define FRAME_death14 74
#define FRAME_death15 75
#define FRAME_death16 76
#define FRAME_death17 77
#define FRAME_death18 78
#define FRAME_death19 79
#define FRAME_death20 80
#define FRAME_death21 81
#define FRAME_death22 82
#define FRAME_painup1 83
#define FRAME_painup2 84
#define FRAME_painup3 85
#define FRAME_painup4 86
#define FRAME_painup5 87
#define FRAME_painup6 88
#define FRAME_painup7 89
#define MODEL_SCALE 1.000000

628
game/m_gunner.c Normal file
View File

@ -0,0 +1,628 @@
/*
Copyright (C) 1997-2001 Id Software, Inc.
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 the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/*
==============================================================================
GUNNER
==============================================================================
*/
#include "g_local.h"
#include "m_gunner.h"
static int sound_pain;
static int sound_pain2;
static int sound_death;
static int sound_idle;
static int sound_open;
static int sound_search;
static int sound_sight;
void gunner_idlesound (edict_t *self)
{
gi.sound (self, CHAN_VOICE, sound_idle, 1, ATTN_IDLE, 0);
}
void gunner_sight (edict_t *self, edict_t *other)
{
gi.sound (self, CHAN_VOICE, sound_sight, 1, ATTN_NORM, 0);
}
void gunner_search (edict_t *self)
{
gi.sound (self, CHAN_VOICE, sound_search, 1, ATTN_NORM, 0);
}
qboolean visible (edict_t *self, edict_t *other);
void GunnerGrenade (edict_t *self);
void GunnerFire (edict_t *self);
void gunner_fire_chain(edict_t *self);
void gunner_refire_chain(edict_t *self);
void gunner_stand (edict_t *self);
mframe_t gunner_frames_fidget [] =
{
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, gunner_idlesound,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL
};
mmove_t gunner_move_fidget = {FRAME_stand31, FRAME_stand70, gunner_frames_fidget, gunner_stand};
void gunner_fidget (edict_t *self)
{
if (self->monsterinfo.aiflags & AI_STAND_GROUND)
return;
if (random() <= 0.05)
self->monsterinfo.currentmove = &gunner_move_fidget;
}
mframe_t gunner_frames_stand [] =
{
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, gunner_fidget,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, gunner_fidget,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, gunner_fidget
};
mmove_t gunner_move_stand = {FRAME_stand01, FRAME_stand30, gunner_frames_stand, NULL};
void gunner_stand (edict_t *self)
{
self->monsterinfo.currentmove = &gunner_move_stand;
}
mframe_t gunner_frames_walk [] =
{
ai_walk, 0, NULL,
ai_walk, 3, NULL,
ai_walk, 4, NULL,
ai_walk, 5, NULL,
ai_walk, 7, NULL,
ai_walk, 2, NULL,
ai_walk, 6, NULL,
ai_walk, 4, NULL,
ai_walk, 2, NULL,
ai_walk, 7, NULL,
ai_walk, 5, NULL,
ai_walk, 7, NULL,
ai_walk, 4, NULL
};
mmove_t gunner_move_walk = {FRAME_walk07, FRAME_walk19, gunner_frames_walk, NULL};
void gunner_walk (edict_t *self)
{
self->monsterinfo.currentmove = &gunner_move_walk;
}
mframe_t gunner_frames_run [] =
{
ai_run, 26, NULL,
ai_run, 9, NULL,
ai_run, 9, NULL,
ai_run, 9, NULL,
ai_run, 15, NULL,
ai_run, 10, NULL,
ai_run, 13, NULL,
ai_run, 6, NULL
};
mmove_t gunner_move_run = {FRAME_run01, FRAME_run08, gunner_frames_run, NULL};
void gunner_run (edict_t *self)
{
if (self->monsterinfo.aiflags & AI_STAND_GROUND)
self->monsterinfo.currentmove = &gunner_move_stand;
else
self->monsterinfo.currentmove = &gunner_move_run;
}
mframe_t gunner_frames_runandshoot [] =
{
ai_run, 32, NULL,
ai_run, 15, NULL,
ai_run, 10, NULL,
ai_run, 18, NULL,
ai_run, 8, NULL,
ai_run, 20, NULL
};
mmove_t gunner_move_runandshoot = {FRAME_runs01, FRAME_runs06, gunner_frames_runandshoot, NULL};
void gunner_runandshoot (edict_t *self)
{
self->monsterinfo.currentmove = &gunner_move_runandshoot;
}
mframe_t gunner_frames_pain3 [] =
{
ai_move, -3, NULL,
ai_move, 1, NULL,
ai_move, 1, NULL,
ai_move, 0, NULL,
ai_move, 1, NULL
};
mmove_t gunner_move_pain3 = {FRAME_pain301, FRAME_pain305, gunner_frames_pain3, gunner_run};
mframe_t gunner_frames_pain2 [] =
{
ai_move, -2, NULL,
ai_move, 11, NULL,
ai_move, 6, NULL,
ai_move, 2, NULL,
ai_move, -1, NULL,
ai_move, -7, NULL,
ai_move, -2, NULL,
ai_move, -7, NULL
};
mmove_t gunner_move_pain2 = {FRAME_pain201, FRAME_pain208, gunner_frames_pain2, gunner_run};
mframe_t gunner_frames_pain1 [] =
{
ai_move, 2, NULL,
ai_move, 0, NULL,
ai_move, -5, NULL,
ai_move, 3, NULL,
ai_move, -1, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 1, NULL,
ai_move, 1, NULL,
ai_move, 2, NULL,
ai_move, 1, NULL,
ai_move, 0, NULL,
ai_move, -2, NULL,
ai_move, -2, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL
};
mmove_t gunner_move_pain1 = {FRAME_pain101, FRAME_pain118, gunner_frames_pain1, gunner_run};
void gunner_pain (edict_t *self, edict_t *other, float kick, int damage)
{
if (self->health < (self->max_health / 2))
self->s.skinnum = 1;
if (level.time < self->pain_debounce_time)
return;
self->pain_debounce_time = level.time + 3;
if (rand()&1)
gi.sound (self, CHAN_VOICE, sound_pain, 1, ATTN_NORM, 0);
else
gi.sound (self, CHAN_VOICE, sound_pain2, 1, ATTN_NORM, 0);
if (skill->value == 3)
return; // no pain anims in nightmare
if (damage <= 10)
self->monsterinfo.currentmove = &gunner_move_pain3;
else if (damage <= 25)
self->monsterinfo.currentmove = &gunner_move_pain2;
else
self->monsterinfo.currentmove = &gunner_move_pain1;
}
void gunner_dead (edict_t *self)
{
VectorSet (self->mins, -16, -16, -24);
VectorSet (self->maxs, 16, 16, -8);
self->movetype = MOVETYPE_TOSS;
self->svflags |= SVF_DEADMONSTER;
self->nextthink = 0;
gi.linkentity (self);
}
mframe_t gunner_frames_death [] =
{
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, -7, NULL,
ai_move, -3, NULL,
ai_move, -5, NULL,
ai_move, 8, NULL,
ai_move, 6, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL
};
mmove_t gunner_move_death = {FRAME_death01, FRAME_death11, gunner_frames_death, gunner_dead};
void gunner_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
{
int n;
// check for gib
if (self->health <= self->gib_health)
{
gi.sound (self, CHAN_VOICE, gi.soundindex ("misc/udeath.wav"), 1, ATTN_NORM, 0);
for (n= 0; n < 2; n++)
ThrowGib (self, "models/objects/gibs/bone/tris.md2", damage, GIB_ORGANIC);
for (n= 0; n < 4; n++)
ThrowGib (self, "models/objects/gibs/sm_meat/tris.md2", damage, GIB_ORGANIC);
ThrowHead (self, "models/objects/gibs/head2/tris.md2", damage, GIB_ORGANIC);
self->deadflag = DEAD_DEAD;
return;
}
if (self->deadflag == DEAD_DEAD)
return;
// regular death
gi.sound (self, CHAN_VOICE, sound_death, 1, ATTN_NORM, 0);
self->deadflag = DEAD_DEAD;
self->takedamage = DAMAGE_YES;
self->monsterinfo.currentmove = &gunner_move_death;
}
void gunner_duck_down (edict_t *self)
{
if (self->monsterinfo.aiflags & AI_DUCKED)
return;
self->monsterinfo.aiflags |= AI_DUCKED;
if (skill->value >= 2)
{
if (random() > 0.5)
GunnerGrenade (self);
}
self->maxs[2] -= 32;
self->takedamage = DAMAGE_YES;
self->monsterinfo.pausetime = level.time + 1;
gi.linkentity (self);
}
void gunner_duck_hold (edict_t *self)
{
if (level.time >= self->monsterinfo.pausetime)
self->monsterinfo.aiflags &= ~AI_HOLD_FRAME;
else
self->monsterinfo.aiflags |= AI_HOLD_FRAME;
}
void gunner_duck_up (edict_t *self)
{
self->monsterinfo.aiflags &= ~AI_DUCKED;
self->maxs[2] += 32;
self->takedamage = DAMAGE_AIM;
gi.linkentity (self);
}
mframe_t gunner_frames_duck [] =
{
ai_move, 1, gunner_duck_down,
ai_move, 1, NULL,
ai_move, 1, gunner_duck_hold,
ai_move, 0, NULL,
ai_move, -1, NULL,
ai_move, -1, NULL,
ai_move, 0, gunner_duck_up,
ai_move, -1, NULL
};
mmove_t gunner_move_duck = {FRAME_duck01, FRAME_duck08, gunner_frames_duck, gunner_run};
void gunner_dodge (edict_t *self, edict_t *attacker, float eta)
{
if (random() > 0.25)
return;
if (!self->enemy)
self->enemy = attacker;
self->monsterinfo.currentmove = &gunner_move_duck;
}
void gunner_opengun (edict_t *self)
{
gi.sound (self, CHAN_VOICE, sound_open, 1, ATTN_IDLE, 0);
}
void GunnerFire (edict_t *self)
{
vec3_t start;
vec3_t forward, right;
vec3_t target;
vec3_t aim;
int flash_number;
flash_number = MZ2_GUNNER_MACHINEGUN_1 + (self->s.frame - FRAME_attak216);
AngleVectors (self->s.angles, forward, right, NULL);
G_ProjectSource (self->s.origin, monster_flash_offset[flash_number], forward, right, start);
// project enemy back a bit and target there
VectorCopy (self->enemy->s.origin, target);
VectorMA (target, -0.2, self->enemy->velocity, target);
target[2] += self->enemy->viewheight;
VectorSubtract (target, start, aim);
VectorNormalize (aim);
monster_fire_bullet (self, start, aim, 3, 4, DEFAULT_BULLET_HSPREAD, DEFAULT_BULLET_VSPREAD, flash_number);
}
void GunnerGrenade (edict_t *self)
{
vec3_t start;
vec3_t forward, right;
vec3_t aim;
int flash_number;
if (self->s.frame == FRAME_attak105)
flash_number = MZ2_GUNNER_GRENADE_1;
else if (self->s.frame == FRAME_attak108)
flash_number = MZ2_GUNNER_GRENADE_2;
else if (self->s.frame == FRAME_attak111)
flash_number = MZ2_GUNNER_GRENADE_3;
else // (self->s.frame == FRAME_attak114)
flash_number = MZ2_GUNNER_GRENADE_4;
AngleVectors (self->s.angles, forward, right, NULL);
G_ProjectSource (self->s.origin, monster_flash_offset[flash_number], forward, right, start);
//FIXME : do a spread -225 -75 75 225 degrees around forward
VectorCopy (forward, aim);
monster_fire_grenade (self, start, aim, 50, 600, flash_number);
}
mframe_t gunner_frames_attack_chain [] =
{
/*
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
*/
ai_charge, 0, gunner_opengun,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL
};
mmove_t gunner_move_attack_chain = {FRAME_attak209, FRAME_attak215, gunner_frames_attack_chain, gunner_fire_chain};
mframe_t gunner_frames_fire_chain [] =
{
ai_charge, 0, GunnerFire,
ai_charge, 0, GunnerFire,
ai_charge, 0, GunnerFire,
ai_charge, 0, GunnerFire,
ai_charge, 0, GunnerFire,
ai_charge, 0, GunnerFire,
ai_charge, 0, GunnerFire,
ai_charge, 0, GunnerFire
};
mmove_t gunner_move_fire_chain = {FRAME_attak216, FRAME_attak223, gunner_frames_fire_chain, gunner_refire_chain};
mframe_t gunner_frames_endfire_chain [] =
{
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL
};
mmove_t gunner_move_endfire_chain = {FRAME_attak224, FRAME_attak230, gunner_frames_endfire_chain, gunner_run};
mframe_t gunner_frames_attack_grenade [] =
{
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, GunnerGrenade,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, GunnerGrenade,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, GunnerGrenade,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, GunnerGrenade,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL
};
mmove_t gunner_move_attack_grenade = {FRAME_attak101, FRAME_attak121, gunner_frames_attack_grenade, gunner_run};
void gunner_attack(edict_t *self)
{
if (range (self, self->enemy) == RANGE_MELEE)
{
self->monsterinfo.currentmove = &gunner_move_attack_chain;
}
else
{
if (random() <= 0.5)
self->monsterinfo.currentmove = &gunner_move_attack_grenade;
else
self->monsterinfo.currentmove = &gunner_move_attack_chain;
}
}
void gunner_fire_chain(edict_t *self)
{
self->monsterinfo.currentmove = &gunner_move_fire_chain;
}
void gunner_refire_chain(edict_t *self)
{
if (self->enemy->health > 0)
if ( visible (self, self->enemy) )
if (random() <= 0.5)
{
self->monsterinfo.currentmove = &gunner_move_fire_chain;
return;
}
self->monsterinfo.currentmove = &gunner_move_endfire_chain;
}
/*QUAKED monster_gunner (1 .5 0) (-16 -16 -24) (16 16 32) Ambush Trigger_Spawn Sight
*/
void SP_monster_gunner (edict_t *self)
{
if (deathmatch->value)
{
G_FreeEdict (self);
return;
}
sound_death = gi.soundindex ("gunner/death1.wav");
sound_pain = gi.soundindex ("gunner/gunpain2.wav");
sound_pain2 = gi.soundindex ("gunner/gunpain1.wav");
sound_idle = gi.soundindex ("gunner/gunidle1.wav");
sound_open = gi.soundindex ("gunner/gunatck1.wav");
sound_search = gi.soundindex ("gunner/gunsrch1.wav");
sound_sight = gi.soundindex ("gunner/sight1.wav");
gi.soundindex ("gunner/gunatck2.wav");
gi.soundindex ("gunner/gunatck3.wav");
self->movetype = MOVETYPE_STEP;
self->solid = SOLID_BBOX;
self->s.modelindex = gi.modelindex ("models/monsters/gunner/tris.md2");
VectorSet (self->mins, -16, -16, -24);
VectorSet (self->maxs, 16, 16, 32);
self->health = 175;
self->gib_health = -70;
self->mass = 200;
self->pain = gunner_pain;
self->die = gunner_die;
self->monsterinfo.stand = gunner_stand;
self->monsterinfo.walk = gunner_walk;
self->monsterinfo.run = gunner_run;
self->monsterinfo.dodge = gunner_dodge;
self->monsterinfo.attack = gunner_attack;
self->monsterinfo.melee = NULL;
self->monsterinfo.sight = gunner_sight;
self->monsterinfo.search = gunner_search;
gi.linkentity (self);
self->monsterinfo.currentmove = &gunner_move_stand;
self->monsterinfo.scale = MODEL_SCALE;
walkmonster_start (self);
}

234
game/m_gunner.h Normal file
View File

@ -0,0 +1,234 @@
/*
Copyright (C) 1997-2001 Id Software, Inc.
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 the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
// G:\quake2\baseq2\models/gunner
// This file generated by ModelGen - Do NOT Modify
#define FRAME_stand01 0
#define FRAME_stand02 1
#define FRAME_stand03 2
#define FRAME_stand04 3
#define FRAME_stand05 4
#define FRAME_stand06 5
#define FRAME_stand07 6
#define FRAME_stand08 7
#define FRAME_stand09 8
#define FRAME_stand10 9
#define FRAME_stand11 10
#define FRAME_stand12 11
#define FRAME_stand13 12
#define FRAME_stand14 13
#define FRAME_stand15 14
#define FRAME_stand16 15
#define FRAME_stand17 16
#define FRAME_stand18 17
#define FRAME_stand19 18
#define FRAME_stand20 19
#define FRAME_stand21 20
#define FRAME_stand22 21
#define FRAME_stand23 22
#define FRAME_stand24 23
#define FRAME_stand25 24
#define FRAME_stand26 25
#define FRAME_stand27 26
#define FRAME_stand28 27
#define FRAME_stand29 28
#define FRAME_stand30 29
#define FRAME_stand31 30
#define FRAME_stand32 31
#define FRAME_stand33 32
#define FRAME_stand34 33
#define FRAME_stand35 34
#define FRAME_stand36 35
#define FRAME_stand37 36
#define FRAME_stand38 37
#define FRAME_stand39 38
#define FRAME_stand40 39
#define FRAME_stand41 40
#define FRAME_stand42 41
#define FRAME_stand43 42
#define FRAME_stand44 43
#define FRAME_stand45 44
#define FRAME_stand46 45
#define FRAME_stand47 46
#define FRAME_stand48 47
#define FRAME_stand49 48
#define FRAME_stand50 49
#define FRAME_stand51 50
#define FRAME_stand52 51
#define FRAME_stand53 52
#define FRAME_stand54 53
#define FRAME_stand55 54
#define FRAME_stand56 55
#define FRAME_stand57 56
#define FRAME_stand58 57
#define FRAME_stand59 58
#define FRAME_stand60 59
#define FRAME_stand61 60
#define FRAME_stand62 61
#define FRAME_stand63 62
#define FRAME_stand64 63
#define FRAME_stand65 64
#define FRAME_stand66 65
#define FRAME_stand67 66
#define FRAME_stand68 67
#define FRAME_stand69 68
#define FRAME_stand70 69
#define FRAME_walk01 70
#define FRAME_walk02 71
#define FRAME_walk03 72
#define FRAME_walk04 73
#define FRAME_walk05 74
#define FRAME_walk06 75
#define FRAME_walk07 76
#define FRAME_walk08 77
#define FRAME_walk09 78
#define FRAME_walk10 79
#define FRAME_walk11 80
#define FRAME_walk12 81
#define FRAME_walk13 82
#define FRAME_walk14 83
#define FRAME_walk15 84
#define FRAME_walk16 85
#define FRAME_walk17 86
#define FRAME_walk18 87
#define FRAME_walk19 88
#define FRAME_walk20 89
#define FRAME_walk21 90
#define FRAME_walk22 91
#define FRAME_walk23 92
#define FRAME_walk24 93
#define FRAME_run01 94
#define FRAME_run02 95
#define FRAME_run03 96
#define FRAME_run04 97
#define FRAME_run05 98
#define FRAME_run06 99
#define FRAME_run07 100
#define FRAME_run08 101
#define FRAME_runs01 102
#define FRAME_runs02 103
#define FRAME_runs03 104
#define FRAME_runs04 105
#define FRAME_runs05 106
#define FRAME_runs06 107
#define FRAME_attak101 108
#define FRAME_attak102 109
#define FRAME_attak103 110
#define FRAME_attak104 111
#define FRAME_attak105 112
#define FRAME_attak106 113
#define FRAME_attak107 114
#define FRAME_attak108 115
#define FRAME_attak109 116
#define FRAME_attak110 117
#define FRAME_attak111 118
#define FRAME_attak112 119
#define FRAME_attak113 120
#define FRAME_attak114 121
#define FRAME_attak115 122
#define FRAME_attak116 123
#define FRAME_attak117 124
#define FRAME_attak118 125
#define FRAME_attak119 126
#define FRAME_attak120 127
#define FRAME_attak121 128
#define FRAME_attak201 129
#define FRAME_attak202 130
#define FRAME_attak203 131
#define FRAME_attak204 132
#define FRAME_attak205 133
#define FRAME_attak206 134
#define FRAME_attak207 135
#define FRAME_attak208 136
#define FRAME_attak209 137
#define FRAME_attak210 138
#define FRAME_attak211 139
#define FRAME_attak212 140
#define FRAME_attak213 141
#define FRAME_attak214 142
#define FRAME_attak215 143
#define FRAME_attak216 144
#define FRAME_attak217 145
#define FRAME_attak218 146
#define FRAME_attak219 147
#define FRAME_attak220 148
#define FRAME_attak221 149
#define FRAME_attak222 150
#define FRAME_attak223 151
#define FRAME_attak224 152
#define FRAME_attak225 153
#define FRAME_attak226 154
#define FRAME_attak227 155
#define FRAME_attak228 156
#define FRAME_attak229 157
#define FRAME_attak230 158
#define FRAME_pain101 159
#define FRAME_pain102 160
#define FRAME_pain103 161
#define FRAME_pain104 162
#define FRAME_pain105 163
#define FRAME_pain106 164
#define FRAME_pain107 165
#define FRAME_pain108 166
#define FRAME_pain109 167
#define FRAME_pain110 168
#define FRAME_pain111 169
#define FRAME_pain112 170
#define FRAME_pain113 171
#define FRAME_pain114 172
#define FRAME_pain115 173
#define FRAME_pain116 174
#define FRAME_pain117 175
#define FRAME_pain118 176
#define FRAME_pain201 177
#define FRAME_pain202 178
#define FRAME_pain203 179
#define FRAME_pain204 180
#define FRAME_pain205 181
#define FRAME_pain206 182
#define FRAME_pain207 183
#define FRAME_pain208 184
#define FRAME_pain301 185
#define FRAME_pain302 186
#define FRAME_pain303 187
#define FRAME_pain304 188
#define FRAME_pain305 189
#define FRAME_death01 190
#define FRAME_death02 191
#define FRAME_death03 192
#define FRAME_death04 193
#define FRAME_death05 194
#define FRAME_death06 195
#define FRAME_death07 196
#define FRAME_death08 197
#define FRAME_death09 198
#define FRAME_death10 199
#define FRAME_death11 200
#define FRAME_duck01 201
#define FRAME_duck02 202
#define FRAME_duck03 203
#define FRAME_duck04 204
#define FRAME_duck05 205
#define FRAME_duck06 206
#define FRAME_duck07 207
#define FRAME_duck08 208
#define MODEL_SCALE 1.150000

620
game/m_hover.c Normal file
View File

@ -0,0 +1,620 @@
/*
Copyright (C) 1997-2001 Id Software, Inc.
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 the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/*
==============================================================================
hover
==============================================================================
*/
#include "g_local.h"
#include "m_hover.h"
qboolean visible (edict_t *self, edict_t *other);
static int sound_pain1;
static int sound_pain2;
static int sound_death1;
static int sound_death2;
static int sound_sight;
static int sound_search1;
static int sound_search2;
void hover_sight (edict_t *self, edict_t *other)
{
gi.sound (self, CHAN_VOICE, sound_sight, 1, ATTN_NORM, 0);
}
void hover_search (edict_t *self)
{
if (random() < 0.5)
gi.sound (self, CHAN_VOICE, sound_search1, 1, ATTN_NORM, 0);
else
gi.sound (self, CHAN_VOICE, sound_search2, 1, ATTN_NORM, 0);
}
void hover_run (edict_t *self);
void hover_stand (edict_t *self);
void hover_dead (edict_t *self);
void hover_attack (edict_t *self);
void hover_reattack (edict_t *self);
void hover_fire_blaster (edict_t *self);
void hover_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point);
mframe_t hover_frames_stand [] =
{
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL
};
mmove_t hover_move_stand = {FRAME_stand01, FRAME_stand30, hover_frames_stand, NULL};
mframe_t hover_frames_stop1 [] =
{
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL
};
mmove_t hover_move_stop1 = {FRAME_stop101, FRAME_stop109, hover_frames_stop1, NULL};
mframe_t hover_frames_stop2 [] =
{
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL
};
mmove_t hover_move_stop2 = {FRAME_stop201, FRAME_stop208, hover_frames_stop2, NULL};
mframe_t hover_frames_takeoff [] =
{
ai_move, 0, NULL,
ai_move, -2, NULL,
ai_move, 5, NULL,
ai_move, -1, NULL,
ai_move, 1, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, -1, NULL,
ai_move, -1, NULL,
ai_move, -1, NULL,
ai_move, 0, NULL,
ai_move, 2, NULL,
ai_move, 2, NULL,
ai_move, 1, NULL,
ai_move, 1, NULL,
ai_move, -6, NULL,
ai_move, -9, NULL,
ai_move, 1, NULL,
ai_move, 0, NULL,
ai_move, 2, NULL,
ai_move, 2, NULL,
ai_move, 1, NULL,
ai_move, 1, NULL,
ai_move, 1, NULL,
ai_move, 2, NULL,
ai_move, 0, NULL,
ai_move, 2, NULL,
ai_move, 3, NULL,
ai_move, 2, NULL,
ai_move, 0, NULL
};
mmove_t hover_move_takeoff = {FRAME_takeof01, FRAME_takeof30, hover_frames_takeoff, NULL};
mframe_t hover_frames_pain3 [] =
{
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL
};
mmove_t hover_move_pain3 = {FRAME_pain301, FRAME_pain309, hover_frames_pain3, hover_run};
mframe_t hover_frames_pain2 [] =
{
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL
};
mmove_t hover_move_pain2 = {FRAME_pain201, FRAME_pain212, hover_frames_pain2, hover_run};
mframe_t hover_frames_pain1 [] =
{
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 2, NULL,
ai_move, -8, NULL,
ai_move, -4, NULL,
ai_move, -6, NULL,
ai_move, -4, NULL,
ai_move, -3, NULL,
ai_move, 1, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 3, NULL,
ai_move, 1, NULL,
ai_move, 0, NULL,
ai_move, 2, NULL,
ai_move, 3, NULL,
ai_move, 2, NULL,
ai_move, 7, NULL,
ai_move, 1, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 2, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 5, NULL,
ai_move, 3, NULL,
ai_move, 4, NULL
};
mmove_t hover_move_pain1 = {FRAME_pain101, FRAME_pain128, hover_frames_pain1, hover_run};
mframe_t hover_frames_land [] =
{
ai_move, 0, NULL
};
mmove_t hover_move_land = {FRAME_land01, FRAME_land01, hover_frames_land, NULL};
mframe_t hover_frames_forward [] =
{
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL
};
mmove_t hover_move_forward = {FRAME_forwrd01, FRAME_forwrd35, hover_frames_forward, NULL};
mframe_t hover_frames_walk [] =
{
ai_walk, 4, NULL,
ai_walk, 4, NULL,
ai_walk, 4, NULL,
ai_walk, 4, NULL,
ai_walk, 4, NULL,
ai_walk, 4, NULL,
ai_walk, 4, NULL,
ai_walk, 4, NULL,
ai_walk, 4, NULL,
ai_walk, 4, NULL,
ai_walk, 4, NULL,
ai_walk, 4, NULL,
ai_walk, 4, NULL,
ai_walk, 4, NULL,
ai_walk, 4, NULL,
ai_walk, 4, NULL,
ai_walk, 4, NULL,
ai_walk, 4, NULL,
ai_walk, 4, NULL,
ai_walk, 4, NULL,
ai_walk, 4, NULL,
ai_walk, 4, NULL,
ai_walk, 4, NULL,
ai_walk, 4, NULL,
ai_walk, 4, NULL,
ai_walk, 4, NULL,
ai_walk, 4, NULL,
ai_walk, 4, NULL,
ai_walk, 4, NULL,
ai_walk, 4, NULL,
ai_walk, 4, NULL,
ai_walk, 4, NULL,
ai_walk, 4, NULL,
ai_walk, 4, NULL,
ai_walk, 4, NULL
};
mmove_t hover_move_walk = {FRAME_forwrd01, FRAME_forwrd35, hover_frames_walk, NULL};
mframe_t hover_frames_run [] =
{
ai_run, 10, NULL,
ai_run, 10, NULL,
ai_run, 10, NULL,
ai_run, 10, NULL,
ai_run, 10, NULL,
ai_run, 10, NULL,
ai_run, 10, NULL,
ai_run, 10, NULL,
ai_run, 10, NULL,
ai_run, 10, NULL,
ai_run, 10, NULL,
ai_run, 10, NULL,
ai_run, 10, NULL,
ai_run, 10, NULL,
ai_run, 10, NULL,
ai_run, 10, NULL,
ai_run, 10, NULL,
ai_run, 10, NULL,
ai_run, 10, NULL,
ai_run, 10, NULL,
ai_run, 10, NULL,
ai_run, 10, NULL,
ai_run, 10, NULL,
ai_run, 10, NULL,
ai_run, 10, NULL,
ai_run, 10, NULL,
ai_run, 10, NULL,
ai_run, 10, NULL,
ai_run, 10, NULL,
ai_run, 10, NULL,
ai_run, 10, NULL,
ai_run, 10, NULL,
ai_run, 10, NULL,
ai_run, 10, NULL,
ai_run, 10, NULL
};
mmove_t hover_move_run = {FRAME_forwrd01, FRAME_forwrd35, hover_frames_run, NULL};
mframe_t hover_frames_death1 [] =
{
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, -10,NULL,
ai_move, 3, NULL,
ai_move, 5, NULL,
ai_move, 4, NULL,
ai_move, 7, NULL
};
mmove_t hover_move_death1 = {FRAME_death101, FRAME_death111, hover_frames_death1, hover_dead};
mframe_t hover_frames_backward [] =
{
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL
};
mmove_t hover_move_backward = {FRAME_backwd01, FRAME_backwd24, hover_frames_backward, NULL};
mframe_t hover_frames_start_attack [] =
{
ai_charge, 1, NULL,
ai_charge, 1, NULL,
ai_charge, 1, NULL
};
mmove_t hover_move_start_attack = {FRAME_attak101, FRAME_attak103, hover_frames_start_attack, hover_attack};
mframe_t hover_frames_attack1 [] =
{
ai_charge, -10, hover_fire_blaster,
ai_charge, -10, hover_fire_blaster,
ai_charge, 0, hover_reattack,
};
mmove_t hover_move_attack1 = {FRAME_attak104, FRAME_attak106, hover_frames_attack1, NULL};
mframe_t hover_frames_end_attack [] =
{
ai_charge, 1, NULL,
ai_charge, 1, NULL
};
mmove_t hover_move_end_attack = {FRAME_attak107, FRAME_attak108, hover_frames_end_attack, hover_run};
void hover_reattack (edict_t *self)
{
if (self->enemy->health > 0 )
if (visible (self, self->enemy) )
if (random() <= 0.6)
{
self->monsterinfo.currentmove = &hover_move_attack1;
return;
}
self->monsterinfo.currentmove = &hover_move_end_attack;
}
void hover_fire_blaster (edict_t *self)
{
vec3_t start;
vec3_t forward, right;
vec3_t end;
vec3_t dir;
int effect;
if (self->s.frame == FRAME_attak104)
effect = EF_HYPERBLASTER;
else
effect = 0;
AngleVectors (self->s.angles, forward, right, NULL);
G_ProjectSource (self->s.origin, monster_flash_offset[MZ2_HOVER_BLASTER_1], forward, right, start);
VectorCopy (self->enemy->s.origin, end);
end[2] += self->enemy->viewheight;
VectorSubtract (end, start, dir);
monster_fire_blaster (self, start, dir, 1, 1000, MZ2_HOVER_BLASTER_1, effect);
}
void hover_stand (edict_t *self)
{
self->monsterinfo.currentmove = &hover_move_stand;
}
void hover_run (edict_t *self)
{
if (self->monsterinfo.aiflags & AI_STAND_GROUND)
self->monsterinfo.currentmove = &hover_move_stand;
else
self->monsterinfo.currentmove = &hover_move_run;
}
void hover_walk (edict_t *self)
{
self->monsterinfo.currentmove = &hover_move_walk;
}
void hover_start_attack (edict_t *self)
{
self->monsterinfo.currentmove = &hover_move_start_attack;
}
void hover_attack(edict_t *self)
{
self->monsterinfo.currentmove = &hover_move_attack1;
}
void hover_pain (edict_t *self, edict_t *other, float kick, int damage)
{
if (self->health < (self->max_health / 2))
self->s.skinnum = 1;
if (level.time < self->pain_debounce_time)
return;
self->pain_debounce_time = level.time + 3;
if (skill->value == 3)
return; // no pain anims in nightmare
if (damage <= 25)
{
if (random() < 0.5)
{
gi.sound (self, CHAN_VOICE, sound_pain1, 1, ATTN_NORM, 0);
self->monsterinfo.currentmove = &hover_move_pain3;
}
else
{
gi.sound (self, CHAN_VOICE, sound_pain2, 1, ATTN_NORM, 0);
self->monsterinfo.currentmove = &hover_move_pain2;
}
}
else
{
gi.sound (self, CHAN_VOICE, sound_pain1, 1, ATTN_NORM, 0);
self->monsterinfo.currentmove = &hover_move_pain1;
}
}
void hover_deadthink (edict_t *self)
{
if (!self->groundentity && level.time < self->timestamp)
{
self->nextthink = level.time + FRAMETIME;
return;
}
BecomeExplosion1(self);
}
void hover_dead (edict_t *self)
{
VectorSet (self->mins, -16, -16, -24);
VectorSet (self->maxs, 16, 16, -8);
self->movetype = MOVETYPE_TOSS;
self->think = hover_deadthink;
self->nextthink = level.time + FRAMETIME;
self->timestamp = level.time + 15;
gi.linkentity (self);
}
void hover_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
{
int n;
// check for gib
if (self->health <= self->gib_health)
{
gi.sound (self, CHAN_VOICE, gi.soundindex ("misc/udeath.wav"), 1, ATTN_NORM, 0);
for (n= 0; n < 2; n++)
ThrowGib (self, "models/objects/gibs/bone/tris.md2", damage, GIB_ORGANIC);
for (n= 0; n < 2; n++)
ThrowGib (self, "models/objects/gibs/sm_meat/tris.md2", damage, GIB_ORGANIC);
ThrowHead (self, "models/objects/gibs/sm_meat/tris.md2", damage, GIB_ORGANIC);
self->deadflag = DEAD_DEAD;
return;
}
if (self->deadflag == DEAD_DEAD)
return;
// regular death
if (random() < 0.5)
gi.sound (self, CHAN_VOICE, sound_death1, 1, ATTN_NORM, 0);
else
gi.sound (self, CHAN_VOICE, sound_death2, 1, ATTN_NORM, 0);
self->deadflag = DEAD_DEAD;
self->takedamage = DAMAGE_YES;
self->monsterinfo.currentmove = &hover_move_death1;
}
/*QUAKED monster_hover (1 .5 0) (-16 -16 -24) (16 16 32) Ambush Trigger_Spawn Sight
*/
void SP_monster_hover (edict_t *self)
{
if (deathmatch->value)
{
G_FreeEdict (self);
return;
}
sound_pain1 = gi.soundindex ("hover/hovpain1.wav");
sound_pain2 = gi.soundindex ("hover/hovpain2.wav");
sound_death1 = gi.soundindex ("hover/hovdeth1.wav");
sound_death2 = gi.soundindex ("hover/hovdeth2.wav");
sound_sight = gi.soundindex ("hover/hovsght1.wav");
sound_search1 = gi.soundindex ("hover/hovsrch1.wav");
sound_search2 = gi.soundindex ("hover/hovsrch2.wav");
gi.soundindex ("hover/hovatck1.wav");
self->s.sound = gi.soundindex ("hover/hovidle1.wav");
self->movetype = MOVETYPE_STEP;
self->solid = SOLID_BBOX;
self->s.modelindex = gi.modelindex("models/monsters/hover/tris.md2");
VectorSet (self->mins, -24, -24, -24);
VectorSet (self->maxs, 24, 24, 32);
self->health = 240;
self->gib_health = -100;
self->mass = 150;
self->pain = hover_pain;
self->die = hover_die;
self->monsterinfo.stand = hover_stand;
self->monsterinfo.walk = hover_walk;
self->monsterinfo.run = hover_run;
// self->monsterinfo.dodge = hover_dodge;
self->monsterinfo.attack = hover_start_attack;
self->monsterinfo.sight = hover_sight;
self->monsterinfo.search = hover_search;
gi.linkentity (self);
self->monsterinfo.currentmove = &hover_move_stand;
self->monsterinfo.scale = MODEL_SCALE;
flymonster_start (self);
}

230
game/m_hover.h Normal file
View File

@ -0,0 +1,230 @@
/*
Copyright (C) 1997-2001 Id Software, Inc.
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 the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
// G:\quake2\baseq2\models/monsters/hover
// This file generated by ModelGen - Do NOT Modify
#define FRAME_stand01 0
#define FRAME_stand02 1
#define FRAME_stand03 2
#define FRAME_stand04 3
#define FRAME_stand05 4
#define FRAME_stand06 5
#define FRAME_stand07 6
#define FRAME_stand08 7
#define FRAME_stand09 8
#define FRAME_stand10 9
#define FRAME_stand11 10
#define FRAME_stand12 11
#define FRAME_stand13 12
#define FRAME_stand14 13
#define FRAME_stand15 14
#define FRAME_stand16 15
#define FRAME_stand17 16
#define FRAME_stand18 17
#define FRAME_stand19 18
#define FRAME_stand20 19
#define FRAME_stand21 20
#define FRAME_stand22 21
#define FRAME_stand23 22
#define FRAME_stand24 23
#define FRAME_stand25 24
#define FRAME_stand26 25
#define FRAME_stand27 26
#define FRAME_stand28 27
#define FRAME_stand29 28
#define FRAME_stand30 29
#define FRAME_forwrd01 30
#define FRAME_forwrd02 31
#define FRAME_forwrd03 32
#define FRAME_forwrd04 33
#define FRAME_forwrd05 34
#define FRAME_forwrd06 35
#define FRAME_forwrd07 36
#define FRAME_forwrd08 37
#define FRAME_forwrd09 38
#define FRAME_forwrd10 39
#define FRAME_forwrd11 40
#define FRAME_forwrd12 41
#define FRAME_forwrd13 42
#define FRAME_forwrd14 43
#define FRAME_forwrd15 44
#define FRAME_forwrd16 45
#define FRAME_forwrd17 46
#define FRAME_forwrd18 47
#define FRAME_forwrd19 48
#define FRAME_forwrd20 49
#define FRAME_forwrd21 50
#define FRAME_forwrd22 51
#define FRAME_forwrd23 52
#define FRAME_forwrd24 53
#define FRAME_forwrd25 54
#define FRAME_forwrd26 55
#define FRAME_forwrd27 56
#define FRAME_forwrd28 57
#define FRAME_forwrd29 58
#define FRAME_forwrd30 59
#define FRAME_forwrd31 60
#define FRAME_forwrd32 61
#define FRAME_forwrd33 62
#define FRAME_forwrd34 63
#define FRAME_forwrd35 64
#define FRAME_stop101 65
#define FRAME_stop102 66
#define FRAME_stop103 67
#define FRAME_stop104 68
#define FRAME_stop105 69
#define FRAME_stop106 70
#define FRAME_stop107 71
#define FRAME_stop108 72
#define FRAME_stop109 73
#define FRAME_stop201 74
#define FRAME_stop202 75
#define FRAME_stop203 76
#define FRAME_stop204 77
#define FRAME_stop205 78
#define FRAME_stop206 79
#define FRAME_stop207 80
#define FRAME_stop208 81
#define FRAME_takeof01 82
#define FRAME_takeof02 83
#define FRAME_takeof03 84
#define FRAME_takeof04 85
#define FRAME_takeof05 86
#define FRAME_takeof06 87
#define FRAME_takeof07 88
#define FRAME_takeof08 89
#define FRAME_takeof09 90
#define FRAME_takeof10 91
#define FRAME_takeof11 92
#define FRAME_takeof12 93
#define FRAME_takeof13 94
#define FRAME_takeof14 95
#define FRAME_takeof15 96
#define FRAME_takeof16 97
#define FRAME_takeof17 98
#define FRAME_takeof18 99
#define FRAME_takeof19 100
#define FRAME_takeof20 101
#define FRAME_takeof21 102
#define FRAME_takeof22 103
#define FRAME_takeof23 104
#define FRAME_takeof24 105
#define FRAME_takeof25 106
#define FRAME_takeof26 107
#define FRAME_takeof27 108
#define FRAME_takeof28 109
#define FRAME_takeof29 110
#define FRAME_takeof30 111
#define FRAME_land01 112
#define FRAME_pain101 113
#define FRAME_pain102 114
#define FRAME_pain103 115
#define FRAME_pain104 116
#define FRAME_pain105 117
#define FRAME_pain106 118
#define FRAME_pain107 119
#define FRAME_pain108 120
#define FRAME_pain109 121
#define FRAME_pain110 122
#define FRAME_pain111 123
#define FRAME_pain112 124
#define FRAME_pain113 125
#define FRAME_pain114 126
#define FRAME_pain115 127
#define FRAME_pain116 128
#define FRAME_pain117 129
#define FRAME_pain118 130
#define FRAME_pain119 131
#define FRAME_pain120 132
#define FRAME_pain121 133
#define FRAME_pain122 134
#define FRAME_pain123 135
#define FRAME_pain124 136
#define FRAME_pain125 137
#define FRAME_pain126 138
#define FRAME_pain127 139
#define FRAME_pain128 140
#define FRAME_pain201 141
#define FRAME_pain202 142
#define FRAME_pain203 143
#define FRAME_pain204 144
#define FRAME_pain205 145
#define FRAME_pain206 146
#define FRAME_pain207 147
#define FRAME_pain208 148
#define FRAME_pain209 149
#define FRAME_pain210 150
#define FRAME_pain211 151
#define FRAME_pain212 152
#define FRAME_pain301 153
#define FRAME_pain302 154
#define FRAME_pain303 155
#define FRAME_pain304 156
#define FRAME_pain305 157
#define FRAME_pain306 158
#define FRAME_pain307 159
#define FRAME_pain308 160
#define FRAME_pain309 161
#define FRAME_death101 162
#define FRAME_death102 163
#define FRAME_death103 164
#define FRAME_death104 165
#define FRAME_death105 166
#define FRAME_death106 167
#define FRAME_death107 168
#define FRAME_death108 169
#define FRAME_death109 170
#define FRAME_death110 171
#define FRAME_death111 172
#define FRAME_backwd01 173
#define FRAME_backwd02 174
#define FRAME_backwd03 175
#define FRAME_backwd04 176
#define FRAME_backwd05 177
#define FRAME_backwd06 178
#define FRAME_backwd07 179
#define FRAME_backwd08 180
#define FRAME_backwd09 181
#define FRAME_backwd10 182
#define FRAME_backwd11 183
#define FRAME_backwd12 184
#define FRAME_backwd13 185
#define FRAME_backwd14 186
#define FRAME_backwd15 187
#define FRAME_backwd16 188
#define FRAME_backwd17 189
#define FRAME_backwd18 190
#define FRAME_backwd19 191
#define FRAME_backwd20 192
#define FRAME_backwd21 193
#define FRAME_backwd22 194
#define FRAME_backwd23 195
#define FRAME_backwd24 196
#define FRAME_attak101 197
#define FRAME_attak102 198
#define FRAME_attak103 199
#define FRAME_attak104 200
#define FRAME_attak105 201
#define FRAME_attak106 202
#define FRAME_attak107 203
#define FRAME_attak108 204
#define MODEL_SCALE 1.000000

607
game/m_infantry.c Normal file
View File

@ -0,0 +1,607 @@
/*
Copyright (C) 1997-2001 Id Software, Inc.
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 the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/*
==============================================================================
INFANTRY
==============================================================================
*/
#include "g_local.h"
#include "m_infantry.h"
void InfantryMachineGun (edict_t *self);
static int sound_pain1;
static int sound_pain2;
static int sound_die1;
static int sound_die2;
static int sound_gunshot;
static int sound_weapon_cock;
static int sound_punch_swing;
static int sound_punch_hit;
static int sound_sight;
static int sound_search;
static int sound_idle;
mframe_t infantry_frames_stand [] =
{
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL
};
mmove_t infantry_move_stand = {FRAME_stand50, FRAME_stand71, infantry_frames_stand, NULL};
void infantry_stand (edict_t *self)
{
self->monsterinfo.currentmove = &infantry_move_stand;
}
mframe_t infantry_frames_fidget [] =
{
ai_stand, 1, NULL,
ai_stand, 0, NULL,
ai_stand, 1, NULL,
ai_stand, 3, NULL,
ai_stand, 6, NULL,
ai_stand, 3, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 1, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 1, NULL,
ai_stand, 0, NULL,
ai_stand, -1, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 1, NULL,
ai_stand, 0, NULL,
ai_stand, -2, NULL,
ai_stand, 1, NULL,
ai_stand, 1, NULL,
ai_stand, 1, NULL,
ai_stand, -1, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, -1, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, -1, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 1, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, -1, NULL,
ai_stand, -1, NULL,
ai_stand, 0, NULL,
ai_stand, -3, NULL,
ai_stand, -2, NULL,
ai_stand, -3, NULL,
ai_stand, -3, NULL,
ai_stand, -2, NULL
};
mmove_t infantry_move_fidget = {FRAME_stand01, FRAME_stand49, infantry_frames_fidget, infantry_stand};
void infantry_fidget (edict_t *self)
{
self->monsterinfo.currentmove = &infantry_move_fidget;
gi.sound (self, CHAN_VOICE, sound_idle, 1, ATTN_IDLE, 0);
}
mframe_t infantry_frames_walk [] =
{
ai_walk, 5, NULL,
ai_walk, 4, NULL,
ai_walk, 4, NULL,
ai_walk, 5, NULL,
ai_walk, 4, NULL,
ai_walk, 5, NULL,
ai_walk, 6, NULL,
ai_walk, 4, NULL,
ai_walk, 4, NULL,
ai_walk, 4, NULL,
ai_walk, 4, NULL,
ai_walk, 5, NULL
};
mmove_t infantry_move_walk = {FRAME_walk03, FRAME_walk14, infantry_frames_walk, NULL};
void infantry_walk (edict_t *self)
{
self->monsterinfo.currentmove = &infantry_move_walk;
}
mframe_t infantry_frames_run [] =
{
ai_run, 10, NULL,
ai_run, 20, NULL,
ai_run, 5, NULL,
ai_run, 7, NULL,
ai_run, 30, NULL,
ai_run, 35, NULL,
ai_run, 2, NULL,
ai_run, 6, NULL
};
mmove_t infantry_move_run = {FRAME_run01, FRAME_run08, infantry_frames_run, NULL};
void infantry_run (edict_t *self)
{
if (self->monsterinfo.aiflags & AI_STAND_GROUND)
self->monsterinfo.currentmove = &infantry_move_stand;
else
self->monsterinfo.currentmove = &infantry_move_run;
}
mframe_t infantry_frames_pain1 [] =
{
ai_move, -3, NULL,
ai_move, -2, NULL,
ai_move, -1, NULL,
ai_move, -2, NULL,
ai_move, -1, NULL,
ai_move, 1, NULL,
ai_move, -1, NULL,
ai_move, 1, NULL,
ai_move, 6, NULL,
ai_move, 2, NULL
};
mmove_t infantry_move_pain1 = {FRAME_pain101, FRAME_pain110, infantry_frames_pain1, infantry_run};
mframe_t infantry_frames_pain2 [] =
{
ai_move, -3, NULL,
ai_move, -3, NULL,
ai_move, 0, NULL,
ai_move, -1, NULL,
ai_move, -2, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 2, NULL,
ai_move, 5, NULL,
ai_move, 2, NULL
};
mmove_t infantry_move_pain2 = {FRAME_pain201, FRAME_pain210, infantry_frames_pain2, infantry_run};
void infantry_pain (edict_t *self, edict_t *other, float kick, int damage)
{
int n;
if (self->health < (self->max_health / 2))
self->s.skinnum = 1;
if (level.time < self->pain_debounce_time)
return;
self->pain_debounce_time = level.time + 3;
if (skill->value == 3)
return; // no pain anims in nightmare
n = rand() % 2;
if (n == 0)
{
self->monsterinfo.currentmove = &infantry_move_pain1;
gi.sound (self, CHAN_VOICE, sound_pain1, 1, ATTN_NORM, 0);
}
else
{
self->monsterinfo.currentmove = &infantry_move_pain2;
gi.sound (self, CHAN_VOICE, sound_pain2, 1, ATTN_NORM, 0);
}
}
vec3_t aimangles[] =
{
0.0, 5.0, 0.0,
10.0, 15.0, 0.0,
20.0, 25.0, 0.0,
25.0, 35.0, 0.0,
30.0, 40.0, 0.0,
30.0, 45.0, 0.0,
25.0, 50.0, 0.0,
20.0, 40.0, 0.0,
15.0, 35.0, 0.0,
40.0, 35.0, 0.0,
70.0, 35.0, 0.0,
90.0, 35.0, 0.0
};
void InfantryMachineGun (edict_t *self)
{
vec3_t start, target;
vec3_t forward, right;
vec3_t vec;
int flash_number;
if (self->s.frame == FRAME_attak111)
{
flash_number = MZ2_INFANTRY_MACHINEGUN_1;
AngleVectors (self->s.angles, forward, right, NULL);
G_ProjectSource (self->s.origin, monster_flash_offset[flash_number], forward, right, start);
if (self->enemy)
{
VectorMA (self->enemy->s.origin, -0.2, self->enemy->velocity, target);
target[2] += self->enemy->viewheight;
VectorSubtract (target, start, forward);
VectorNormalize (forward);
}
else
{
AngleVectors (self->s.angles, forward, right, NULL);
}
}
else
{
flash_number = MZ2_INFANTRY_MACHINEGUN_2 + (self->s.frame - FRAME_death211);
AngleVectors (self->s.angles, forward, right, NULL);
G_ProjectSource (self->s.origin, monster_flash_offset[flash_number], forward, right, start);
VectorSubtract (self->s.angles, aimangles[flash_number-MZ2_INFANTRY_MACHINEGUN_2], vec);
AngleVectors (vec, forward, NULL, NULL);
}
monster_fire_bullet (self, start, forward, 3, 4, DEFAULT_BULLET_HSPREAD, DEFAULT_BULLET_VSPREAD, flash_number);
}
void infantry_sight (edict_t *self, edict_t *other)
{
gi.sound (self, CHAN_BODY, sound_sight, 1, ATTN_NORM, 0);
}
void infantry_dead (edict_t *self)
{
VectorSet (self->mins, -16, -16, -24);
VectorSet (self->maxs, 16, 16, -8);
self->movetype = MOVETYPE_TOSS;
self->svflags |= SVF_DEADMONSTER;
gi.linkentity (self);
M_FlyCheck (self);
}
mframe_t infantry_frames_death1 [] =
{
ai_move, -4, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, -1, NULL,
ai_move, -4, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, -1, NULL,
ai_move, 3, NULL,
ai_move, 1, NULL,
ai_move, 1, NULL,
ai_move, -2, NULL,
ai_move, 2, NULL,
ai_move, 2, NULL,
ai_move, 9, NULL,
ai_move, 9, NULL,
ai_move, 5, NULL,
ai_move, -3, NULL,
ai_move, -3, NULL
};
mmove_t infantry_move_death1 = {FRAME_death101, FRAME_death120, infantry_frames_death1, infantry_dead};
// Off with his head
mframe_t infantry_frames_death2 [] =
{
ai_move, 0, NULL,
ai_move, 1, NULL,
ai_move, 5, NULL,
ai_move, -1, NULL,
ai_move, 0, NULL,
ai_move, 1, NULL,
ai_move, 1, NULL,
ai_move, 4, NULL,
ai_move, 3, NULL,
ai_move, 0, NULL,
ai_move, -2, InfantryMachineGun,
ai_move, -2, InfantryMachineGun,
ai_move, -3, InfantryMachineGun,
ai_move, -1, InfantryMachineGun,
ai_move, -2, InfantryMachineGun,
ai_move, 0, InfantryMachineGun,
ai_move, 2, InfantryMachineGun,
ai_move, 2, InfantryMachineGun,
ai_move, 3, InfantryMachineGun,
ai_move, -10, InfantryMachineGun,
ai_move, -7, InfantryMachineGun,
ai_move, -8, InfantryMachineGun,
ai_move, -6, NULL,
ai_move, 4, NULL,
ai_move, 0, NULL
};
mmove_t infantry_move_death2 = {FRAME_death201, FRAME_death225, infantry_frames_death2, infantry_dead};
mframe_t infantry_frames_death3 [] =
{
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, -6, NULL,
ai_move, -11, NULL,
ai_move, -3, NULL,
ai_move, -11, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL
};
mmove_t infantry_move_death3 = {FRAME_death301, FRAME_death309, infantry_frames_death3, infantry_dead};
void infantry_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
{
int n;
// check for gib
if (self->health <= self->gib_health)
{
gi.sound (self, CHAN_VOICE, gi.soundindex ("misc/udeath.wav"), 1, ATTN_NORM, 0);
for (n= 0; n < 2; n++)
ThrowGib (self, "models/objects/gibs/bone/tris.md2", damage, GIB_ORGANIC);
for (n= 0; n < 4; n++)
ThrowGib (self, "models/objects/gibs/sm_meat/tris.md2", damage, GIB_ORGANIC);
ThrowHead (self, "models/objects/gibs/head2/tris.md2", damage, GIB_ORGANIC);
self->deadflag = DEAD_DEAD;
return;
}
if (self->deadflag == DEAD_DEAD)
return;
// regular death
self->deadflag = DEAD_DEAD;
self->takedamage = DAMAGE_YES;
n = rand() % 3;
if (n == 0)
{
self->monsterinfo.currentmove = &infantry_move_death1;
gi.sound (self, CHAN_VOICE, sound_die2, 1, ATTN_NORM, 0);
}
else if (n == 1)
{
self->monsterinfo.currentmove = &infantry_move_death2;
gi.sound (self, CHAN_VOICE, sound_die1, 1, ATTN_NORM, 0);
}
else
{
self->monsterinfo.currentmove = &infantry_move_death3;
gi.sound (self, CHAN_VOICE, sound_die2, 1, ATTN_NORM, 0);
}
}
void infantry_duck_down (edict_t *self)
{
if (self->monsterinfo.aiflags & AI_DUCKED)
return;
self->monsterinfo.aiflags |= AI_DUCKED;
self->maxs[2] -= 32;
self->takedamage = DAMAGE_YES;
self->monsterinfo.pausetime = level.time + 1;
gi.linkentity (self);
}
void infantry_duck_hold (edict_t *self)
{
if (level.time >= self->monsterinfo.pausetime)
self->monsterinfo.aiflags &= ~AI_HOLD_FRAME;
else
self->monsterinfo.aiflags |= AI_HOLD_FRAME;
}
void infantry_duck_up (edict_t *self)
{
self->monsterinfo.aiflags &= ~AI_DUCKED;
self->maxs[2] += 32;
self->takedamage = DAMAGE_AIM;
gi.linkentity (self);
}
mframe_t infantry_frames_duck [] =
{
ai_move, -2, infantry_duck_down,
ai_move, -5, infantry_duck_hold,
ai_move, 3, NULL,
ai_move, 4, infantry_duck_up,
ai_move, 0, NULL
};
mmove_t infantry_move_duck = {FRAME_duck01, FRAME_duck05, infantry_frames_duck, infantry_run};
void infantry_dodge (edict_t *self, edict_t *attacker, float eta)
{
if (random() > 0.25)
return;
if (!self->enemy)
self->enemy = attacker;
self->monsterinfo.currentmove = &infantry_move_duck;
}
void infantry_cock_gun (edict_t *self)
{
int n;
gi.sound (self, CHAN_WEAPON, sound_weapon_cock, 1, ATTN_NORM, 0);
n = (rand() & 15) + 3 + 7;
self->monsterinfo.pausetime = level.time + n * FRAMETIME;
}
void infantry_fire (edict_t *self)
{
InfantryMachineGun (self);
if (level.time >= self->monsterinfo.pausetime)
self->monsterinfo.aiflags &= ~AI_HOLD_FRAME;
else
self->monsterinfo.aiflags |= AI_HOLD_FRAME;
}
mframe_t infantry_frames_attack1 [] =
{
ai_charge, 4, NULL,
ai_charge, -1, NULL,
ai_charge, -1, NULL,
ai_charge, 0, infantry_cock_gun,
ai_charge, -1, NULL,
ai_charge, 1, NULL,
ai_charge, 1, NULL,
ai_charge, 2, NULL,
ai_charge, -2, NULL,
ai_charge, -3, NULL,
ai_charge, 1, infantry_fire,
ai_charge, 5, NULL,
ai_charge, -1, NULL,
ai_charge, -2, NULL,
ai_charge, -3, NULL
};
mmove_t infantry_move_attack1 = {FRAME_attak101, FRAME_attak115, infantry_frames_attack1, infantry_run};
void infantry_swing (edict_t *self)
{
gi.sound (self, CHAN_WEAPON, sound_punch_swing, 1, ATTN_NORM, 0);
}
void infantry_smack (edict_t *self)
{
vec3_t aim;
VectorSet (aim, MELEE_DISTANCE, 0, 0);
if (fire_hit (self, aim, (5 + (rand() % 5)), 50))
gi.sound (self, CHAN_WEAPON, sound_punch_hit, 1, ATTN_NORM, 0);
}
mframe_t infantry_frames_attack2 [] =
{
ai_charge, 3, NULL,
ai_charge, 6, NULL,
ai_charge, 0, infantry_swing,
ai_charge, 8, NULL,
ai_charge, 5, NULL,
ai_charge, 8, infantry_smack,
ai_charge, 6, NULL,
ai_charge, 3, NULL,
};
mmove_t infantry_move_attack2 = {FRAME_attak201, FRAME_attak208, infantry_frames_attack2, infantry_run};
void infantry_attack(edict_t *self)
{
if (range (self, self->enemy) == RANGE_MELEE)
self->monsterinfo.currentmove = &infantry_move_attack2;
else
self->monsterinfo.currentmove = &infantry_move_attack1;
}
/*QUAKED monster_infantry (1 .5 0) (-16 -16 -24) (16 16 32) Ambush Trigger_Spawn Sight
*/
void SP_monster_infantry (edict_t *self)
{
if (deathmatch->value)
{
G_FreeEdict (self);
return;
}
sound_pain1 = gi.soundindex ("infantry/infpain1.wav");
sound_pain2 = gi.soundindex ("infantry/infpain2.wav");
sound_die1 = gi.soundindex ("infantry/infdeth1.wav");
sound_die2 = gi.soundindex ("infantry/infdeth2.wav");
sound_gunshot = gi.soundindex ("infantry/infatck1.wav");
sound_weapon_cock = gi.soundindex ("infantry/infatck3.wav");
sound_punch_swing = gi.soundindex ("infantry/infatck2.wav");
sound_punch_hit = gi.soundindex ("infantry/melee2.wav");
sound_sight = gi.soundindex ("infantry/infsght1.wav");
sound_search = gi.soundindex ("infantry/infsrch1.wav");
sound_idle = gi.soundindex ("infantry/infidle1.wav");
self->movetype = MOVETYPE_STEP;
self->solid = SOLID_BBOX;
self->s.modelindex = gi.modelindex("models/monsters/infantry/tris.md2");
VectorSet (self->mins, -16, -16, -24);
VectorSet (self->maxs, 16, 16, 32);
self->health = 100;
self->gib_health = -40;
self->mass = 200;
self->pain = infantry_pain;
self->die = infantry_die;
self->monsterinfo.stand = infantry_stand;
self->monsterinfo.walk = infantry_walk;
self->monsterinfo.run = infantry_run;
self->monsterinfo.dodge = infantry_dodge;
self->monsterinfo.attack = infantry_attack;
self->monsterinfo.melee = NULL;
self->monsterinfo.sight = infantry_sight;
self->monsterinfo.idle = infantry_fidget;
gi.linkentity (self);
self->monsterinfo.currentmove = &infantry_move_stand;
self->monsterinfo.scale = MODEL_SCALE;
walkmonster_start (self);
}

232
game/m_infantry.h Normal file
View File

@ -0,0 +1,232 @@
/*
Copyright (C) 1997-2001 Id Software, Inc.
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 the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
// G:\quake2\baseq2\models/monsters/infantry
// This file generated by ModelGen - Do NOT Modify
#define FRAME_gun02 0
#define FRAME_stand01 1
#define FRAME_stand02 2
#define FRAME_stand03 3
#define FRAME_stand04 4
#define FRAME_stand05 5
#define FRAME_stand06 6
#define FRAME_stand07 7
#define FRAME_stand08 8
#define FRAME_stand09 9
#define FRAME_stand10 10
#define FRAME_stand11 11
#define FRAME_stand12 12
#define FRAME_stand13 13
#define FRAME_stand14 14
#define FRAME_stand15 15
#define FRAME_stand16 16
#define FRAME_stand17 17
#define FRAME_stand18 18
#define FRAME_stand19 19
#define FRAME_stand20 20
#define FRAME_stand21 21
#define FRAME_stand22 22
#define FRAME_stand23 23
#define FRAME_stand24 24
#define FRAME_stand25 25
#define FRAME_stand26 26
#define FRAME_stand27 27
#define FRAME_stand28 28
#define FRAME_stand29 29
#define FRAME_stand30 30
#define FRAME_stand31 31
#define FRAME_stand32 32
#define FRAME_stand33 33
#define FRAME_stand34 34
#define FRAME_stand35 35
#define FRAME_stand36 36
#define FRAME_stand37 37
#define FRAME_stand38 38
#define FRAME_stand39 39
#define FRAME_stand40 40
#define FRAME_stand41 41
#define FRAME_stand42 42
#define FRAME_stand43 43
#define FRAME_stand44 44
#define FRAME_stand45 45
#define FRAME_stand46 46
#define FRAME_stand47 47
#define FRAME_stand48 48
#define FRAME_stand49 49
#define FRAME_stand50 50
#define FRAME_stand51 51
#define FRAME_stand52 52
#define FRAME_stand53 53
#define FRAME_stand54 54
#define FRAME_stand55 55
#define FRAME_stand56 56
#define FRAME_stand57 57
#define FRAME_stand58 58
#define FRAME_stand59 59
#define FRAME_stand60 60
#define FRAME_stand61 61
#define FRAME_stand62 62
#define FRAME_stand63 63
#define FRAME_stand64 64
#define FRAME_stand65 65
#define FRAME_stand66 66
#define FRAME_stand67 67
#define FRAME_stand68 68
#define FRAME_stand69 69
#define FRAME_stand70 70
#define FRAME_stand71 71
#define FRAME_walk01 72
#define FRAME_walk02 73
#define FRAME_walk03 74
#define FRAME_walk04 75
#define FRAME_walk05 76
#define FRAME_walk06 77
#define FRAME_walk07 78
#define FRAME_walk08 79
#define FRAME_walk09 80
#define FRAME_walk10 81
#define FRAME_walk11 82
#define FRAME_walk12 83
#define FRAME_walk13 84
#define FRAME_walk14 85
#define FRAME_walk15 86
#define FRAME_walk16 87
#define FRAME_walk17 88
#define FRAME_walk18 89
#define FRAME_walk19 90
#define FRAME_walk20 91
#define FRAME_run01 92
#define FRAME_run02 93
#define FRAME_run03 94
#define FRAME_run04 95
#define FRAME_run05 96
#define FRAME_run06 97
#define FRAME_run07 98
#define FRAME_run08 99
#define FRAME_pain101 100
#define FRAME_pain102 101
#define FRAME_pain103 102
#define FRAME_pain104 103
#define FRAME_pain105 104
#define FRAME_pain106 105
#define FRAME_pain107 106
#define FRAME_pain108 107
#define FRAME_pain109 108
#define FRAME_pain110 109
#define FRAME_pain201 110
#define FRAME_pain202 111
#define FRAME_pain203 112
#define FRAME_pain204 113
#define FRAME_pain205 114
#define FRAME_pain206 115
#define FRAME_pain207 116
#define FRAME_pain208 117
#define FRAME_pain209 118
#define FRAME_pain210 119
#define FRAME_duck01 120
#define FRAME_duck02 121
#define FRAME_duck03 122
#define FRAME_duck04 123
#define FRAME_duck05 124
#define FRAME_death101 125
#define FRAME_death102 126
#define FRAME_death103 127
#define FRAME_death104 128
#define FRAME_death105 129
#define FRAME_death106 130
#define FRAME_death107 131
#define FRAME_death108 132
#define FRAME_death109 133
#define FRAME_death110 134
#define FRAME_death111 135
#define FRAME_death112 136
#define FRAME_death113 137
#define FRAME_death114 138
#define FRAME_death115 139
#define FRAME_death116 140
#define FRAME_death117 141
#define FRAME_death118 142
#define FRAME_death119 143
#define FRAME_death120 144
#define FRAME_death201 145
#define FRAME_death202 146
#define FRAME_death203 147
#define FRAME_death204 148
#define FRAME_death205 149
#define FRAME_death206 150
#define FRAME_death207 151
#define FRAME_death208 152
#define FRAME_death209 153
#define FRAME_death210 154
#define FRAME_death211 155
#define FRAME_death212 156
#define FRAME_death213 157
#define FRAME_death214 158
#define FRAME_death215 159
#define FRAME_death216 160
#define FRAME_death217 161
#define FRAME_death218 162
#define FRAME_death219 163
#define FRAME_death220 164
#define FRAME_death221 165
#define FRAME_death222 166
#define FRAME_death223 167
#define FRAME_death224 168
#define FRAME_death225 169
#define FRAME_death301 170
#define FRAME_death302 171
#define FRAME_death303 172
#define FRAME_death304 173
#define FRAME_death305 174
#define FRAME_death306 175
#define FRAME_death307 176
#define FRAME_death308 177
#define FRAME_death309 178
#define FRAME_block01 179
#define FRAME_block02 180
#define FRAME_block03 181
#define FRAME_block04 182
#define FRAME_block05 183
#define FRAME_attak101 184
#define FRAME_attak102 185
#define FRAME_attak103 186
#define FRAME_attak104 187
#define FRAME_attak105 188
#define FRAME_attak106 189
#define FRAME_attak107 190
#define FRAME_attak108 191
#define FRAME_attak109 192
#define FRAME_attak110 193
#define FRAME_attak111 194
#define FRAME_attak112 195
#define FRAME_attak113 196
#define FRAME_attak114 197
#define FRAME_attak115 198
#define FRAME_attak201 199
#define FRAME_attak202 200
#define FRAME_attak203 201
#define FRAME_attak204 202
#define FRAME_attak205 203
#define FRAME_attak206 204
#define FRAME_attak207 205
#define FRAME_attak208 206
#define MODEL_SCALE 1.000000

693
game/m_insane.c Normal file
View File

@ -0,0 +1,693 @@
/*
Copyright (C) 1997-2001 Id Software, Inc.
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 the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/*
==============================================================================
insane
==============================================================================
*/
#include "g_local.h"
#include "m_insane.h"
static int sound_fist;
static int sound_shake;
static int sound_moan;
static int sound_scream[8];
void insane_fist (edict_t *self)
{
gi.sound (self, CHAN_VOICE, sound_fist, 1, ATTN_IDLE, 0);
}
void insane_shake (edict_t *self)
{
gi.sound (self, CHAN_VOICE, sound_shake, 1, ATTN_IDLE, 0);
}
void insane_moan (edict_t *self)
{
gi.sound (self, CHAN_VOICE, sound_moan, 1, ATTN_IDLE, 0);
}
void insane_scream (edict_t *self)
{
gi.sound (self, CHAN_VOICE, sound_scream[rand()%8], 1, ATTN_IDLE, 0);
}
void insane_stand (edict_t *self);
void insane_dead (edict_t *self);
void insane_cross (edict_t *self);
void insane_walk (edict_t *self);
void insane_run (edict_t *self);
void insane_checkdown (edict_t *self);
void insane_checkup (edict_t *self);
void insane_onground (edict_t *self);
mframe_t insane_frames_stand_normal [] =
{
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, insane_checkdown
};
mmove_t insane_move_stand_normal = {FRAME_stand60, FRAME_stand65, insane_frames_stand_normal, insane_stand};
mframe_t insane_frames_stand_insane [] =
{
ai_stand, 0, insane_shake,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, insane_checkdown
};
mmove_t insane_move_stand_insane = {FRAME_stand65, FRAME_stand94, insane_frames_stand_insane, insane_stand};
mframe_t insane_frames_uptodown [] =
{
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, insane_moan,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 2.7, NULL,
ai_move, 4.1, NULL,
ai_move, 6, NULL,
ai_move, 7.6, NULL,
ai_move, 3.6, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, insane_fist,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, insane_fist,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL
};
mmove_t insane_move_uptodown = {FRAME_stand1, FRAME_stand40, insane_frames_uptodown, insane_onground};
mframe_t insane_frames_downtoup [] =
{
ai_move, -0.7, NULL, // 41
ai_move, -1.2, NULL, // 42
ai_move, -1.5, NULL, // 43
ai_move, -4.5, NULL, // 44
ai_move, -3.5, NULL, // 45
ai_move, -0.2, NULL, // 46
ai_move, 0, NULL, // 47
ai_move, -1.3, NULL, // 48
ai_move, -3, NULL, // 49
ai_move, -2, NULL, // 50
ai_move, 0, NULL, // 51
ai_move, 0, NULL, // 52
ai_move, 0, NULL, // 53
ai_move, -3.3, NULL, // 54
ai_move, -1.6, NULL, // 55
ai_move, -0.3, NULL, // 56
ai_move, 0, NULL, // 57
ai_move, 0, NULL, // 58
ai_move, 0, NULL // 59
};
mmove_t insane_move_downtoup = {FRAME_stand41, FRAME_stand59, insane_frames_downtoup, insane_stand};
mframe_t insane_frames_jumpdown [] =
{
ai_move, 0.2, NULL,
ai_move, 11.5, NULL,
ai_move, 5.1, NULL,
ai_move, 7.1, NULL,
ai_move, 0, NULL
};
mmove_t insane_move_jumpdown = {FRAME_stand96, FRAME_stand100, insane_frames_jumpdown, insane_onground};
mframe_t insane_frames_down [] =
{
ai_move, 0, NULL, // 100
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL, // 110
ai_move, -1.7, NULL,
ai_move, -1.6, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, insane_fist,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL, // 120
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL, // 130
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, insane_moan,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL, // 140
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL, // 150
ai_move, 0.5, NULL,
ai_move, 0, NULL,
ai_move, -0.2, insane_scream,
ai_move, 0, NULL,
ai_move, 0.2, NULL,
ai_move, 0.4, NULL,
ai_move, 0.6, NULL,
ai_move, 0.8, NULL,
ai_move, 0.7, NULL,
ai_move, 0, insane_checkup // 160
};
mmove_t insane_move_down = {FRAME_stand100, FRAME_stand160, insane_frames_down, insane_onground};
mframe_t insane_frames_walk_normal [] =
{
ai_walk, 0, insane_scream,
ai_walk, 2.5, NULL,
ai_walk, 3.5, NULL,
ai_walk, 1.7, NULL,
ai_walk, 2.3, NULL,
ai_walk, 2.4, NULL,
ai_walk, 2.2, NULL,
ai_walk, 4.2, NULL,
ai_walk, 5.6, NULL,
ai_walk, 3.3, NULL,
ai_walk, 2.4, NULL,
ai_walk, 0.9, NULL,
ai_walk, 0, NULL
};
mmove_t insane_move_walk_normal = {FRAME_walk27, FRAME_walk39, insane_frames_walk_normal, insane_walk};
mmove_t insane_move_run_normal = {FRAME_walk27, FRAME_walk39, insane_frames_walk_normal, insane_run};
mframe_t insane_frames_walk_insane [] =
{
ai_walk, 0, insane_scream, // walk 1
ai_walk, 3.4, NULL, // walk 2
ai_walk, 3.6, NULL, // 3
ai_walk, 2.9, NULL, // 4
ai_walk, 2.2, NULL, // 5
ai_walk, 2.6, NULL, // 6
ai_walk, 0, NULL, // 7
ai_walk, 0.7, NULL, // 8
ai_walk, 4.8, NULL, // 9
ai_walk, 5.3, NULL, // 10
ai_walk, 1.1, NULL, // 11
ai_walk, 2, NULL, // 12
ai_walk, 0.5, NULL, // 13
ai_walk, 0, NULL, // 14
ai_walk, 0, NULL, // 15
ai_walk, 4.9, NULL, // 16
ai_walk, 6.7, NULL, // 17
ai_walk, 3.8, NULL, // 18
ai_walk, 2, NULL, // 19
ai_walk, 0.2, NULL, // 20
ai_walk, 0, NULL, // 21
ai_walk, 3.4, NULL, // 22
ai_walk, 6.4, NULL, // 23
ai_walk, 5, NULL, // 24
ai_walk, 1.8, NULL, // 25
ai_walk, 0, NULL // 26
};
mmove_t insane_move_walk_insane = {FRAME_walk1, FRAME_walk26, insane_frames_walk_insane, insane_walk};
mmove_t insane_move_run_insane = {FRAME_walk1, FRAME_walk26, insane_frames_walk_insane, insane_run};
mframe_t insane_frames_stand_pain [] =
{
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL
};
mmove_t insane_move_stand_pain = {FRAME_st_pain2, FRAME_st_pain12, insane_frames_stand_pain, insane_run};
mframe_t insane_frames_stand_death [] =
{
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL
};
mmove_t insane_move_stand_death = {FRAME_st_death2, FRAME_st_death18, insane_frames_stand_death, insane_dead};
mframe_t insane_frames_crawl [] =
{
ai_walk, 0, insane_scream,
ai_walk, 1.5, NULL,
ai_walk, 2.1, NULL,
ai_walk, 3.6, NULL,
ai_walk, 2, NULL,
ai_walk, 0.9, NULL,
ai_walk, 3, NULL,
ai_walk, 3.4, NULL,
ai_walk, 2.4, NULL
};
mmove_t insane_move_crawl = {FRAME_crawl1, FRAME_crawl9, insane_frames_crawl, NULL};
mmove_t insane_move_runcrawl = {FRAME_crawl1, FRAME_crawl9, insane_frames_crawl, NULL};
mframe_t insane_frames_crawl_pain [] =
{
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL
};
mmove_t insane_move_crawl_pain = {FRAME_cr_pain2, FRAME_cr_pain10, insane_frames_crawl_pain, insane_run};
mframe_t insane_frames_crawl_death [] =
{
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL
};
mmove_t insane_move_crawl_death = {FRAME_cr_death10, FRAME_cr_death16, insane_frames_crawl_death, insane_dead};
mframe_t insane_frames_cross [] =
{
ai_move, 0, insane_moan,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL
};
mmove_t insane_move_cross = {FRAME_cross1, FRAME_cross15, insane_frames_cross, insane_cross};
mframe_t insane_frames_struggle_cross [] =
{
ai_move, 0, insane_scream,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL
};
mmove_t insane_move_struggle_cross = {FRAME_cross16, FRAME_cross30, insane_frames_struggle_cross, insane_cross};
void insane_cross (edict_t *self)
{
if (random() < 0.8)
self->monsterinfo.currentmove = &insane_move_cross;
else
self->monsterinfo.currentmove = &insane_move_struggle_cross;
}
void insane_walk (edict_t *self)
{
if ( self->spawnflags & 16 ) // Hold Ground?
if (self->s.frame == FRAME_cr_pain10)
{
self->monsterinfo.currentmove = &insane_move_down;
return;
}
if (self->spawnflags & 4)
self->monsterinfo.currentmove = &insane_move_crawl;
else
if (random() <= 0.5)
self->monsterinfo.currentmove = &insane_move_walk_normal;
else
self->monsterinfo.currentmove = &insane_move_walk_insane;
}
void insane_run (edict_t *self)
{
if ( self->spawnflags & 16 ) // Hold Ground?
if (self->s.frame == FRAME_cr_pain10)
{
self->monsterinfo.currentmove = &insane_move_down;
return;
}
if (self->spawnflags & 4) // Crawling?
self->monsterinfo.currentmove = &insane_move_runcrawl;
else
if (random() <= 0.5) // Else, mix it up
self->monsterinfo.currentmove = &insane_move_run_normal;
else
self->monsterinfo.currentmove = &insane_move_run_insane;
}
void insane_pain (edict_t *self, edict_t *other, float kick, int damage)
{
int l,r;
// if (self->health < (self->max_health / 2))
// self->s.skinnum = 1;
if (level.time < self->pain_debounce_time)
return;
self->pain_debounce_time = level.time + 3;
r = 1 + (rand()&1);
if (self->health < 25)
l = 25;
else if (self->health < 50)
l = 50;
else if (self->health < 75)
l = 75;
else
l = 100;
gi.sound (self, CHAN_VOICE, gi.soundindex (va("player/male/pain%i_%i.wav", l, r)), 1, ATTN_IDLE, 0);
if (skill->value == 3)
return; // no pain anims in nightmare
// Don't go into pain frames if crucified.
if (self->spawnflags & 8)
{
self->monsterinfo.currentmove = &insane_move_struggle_cross;
return;
}
if ( ((self->s.frame >= FRAME_crawl1) && (self->s.frame <= FRAME_crawl9)) || ((self->s.frame >= FRAME_stand99) && (self->s.frame <= FRAME_stand160)) )
{
self->monsterinfo.currentmove = &insane_move_crawl_pain;
}
else
self->monsterinfo.currentmove = &insane_move_stand_pain;
}
void insane_onground (edict_t *self)
{
self->monsterinfo.currentmove = &insane_move_down;
}
void insane_checkdown (edict_t *self)
{
// if ( (self->s.frame == FRAME_stand94) || (self->s.frame == FRAME_stand65) )
if (self->spawnflags & 32) // Always stand
return;
if (random() < 0.3)
if (random() < 0.5)
self->monsterinfo.currentmove = &insane_move_uptodown;
else
self->monsterinfo.currentmove = &insane_move_jumpdown;
}
void insane_checkup (edict_t *self)
{
// If Hold_Ground and Crawl are set
if ( (self->spawnflags & 4) && (self->spawnflags & 16) )
return;
if (random() < 0.5)
self->monsterinfo.currentmove = &insane_move_downtoup;
}
void insane_stand (edict_t *self)
{
if (self->spawnflags & 8) // If crucified
{
self->monsterinfo.currentmove = &insane_move_cross;
self->monsterinfo.aiflags |= AI_STAND_GROUND;
}
// If Hold_Ground and Crawl are set
else if ( (self->spawnflags & 4) && (self->spawnflags & 16) )
self->monsterinfo.currentmove = &insane_move_down;
else
if (random() < 0.5)
self->monsterinfo.currentmove = &insane_move_stand_normal;
else
self->monsterinfo.currentmove = &insane_move_stand_insane;
}
void insane_dead (edict_t *self)
{
if (self->spawnflags & 8)
{
self->flags |= FL_FLY;
}
else
{
VectorSet (self->mins, -16, -16, -24);
VectorSet (self->maxs, 16, 16, -8);
self->movetype = MOVETYPE_TOSS;
}
self->svflags |= SVF_DEADMONSTER;
self->nextthink = 0;
gi.linkentity (self);
}
void insane_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
{
int n;
if (self->health <= self->gib_health)
{
gi.sound (self, CHAN_VOICE, gi.soundindex ("misc/udeath.wav"), 1, ATTN_IDLE, 0);
for (n= 0; n < 2; n++)
ThrowGib (self, "models/objects/gibs/bone/tris.md2", damage, GIB_ORGANIC);
for (n= 0; n < 4; n++)
ThrowGib (self, "models/objects/gibs/sm_meat/tris.md2", damage, GIB_ORGANIC);
ThrowHead (self, "models/objects/gibs/head2/tris.md2", damage, GIB_ORGANIC);
self->deadflag = DEAD_DEAD;
return;
}
if (self->deadflag == DEAD_DEAD)
return;
gi.sound (self, CHAN_VOICE, gi.soundindex(va("player/male/death%i.wav", (rand()%4)+1)), 1, ATTN_IDLE, 0);
self->deadflag = DEAD_DEAD;
self->takedamage = DAMAGE_YES;
if (self->spawnflags & 8)
{
insane_dead (self);
}
else
{
if ( ((self->s.frame >= FRAME_crawl1) && (self->s.frame <= FRAME_crawl9)) || ((self->s.frame >= FRAME_stand99) && (self->s.frame <= FRAME_stand160)) )
self->monsterinfo.currentmove = &insane_move_crawl_death;
else
self->monsterinfo.currentmove = &insane_move_stand_death;
}
}
/*QUAKED misc_insane (1 .5 0) (-16 -16 -24) (16 16 32) Ambush Trigger_Spawn CRAWL CRUCIFIED STAND_GROUND ALWAYS_STAND
*/
void SP_misc_insane (edict_t *self)
{
// static int skin = 0; //@@
if (deathmatch->value)
{
G_FreeEdict (self);
return;
}
sound_fist = gi.soundindex ("insane/insane11.wav");
sound_shake = gi.soundindex ("insane/insane5.wav");
sound_moan = gi.soundindex ("insane/insane7.wav");
sound_scream[0] = gi.soundindex ("insane/insane1.wav");
sound_scream[1] = gi.soundindex ("insane/insane2.wav");
sound_scream[2] = gi.soundindex ("insane/insane3.wav");
sound_scream[3] = gi.soundindex ("insane/insane4.wav");
sound_scream[4] = gi.soundindex ("insane/insane6.wav");
sound_scream[5] = gi.soundindex ("insane/insane8.wav");
sound_scream[6] = gi.soundindex ("insane/insane9.wav");
sound_scream[7] = gi.soundindex ("insane/insane10.wav");
self->movetype = MOVETYPE_STEP;
self->solid = SOLID_BBOX;
self->s.modelindex = gi.modelindex("models/monsters/insane/tris.md2");
VectorSet (self->mins, -16, -16, -24);
VectorSet (self->maxs, 16, 16, 32);
self->health = 100;
self->gib_health = -50;
self->mass = 300;
self->pain = insane_pain;
self->die = insane_die;
self->monsterinfo.stand = insane_stand;
self->monsterinfo.walk = insane_walk;
self->monsterinfo.run = insane_run;
self->monsterinfo.dodge = NULL;
self->monsterinfo.attack = NULL;
self->monsterinfo.melee = NULL;
self->monsterinfo.sight = NULL;
self->monsterinfo.aiflags |= AI_GOOD_GUY;
//@@
// self->s.skinnum = skin;
// skin++;
// if (skin > 12)
// skin = 0;
gi.linkentity (self);
if (self->spawnflags & 16) // Stand Ground
self->monsterinfo.aiflags |= AI_STAND_GROUND;
self->monsterinfo.currentmove = &insane_move_stand_normal;
self->monsterinfo.scale = MODEL_SCALE;
if (self->spawnflags & 8) // Crucified ?
{
VectorSet (self->mins, -16, 0, 0);
VectorSet (self->maxs, 16, 8, 32);
self->flags |= FL_NO_KNOCKBACK;
flymonster_start (self);
}
else
{
walkmonster_start (self);
self->s.skinnum = rand()%3;
}
}

307
game/m_insane.h Normal file
View File

@ -0,0 +1,307 @@
/*
Copyright (C) 1997-2001 Id Software, Inc.
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 the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
// G:\quake2\baseq2\models/monsters/insane
// This file generated by ModelGen - Do NOT Modify
#define FRAME_stand1 0
#define FRAME_stand2 1
#define FRAME_stand3 2
#define FRAME_stand4 3
#define FRAME_stand5 4
#define FRAME_stand6 5
#define FRAME_stand7 6
#define FRAME_stand8 7
#define FRAME_stand9 8
#define FRAME_stand10 9
#define FRAME_stand11 10
#define FRAME_stand12 11
#define FRAME_stand13 12
#define FRAME_stand14 13
#define FRAME_stand15 14
#define FRAME_stand16 15
#define FRAME_stand17 16
#define FRAME_stand18 17
#define FRAME_stand19 18
#define FRAME_stand20 19
#define FRAME_stand21 20
#define FRAME_stand22 21
#define FRAME_stand23 22
#define FRAME_stand24 23
#define FRAME_stand25 24
#define FRAME_stand26 25
#define FRAME_stand27 26
#define FRAME_stand28 27
#define FRAME_stand29 28
#define FRAME_stand30 29
#define FRAME_stand31 30
#define FRAME_stand32 31
#define FRAME_stand33 32
#define FRAME_stand34 33
#define FRAME_stand35 34
#define FRAME_stand36 35
#define FRAME_stand37 36
#define FRAME_stand38 37
#define FRAME_stand39 38
#define FRAME_stand40 39
#define FRAME_stand41 40
#define FRAME_stand42 41
#define FRAME_stand43 42
#define FRAME_stand44 43
#define FRAME_stand45 44
#define FRAME_stand46 45
#define FRAME_stand47 46
#define FRAME_stand48 47
#define FRAME_stand49 48
#define FRAME_stand50 49
#define FRAME_stand51 50
#define FRAME_stand52 51
#define FRAME_stand53 52
#define FRAME_stand54 53
#define FRAME_stand55 54
#define FRAME_stand56 55
#define FRAME_stand57 56
#define FRAME_stand58 57
#define FRAME_stand59 58
#define FRAME_stand60 59
#define FRAME_stand61 60
#define FRAME_stand62 61
#define FRAME_stand63 62
#define FRAME_stand64 63
#define FRAME_stand65 64
#define FRAME_stand66 65
#define FRAME_stand67 66
#define FRAME_stand68 67
#define FRAME_stand69 68
#define FRAME_stand70 69
#define FRAME_stand71 70
#define FRAME_stand72 71
#define FRAME_stand73 72
#define FRAME_stand74 73
#define FRAME_stand75 74
#define FRAME_stand76 75
#define FRAME_stand77 76
#define FRAME_stand78 77
#define FRAME_stand79 78
#define FRAME_stand80 79
#define FRAME_stand81 80
#define FRAME_stand82 81
#define FRAME_stand83 82
#define FRAME_stand84 83
#define FRAME_stand85 84
#define FRAME_stand86 85
#define FRAME_stand87 86
#define FRAME_stand88 87
#define FRAME_stand89 88
#define FRAME_stand90 89
#define FRAME_stand91 90
#define FRAME_stand92 91
#define FRAME_stand93 92
#define FRAME_stand94 93
#define FRAME_stand95 94
#define FRAME_stand96 95
#define FRAME_stand97 96
#define FRAME_stand98 97
#define FRAME_stand99 98
#define FRAME_stand100 99
#define FRAME_stand101 100
#define FRAME_stand102 101
#define FRAME_stand103 102
#define FRAME_stand104 103
#define FRAME_stand105 104
#define FRAME_stand106 105
#define FRAME_stand107 106
#define FRAME_stand108 107
#define FRAME_stand109 108
#define FRAME_stand110 109
#define FRAME_stand111 110
#define FRAME_stand112 111
#define FRAME_stand113 112
#define FRAME_stand114 113
#define FRAME_stand115 114
#define FRAME_stand116 115
#define FRAME_stand117 116
#define FRAME_stand118 117
#define FRAME_stand119 118
#define FRAME_stand120 119
#define FRAME_stand121 120
#define FRAME_stand122 121
#define FRAME_stand123 122
#define FRAME_stand124 123
#define FRAME_stand125 124
#define FRAME_stand126 125
#define FRAME_stand127 126
#define FRAME_stand128 127
#define FRAME_stand129 128
#define FRAME_stand130 129
#define FRAME_stand131 130
#define FRAME_stand132 131
#define FRAME_stand133 132
#define FRAME_stand134 133
#define FRAME_stand135 134
#define FRAME_stand136 135
#define FRAME_stand137 136
#define FRAME_stand138 137
#define FRAME_stand139 138
#define FRAME_stand140 139
#define FRAME_stand141 140
#define FRAME_stand142 141
#define FRAME_stand143 142
#define FRAME_stand144 143
#define FRAME_stand145 144
#define FRAME_stand146 145
#define FRAME_stand147 146
#define FRAME_stand148 147
#define FRAME_stand149 148
#define FRAME_stand150 149
#define FRAME_stand151 150
#define FRAME_stand152 151
#define FRAME_stand153 152
#define FRAME_stand154 153
#define FRAME_stand155 154
#define FRAME_stand156 155
#define FRAME_stand157 156
#define FRAME_stand158 157
#define FRAME_stand159 158
#define FRAME_stand160 159
#define FRAME_walk27 160
#define FRAME_walk28 161
#define FRAME_walk29 162
#define FRAME_walk30 163
#define FRAME_walk31 164
#define FRAME_walk32 165
#define FRAME_walk33 166
#define FRAME_walk34 167
#define FRAME_walk35 168
#define FRAME_walk36 169
#define FRAME_walk37 170
#define FRAME_walk38 171
#define FRAME_walk39 172
#define FRAME_walk1 173
#define FRAME_walk2 174
#define FRAME_walk3 175
#define FRAME_walk4 176
#define FRAME_walk5 177
#define FRAME_walk6 178
#define FRAME_walk7 179
#define FRAME_walk8 180
#define FRAME_walk9 181
#define FRAME_walk10 182
#define FRAME_walk11 183
#define FRAME_walk12 184
#define FRAME_walk13 185
#define FRAME_walk14 186
#define FRAME_walk15 187
#define FRAME_walk16 188
#define FRAME_walk17 189
#define FRAME_walk18 190
#define FRAME_walk19 191
#define FRAME_walk20 192
#define FRAME_walk21 193
#define FRAME_walk22 194
#define FRAME_walk23 195
#define FRAME_walk24 196
#define FRAME_walk25 197
#define FRAME_walk26 198
#define FRAME_st_pain2 199
#define FRAME_st_pain3 200
#define FRAME_st_pain4 201
#define FRAME_st_pain5 202
#define FRAME_st_pain6 203
#define FRAME_st_pain7 204
#define FRAME_st_pain8 205
#define FRAME_st_pain9 206
#define FRAME_st_pain10 207
#define FRAME_st_pain11 208
#define FRAME_st_pain12 209
#define FRAME_st_death2 210
#define FRAME_st_death3 211
#define FRAME_st_death4 212
#define FRAME_st_death5 213
#define FRAME_st_death6 214
#define FRAME_st_death7 215
#define FRAME_st_death8 216
#define FRAME_st_death9 217
#define FRAME_st_death10 218
#define FRAME_st_death11 219
#define FRAME_st_death12 220
#define FRAME_st_death13 221
#define FRAME_st_death14 222
#define FRAME_st_death15 223
#define FRAME_st_death16 224
#define FRAME_st_death17 225
#define FRAME_st_death18 226
#define FRAME_crawl1 227
#define FRAME_crawl2 228
#define FRAME_crawl3 229
#define FRAME_crawl4 230
#define FRAME_crawl5 231
#define FRAME_crawl6 232
#define FRAME_crawl7 233
#define FRAME_crawl8 234
#define FRAME_crawl9 235
#define FRAME_cr_pain2 236
#define FRAME_cr_pain3 237
#define FRAME_cr_pain4 238
#define FRAME_cr_pain5 239
#define FRAME_cr_pain6 240
#define FRAME_cr_pain7 241
#define FRAME_cr_pain8 242
#define FRAME_cr_pain9 243
#define FRAME_cr_pain10 244
#define FRAME_cr_death10 245
#define FRAME_cr_death11 246
#define FRAME_cr_death12 247
#define FRAME_cr_death13 248
#define FRAME_cr_death14 249
#define FRAME_cr_death15 250
#define FRAME_cr_death16 251
#define FRAME_cross1 252
#define FRAME_cross2 253
#define FRAME_cross3 254
#define FRAME_cross4 255
#define FRAME_cross5 256
#define FRAME_cross6 257
#define FRAME_cross7 258
#define FRAME_cross8 259
#define FRAME_cross9 260
#define FRAME_cross10 261
#define FRAME_cross11 262
#define FRAME_cross12 263
#define FRAME_cross13 264
#define FRAME_cross14 265
#define FRAME_cross15 266
#define FRAME_cross16 267
#define FRAME_cross17 268
#define FRAME_cross18 269
#define FRAME_cross19 270
#define FRAME_cross20 271
#define FRAME_cross21 272
#define FRAME_cross22 273
#define FRAME_cross23 274
#define FRAME_cross24 275
#define FRAME_cross25 276
#define FRAME_cross26 277
#define FRAME_cross27 278
#define FRAME_cross28 279
#define FRAME_cross29 280
#define FRAME_cross30 281
#define MODEL_SCALE 1.000000

769
game/m_medic.c Normal file
View File

@ -0,0 +1,769 @@
/*
Copyright (C) 1997-2001 Id Software, Inc.
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 the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/*
==============================================================================
MEDIC
==============================================================================
*/
#include "g_local.h"
#include "m_medic.h"
qboolean visible (edict_t *self, edict_t *other);
static int sound_idle1;
static int sound_pain1;
static int sound_pain2;
static int sound_die;
static int sound_sight;
static int sound_search;
static int sound_hook_launch;
static int sound_hook_hit;
static int sound_hook_heal;
static int sound_hook_retract;
edict_t *medic_FindDeadMonster (edict_t *self)
{
edict_t *ent = NULL;
edict_t *best = NULL;
while ((ent = findradius(ent, self->s.origin, 1024)) != NULL)
{
if (ent == self)
continue;
if (!(ent->svflags & SVF_MONSTER))
continue;
if (ent->monsterinfo.aiflags & AI_GOOD_GUY)
continue;
if (ent->owner)
continue;
if (ent->health > 0)
continue;
if (ent->nextthink)
continue;
if (!visible(self, ent))
continue;
if (!best)
{
best = ent;
continue;
}
if (ent->max_health <= best->max_health)
continue;
best = ent;
}
return best;
}
void medic_idle (edict_t *self)
{
edict_t *ent;
gi.sound (self, CHAN_VOICE, sound_idle1, 1, ATTN_IDLE, 0);
ent = medic_FindDeadMonster(self);
if (ent)
{
self->enemy = ent;
self->enemy->owner = self;
self->monsterinfo.aiflags |= AI_MEDIC;
FoundTarget (self);
}
}
void medic_search (edict_t *self)
{
edict_t *ent;
gi.sound (self, CHAN_VOICE, sound_search, 1, ATTN_IDLE, 0);
if (!self->oldenemy)
{
ent = medic_FindDeadMonster(self);
if (ent)
{
self->oldenemy = self->enemy;
self->enemy = ent;
self->enemy->owner = self;
self->monsterinfo.aiflags |= AI_MEDIC;
FoundTarget (self);
}
}
}
void medic_sight (edict_t *self, edict_t *other)
{
gi.sound (self, CHAN_VOICE, sound_sight, 1, ATTN_NORM, 0);
}
mframe_t medic_frames_stand [] =
{
ai_stand, 0, medic_idle,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
};
mmove_t medic_move_stand = {FRAME_wait1, FRAME_wait90, medic_frames_stand, NULL};
void medic_stand (edict_t *self)
{
self->monsterinfo.currentmove = &medic_move_stand;
}
mframe_t medic_frames_walk [] =
{
ai_walk, 6.2, NULL,
ai_walk, 18.1, NULL,
ai_walk, 1, NULL,
ai_walk, 9, NULL,
ai_walk, 10, NULL,
ai_walk, 9, NULL,
ai_walk, 11, NULL,
ai_walk, 11.6, NULL,
ai_walk, 2, NULL,
ai_walk, 9.9, NULL,
ai_walk, 14, NULL,
ai_walk, 9.3, NULL
};
mmove_t medic_move_walk = {FRAME_walk1, FRAME_walk12, medic_frames_walk, NULL};
void medic_walk (edict_t *self)
{
self->monsterinfo.currentmove = &medic_move_walk;
}
mframe_t medic_frames_run [] =
{
ai_run, 18, NULL,
ai_run, 22.5, NULL,
ai_run, 25.4, NULL,
ai_run, 23.4, NULL,
ai_run, 24, NULL,
ai_run, 35.6, NULL
};
mmove_t medic_move_run = {FRAME_run1, FRAME_run6, medic_frames_run, NULL};
void medic_run (edict_t *self)
{
if (!(self->monsterinfo.aiflags & AI_MEDIC))
{
edict_t *ent;
ent = medic_FindDeadMonster(self);
if (ent)
{
self->oldenemy = self->enemy;
self->enemy = ent;
self->enemy->owner = self;
self->monsterinfo.aiflags |= AI_MEDIC;
FoundTarget (self);
return;
}
}
if (self->monsterinfo.aiflags & AI_STAND_GROUND)
self->monsterinfo.currentmove = &medic_move_stand;
else
self->monsterinfo.currentmove = &medic_move_run;
}
mframe_t medic_frames_pain1 [] =
{
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL
};
mmove_t medic_move_pain1 = {FRAME_paina1, FRAME_paina8, medic_frames_pain1, medic_run};
mframe_t medic_frames_pain2 [] =
{
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL
};
mmove_t medic_move_pain2 = {FRAME_painb1, FRAME_painb15, medic_frames_pain2, medic_run};
void medic_pain (edict_t *self, edict_t *other, float kick, int damage)
{
if (self->health < (self->max_health / 2))
self->s.skinnum = 1;
if (level.time < self->pain_debounce_time)
return;
self->pain_debounce_time = level.time + 3;
if (skill->value == 3)
return; // no pain anims in nightmare
if (random() < 0.5)
{
self->monsterinfo.currentmove = &medic_move_pain1;
gi.sound (self, CHAN_VOICE, sound_pain1, 1, ATTN_NORM, 0);
}
else
{
self->monsterinfo.currentmove = &medic_move_pain2;
gi.sound (self, CHAN_VOICE, sound_pain2, 1, ATTN_NORM, 0);
}
}
void medic_fire_blaster (edict_t *self)
{
vec3_t start;
vec3_t forward, right;
vec3_t end;
vec3_t dir;
int effect;
if ((self->s.frame == FRAME_attack9) || (self->s.frame == FRAME_attack12))
effect = EF_BLASTER;
else if ((self->s.frame == FRAME_attack19) || (self->s.frame == FRAME_attack22) || (self->s.frame == FRAME_attack25) || (self->s.frame == FRAME_attack28))
effect = EF_HYPERBLASTER;
else
effect = 0;
AngleVectors (self->s.angles, forward, right, NULL);
G_ProjectSource (self->s.origin, monster_flash_offset[MZ2_MEDIC_BLASTER_1], forward, right, start);
VectorCopy (self->enemy->s.origin, end);
end[2] += self->enemy->viewheight;
VectorSubtract (end, start, dir);
monster_fire_blaster (self, start, dir, 2, 1000, MZ2_MEDIC_BLASTER_1, effect);
}
void medic_dead (edict_t *self)
{
VectorSet (self->mins, -16, -16, -24);
VectorSet (self->maxs, 16, 16, -8);
self->movetype = MOVETYPE_TOSS;
self->svflags |= SVF_DEADMONSTER;
self->nextthink = 0;
gi.linkentity (self);
}
mframe_t medic_frames_death [] =
{
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL
};
mmove_t medic_move_death = {FRAME_death1, FRAME_death30, medic_frames_death, medic_dead};
void medic_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
{
int n;
// if we had a pending patient, free him up for another medic
if ((self->enemy) && (self->enemy->owner == self))
self->enemy->owner = NULL;
// check for gib
if (self->health <= self->gib_health)
{
gi.sound (self, CHAN_VOICE, gi.soundindex ("misc/udeath.wav"), 1, ATTN_NORM, 0);
for (n= 0; n < 2; n++)
ThrowGib (self, "models/objects/gibs/bone/tris.md2", damage, GIB_ORGANIC);
for (n= 0; n < 4; n++)
ThrowGib (self, "models/objects/gibs/sm_meat/tris.md2", damage, GIB_ORGANIC);
ThrowHead (self, "models/objects/gibs/head2/tris.md2", damage, GIB_ORGANIC);
self->deadflag = DEAD_DEAD;
return;
}
if (self->deadflag == DEAD_DEAD)
return;
// regular death
gi.sound (self, CHAN_VOICE, sound_die, 1, ATTN_NORM, 0);
self->deadflag = DEAD_DEAD;
self->takedamage = DAMAGE_YES;
self->monsterinfo.currentmove = &medic_move_death;
}
void medic_duck_down (edict_t *self)
{
if (self->monsterinfo.aiflags & AI_DUCKED)
return;
self->monsterinfo.aiflags |= AI_DUCKED;
self->maxs[2] -= 32;
self->takedamage = DAMAGE_YES;
self->monsterinfo.pausetime = level.time + 1;
gi.linkentity (self);
}
void medic_duck_hold (edict_t *self)
{
if (level.time >= self->monsterinfo.pausetime)
self->monsterinfo.aiflags &= ~AI_HOLD_FRAME;
else
self->monsterinfo.aiflags |= AI_HOLD_FRAME;
}
void medic_duck_up (edict_t *self)
{
self->monsterinfo.aiflags &= ~AI_DUCKED;
self->maxs[2] += 32;
self->takedamage = DAMAGE_AIM;
gi.linkentity (self);
}
mframe_t medic_frames_duck [] =
{
ai_move, -1, NULL,
ai_move, -1, NULL,
ai_move, -1, medic_duck_down,
ai_move, -1, medic_duck_hold,
ai_move, -1, NULL,
ai_move, -1, NULL,
ai_move, -1, medic_duck_up,
ai_move, -1, NULL,
ai_move, -1, NULL,
ai_move, -1, NULL,
ai_move, -1, NULL,
ai_move, -1, NULL,
ai_move, -1, NULL,
ai_move, -1, NULL,
ai_move, -1, NULL,
ai_move, -1, NULL
};
mmove_t medic_move_duck = {FRAME_duck1, FRAME_duck16, medic_frames_duck, medic_run};
void medic_dodge (edict_t *self, edict_t *attacker, float eta)
{
if (random() > 0.25)
return;
if (!self->enemy)
self->enemy = attacker;
self->monsterinfo.currentmove = &medic_move_duck;
}
mframe_t medic_frames_attackHyperBlaster [] =
{
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, medic_fire_blaster,
ai_charge, 0, medic_fire_blaster,
ai_charge, 0, medic_fire_blaster,
ai_charge, 0, medic_fire_blaster,
ai_charge, 0, medic_fire_blaster,
ai_charge, 0, medic_fire_blaster,
ai_charge, 0, medic_fire_blaster,
ai_charge, 0, medic_fire_blaster,
ai_charge, 0, medic_fire_blaster,
ai_charge, 0, medic_fire_blaster,
ai_charge, 0, medic_fire_blaster,
ai_charge, 0, medic_fire_blaster
};
mmove_t medic_move_attackHyperBlaster = {FRAME_attack15, FRAME_attack30, medic_frames_attackHyperBlaster, medic_run};
void medic_continue (edict_t *self)
{
if (visible (self, self->enemy) )
if (random() <= 0.95)
self->monsterinfo.currentmove = &medic_move_attackHyperBlaster;
}
mframe_t medic_frames_attackBlaster [] =
{
ai_charge, 0, NULL,
ai_charge, 5, NULL,
ai_charge, 5, NULL,
ai_charge, 3, NULL,
ai_charge, 2, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, medic_fire_blaster,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, medic_fire_blaster,
ai_charge, 0, NULL,
ai_charge, 0, medic_continue // Change to medic_continue... Else, go to frame 32
};
mmove_t medic_move_attackBlaster = {FRAME_attack1, FRAME_attack14, medic_frames_attackBlaster, medic_run};
void medic_hook_launch (edict_t *self)
{
gi.sound (self, CHAN_WEAPON, sound_hook_launch, 1, ATTN_NORM, 0);
}
void ED_CallSpawn (edict_t *ent);
static vec3_t medic_cable_offsets[] =
{
45.0, -9.2, 15.5,
48.4, -9.7, 15.2,
47.8, -9.8, 15.8,
47.3, -9.3, 14.3,
45.4, -10.1, 13.1,
41.9, -12.7, 12.0,
37.8, -15.8, 11.2,
34.3, -18.4, 10.7,
32.7, -19.7, 10.4,
32.7, -19.7, 10.4
};
void medic_cable_attack (edict_t *self)
{
vec3_t offset, start, end, f, r;
trace_t tr;
vec3_t dir, angles;
float distance;
if (!self->enemy->inuse)
return;
AngleVectors (self->s.angles, f, r, NULL);
VectorCopy (medic_cable_offsets[self->s.frame - FRAME_attack42], offset);
G_ProjectSource (self->s.origin, offset, f, r, start);
// check for max distance
VectorSubtract (start, self->enemy->s.origin, dir);
distance = VectorLength(dir);
if (distance > 256)
return;
// check for min/max pitch
vectoangles (dir, angles);
if (angles[0] < -180)
angles[0] += 360;
if (fabs(angles[0]) > 45)
return;
tr = gi.trace (start, NULL, NULL, self->enemy->s.origin, self, MASK_SHOT);
if (tr.fraction != 1.0 && tr.ent != self->enemy)
return;
if (self->s.frame == FRAME_attack43)
{
gi.sound (self->enemy, CHAN_AUTO, sound_hook_hit, 1, ATTN_NORM, 0);
self->enemy->monsterinfo.aiflags |= AI_RESURRECTING;
}
else if (self->s.frame == FRAME_attack50)
{
self->enemy->spawnflags = 0;
self->enemy->monsterinfo.aiflags = 0;
self->enemy->target = NULL;
self->enemy->targetname = NULL;
self->enemy->combattarget = NULL;
self->enemy->deathtarget = NULL;
self->enemy->owner = self;
ED_CallSpawn (self->enemy);
self->enemy->owner = NULL;
if (self->enemy->think)
{
self->enemy->nextthink = level.time;
self->enemy->think (self->enemy);
}
self->enemy->monsterinfo.aiflags |= AI_RESURRECTING;
if (self->oldenemy && self->oldenemy->client)
{
self->enemy->enemy = self->oldenemy;
FoundTarget (self->enemy);
}
}
else
{
if (self->s.frame == FRAME_attack44)
gi.sound (self, CHAN_WEAPON, sound_hook_heal, 1, ATTN_NORM, 0);
}
// adjust start for beam origin being in middle of a segment
VectorMA (start, 8, f, start);
// adjust end z for end spot since the monster is currently dead
VectorCopy (self->enemy->s.origin, end);
end[2] = self->enemy->absmin[2] + self->enemy->size[2] / 2;
gi.WriteByte (svc_temp_entity);
gi.WriteByte (TE_MEDIC_CABLE_ATTACK);
gi.WriteShort (self - g_edicts);
gi.WritePosition (start);
gi.WritePosition (end);
gi.multicast (self->s.origin, MULTICAST_PVS);
}
void medic_hook_retract (edict_t *self)
{
gi.sound (self, CHAN_WEAPON, sound_hook_retract, 1, ATTN_NORM, 0);
self->enemy->monsterinfo.aiflags &= ~AI_RESURRECTING;
}
mframe_t medic_frames_attackCable [] =
{
ai_move, 2, NULL,
ai_move, 3, NULL,
ai_move, 5, NULL,
ai_move, 4.4, NULL,
ai_charge, 4.7, NULL,
ai_charge, 5, NULL,
ai_charge, 6, NULL,
ai_charge, 4, NULL,
ai_charge, 0, NULL,
ai_move, 0, medic_hook_launch,
ai_move, 0, medic_cable_attack,
ai_move, 0, medic_cable_attack,
ai_move, 0, medic_cable_attack,
ai_move, 0, medic_cable_attack,
ai_move, 0, medic_cable_attack,
ai_move, 0, medic_cable_attack,
ai_move, 0, medic_cable_attack,
ai_move, 0, medic_cable_attack,
ai_move, 0, medic_cable_attack,
ai_move, -15, medic_hook_retract,
ai_move, -1.5, NULL,
ai_move, -1.2, NULL,
ai_move, -3, NULL,
ai_move, -2, NULL,
ai_move, 0.3, NULL,
ai_move, 0.7, NULL,
ai_move, 1.2, NULL,
ai_move, 1.3, NULL
};
mmove_t medic_move_attackCable = {FRAME_attack33, FRAME_attack60, medic_frames_attackCable, medic_run};
void medic_attack(edict_t *self)
{
if (self->monsterinfo.aiflags & AI_MEDIC)
self->monsterinfo.currentmove = &medic_move_attackCable;
else
self->monsterinfo.currentmove = &medic_move_attackBlaster;
}
qboolean medic_checkattack (edict_t *self)
{
if (self->monsterinfo.aiflags & AI_MEDIC)
{
medic_attack(self);
return true;
}
return M_CheckAttack (self);
}
/*QUAKED monster_medic (1 .5 0) (-16 -16 -24) (16 16 32) Ambush Trigger_Spawn Sight
*/
void SP_monster_medic (edict_t *self)
{
if (deathmatch->value)
{
G_FreeEdict (self);
return;
}
sound_idle1 = gi.soundindex ("medic/idle.wav");
sound_pain1 = gi.soundindex ("medic/medpain1.wav");
sound_pain2 = gi.soundindex ("medic/medpain2.wav");
sound_die = gi.soundindex ("medic/meddeth1.wav");
sound_sight = gi.soundindex ("medic/medsght1.wav");
sound_search = gi.soundindex ("medic/medsrch1.wav");
sound_hook_launch = gi.soundindex ("medic/medatck2.wav");
sound_hook_hit = gi.soundindex ("medic/medatck3.wav");
sound_hook_heal = gi.soundindex ("medic/medatck4.wav");
sound_hook_retract = gi.soundindex ("medic/medatck5.wav");
gi.soundindex ("medic/medatck1.wav");
self->movetype = MOVETYPE_STEP;
self->solid = SOLID_BBOX;
self->s.modelindex = gi.modelindex ("models/monsters/medic/tris.md2");
VectorSet (self->mins, -24, -24, -24);
VectorSet (self->maxs, 24, 24, 32);
self->health = 300;
self->gib_health = -130;
self->mass = 400;
self->pain = medic_pain;
self->die = medic_die;
self->monsterinfo.stand = medic_stand;
self->monsterinfo.walk = medic_walk;
self->monsterinfo.run = medic_run;
self->monsterinfo.dodge = medic_dodge;
self->monsterinfo.attack = medic_attack;
self->monsterinfo.melee = NULL;
self->monsterinfo.sight = medic_sight;
self->monsterinfo.idle = medic_idle;
self->monsterinfo.search = medic_search;
self->monsterinfo.checkattack = medic_checkattack;
gi.linkentity (self);
self->monsterinfo.currentmove = &medic_move_stand;
self->monsterinfo.scale = MODEL_SCALE;
walkmonster_start (self);
}

262
game/m_medic.h Normal file
View File

@ -0,0 +1,262 @@
/*
Copyright (C) 1997-2001 Id Software, Inc.
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 the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
// G:\quake2\baseq2\models/monsters/medic
// This file generated by ModelGen - Do NOT Modify
#define FRAME_walk1 0
#define FRAME_walk2 1
#define FRAME_walk3 2
#define FRAME_walk4 3
#define FRAME_walk5 4
#define FRAME_walk6 5
#define FRAME_walk7 6
#define FRAME_walk8 7
#define FRAME_walk9 8
#define FRAME_walk10 9
#define FRAME_walk11 10
#define FRAME_walk12 11
#define FRAME_wait1 12
#define FRAME_wait2 13
#define FRAME_wait3 14
#define FRAME_wait4 15
#define FRAME_wait5 16
#define FRAME_wait6 17
#define FRAME_wait7 18
#define FRAME_wait8 19
#define FRAME_wait9 20
#define FRAME_wait10 21
#define FRAME_wait11 22
#define FRAME_wait12 23
#define FRAME_wait13 24
#define FRAME_wait14 25
#define FRAME_wait15 26
#define FRAME_wait16 27
#define FRAME_wait17 28
#define FRAME_wait18 29
#define FRAME_wait19 30
#define FRAME_wait20 31
#define FRAME_wait21 32
#define FRAME_wait22 33
#define FRAME_wait23 34
#define FRAME_wait24 35
#define FRAME_wait25 36
#define FRAME_wait26 37
#define FRAME_wait27 38
#define FRAME_wait28 39
#define FRAME_wait29 40
#define FRAME_wait30 41
#define FRAME_wait31 42
#define FRAME_wait32 43
#define FRAME_wait33 44
#define FRAME_wait34 45
#define FRAME_wait35 46
#define FRAME_wait36 47
#define FRAME_wait37 48
#define FRAME_wait38 49
#define FRAME_wait39 50
#define FRAME_wait40 51
#define FRAME_wait41 52
#define FRAME_wait42 53
#define FRAME_wait43 54
#define FRAME_wait44 55
#define FRAME_wait45 56
#define FRAME_wait46 57
#define FRAME_wait47 58
#define FRAME_wait48 59
#define FRAME_wait49 60
#define FRAME_wait50 61
#define FRAME_wait51 62
#define FRAME_wait52 63
#define FRAME_wait53 64
#define FRAME_wait54 65
#define FRAME_wait55 66
#define FRAME_wait56 67
#define FRAME_wait57 68
#define FRAME_wait58 69
#define FRAME_wait59 70
#define FRAME_wait60 71
#define FRAME_wait61 72
#define FRAME_wait62 73
#define FRAME_wait63 74
#define FRAME_wait64 75
#define FRAME_wait65 76
#define FRAME_wait66 77
#define FRAME_wait67 78
#define FRAME_wait68 79
#define FRAME_wait69 80
#define FRAME_wait70 81
#define FRAME_wait71 82
#define FRAME_wait72 83
#define FRAME_wait73 84
#define FRAME_wait74 85
#define FRAME_wait75 86
#define FRAME_wait76 87
#define FRAME_wait77 88
#define FRAME_wait78 89
#define FRAME_wait79 90
#define FRAME_wait80 91
#define FRAME_wait81 92
#define FRAME_wait82 93
#define FRAME_wait83 94
#define FRAME_wait84 95
#define FRAME_wait85 96
#define FRAME_wait86 97
#define FRAME_wait87 98
#define FRAME_wait88 99
#define FRAME_wait89 100
#define FRAME_wait90 101
#define FRAME_run1 102
#define FRAME_run2 103
#define FRAME_run3 104
#define FRAME_run4 105
#define FRAME_run5 106
#define FRAME_run6 107
#define FRAME_paina1 108
#define FRAME_paina2 109
#define FRAME_paina3 110
#define FRAME_paina4 111
#define FRAME_paina5 112
#define FRAME_paina6 113
#define FRAME_paina7 114
#define FRAME_paina8 115
#define FRAME_painb1 116
#define FRAME_painb2 117
#define FRAME_painb3 118
#define FRAME_painb4 119
#define FRAME_painb5 120
#define FRAME_painb6 121
#define FRAME_painb7 122
#define FRAME_painb8 123
#define FRAME_painb9 124
#define FRAME_painb10 125
#define FRAME_painb11 126
#define FRAME_painb12 127
#define FRAME_painb13 128
#define FRAME_painb14 129
#define FRAME_painb15 130
#define FRAME_duck1 131
#define FRAME_duck2 132
#define FRAME_duck3 133
#define FRAME_duck4 134
#define FRAME_duck5 135
#define FRAME_duck6 136
#define FRAME_duck7 137
#define FRAME_duck8 138
#define FRAME_duck9 139
#define FRAME_duck10 140
#define FRAME_duck11 141
#define FRAME_duck12 142
#define FRAME_duck13 143
#define FRAME_duck14 144
#define FRAME_duck15 145
#define FRAME_duck16 146
#define FRAME_death1 147
#define FRAME_death2 148
#define FRAME_death3 149
#define FRAME_death4 150
#define FRAME_death5 151
#define FRAME_death6 152
#define FRAME_death7 153
#define FRAME_death8 154
#define FRAME_death9 155
#define FRAME_death10 156
#define FRAME_death11 157
#define FRAME_death12 158
#define FRAME_death13 159
#define FRAME_death14 160
#define FRAME_death15 161
#define FRAME_death16 162
#define FRAME_death17 163
#define FRAME_death18 164
#define FRAME_death19 165
#define FRAME_death20 166
#define FRAME_death21 167
#define FRAME_death22 168
#define FRAME_death23 169
#define FRAME_death24 170
#define FRAME_death25 171
#define FRAME_death26 172
#define FRAME_death27 173
#define FRAME_death28 174
#define FRAME_death29 175
#define FRAME_death30 176
#define FRAME_attack1 177
#define FRAME_attack2 178
#define FRAME_attack3 179
#define FRAME_attack4 180
#define FRAME_attack5 181
#define FRAME_attack6 182
#define FRAME_attack7 183
#define FRAME_attack8 184
#define FRAME_attack9 185
#define FRAME_attack10 186
#define FRAME_attack11 187
#define FRAME_attack12 188
#define FRAME_attack13 189
#define FRAME_attack14 190
#define FRAME_attack15 191
#define FRAME_attack16 192
#define FRAME_attack17 193
#define FRAME_attack18 194
#define FRAME_attack19 195
#define FRAME_attack20 196
#define FRAME_attack21 197
#define FRAME_attack22 198
#define FRAME_attack23 199
#define FRAME_attack24 200
#define FRAME_attack25 201
#define FRAME_attack26 202
#define FRAME_attack27 203
#define FRAME_attack28 204
#define FRAME_attack29 205
#define FRAME_attack30 206
#define FRAME_attack31 207
#define FRAME_attack32 208
#define FRAME_attack33 209
#define FRAME_attack34 210
#define FRAME_attack35 211
#define FRAME_attack36 212
#define FRAME_attack37 213
#define FRAME_attack38 214
#define FRAME_attack39 215
#define FRAME_attack40 216
#define FRAME_attack41 217
#define FRAME_attack42 218
#define FRAME_attack43 219
#define FRAME_attack44 220
#define FRAME_attack45 221
#define FRAME_attack46 222
#define FRAME_attack47 223
#define FRAME_attack48 224
#define FRAME_attack49 225
#define FRAME_attack50 226
#define FRAME_attack51 227
#define FRAME_attack52 228
#define FRAME_attack53 229
#define FRAME_attack54 230
#define FRAME_attack55 231
#define FRAME_attack56 232
#define FRAME_attack57 233
#define FRAME_attack58 234
#define FRAME_attack59 235
#define FRAME_attack60 236
#define MODEL_SCALE 1.000000

556
game/m_move.c Normal file
View File

@ -0,0 +1,556 @@
/*
Copyright (C) 1997-2001 Id Software, Inc.
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 the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
// m_move.c -- monster movement
#include "g_local.h"
#define STEPSIZE 18
/*
=============
M_CheckBottom
Returns false if any part of the bottom of the entity is off an edge that
is not a staircase.
=============
*/
int c_yes, c_no;
qboolean M_CheckBottom (edict_t *ent)
{
vec3_t mins, maxs, start, stop;
trace_t trace;
int x, y;
float mid, bottom;
VectorAdd (ent->s.origin, ent->mins, mins);
VectorAdd (ent->s.origin, ent->maxs, maxs);
// if all of the points under the corners are solid world, don't bother
// with the tougher checks
// the corners must be within 16 of the midpoint
start[2] = mins[2] - 1;
for (x=0 ; x<=1 ; x++)
for (y=0 ; y<=1 ; y++)
{
start[0] = x ? maxs[0] : mins[0];
start[1] = y ? maxs[1] : mins[1];
if (gi.pointcontents (start) != CONTENTS_SOLID)
goto realcheck;
}
c_yes++;
return true; // we got out easy
realcheck:
c_no++;
//
// check it for real...
//
start[2] = mins[2];
// the midpoint must be within 16 of the bottom
start[0] = stop[0] = (mins[0] + maxs[0])*0.5;
start[1] = stop[1] = (mins[1] + maxs[1])*0.5;
stop[2] = start[2] - 2*STEPSIZE;
trace = gi.trace (start, vec3_origin, vec3_origin, stop, ent, MASK_MONSTERSOLID);
if (trace.fraction == 1.0)
return false;
mid = bottom = trace.endpos[2];
// the corners must be within 16 of the midpoint
for (x=0 ; x<=1 ; x++)
for (y=0 ; y<=1 ; y++)
{
start[0] = stop[0] = x ? maxs[0] : mins[0];
start[1] = stop[1] = y ? maxs[1] : mins[1];
trace = gi.trace (start, vec3_origin, vec3_origin, stop, ent, MASK_MONSTERSOLID);
if (trace.fraction != 1.0 && trace.endpos[2] > bottom)
bottom = trace.endpos[2];
if (trace.fraction == 1.0 || mid - trace.endpos[2] > STEPSIZE)
return false;
}
c_yes++;
return true;
}
/*
=============
SV_movestep
Called by monster program code.
The move will be adjusted for slopes and stairs, but if the move isn't
possible, no move is done, false is returned, and
pr_global_struct->trace_normal is set to the normal of the blocking wall
=============
*/
//FIXME since we need to test end position contents here, can we avoid doing
//it again later in catagorize position?
qboolean SV_movestep (edict_t *ent, vec3_t move, qboolean relink)
{
float dz;
vec3_t oldorg, neworg, end;
trace_t trace;
int i;
float stepsize;
vec3_t test;
int contents;
// try the move
VectorCopy (ent->s.origin, oldorg);
VectorAdd (ent->s.origin, move, neworg);
// flying monsters don't step up
if ( ent->flags & (FL_SWIM | FL_FLY) )
{
// try one move with vertical motion, then one without
for (i=0 ; i<2 ; i++)
{
VectorAdd (ent->s.origin, move, neworg);
if (i == 0 && ent->enemy)
{
if (!ent->goalentity)
ent->goalentity = ent->enemy;
dz = ent->s.origin[2] - ent->goalentity->s.origin[2];
if (ent->goalentity->client)
{
if (dz > 40)
neworg[2] -= 8;
if (!((ent->flags & FL_SWIM) && (ent->waterlevel < 2)))
if (dz < 30)
neworg[2] += 8;
}
else
{
if (dz > 8)
neworg[2] -= 8;
else if (dz > 0)
neworg[2] -= dz;
else if (dz < -8)
neworg[2] += 8;
else
neworg[2] += dz;
}
}
trace = gi.trace (ent->s.origin, ent->mins, ent->maxs, neworg, ent, MASK_MONSTERSOLID);
// fly monsters don't enter water voluntarily
if (ent->flags & FL_FLY)
{
if (!ent->waterlevel)
{
test[0] = trace.endpos[0];
test[1] = trace.endpos[1];
test[2] = trace.endpos[2] + ent->mins[2] + 1;
contents = gi.pointcontents(test);
if (contents & MASK_WATER)
return false;
}
}
// swim monsters don't exit water voluntarily
if (ent->flags & FL_SWIM)
{
if (ent->waterlevel < 2)
{
test[0] = trace.endpos[0];
test[1] = trace.endpos[1];
test[2] = trace.endpos[2] + ent->mins[2] + 1;
contents = gi.pointcontents(test);
if (!(contents & MASK_WATER))
return false;
}
}
if (trace.fraction == 1)
{
VectorCopy (trace.endpos, ent->s.origin);
if (relink)
{
gi.linkentity (ent);
G_TouchTriggers (ent);
}
return true;
}
if (!ent->enemy)
break;
}
return false;
}
// push down from a step height above the wished position
if (!(ent->monsterinfo.aiflags & AI_NOSTEP))
stepsize = STEPSIZE;
else
stepsize = 1;
neworg[2] += stepsize;
VectorCopy (neworg, end);
end[2] -= stepsize*2;
trace = gi.trace (neworg, ent->mins, ent->maxs, end, ent, MASK_MONSTERSOLID);
if (trace.allsolid)
return false;
if (trace.startsolid)
{
neworg[2] -= stepsize;
trace = gi.trace (neworg, ent->mins, ent->maxs, end, ent, MASK_MONSTERSOLID);
if (trace.allsolid || trace.startsolid)
return false;
}
// don't go in to water
if (ent->waterlevel == 0)
{
test[0] = trace.endpos[0];
test[1] = trace.endpos[1];
test[2] = trace.endpos[2] + ent->mins[2] + 1;
contents = gi.pointcontents(test);
if (contents & MASK_WATER)
return false;
}
if (trace.fraction == 1)
{
// if monster had the ground pulled out, go ahead and fall
if ( ent->flags & FL_PARTIALGROUND )
{
VectorAdd (ent->s.origin, move, ent->s.origin);
if (relink)
{
gi.linkentity (ent);
G_TouchTriggers (ent);
}
ent->groundentity = NULL;
return true;
}
return false; // walked off an edge
}
// check point traces down for dangling corners
VectorCopy (trace.endpos, ent->s.origin);
if (!M_CheckBottom (ent))
{
if ( ent->flags & FL_PARTIALGROUND )
{ // entity had floor mostly pulled out from underneath it
// and is trying to correct
if (relink)
{
gi.linkentity (ent);
G_TouchTriggers (ent);
}
return true;
}
VectorCopy (oldorg, ent->s.origin);
return false;
}
if ( ent->flags & FL_PARTIALGROUND )
{
ent->flags &= ~FL_PARTIALGROUND;
}
ent->groundentity = trace.ent;
ent->groundentity_linkcount = trace.ent->linkcount;
// the move is ok
if (relink)
{
gi.linkentity (ent);
G_TouchTriggers (ent);
}
return true;
}
//============================================================================
/*
===============
M_ChangeYaw
===============
*/
void M_ChangeYaw (edict_t *ent)
{
float ideal;
float current;
float move;
float speed;
current = anglemod(ent->s.angles[YAW]);
ideal = ent->ideal_yaw;
if (current == ideal)
return;
move = ideal - current;
speed = ent->yaw_speed;
if (ideal > current)
{
if (move >= 180)
move = move - 360;
}
else
{
if (move <= -180)
move = move + 360;
}
if (move > 0)
{
if (move > speed)
move = speed;
}
else
{
if (move < -speed)
move = -speed;
}
ent->s.angles[YAW] = anglemod (current + move);
}
/*
======================
SV_StepDirection
Turns to the movement direction, and walks the current distance if
facing it.
======================
*/
qboolean SV_StepDirection (edict_t *ent, float yaw, float dist)
{
vec3_t move, oldorigin;
float delta;
ent->ideal_yaw = yaw;
M_ChangeYaw (ent);
yaw = yaw*M_PI*2 / 360;
move[0] = cos(yaw)*dist;
move[1] = sin(yaw)*dist;
move[2] = 0;
VectorCopy (ent->s.origin, oldorigin);
if (SV_movestep (ent, move, false))
{
delta = ent->s.angles[YAW] - ent->ideal_yaw;
if (delta > 45 && delta < 315)
{ // not turned far enough, so don't take the step
VectorCopy (oldorigin, ent->s.origin);
}
gi.linkentity (ent);
G_TouchTriggers (ent);
return true;
}
gi.linkentity (ent);
G_TouchTriggers (ent);
return false;
}
/*
======================
SV_FixCheckBottom
======================
*/
void SV_FixCheckBottom (edict_t *ent)
{
ent->flags |= FL_PARTIALGROUND;
}
/*
================
SV_NewChaseDir
================
*/
#define DI_NODIR -1
void SV_NewChaseDir (edict_t *actor, edict_t *enemy, float dist)
{
float deltax,deltay;
float d[3];
float tdir, olddir, turnaround;
//FIXME: how did we get here with no enemy
if (!enemy)
return;
olddir = anglemod( (int)(actor->ideal_yaw/45)*45 );
turnaround = anglemod(olddir - 180);
deltax = enemy->s.origin[0] - actor->s.origin[0];
deltay = enemy->s.origin[1] - actor->s.origin[1];
if (deltax>10)
d[1]= 0;
else if (deltax<-10)
d[1]= 180;
else
d[1]= DI_NODIR;
if (deltay<-10)
d[2]= 270;
else if (deltay>10)
d[2]= 90;
else
d[2]= DI_NODIR;
// try direct route
if (d[1] != DI_NODIR && d[2] != DI_NODIR)
{
if (d[1] == 0)
tdir = d[2] == 90 ? 45 : 315;
else
tdir = d[2] == 90 ? 135 : 215;
if (tdir != turnaround && SV_StepDirection(actor, tdir, dist))
return;
}
// try other directions
if ( ((rand()&3) & 1) || abs(deltay)>abs(deltax))
{
tdir=d[1];
d[1]=d[2];
d[2]=tdir;
}
if (d[1]!=DI_NODIR && d[1]!=turnaround
&& SV_StepDirection(actor, d[1], dist))
return;
if (d[2]!=DI_NODIR && d[2]!=turnaround
&& SV_StepDirection(actor, d[2], dist))
return;
/* there is no direct path to the player, so pick another direction */
if (olddir!=DI_NODIR && SV_StepDirection(actor, olddir, dist))
return;
if (rand()&1) /*randomly determine direction of search*/
{
for (tdir=0 ; tdir<=315 ; tdir += 45)
if (tdir!=turnaround && SV_StepDirection(actor, tdir, dist) )
return;
}
else
{
for (tdir=315 ; tdir >=0 ; tdir -= 45)
if (tdir!=turnaround && SV_StepDirection(actor, tdir, dist) )
return;
}
if (turnaround != DI_NODIR && SV_StepDirection(actor, turnaround, dist) )
return;
actor->ideal_yaw = olddir; // can't move
// if a bridge was pulled out from underneath a monster, it may not have
// a valid standing position at all
if (!M_CheckBottom (actor))
SV_FixCheckBottom (actor);
}
/*
======================
SV_CloseEnough
======================
*/
qboolean SV_CloseEnough (edict_t *ent, edict_t *goal, float dist)
{
int i;
for (i=0 ; i<3 ; i++)
{
if (goal->absmin[i] > ent->absmax[i] + dist)
return false;
if (goal->absmax[i] < ent->absmin[i] - dist)
return false;
}
return true;
}
/*
======================
M_MoveToGoal
======================
*/
void M_MoveToGoal (edict_t *ent, float dist)
{
edict_t *goal;
goal = ent->goalentity;
if (!ent->groundentity && !(ent->flags & (FL_FLY|FL_SWIM)))
return;
// if the next step hits the enemy, return immediately
if (ent->enemy && SV_CloseEnough (ent, ent->enemy, dist) )
return;
// bump around...
if ( (rand()&3)==1 || !SV_StepDirection (ent, ent->ideal_yaw, dist))
{
if (ent->inuse)
SV_NewChaseDir (ent, goal, dist);
}
}
/*
===============
M_walkmove
===============
*/
qboolean M_walkmove (edict_t *ent, float yaw, float dist)
{
vec3_t move;
if (!ent->groundentity && !(ent->flags & (FL_FLY|FL_SWIM)))
return false;
yaw = yaw*M_PI*2 / 360;
move[0] = cos(yaw)*dist;
move[1] = sin(yaw)*dist;
move[2] = 0;
return SV_movestep(ent, move, true);
}

663
game/m_mutant.c Normal file
View File

@ -0,0 +1,663 @@
/*
Copyright (C) 1997-2001 Id Software, Inc.
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 the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/*
==============================================================================
mutant
==============================================================================
*/
#include "g_local.h"
#include "m_mutant.h"
static int sound_swing;
static int sound_hit;
static int sound_hit2;
static int sound_death;
static int sound_idle;
static int sound_pain1;
static int sound_pain2;
static int sound_sight;
static int sound_search;
static int sound_step1;
static int sound_step2;
static int sound_step3;
static int sound_thud;
//
// SOUNDS
//
void mutant_step (edict_t *self)
{
int n;
n = (rand() + 1) % 3;
if (n == 0)
gi.sound (self, CHAN_VOICE, sound_step1, 1, ATTN_NORM, 0);
else if (n == 1)
gi.sound (self, CHAN_VOICE, sound_step2, 1, ATTN_NORM, 0);
else
gi.sound (self, CHAN_VOICE, sound_step3, 1, ATTN_NORM, 0);
}
void mutant_sight (edict_t *self, edict_t *other)
{
gi.sound (self, CHAN_VOICE, sound_sight, 1, ATTN_NORM, 0);
}
void mutant_search (edict_t *self)
{
gi.sound (self, CHAN_VOICE, sound_search, 1, ATTN_NORM, 0);
}
void mutant_swing (edict_t *self)
{
gi.sound (self, CHAN_VOICE, sound_swing, 1, ATTN_NORM, 0);
}
//
// STAND
//
mframe_t mutant_frames_stand [] =
{
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL, // 10
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL, // 20
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL, // 30
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL, // 40
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL, // 50
ai_stand, 0, NULL
};
mmove_t mutant_move_stand = {FRAME_stand101, FRAME_stand151, mutant_frames_stand, NULL};
void mutant_stand (edict_t *self)
{
self->monsterinfo.currentmove = &mutant_move_stand;
}
//
// IDLE
//
void mutant_idle_loop (edict_t *self)
{
if (random() < 0.75)
self->monsterinfo.nextframe = FRAME_stand155;
}
mframe_t mutant_frames_idle [] =
{
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL, // scratch loop start
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, mutant_idle_loop, // scratch loop end
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL
};
mmove_t mutant_move_idle = {FRAME_stand152, FRAME_stand164, mutant_frames_idle, mutant_stand};
void mutant_idle (edict_t *self)
{
self->monsterinfo.currentmove = &mutant_move_idle;
gi.sound (self, CHAN_VOICE, sound_idle, 1, ATTN_IDLE, 0);
}
//
// WALK
//
void mutant_walk (edict_t *self);
mframe_t mutant_frames_walk [] =
{
ai_walk, 3, NULL,
ai_walk, 1, NULL,
ai_walk, 5, NULL,
ai_walk, 10, NULL,
ai_walk, 13, NULL,
ai_walk, 10, NULL,
ai_walk, 0, NULL,
ai_walk, 5, NULL,
ai_walk, 6, NULL,
ai_walk, 16, NULL,
ai_walk, 15, NULL,
ai_walk, 6, NULL
};
mmove_t mutant_move_walk = {FRAME_walk05, FRAME_walk16, mutant_frames_walk, NULL};
void mutant_walk_loop (edict_t *self)
{
self->monsterinfo.currentmove = &mutant_move_walk;
}
mframe_t mutant_frames_start_walk [] =
{
ai_walk, 5, NULL,
ai_walk, 5, NULL,
ai_walk, -2, NULL,
ai_walk, 1, NULL
};
mmove_t mutant_move_start_walk = {FRAME_walk01, FRAME_walk04, mutant_frames_start_walk, mutant_walk_loop};
void mutant_walk (edict_t *self)
{
self->monsterinfo.currentmove = &mutant_move_start_walk;
}
//
// RUN
//
mframe_t mutant_frames_run [] =
{
ai_run, 40, NULL,
ai_run, 40, mutant_step,
ai_run, 24, NULL,
ai_run, 5, mutant_step,
ai_run, 17, NULL,
ai_run, 10, NULL
};
mmove_t mutant_move_run = {FRAME_run03, FRAME_run08, mutant_frames_run, NULL};
void mutant_run (edict_t *self)
{
if (self->monsterinfo.aiflags & AI_STAND_GROUND)
self->monsterinfo.currentmove = &mutant_move_stand;
else
self->monsterinfo.currentmove = &mutant_move_run;
}
//
// MELEE
//
void mutant_hit_left (edict_t *self)
{
vec3_t aim;
VectorSet (aim, MELEE_DISTANCE, self->mins[0], 8);
if (fire_hit (self, aim, (10 + (rand() %5)), 100))
gi.sound (self, CHAN_WEAPON, sound_hit, 1, ATTN_NORM, 0);
else
gi.sound (self, CHAN_WEAPON, sound_swing, 1, ATTN_NORM, 0);
}
void mutant_hit_right (edict_t *self)
{
vec3_t aim;
VectorSet (aim, MELEE_DISTANCE, self->maxs[0], 8);
if (fire_hit (self, aim, (10 + (rand() %5)), 100))
gi.sound (self, CHAN_WEAPON, sound_hit2, 1, ATTN_NORM, 0);
else
gi.sound (self, CHAN_WEAPON, sound_swing, 1, ATTN_NORM, 0);
}
void mutant_check_refire (edict_t *self)
{
if (!self->enemy || !self->enemy->inuse || self->enemy->health <= 0)
return;
if ( ((skill->value == 3) && (random() < 0.5)) || (range(self, self->enemy) == RANGE_MELEE) )
self->monsterinfo.nextframe = FRAME_attack09;
}
mframe_t mutant_frames_attack [] =
{
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, mutant_hit_left,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, mutant_hit_right,
ai_charge, 0, mutant_check_refire
};
mmove_t mutant_move_attack = {FRAME_attack09, FRAME_attack15, mutant_frames_attack, mutant_run};
void mutant_melee (edict_t *self)
{
self->monsterinfo.currentmove = &mutant_move_attack;
}
//
// ATTACK
//
void mutant_jump_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
{
if (self->health <= 0)
{
self->touch = NULL;
return;
}
if (other->takedamage)
{
if (VectorLength(self->velocity) > 400)
{
vec3_t point;
vec3_t normal;
int damage;
VectorCopy (self->velocity, normal);
VectorNormalize(normal);
VectorMA (self->s.origin, self->maxs[0], normal, point);
damage = 40 + 10 * random();
T_Damage (other, self, self, self->velocity, point, normal, damage, damage, 0, MOD_UNKNOWN);
}
}
if (!M_CheckBottom (self))
{
if (self->groundentity)
{
self->monsterinfo.nextframe = FRAME_attack02;
self->touch = NULL;
}
return;
}
self->touch = NULL;
}
void mutant_jump_takeoff (edict_t *self)
{
vec3_t forward;
gi.sound (self, CHAN_VOICE, sound_sight, 1, ATTN_NORM, 0);
AngleVectors (self->s.angles, forward, NULL, NULL);
self->s.origin[2] += 1;
VectorScale (forward, 600, self->velocity);
self->velocity[2] = 250;
self->groundentity = NULL;
self->monsterinfo.aiflags |= AI_DUCKED;
self->monsterinfo.attack_finished = level.time + 3;
self->touch = mutant_jump_touch;
}
void mutant_check_landing (edict_t *self)
{
if (self->groundentity)
{
gi.sound (self, CHAN_WEAPON, sound_thud, 1, ATTN_NORM, 0);
self->monsterinfo.attack_finished = 0;
self->monsterinfo.aiflags &= ~AI_DUCKED;
return;
}
if (level.time > self->monsterinfo.attack_finished)
self->monsterinfo.nextframe = FRAME_attack02;
else
self->monsterinfo.nextframe = FRAME_attack05;
}
mframe_t mutant_frames_jump [] =
{
ai_charge, 0, NULL,
ai_charge, 17, NULL,
ai_charge, 15, mutant_jump_takeoff,
ai_charge, 15, NULL,
ai_charge, 15, mutant_check_landing,
ai_charge, 0, NULL,
ai_charge, 3, NULL,
ai_charge, 0, NULL
};
mmove_t mutant_move_jump = {FRAME_attack01, FRAME_attack08, mutant_frames_jump, mutant_run};
void mutant_jump (edict_t *self)
{
self->monsterinfo.currentmove = &mutant_move_jump;
}
//
// CHECKATTACK
//
qboolean mutant_check_melee (edict_t *self)
{
if (range (self, self->enemy) == RANGE_MELEE)
return true;
return false;
}
qboolean mutant_check_jump (edict_t *self)
{
vec3_t v;
float distance;
if (self->absmin[2] > (self->enemy->absmin[2] + 0.75 * self->enemy->size[2]))
return false;
if (self->absmax[2] < (self->enemy->absmin[2] + 0.25 * self->enemy->size[2]))
return false;
v[0] = self->s.origin[0] - self->enemy->s.origin[0];
v[1] = self->s.origin[1] - self->enemy->s.origin[1];
v[2] = 0;
distance = VectorLength(v);
if (distance < 100)
return false;
if (distance > 100)
{
if (random() < 0.9)
return false;
}
return true;
}
qboolean mutant_checkattack (edict_t *self)
{
if (!self->enemy || self->enemy->health <= 0)
return false;
if (mutant_check_melee(self))
{
self->monsterinfo.attack_state = AS_MELEE;
return true;
}
if (mutant_check_jump(self))
{
self->monsterinfo.attack_state = AS_MISSILE;
// FIXME play a jump sound here
return true;
}
return false;
}
//
// PAIN
//
mframe_t mutant_frames_pain1 [] =
{
ai_move, 4, NULL,
ai_move, -3, NULL,
ai_move, -8, NULL,
ai_move, 2, NULL,
ai_move, 5, NULL
};
mmove_t mutant_move_pain1 = {FRAME_pain101, FRAME_pain105, mutant_frames_pain1, mutant_run};
mframe_t mutant_frames_pain2 [] =
{
ai_move, -24,NULL,
ai_move, 11, NULL,
ai_move, 5, NULL,
ai_move, -2, NULL,
ai_move, 6, NULL,
ai_move, 4, NULL
};
mmove_t mutant_move_pain2 = {FRAME_pain201, FRAME_pain206, mutant_frames_pain2, mutant_run};
mframe_t mutant_frames_pain3 [] =
{
ai_move, -22,NULL,
ai_move, 3, NULL,
ai_move, 3, NULL,
ai_move, 2, NULL,
ai_move, 1, NULL,
ai_move, 1, NULL,
ai_move, 6, NULL,
ai_move, 3, NULL,
ai_move, 2, NULL,
ai_move, 0, NULL,
ai_move, 1, NULL
};
mmove_t mutant_move_pain3 = {FRAME_pain301, FRAME_pain311, mutant_frames_pain3, mutant_run};
void mutant_pain (edict_t *self, edict_t *other, float kick, int damage)
{
float r;
if (self->health < (self->max_health / 2))
self->s.skinnum = 1;
if (level.time < self->pain_debounce_time)
return;
self->pain_debounce_time = level.time + 3;
if (skill->value == 3)
return; // no pain anims in nightmare
r = random();
if (r < 0.33)
{
gi.sound (self, CHAN_VOICE, sound_pain1, 1, ATTN_NORM, 0);
self->monsterinfo.currentmove = &mutant_move_pain1;
}
else if (r < 0.66)
{
gi.sound (self, CHAN_VOICE, sound_pain2, 1, ATTN_NORM, 0);
self->monsterinfo.currentmove = &mutant_move_pain2;
}
else
{
gi.sound (self, CHAN_VOICE, sound_pain1, 1, ATTN_NORM, 0);
self->monsterinfo.currentmove = &mutant_move_pain3;
}
}
//
// DEATH
//
void mutant_dead (edict_t *self)
{
VectorSet (self->mins, -16, -16, -24);
VectorSet (self->maxs, 16, 16, -8);
self->movetype = MOVETYPE_TOSS;
self->svflags |= SVF_DEADMONSTER;
gi.linkentity (self);
M_FlyCheck (self);
}
mframe_t mutant_frames_death1 [] =
{
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL
};
mmove_t mutant_move_death1 = {FRAME_death101, FRAME_death109, mutant_frames_death1, mutant_dead};
mframe_t mutant_frames_death2 [] =
{
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL
};
mmove_t mutant_move_death2 = {FRAME_death201, FRAME_death210, mutant_frames_death2, mutant_dead};
void mutant_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
{
int n;
if (self->health <= self->gib_health)
{
gi.sound (self, CHAN_VOICE, gi.soundindex ("misc/udeath.wav"), 1, ATTN_NORM, 0);
for (n= 0; n < 2; n++)
ThrowGib (self, "models/objects/gibs/bone/tris.md2", damage, GIB_ORGANIC);
for (n= 0; n < 4; n++)
ThrowGib (self, "models/objects/gibs/sm_meat/tris.md2", damage, GIB_ORGANIC);
ThrowHead (self, "models/objects/gibs/head2/tris.md2", damage, GIB_ORGANIC);
self->deadflag = DEAD_DEAD;
return;
}
if (self->deadflag == DEAD_DEAD)
return;
gi.sound (self, CHAN_VOICE, sound_death, 1, ATTN_NORM, 0);
self->deadflag = DEAD_DEAD;
self->takedamage = DAMAGE_YES;
self->s.skinnum = 1;
if (random() < 0.5)
self->monsterinfo.currentmove = &mutant_move_death1;
else
self->monsterinfo.currentmove = &mutant_move_death2;
}
//
// SPAWN
//
/*QUAKED monster_mutant (1 .5 0) (-32 -32 -24) (32 32 32) Ambush Trigger_Spawn Sight
*/
void SP_monster_mutant (edict_t *self)
{
if (deathmatch->value)
{
G_FreeEdict (self);
return;
}
sound_swing = gi.soundindex ("mutant/mutatck1.wav");
sound_hit = gi.soundindex ("mutant/mutatck2.wav");
sound_hit2 = gi.soundindex ("mutant/mutatck3.wav");
sound_death = gi.soundindex ("mutant/mutdeth1.wav");
sound_idle = gi.soundindex ("mutant/mutidle1.wav");
sound_pain1 = gi.soundindex ("mutant/mutpain1.wav");
sound_pain2 = gi.soundindex ("mutant/mutpain2.wav");
sound_sight = gi.soundindex ("mutant/mutsght1.wav");
sound_search = gi.soundindex ("mutant/mutsrch1.wav");
sound_step1 = gi.soundindex ("mutant/step1.wav");
sound_step2 = gi.soundindex ("mutant/step2.wav");
sound_step3 = gi.soundindex ("mutant/step3.wav");
sound_thud = gi.soundindex ("mutant/thud1.wav");
self->movetype = MOVETYPE_STEP;
self->solid = SOLID_BBOX;
self->s.modelindex = gi.modelindex ("models/monsters/mutant/tris.md2");
VectorSet (self->mins, -32, -32, -24);
VectorSet (self->maxs, 32, 32, 48);
self->health = 300;
self->gib_health = -120;
self->mass = 300;
self->pain = mutant_pain;
self->die = mutant_die;
self->monsterinfo.stand = mutant_stand;
self->monsterinfo.walk = mutant_walk;
self->monsterinfo.run = mutant_run;
self->monsterinfo.dodge = NULL;
self->monsterinfo.attack = mutant_jump;
self->monsterinfo.melee = mutant_melee;
self->monsterinfo.sight = mutant_sight;
self->monsterinfo.search = mutant_search;
self->monsterinfo.idle = mutant_idle;
self->monsterinfo.checkattack = mutant_checkattack;
gi.linkentity (self);
self->monsterinfo.currentmove = &mutant_move_stand;
self->monsterinfo.scale = MODEL_SCALE;
walkmonster_start (self);
}

174
game/m_mutant.h Normal file
View File

@ -0,0 +1,174 @@
/*
Copyright (C) 1997-2001 Id Software, Inc.
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 the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
// G:\quake2\baseq2\models/monsters/mutant
// This file generated by ModelGen - Do NOT Modify
#define FRAME_attack01 0
#define FRAME_attack02 1
#define FRAME_attack03 2
#define FRAME_attack04 3
#define FRAME_attack05 4
#define FRAME_attack06 5
#define FRAME_attack07 6
#define FRAME_attack08 7
#define FRAME_attack09 8
#define FRAME_attack10 9
#define FRAME_attack11 10
#define FRAME_attack12 11
#define FRAME_attack13 12
#define FRAME_attack14 13
#define FRAME_attack15 14
#define FRAME_death101 15
#define FRAME_death102 16
#define FRAME_death103 17
#define FRAME_death104 18
#define FRAME_death105 19
#define FRAME_death106 20
#define FRAME_death107 21
#define FRAME_death108 22
#define FRAME_death109 23
#define FRAME_death201 24
#define FRAME_death202 25
#define FRAME_death203 26
#define FRAME_death204 27
#define FRAME_death205 28
#define FRAME_death206 29
#define FRAME_death207 30
#define FRAME_death208 31
#define FRAME_death209 32
#define FRAME_death210 33
#define FRAME_pain101 34
#define FRAME_pain102 35
#define FRAME_pain103 36
#define FRAME_pain104 37
#define FRAME_pain105 38
#define FRAME_pain201 39
#define FRAME_pain202 40
#define FRAME_pain203 41
#define FRAME_pain204 42
#define FRAME_pain205 43
#define FRAME_pain206 44
#define FRAME_pain301 45
#define FRAME_pain302 46
#define FRAME_pain303 47
#define FRAME_pain304 48
#define FRAME_pain305 49
#define FRAME_pain306 50
#define FRAME_pain307 51
#define FRAME_pain308 52
#define FRAME_pain309 53
#define FRAME_pain310 54
#define FRAME_pain311 55
#define FRAME_run03 56
#define FRAME_run04 57
#define FRAME_run05 58
#define FRAME_run06 59
#define FRAME_run07 60
#define FRAME_run08 61
#define FRAME_stand101 62
#define FRAME_stand102 63
#define FRAME_stand103 64
#define FRAME_stand104 65
#define FRAME_stand105 66
#define FRAME_stand106 67
#define FRAME_stand107 68
#define FRAME_stand108 69
#define FRAME_stand109 70
#define FRAME_stand110 71
#define FRAME_stand111 72
#define FRAME_stand112 73
#define FRAME_stand113 74
#define FRAME_stand114 75
#define FRAME_stand115 76
#define FRAME_stand116 77
#define FRAME_stand117 78
#define FRAME_stand118 79
#define FRAME_stand119 80
#define FRAME_stand120 81
#define FRAME_stand121 82
#define FRAME_stand122 83
#define FRAME_stand123 84
#define FRAME_stand124 85
#define FRAME_stand125 86
#define FRAME_stand126 87
#define FRAME_stand127 88
#define FRAME_stand128 89
#define FRAME_stand129 90
#define FRAME_stand130 91
#define FRAME_stand131 92
#define FRAME_stand132 93
#define FRAME_stand133 94
#define FRAME_stand134 95
#define FRAME_stand135 96
#define FRAME_stand136 97
#define FRAME_stand137 98
#define FRAME_stand138 99
#define FRAME_stand139 100
#define FRAME_stand140 101
#define FRAME_stand141 102
#define FRAME_stand142 103
#define FRAME_stand143 104
#define FRAME_stand144 105
#define FRAME_stand145 106
#define FRAME_stand146 107
#define FRAME_stand147 108
#define FRAME_stand148 109
#define FRAME_stand149 110
#define FRAME_stand150 111
#define FRAME_stand151 112
#define FRAME_stand152 113
#define FRAME_stand153 114
#define FRAME_stand154 115
#define FRAME_stand155 116
#define FRAME_stand156 117
#define FRAME_stand157 118
#define FRAME_stand158 119
#define FRAME_stand159 120
#define FRAME_stand160 121
#define FRAME_stand161 122
#define FRAME_stand162 123
#define FRAME_stand163 124
#define FRAME_stand164 125
#define FRAME_walk01 126
#define FRAME_walk02 127
#define FRAME_walk03 128
#define FRAME_walk04 129
#define FRAME_walk05 130
#define FRAME_walk06 131
#define FRAME_walk07 132
#define FRAME_walk08 133
#define FRAME_walk09 134
#define FRAME_walk10 135
#define FRAME_walk11 136
#define FRAME_walk12 137
#define FRAME_walk13 138
#define FRAME_walk14 139
#define FRAME_walk15 140
#define FRAME_walk16 141
#define FRAME_walk17 142
#define FRAME_walk18 143
#define FRAME_walk19 144
#define FRAME_walk20 145
#define FRAME_walk21 146
#define FRAME_walk22 147
#define FRAME_walk23 148
#define MODEL_SCALE 1.000000

552
game/m_parasite.c Normal file
View File

@ -0,0 +1,552 @@
/*
Copyright (C) 1997-2001 Id Software, Inc.
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 the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/*
==============================================================================
parasite
==============================================================================
*/
#include "g_local.h"
#include "m_parasite.h"
static int sound_pain1;
static int sound_pain2;
static int sound_die;
static int sound_launch;
static int sound_impact;
static int sound_suck;
static int sound_reelin;
static int sound_sight;
static int sound_tap;
static int sound_scratch;
static int sound_search;
void parasite_stand (edict_t *self);
void parasite_start_run (edict_t *self);
void parasite_run (edict_t *self);
void parasite_walk (edict_t *self);
void parasite_start_walk (edict_t *self);
void parasite_end_fidget (edict_t *self);
void parasite_do_fidget (edict_t *self);
void parasite_refidget (edict_t *self);
void parasite_launch (edict_t *self)
{
gi.sound (self, CHAN_WEAPON, sound_launch, 1, ATTN_NORM, 0);
}
void parasite_reel_in (edict_t *self)
{
gi.sound (self, CHAN_WEAPON, sound_reelin, 1, ATTN_NORM, 0);
}
void parasite_sight (edict_t *self, edict_t *other)
{
gi.sound (self, CHAN_WEAPON, sound_sight, 1, ATTN_NORM, 0);
}
void parasite_tap (edict_t *self)
{
gi.sound (self, CHAN_WEAPON, sound_tap, 1, ATTN_IDLE, 0);
}
void parasite_scratch (edict_t *self)
{
gi.sound (self, CHAN_WEAPON, sound_scratch, 1, ATTN_IDLE, 0);
}
void parasite_search (edict_t *self)
{
gi.sound (self, CHAN_WEAPON, sound_search, 1, ATTN_IDLE, 0);
}
mframe_t parasite_frames_start_fidget [] =
{
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL
};
mmove_t parasite_move_start_fidget = {FRAME_stand18, FRAME_stand21, parasite_frames_start_fidget, parasite_do_fidget};
mframe_t parasite_frames_fidget [] =
{
ai_stand, 0, parasite_scratch,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, parasite_scratch,
ai_stand, 0, NULL,
ai_stand, 0, NULL
};
mmove_t parasite_move_fidget = {FRAME_stand22, FRAME_stand27, parasite_frames_fidget, parasite_refidget};
mframe_t parasite_frames_end_fidget [] =
{
ai_stand, 0, parasite_scratch,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL
};
mmove_t parasite_move_end_fidget = {FRAME_stand28, FRAME_stand35, parasite_frames_end_fidget, parasite_stand};
void parasite_end_fidget (edict_t *self)
{
self->monsterinfo.currentmove = &parasite_move_end_fidget;
}
void parasite_do_fidget (edict_t *self)
{
self->monsterinfo.currentmove = &parasite_move_fidget;
}
void parasite_refidget (edict_t *self)
{
if (random() <= 0.8)
self->monsterinfo.currentmove = &parasite_move_fidget;
else
self->monsterinfo.currentmove = &parasite_move_end_fidget;
}
void parasite_idle (edict_t *self)
{
self->monsterinfo.currentmove = &parasite_move_start_fidget;
}
mframe_t parasite_frames_stand [] =
{
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, parasite_tap,
ai_stand, 0, NULL,
ai_stand, 0, parasite_tap,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, parasite_tap,
ai_stand, 0, NULL,
ai_stand, 0, parasite_tap,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, parasite_tap,
ai_stand, 0, NULL,
ai_stand, 0, parasite_tap
};
mmove_t parasite_move_stand = {FRAME_stand01, FRAME_stand17, parasite_frames_stand, parasite_stand};
void parasite_stand (edict_t *self)
{
self->monsterinfo.currentmove = &parasite_move_stand;
}
mframe_t parasite_frames_run [] =
{
ai_run, 30, NULL,
ai_run, 30, NULL,
ai_run, 22, NULL,
ai_run, 19, NULL,
ai_run, 24, NULL,
ai_run, 28, NULL,
ai_run, 25, NULL
};
mmove_t parasite_move_run = {FRAME_run03, FRAME_run09, parasite_frames_run, NULL};
mframe_t parasite_frames_start_run [] =
{
ai_run, 0, NULL,
ai_run, 30, NULL,
};
mmove_t parasite_move_start_run = {FRAME_run01, FRAME_run02, parasite_frames_start_run, parasite_run};
mframe_t parasite_frames_stop_run [] =
{
ai_run, 20, NULL,
ai_run, 20, NULL,
ai_run, 12, NULL,
ai_run, 10, NULL,
ai_run, 0, NULL,
ai_run, 0, NULL
};
mmove_t parasite_move_stop_run = {FRAME_run10, FRAME_run15, parasite_frames_stop_run, NULL};
void parasite_start_run (edict_t *self)
{
if (self->monsterinfo.aiflags & AI_STAND_GROUND)
self->monsterinfo.currentmove = &parasite_move_stand;
else
self->monsterinfo.currentmove = &parasite_move_start_run;
}
void parasite_run (edict_t *self)
{
if (self->monsterinfo.aiflags & AI_STAND_GROUND)
self->monsterinfo.currentmove = &parasite_move_stand;
else
self->monsterinfo.currentmove = &parasite_move_run;
}
mframe_t parasite_frames_walk [] =
{
ai_walk, 30, NULL,
ai_walk, 30, NULL,
ai_walk, 22, NULL,
ai_walk, 19, NULL,
ai_walk, 24, NULL,
ai_walk, 28, NULL,
ai_walk, 25, NULL
};
mmove_t parasite_move_walk = {FRAME_run03, FRAME_run09, parasite_frames_walk, parasite_walk};
mframe_t parasite_frames_start_walk [] =
{
ai_walk, 0, NULL,
ai_walk, 30, parasite_walk
};
mmove_t parasite_move_start_walk = {FRAME_run01, FRAME_run02, parasite_frames_start_walk, NULL};
mframe_t parasite_frames_stop_walk [] =
{
ai_walk, 20, NULL,
ai_walk, 20, NULL,
ai_walk, 12, NULL,
ai_walk, 10, NULL,
ai_walk, 0, NULL,
ai_walk, 0, NULL
};
mmove_t parasite_move_stop_walk = {FRAME_run10, FRAME_run15, parasite_frames_stop_walk, NULL};
void parasite_start_walk (edict_t *self)
{
self->monsterinfo.currentmove = &parasite_move_start_walk;
}
void parasite_walk (edict_t *self)
{
self->monsterinfo.currentmove = &parasite_move_walk;
}
mframe_t parasite_frames_pain1 [] =
{
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 6, NULL,
ai_move, 16, NULL,
ai_move, -6, NULL,
ai_move, -7, NULL,
ai_move, 0, NULL
};
mmove_t parasite_move_pain1 = {FRAME_pain101, FRAME_pain111, parasite_frames_pain1, parasite_start_run};
void parasite_pain (edict_t *self, edict_t *other, float kick, int damage)
{
if (self->health < (self->max_health / 2))
self->s.skinnum = 1;
if (level.time < self->pain_debounce_time)
return;
self->pain_debounce_time = level.time + 3;
if (skill->value == 3)
return; // no pain anims in nightmare
if (random() < 0.5)
gi.sound (self, CHAN_VOICE, sound_pain1, 1, ATTN_NORM, 0);
else
gi.sound (self, CHAN_VOICE, sound_pain2, 1, ATTN_NORM, 0);
self->monsterinfo.currentmove = &parasite_move_pain1;
}
static qboolean parasite_drain_attack_ok (vec3_t start, vec3_t end)
{
vec3_t dir, angles;
// check for max distance
VectorSubtract (start, end, dir);
if (VectorLength(dir) > 256)
return false;
// check for min/max pitch
vectoangles (dir, angles);
if (angles[0] < -180)
angles[0] += 360;
if (fabs(angles[0]) > 30)
return false;
return true;
}
void parasite_drain_attack (edict_t *self)
{
vec3_t offset, start, f, r, end, dir;
trace_t tr;
int damage;
AngleVectors (self->s.angles, f, r, NULL);
VectorSet (offset, 24, 0, 6);
G_ProjectSource (self->s.origin, offset, f, r, start);
VectorCopy (self->enemy->s.origin, end);
if (!parasite_drain_attack_ok(start, end))
{
end[2] = self->enemy->s.origin[2] + self->enemy->maxs[2] - 8;
if (!parasite_drain_attack_ok(start, end))
{
end[2] = self->enemy->s.origin[2] + self->enemy->mins[2] + 8;
if (!parasite_drain_attack_ok(start, end))
return;
}
}
VectorCopy (self->enemy->s.origin, end);
tr = gi.trace (start, NULL, NULL, end, self, MASK_SHOT);
if (tr.ent != self->enemy)
return;
if (self->s.frame == FRAME_drain03)
{
damage = 5;
gi.sound (self->enemy, CHAN_AUTO, sound_impact, 1, ATTN_NORM, 0);
}
else
{
if (self->s.frame == FRAME_drain04)
gi.sound (self, CHAN_WEAPON, sound_suck, 1, ATTN_NORM, 0);
damage = 2;
}
gi.WriteByte (svc_temp_entity);
gi.WriteByte (TE_PARASITE_ATTACK);
gi.WriteShort (self - g_edicts);
gi.WritePosition (start);
gi.WritePosition (end);
gi.multicast (self->s.origin, MULTICAST_PVS);
VectorSubtract (start, end, dir);
T_Damage (self->enemy, self, self, dir, self->enemy->s.origin, vec3_origin, damage, 0, DAMAGE_NO_KNOCKBACK, MOD_UNKNOWN);
}
mframe_t parasite_frames_drain [] =
{
ai_charge, 0, parasite_launch,
ai_charge, 0, NULL,
ai_charge, 15, parasite_drain_attack, // Target hits
ai_charge, 0, parasite_drain_attack, // drain
ai_charge, 0, parasite_drain_attack, // drain
ai_charge, 0, parasite_drain_attack, // drain
ai_charge, 0, parasite_drain_attack, // drain
ai_charge, -2, parasite_drain_attack, // drain
ai_charge, -2, parasite_drain_attack, // drain
ai_charge, -3, parasite_drain_attack, // drain
ai_charge, -2, parasite_drain_attack, // drain
ai_charge, 0, parasite_drain_attack, // drain
ai_charge, -1, parasite_drain_attack, // drain
ai_charge, 0, parasite_reel_in, // let go
ai_charge, -2, NULL,
ai_charge, -2, NULL,
ai_charge, -3, NULL,
ai_charge, 0, NULL
};
mmove_t parasite_move_drain = {FRAME_drain01, FRAME_drain18, parasite_frames_drain, parasite_start_run};
mframe_t parasite_frames_break [] =
{
ai_charge, 0, NULL,
ai_charge, -3, NULL,
ai_charge, 1, NULL,
ai_charge, 2, NULL,
ai_charge, -3, NULL,
ai_charge, 1, NULL,
ai_charge, 1, NULL,
ai_charge, 3, NULL,
ai_charge, 0, NULL,
ai_charge, -18, NULL,
ai_charge, 3, NULL,
ai_charge, 9, NULL,
ai_charge, 6, NULL,
ai_charge, 0, NULL,
ai_charge, -18, NULL,
ai_charge, 0, NULL,
ai_charge, 8, NULL,
ai_charge, 9, NULL,
ai_charge, 0, NULL,
ai_charge, -18, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL, // airborne
ai_charge, 0, NULL, // airborne
ai_charge, 0, NULL, // slides
ai_charge, 0, NULL, // slides
ai_charge, 0, NULL, // slides
ai_charge, 0, NULL, // slides
ai_charge, 4, NULL,
ai_charge, 11, NULL,
ai_charge, -2, NULL,
ai_charge, -5, NULL,
ai_charge, 1, NULL
};
mmove_t parasite_move_break = {FRAME_break01, FRAME_break32, parasite_frames_break, parasite_start_run};
/*
===
Break Stuff Ends
===
*/
void parasite_attack (edict_t *self)
{
// if (random() <= 0.2)
// self->monsterinfo.currentmove = &parasite_move_break;
// else
self->monsterinfo.currentmove = &parasite_move_drain;
}
/*
===
Death Stuff Starts
===
*/
void parasite_dead (edict_t *self)
{
VectorSet (self->mins, -16, -16, -24);
VectorSet (self->maxs, 16, 16, -8);
self->movetype = MOVETYPE_TOSS;
self->svflags |= SVF_DEADMONSTER;
self->nextthink = 0;
gi.linkentity (self);
}
mframe_t parasite_frames_death [] =
{
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL
};
mmove_t parasite_move_death = {FRAME_death101, FRAME_death107, parasite_frames_death, parasite_dead};
void parasite_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
{
int n;
// check for gib
if (self->health <= self->gib_health)
{
gi.sound (self, CHAN_VOICE, gi.soundindex ("misc/udeath.wav"), 1, ATTN_NORM, 0);
for (n= 0; n < 2; n++)
ThrowGib (self, "models/objects/gibs/bone/tris.md2", damage, GIB_ORGANIC);
for (n= 0; n < 4; n++)
ThrowGib (self, "models/objects/gibs/sm_meat/tris.md2", damage, GIB_ORGANIC);
ThrowHead (self, "models/objects/gibs/head2/tris.md2", damage, GIB_ORGANIC);
self->deadflag = DEAD_DEAD;
return;
}
if (self->deadflag == DEAD_DEAD)
return;
// regular death
gi.sound (self, CHAN_VOICE, sound_die, 1, ATTN_NORM, 0);
self->deadflag = DEAD_DEAD;
self->takedamage = DAMAGE_YES;
self->monsterinfo.currentmove = &parasite_move_death;
}
/*
===
End Death Stuff
===
*/
/*QUAKED monster_parasite (1 .5 0) (-16 -16 -24) (16 16 32) Ambush Trigger_Spawn Sight
*/
void SP_monster_parasite (edict_t *self)
{
if (deathmatch->value)
{
G_FreeEdict (self);
return;
}
sound_pain1 = gi.soundindex ("parasite/parpain1.wav");
sound_pain2 = gi.soundindex ("parasite/parpain2.wav");
sound_die = gi.soundindex ("parasite/pardeth1.wav");
sound_launch = gi.soundindex("parasite/paratck1.wav");
sound_impact = gi.soundindex("parasite/paratck2.wav");
sound_suck = gi.soundindex("parasite/paratck3.wav");
sound_reelin = gi.soundindex("parasite/paratck4.wav");
sound_sight = gi.soundindex("parasite/parsght1.wav");
sound_tap = gi.soundindex("parasite/paridle1.wav");
sound_scratch = gi.soundindex("parasite/paridle2.wav");
sound_search = gi.soundindex("parasite/parsrch1.wav");
self->s.modelindex = gi.modelindex ("models/monsters/parasite/tris.md2");
VectorSet (self->mins, -16, -16, -24);
VectorSet (self->maxs, 16, 16, 24);
self->movetype = MOVETYPE_STEP;
self->solid = SOLID_BBOX;
self->health = 175;
self->gib_health = -50;
self->mass = 250;
self->pain = parasite_pain;
self->die = parasite_die;
self->monsterinfo.stand = parasite_stand;
self->monsterinfo.walk = parasite_start_walk;
self->monsterinfo.run = parasite_start_run;
self->monsterinfo.attack = parasite_attack;
self->monsterinfo.sight = parasite_sight;
self->monsterinfo.idle = parasite_idle;
gi.linkentity (self);
self->monsterinfo.currentmove = &parasite_move_stand;
self->monsterinfo.scale = MODEL_SCALE;
walkmonster_start (self);
}

143
game/m_parasite.h Normal file
View File

@ -0,0 +1,143 @@
/*
Copyright (C) 1997-2001 Id Software, Inc.
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 the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
// G:\quake2\baseq2\models/monsters/parasite
// This file generated by ModelGen - Do NOT Modify
#define FRAME_break01 0
#define FRAME_break02 1
#define FRAME_break03 2
#define FRAME_break04 3
#define FRAME_break05 4
#define FRAME_break06 5
#define FRAME_break07 6
#define FRAME_break08 7
#define FRAME_break09 8
#define FRAME_break10 9
#define FRAME_break11 10
#define FRAME_break12 11
#define FRAME_break13 12
#define FRAME_break14 13
#define FRAME_break15 14
#define FRAME_break16 15
#define FRAME_break17 16
#define FRAME_break18 17
#define FRAME_break19 18
#define FRAME_break20 19
#define FRAME_break21 20
#define FRAME_break22 21
#define FRAME_break23 22
#define FRAME_break24 23
#define FRAME_break25 24
#define FRAME_break26 25
#define FRAME_break27 26
#define FRAME_break28 27
#define FRAME_break29 28
#define FRAME_break30 29
#define FRAME_break31 30
#define FRAME_break32 31
#define FRAME_death101 32
#define FRAME_death102 33
#define FRAME_death103 34
#define FRAME_death104 35
#define FRAME_death105 36
#define FRAME_death106 37
#define FRAME_death107 38
#define FRAME_drain01 39
#define FRAME_drain02 40
#define FRAME_drain03 41
#define FRAME_drain04 42
#define FRAME_drain05 43
#define FRAME_drain06 44
#define FRAME_drain07 45
#define FRAME_drain08 46
#define FRAME_drain09 47
#define FRAME_drain10 48
#define FRAME_drain11 49
#define FRAME_drain12 50
#define FRAME_drain13 51
#define FRAME_drain14 52
#define FRAME_drain15 53
#define FRAME_drain16 54
#define FRAME_drain17 55
#define FRAME_drain18 56
#define FRAME_pain101 57
#define FRAME_pain102 58
#define FRAME_pain103 59
#define FRAME_pain104 60
#define FRAME_pain105 61
#define FRAME_pain106 62
#define FRAME_pain107 63
#define FRAME_pain108 64
#define FRAME_pain109 65
#define FRAME_pain110 66
#define FRAME_pain111 67
#define FRAME_run01 68
#define FRAME_run02 69
#define FRAME_run03 70
#define FRAME_run04 71
#define FRAME_run05 72
#define FRAME_run06 73
#define FRAME_run07 74
#define FRAME_run08 75
#define FRAME_run09 76
#define FRAME_run10 77
#define FRAME_run11 78
#define FRAME_run12 79
#define FRAME_run13 80
#define FRAME_run14 81
#define FRAME_run15 82
#define FRAME_stand01 83
#define FRAME_stand02 84
#define FRAME_stand03 85
#define FRAME_stand04 86
#define FRAME_stand05 87
#define FRAME_stand06 88
#define FRAME_stand07 89
#define FRAME_stand08 90
#define FRAME_stand09 91
#define FRAME_stand10 92
#define FRAME_stand11 93
#define FRAME_stand12 94
#define FRAME_stand13 95
#define FRAME_stand14 96
#define FRAME_stand15 97
#define FRAME_stand16 98
#define FRAME_stand17 99
#define FRAME_stand18 100
#define FRAME_stand19 101
#define FRAME_stand20 102
#define FRAME_stand21 103
#define FRAME_stand22 104
#define FRAME_stand23 105
#define FRAME_stand24 106
#define FRAME_stand25 107
#define FRAME_stand26 108
#define FRAME_stand27 109
#define FRAME_stand28 110
#define FRAME_stand29 111
#define FRAME_stand30 112
#define FRAME_stand31 113
#define FRAME_stand32 114
#define FRAME_stand33 115
#define FRAME_stand34 116
#define FRAME_stand35 117
#define MODEL_SCALE 1.000000

224
game/m_player.h Normal file
View File

@ -0,0 +1,224 @@
/*
Copyright (C) 1997-2001 Id Software, Inc.
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 the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
// G:\quake2\baseq2\models/player_x/frames
// This file generated by qdata - Do NOT Modify
#define FRAME_stand01 0
#define FRAME_stand02 1
#define FRAME_stand03 2
#define FRAME_stand04 3
#define FRAME_stand05 4
#define FRAME_stand06 5
#define FRAME_stand07 6
#define FRAME_stand08 7
#define FRAME_stand09 8
#define FRAME_stand10 9
#define FRAME_stand11 10
#define FRAME_stand12 11
#define FRAME_stand13 12
#define FRAME_stand14 13
#define FRAME_stand15 14
#define FRAME_stand16 15
#define FRAME_stand17 16
#define FRAME_stand18 17
#define FRAME_stand19 18
#define FRAME_stand20 19
#define FRAME_stand21 20
#define FRAME_stand22 21
#define FRAME_stand23 22
#define FRAME_stand24 23
#define FRAME_stand25 24
#define FRAME_stand26 25
#define FRAME_stand27 26
#define FRAME_stand28 27
#define FRAME_stand29 28
#define FRAME_stand30 29
#define FRAME_stand31 30
#define FRAME_stand32 31
#define FRAME_stand33 32
#define FRAME_stand34 33
#define FRAME_stand35 34
#define FRAME_stand36 35
#define FRAME_stand37 36
#define FRAME_stand38 37
#define FRAME_stand39 38
#define FRAME_stand40 39
#define FRAME_run1 40
#define FRAME_run2 41
#define FRAME_run3 42
#define FRAME_run4 43
#define FRAME_run5 44
#define FRAME_run6 45
#define FRAME_attack1 46
#define FRAME_attack2 47
#define FRAME_attack3 48
#define FRAME_attack4 49
#define FRAME_attack5 50
#define FRAME_attack6 51
#define FRAME_attack7 52
#define FRAME_attack8 53
#define FRAME_pain101 54
#define FRAME_pain102 55
#define FRAME_pain103 56
#define FRAME_pain104 57
#define FRAME_pain201 58
#define FRAME_pain202 59
#define FRAME_pain203 60
#define FRAME_pain204 61
#define FRAME_pain301 62
#define FRAME_pain302 63
#define FRAME_pain303 64
#define FRAME_pain304 65
#define FRAME_jump1 66
#define FRAME_jump2 67
#define FRAME_jump3 68
#define FRAME_jump4 69
#define FRAME_jump5 70
#define FRAME_jump6 71
#define FRAME_flip01 72
#define FRAME_flip02 73
#define FRAME_flip03 74
#define FRAME_flip04 75
#define FRAME_flip05 76
#define FRAME_flip06 77
#define FRAME_flip07 78
#define FRAME_flip08 79
#define FRAME_flip09 80
#define FRAME_flip10 81
#define FRAME_flip11 82
#define FRAME_flip12 83
#define FRAME_salute01 84
#define FRAME_salute02 85
#define FRAME_salute03 86
#define FRAME_salute04 87
#define FRAME_salute05 88
#define FRAME_salute06 89
#define FRAME_salute07 90
#define FRAME_salute08 91
#define FRAME_salute09 92
#define FRAME_salute10 93
#define FRAME_salute11 94
#define FRAME_taunt01 95
#define FRAME_taunt02 96
#define FRAME_taunt03 97
#define FRAME_taunt04 98
#define FRAME_taunt05 99
#define FRAME_taunt06 100
#define FRAME_taunt07 101
#define FRAME_taunt08 102
#define FRAME_taunt09 103
#define FRAME_taunt10 104
#define FRAME_taunt11 105
#define FRAME_taunt12 106
#define FRAME_taunt13 107
#define FRAME_taunt14 108
#define FRAME_taunt15 109
#define FRAME_taunt16 110
#define FRAME_taunt17 111
#define FRAME_wave01 112
#define FRAME_wave02 113
#define FRAME_wave03 114
#define FRAME_wave04 115
#define FRAME_wave05 116
#define FRAME_wave06 117
#define FRAME_wave07 118
#define FRAME_wave08 119
#define FRAME_wave09 120
#define FRAME_wave10 121
#define FRAME_wave11 122
#define FRAME_point01 123
#define FRAME_point02 124
#define FRAME_point03 125
#define FRAME_point04 126
#define FRAME_point05 127
#define FRAME_point06 128
#define FRAME_point07 129
#define FRAME_point08 130
#define FRAME_point09 131
#define FRAME_point10 132
#define FRAME_point11 133
#define FRAME_point12 134
#define FRAME_crstnd01 135
#define FRAME_crstnd02 136
#define FRAME_crstnd03 137
#define FRAME_crstnd04 138
#define FRAME_crstnd05 139
#define FRAME_crstnd06 140
#define FRAME_crstnd07 141
#define FRAME_crstnd08 142
#define FRAME_crstnd09 143
#define FRAME_crstnd10 144
#define FRAME_crstnd11 145
#define FRAME_crstnd12 146
#define FRAME_crstnd13 147
#define FRAME_crstnd14 148
#define FRAME_crstnd15 149
#define FRAME_crstnd16 150
#define FRAME_crstnd17 151
#define FRAME_crstnd18 152
#define FRAME_crstnd19 153
#define FRAME_crwalk1 154
#define FRAME_crwalk2 155
#define FRAME_crwalk3 156
#define FRAME_crwalk4 157
#define FRAME_crwalk5 158
#define FRAME_crwalk6 159
#define FRAME_crattak1 160
#define FRAME_crattak2 161
#define FRAME_crattak3 162
#define FRAME_crattak4 163
#define FRAME_crattak5 164
#define FRAME_crattak6 165
#define FRAME_crattak7 166
#define FRAME_crattak8 167
#define FRAME_crattak9 168
#define FRAME_crpain1 169
#define FRAME_crpain2 170
#define FRAME_crpain3 171
#define FRAME_crpain4 172
#define FRAME_crdeath1 173
#define FRAME_crdeath2 174
#define FRAME_crdeath3 175
#define FRAME_crdeath4 176
#define FRAME_crdeath5 177
#define FRAME_death101 178
#define FRAME_death102 179
#define FRAME_death103 180
#define FRAME_death104 181
#define FRAME_death105 182
#define FRAME_death106 183
#define FRAME_death201 184
#define FRAME_death202 185
#define FRAME_death203 186
#define FRAME_death204 187
#define FRAME_death205 188
#define FRAME_death206 189
#define FRAME_death301 190
#define FRAME_death302 191
#define FRAME_death303 192
#define FRAME_death304 193
#define FRAME_death305 194
#define FRAME_death306 195
#define FRAME_death307 196
#define FRAME_death308 197
#define MODEL_SCALE 1.000000

66
game/m_rider.h Normal file
View File

@ -0,0 +1,66 @@
// G:\quake2\baseq2\models/monsters/boss3/rider
// This file generated by ModelGen - Do NOT Modify
#define FRAME_stand201 0
#define FRAME_stand202 1
#define FRAME_stand203 2
#define FRAME_stand204 3
#define FRAME_stand205 4
#define FRAME_stand206 5
#define FRAME_stand207 6
#define FRAME_stand208 7
#define FRAME_stand209 8
#define FRAME_stand210 9
#define FRAME_stand211 10
#define FRAME_stand212 11
#define FRAME_stand213 12
#define FRAME_stand214 13
#define FRAME_stand215 14
#define FRAME_stand216 15
#define FRAME_stand217 16
#define FRAME_stand218 17
#define FRAME_stand219 18
#define FRAME_stand220 19
#define FRAME_stand221 20
#define FRAME_stand222 21
#define FRAME_stand223 22
#define FRAME_stand224 23
#define FRAME_stand225 24
#define FRAME_stand226 25
#define FRAME_stand227 26
#define FRAME_stand228 27
#define FRAME_stand229 28
#define FRAME_stand230 29
#define FRAME_stand231 30
#define FRAME_stand232 31
#define FRAME_stand233 32
#define FRAME_stand234 33
#define FRAME_stand235 34
#define FRAME_stand236 35
#define FRAME_stand237 36
#define FRAME_stand238 37
#define FRAME_stand239 38
#define FRAME_stand240 39
#define FRAME_stand241 40
#define FRAME_stand242 41
#define FRAME_stand243 42
#define FRAME_stand244 43
#define FRAME_stand245 44
#define FRAME_stand246 45
#define FRAME_stand247 46
#define FRAME_stand248 47
#define FRAME_stand249 48
#define FRAME_stand250 49
#define FRAME_stand251 50
#define FRAME_stand252 51
#define FRAME_stand253 52
#define FRAME_stand254 53
#define FRAME_stand255 54
#define FRAME_stand256 55
#define FRAME_stand257 56
#define FRAME_stand258 57
#define FRAME_stand259 58
#define FRAME_stand260 59
#define MODEL_SCALE 1.000000

1299
game/m_soldier.c Normal file

File diff suppressed because it is too large Load Diff

500
game/m_soldier.h Normal file
View File

@ -0,0 +1,500 @@
/*
Copyright (C) 1997-2001 Id Software, Inc.
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 the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
// G:\quake2\baseq2\models/monsters/soldier
// This file generated by ModelGen - Do NOT Modify
#define FRAME_attak101 0
#define FRAME_attak102 1
#define FRAME_attak103 2
#define FRAME_attak104 3
#define FRAME_attak105 4
#define FRAME_attak106 5
#define FRAME_attak107 6
#define FRAME_attak108 7
#define FRAME_attak109 8
#define FRAME_attak110 9
#define FRAME_attak111 10
#define FRAME_attak112 11
#define FRAME_attak201 12
#define FRAME_attak202 13
#define FRAME_attak203 14
#define FRAME_attak204 15
#define FRAME_attak205 16
#define FRAME_attak206 17
#define FRAME_attak207 18
#define FRAME_attak208 19
#define FRAME_attak209 20
#define FRAME_attak210 21
#define FRAME_attak211 22
#define FRAME_attak212 23
#define FRAME_attak213 24
#define FRAME_attak214 25
#define FRAME_attak215 26
#define FRAME_attak216 27
#define FRAME_attak217 28
#define FRAME_attak218 29
#define FRAME_attak301 30
#define FRAME_attak302 31
#define FRAME_attak303 32
#define FRAME_attak304 33
#define FRAME_attak305 34
#define FRAME_attak306 35
#define FRAME_attak307 36
#define FRAME_attak308 37
#define FRAME_attak309 38
#define FRAME_attak401 39
#define FRAME_attak402 40
#define FRAME_attak403 41
#define FRAME_attak404 42
#define FRAME_attak405 43
#define FRAME_attak406 44
#define FRAME_duck01 45
#define FRAME_duck02 46
#define FRAME_duck03 47
#define FRAME_duck04 48
#define FRAME_duck05 49
#define FRAME_pain101 50
#define FRAME_pain102 51
#define FRAME_pain103 52
#define FRAME_pain104 53
#define FRAME_pain105 54
#define FRAME_pain201 55
#define FRAME_pain202 56
#define FRAME_pain203 57
#define FRAME_pain204 58
#define FRAME_pain205 59
#define FRAME_pain206 60
#define FRAME_pain207 61
#define FRAME_pain301 62
#define FRAME_pain302 63
#define FRAME_pain303 64
#define FRAME_pain304 65
#define FRAME_pain305 66
#define FRAME_pain306 67
#define FRAME_pain307 68
#define FRAME_pain308 69
#define FRAME_pain309 70
#define FRAME_pain310 71
#define FRAME_pain311 72
#define FRAME_pain312 73
#define FRAME_pain313 74
#define FRAME_pain314 75
#define FRAME_pain315 76
#define FRAME_pain316 77
#define FRAME_pain317 78
#define FRAME_pain318 79
#define FRAME_pain401 80
#define FRAME_pain402 81
#define FRAME_pain403 82
#define FRAME_pain404 83
#define FRAME_pain405 84
#define FRAME_pain406 85
#define FRAME_pain407 86
#define FRAME_pain408 87
#define FRAME_pain409 88
#define FRAME_pain410 89
#define FRAME_pain411 90
#define FRAME_pain412 91
#define FRAME_pain413 92
#define FRAME_pain414 93
#define FRAME_pain415 94
#define FRAME_pain416 95
#define FRAME_pain417 96
#define FRAME_run01 97
#define FRAME_run02 98
#define FRAME_run03 99
#define FRAME_run04 100
#define FRAME_run05 101
#define FRAME_run06 102
#define FRAME_run07 103
#define FRAME_run08 104
#define FRAME_run09 105
#define FRAME_run10 106
#define FRAME_run11 107
#define FRAME_run12 108
#define FRAME_runs01 109
#define FRAME_runs02 110
#define FRAME_runs03 111
#define FRAME_runs04 112
#define FRAME_runs05 113
#define FRAME_runs06 114
#define FRAME_runs07 115
#define FRAME_runs08 116
#define FRAME_runs09 117
#define FRAME_runs10 118
#define FRAME_runs11 119
#define FRAME_runs12 120
#define FRAME_runs13 121
#define FRAME_runs14 122
#define FRAME_runs15 123
#define FRAME_runs16 124
#define FRAME_runs17 125
#define FRAME_runs18 126
#define FRAME_runt01 127
#define FRAME_runt02 128
#define FRAME_runt03 129
#define FRAME_runt04 130
#define FRAME_runt05 131
#define FRAME_runt06 132
#define FRAME_runt07 133
#define FRAME_runt08 134
#define FRAME_runt09 135
#define FRAME_runt10 136
#define FRAME_runt11 137
#define FRAME_runt12 138
#define FRAME_runt13 139
#define FRAME_runt14 140
#define FRAME_runt15 141
#define FRAME_runt16 142
#define FRAME_runt17 143
#define FRAME_runt18 144
#define FRAME_runt19 145
#define FRAME_stand101 146
#define FRAME_stand102 147
#define FRAME_stand103 148
#define FRAME_stand104 149
#define FRAME_stand105 150
#define FRAME_stand106 151
#define FRAME_stand107 152
#define FRAME_stand108 153
#define FRAME_stand109 154
#define FRAME_stand110 155
#define FRAME_stand111 156
#define FRAME_stand112 157
#define FRAME_stand113 158
#define FRAME_stand114 159
#define FRAME_stand115 160
#define FRAME_stand116 161
#define FRAME_stand117 162
#define FRAME_stand118 163
#define FRAME_stand119 164
#define FRAME_stand120 165
#define FRAME_stand121 166
#define FRAME_stand122 167
#define FRAME_stand123 168
#define FRAME_stand124 169
#define FRAME_stand125 170
#define FRAME_stand126 171
#define FRAME_stand127 172
#define FRAME_stand128 173
#define FRAME_stand129 174
#define FRAME_stand130 175
#define FRAME_stand301 176
#define FRAME_stand302 177
#define FRAME_stand303 178
#define FRAME_stand304 179
#define FRAME_stand305 180
#define FRAME_stand306 181
#define FRAME_stand307 182
#define FRAME_stand308 183
#define FRAME_stand309 184
#define FRAME_stand310 185
#define FRAME_stand311 186
#define FRAME_stand312 187
#define FRAME_stand313 188
#define FRAME_stand314 189
#define FRAME_stand315 190
#define FRAME_stand316 191
#define FRAME_stand317 192
#define FRAME_stand318 193
#define FRAME_stand319 194
#define FRAME_stand320 195
#define FRAME_stand321 196
#define FRAME_stand322 197
#define FRAME_stand323 198
#define FRAME_stand324 199
#define FRAME_stand325 200
#define FRAME_stand326 201
#define FRAME_stand327 202
#define FRAME_stand328 203
#define FRAME_stand329 204
#define FRAME_stand330 205
#define FRAME_stand331 206
#define FRAME_stand332 207
#define FRAME_stand333 208
#define FRAME_stand334 209
#define FRAME_stand335 210
#define FRAME_stand336 211
#define FRAME_stand337 212
#define FRAME_stand338 213
#define FRAME_stand339 214
#define FRAME_walk101 215
#define FRAME_walk102 216
#define FRAME_walk103 217
#define FRAME_walk104 218
#define FRAME_walk105 219
#define FRAME_walk106 220
#define FRAME_walk107 221
#define FRAME_walk108 222
#define FRAME_walk109 223
#define FRAME_walk110 224
#define FRAME_walk111 225
#define FRAME_walk112 226
#define FRAME_walk113 227
#define FRAME_walk114 228
#define FRAME_walk115 229
#define FRAME_walk116 230
#define FRAME_walk117 231
#define FRAME_walk118 232
#define FRAME_walk119 233
#define FRAME_walk120 234
#define FRAME_walk121 235
#define FRAME_walk122 236
#define FRAME_walk123 237
#define FRAME_walk124 238
#define FRAME_walk125 239
#define FRAME_walk126 240
#define FRAME_walk127 241
#define FRAME_walk128 242
#define FRAME_walk129 243
#define FRAME_walk130 244
#define FRAME_walk131 245
#define FRAME_walk132 246
#define FRAME_walk133 247
#define FRAME_walk201 248
#define FRAME_walk202 249
#define FRAME_walk203 250
#define FRAME_walk204 251
#define FRAME_walk205 252
#define FRAME_walk206 253
#define FRAME_walk207 254
#define FRAME_walk208 255
#define FRAME_walk209 256
#define FRAME_walk210 257
#define FRAME_walk211 258
#define FRAME_walk212 259
#define FRAME_walk213 260
#define FRAME_walk214 261
#define FRAME_walk215 262
#define FRAME_walk216 263
#define FRAME_walk217 264
#define FRAME_walk218 265
#define FRAME_walk219 266
#define FRAME_walk220 267
#define FRAME_walk221 268
#define FRAME_walk222 269
#define FRAME_walk223 270
#define FRAME_walk224 271
#define FRAME_death101 272
#define FRAME_death102 273
#define FRAME_death103 274
#define FRAME_death104 275
#define FRAME_death105 276
#define FRAME_death106 277
#define FRAME_death107 278
#define FRAME_death108 279
#define FRAME_death109 280
#define FRAME_death110 281
#define FRAME_death111 282
#define FRAME_death112 283
#define FRAME_death113 284
#define FRAME_death114 285
#define FRAME_death115 286
#define FRAME_death116 287
#define FRAME_death117 288
#define FRAME_death118 289
#define FRAME_death119 290
#define FRAME_death120 291
#define FRAME_death121 292
#define FRAME_death122 293
#define FRAME_death123 294
#define FRAME_death124 295
#define FRAME_death125 296
#define FRAME_death126 297
#define FRAME_death127 298
#define FRAME_death128 299
#define FRAME_death129 300
#define FRAME_death130 301
#define FRAME_death131 302
#define FRAME_death132 303
#define FRAME_death133 304
#define FRAME_death134 305
#define FRAME_death135 306
#define FRAME_death136 307
#define FRAME_death201 308
#define FRAME_death202 309
#define FRAME_death203 310
#define FRAME_death204 311
#define FRAME_death205 312
#define FRAME_death206 313
#define FRAME_death207 314
#define FRAME_death208 315
#define FRAME_death209 316
#define FRAME_death210 317
#define FRAME_death211 318
#define FRAME_death212 319
#define FRAME_death213 320
#define FRAME_death214 321
#define FRAME_death215 322
#define FRAME_death216 323
#define FRAME_death217 324
#define FRAME_death218 325
#define FRAME_death219 326
#define FRAME_death220 327
#define FRAME_death221 328
#define FRAME_death222 329
#define FRAME_death223 330
#define FRAME_death224 331
#define FRAME_death225 332
#define FRAME_death226 333
#define FRAME_death227 334
#define FRAME_death228 335
#define FRAME_death229 336
#define FRAME_death230 337
#define FRAME_death231 338
#define FRAME_death232 339
#define FRAME_death233 340
#define FRAME_death234 341
#define FRAME_death235 342
#define FRAME_death301 343
#define FRAME_death302 344
#define FRAME_death303 345
#define FRAME_death304 346
#define FRAME_death305 347
#define FRAME_death306 348
#define FRAME_death307 349
#define FRAME_death308 350
#define FRAME_death309 351
#define FRAME_death310 352
#define FRAME_death311 353
#define FRAME_death312 354
#define FRAME_death313 355
#define FRAME_death314 356
#define FRAME_death315 357
#define FRAME_death316 358
#define FRAME_death317 359
#define FRAME_death318 360
#define FRAME_death319 361
#define FRAME_death320 362
#define FRAME_death321 363
#define FRAME_death322 364
#define FRAME_death323 365
#define FRAME_death324 366
#define FRAME_death325 367
#define FRAME_death326 368
#define FRAME_death327 369
#define FRAME_death328 370
#define FRAME_death329 371
#define FRAME_death330 372
#define FRAME_death331 373
#define FRAME_death332 374
#define FRAME_death333 375
#define FRAME_death334 376
#define FRAME_death335 377
#define FRAME_death336 378
#define FRAME_death337 379
#define FRAME_death338 380
#define FRAME_death339 381
#define FRAME_death340 382
#define FRAME_death341 383
#define FRAME_death342 384
#define FRAME_death343 385
#define FRAME_death344 386
#define FRAME_death345 387
#define FRAME_death401 388
#define FRAME_death402 389
#define FRAME_death403 390
#define FRAME_death404 391
#define FRAME_death405 392
#define FRAME_death406 393
#define FRAME_death407 394
#define FRAME_death408 395
#define FRAME_death409 396
#define FRAME_death410 397
#define FRAME_death411 398
#define FRAME_death412 399
#define FRAME_death413 400
#define FRAME_death414 401
#define FRAME_death415 402
#define FRAME_death416 403
#define FRAME_death417 404
#define FRAME_death418 405
#define FRAME_death419 406
#define FRAME_death420 407
#define FRAME_death421 408
#define FRAME_death422 409
#define FRAME_death423 410
#define FRAME_death424 411
#define FRAME_death425 412
#define FRAME_death426 413
#define FRAME_death427 414
#define FRAME_death428 415
#define FRAME_death429 416
#define FRAME_death430 417
#define FRAME_death431 418
#define FRAME_death432 419
#define FRAME_death433 420
#define FRAME_death434 421
#define FRAME_death435 422
#define FRAME_death436 423
#define FRAME_death437 424
#define FRAME_death438 425
#define FRAME_death439 426
#define FRAME_death440 427
#define FRAME_death441 428
#define FRAME_death442 429
#define FRAME_death443 430
#define FRAME_death444 431
#define FRAME_death445 432
#define FRAME_death446 433
#define FRAME_death447 434
#define FRAME_death448 435
#define FRAME_death449 436
#define FRAME_death450 437
#define FRAME_death451 438
#define FRAME_death452 439
#define FRAME_death453 440
#define FRAME_death501 441
#define FRAME_death502 442
#define FRAME_death503 443
#define FRAME_death504 444
#define FRAME_death505 445
#define FRAME_death506 446
#define FRAME_death507 447
#define FRAME_death508 448
#define FRAME_death509 449
#define FRAME_death510 450
#define FRAME_death511 451
#define FRAME_death512 452
#define FRAME_death513 453
#define FRAME_death514 454
#define FRAME_death515 455
#define FRAME_death516 456
#define FRAME_death517 457
#define FRAME_death518 458
#define FRAME_death519 459
#define FRAME_death520 460
#define FRAME_death521 461
#define FRAME_death522 462
#define FRAME_death523 463
#define FRAME_death524 464
#define FRAME_death601 465
#define FRAME_death602 466
#define FRAME_death603 467
#define FRAME_death604 468
#define FRAME_death605 469
#define FRAME_death606 470
#define FRAME_death607 471
#define FRAME_death608 472
#define FRAME_death609 473
#define FRAME_death610 474
#define MODEL_SCALE 1.200000

717
game/m_supertank.c Normal file
View File

@ -0,0 +1,717 @@
/*
Copyright (C) 1997-2001 Id Software, Inc.
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 the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/*
==============================================================================
SUPERTANK
==============================================================================
*/
#include "g_local.h"
#include "m_supertank.h"
qboolean visible (edict_t *self, edict_t *other);
static int sound_pain1;
static int sound_pain2;
static int sound_pain3;
static int sound_death;
static int sound_search1;
static int sound_search2;
static int tread_sound;
void BossExplode (edict_t *self);
void TreadSound (edict_t *self)
{
gi.sound (self, CHAN_VOICE, tread_sound, 1, ATTN_NORM, 0);
}
void supertank_search (edict_t *self)
{
if (random() < 0.5)
gi.sound (self, CHAN_VOICE, sound_search1, 1, ATTN_NORM, 0);
else
gi.sound (self, CHAN_VOICE, sound_search2, 1, ATTN_NORM, 0);
}
void supertank_dead (edict_t *self);
void supertankRocket (edict_t *self);
void supertankMachineGun (edict_t *self);
void supertank_reattack1(edict_t *self);
//
// stand
//
mframe_t supertank_frames_stand []=
{
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL
};
mmove_t supertank_move_stand = {FRAME_stand_1, FRAME_stand_60, supertank_frames_stand, NULL};
void supertank_stand (edict_t *self)
{
self->monsterinfo.currentmove = &supertank_move_stand;
}
mframe_t supertank_frames_run [] =
{
ai_run, 12, TreadSound,
ai_run, 12, NULL,
ai_run, 12, NULL,
ai_run, 12, NULL,
ai_run, 12, NULL,
ai_run, 12, NULL,
ai_run, 12, NULL,
ai_run, 12, NULL,
ai_run, 12, NULL,
ai_run, 12, NULL,
ai_run, 12, NULL,
ai_run, 12, NULL,
ai_run, 12, NULL,
ai_run, 12, NULL,
ai_run, 12, NULL,
ai_run, 12, NULL,
ai_run, 12, NULL,
ai_run, 12, NULL
};
mmove_t supertank_move_run = {FRAME_forwrd_1, FRAME_forwrd_18, supertank_frames_run, NULL};
//
// walk
//
mframe_t supertank_frames_forward [] =
{
ai_walk, 4, TreadSound,
ai_walk, 4, NULL,
ai_walk, 4, NULL,
ai_walk, 4, NULL,
ai_walk, 4, NULL,
ai_walk, 4, NULL,
ai_walk, 4, NULL,
ai_walk, 4, NULL,
ai_walk, 4, NULL,
ai_walk, 4, NULL,
ai_walk, 4, NULL,
ai_walk, 4, NULL,
ai_walk, 4, NULL,
ai_walk, 4, NULL,
ai_walk, 4, NULL,
ai_walk, 4, NULL,
ai_walk, 4, NULL,
ai_walk, 4, NULL
};
mmove_t supertank_move_forward = {FRAME_forwrd_1, FRAME_forwrd_18, supertank_frames_forward, NULL};
void supertank_forward (edict_t *self)
{
self->monsterinfo.currentmove = &supertank_move_forward;
}
void supertank_walk (edict_t *self)
{
self->monsterinfo.currentmove = &supertank_move_forward;
}
void supertank_run (edict_t *self)
{
if (self->monsterinfo.aiflags & AI_STAND_GROUND)
self->monsterinfo.currentmove = &supertank_move_stand;
else
self->monsterinfo.currentmove = &supertank_move_run;
}
mframe_t supertank_frames_turn_right [] =
{
ai_move, 0, TreadSound,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL
};
mmove_t supertank_move_turn_right = {FRAME_right_1, FRAME_right_18, supertank_frames_turn_right, supertank_run};
mframe_t supertank_frames_turn_left [] =
{
ai_move, 0, TreadSound,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL
};
mmove_t supertank_move_turn_left = {FRAME_left_1, FRAME_left_18, supertank_frames_turn_left, supertank_run};
mframe_t supertank_frames_pain3 [] =
{
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL
};
mmove_t supertank_move_pain3 = {FRAME_pain3_9, FRAME_pain3_12, supertank_frames_pain3, supertank_run};
mframe_t supertank_frames_pain2 [] =
{
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL
};
mmove_t supertank_move_pain2 = {FRAME_pain2_5, FRAME_pain2_8, supertank_frames_pain2, supertank_run};
mframe_t supertank_frames_pain1 [] =
{
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL
};
mmove_t supertank_move_pain1 = {FRAME_pain1_1, FRAME_pain1_4, supertank_frames_pain1, supertank_run};
mframe_t supertank_frames_death1 [] =
{
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, BossExplode
};
mmove_t supertank_move_death = {FRAME_death_1, FRAME_death_24, supertank_frames_death1, supertank_dead};
mframe_t supertank_frames_backward[] =
{
ai_walk, 0, TreadSound,
ai_walk, 0, NULL,
ai_walk, 0, NULL,
ai_walk, 0, NULL,
ai_walk, 0, NULL,
ai_walk, 0, NULL,
ai_walk, 0, NULL,
ai_walk, 0, NULL,
ai_walk, 0, NULL,
ai_walk, 0, NULL,
ai_walk, 0, NULL,
ai_walk, 0, NULL,
ai_walk, 0, NULL,
ai_walk, 0, NULL,
ai_walk, 0, NULL,
ai_walk, 0, NULL,
ai_walk, 0, NULL,
ai_walk, 0, NULL
};
mmove_t supertank_move_backward = {FRAME_backwd_1, FRAME_backwd_18, supertank_frames_backward, NULL};
mframe_t supertank_frames_attack4[]=
{
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL
};
mmove_t supertank_move_attack4 = {FRAME_attak4_1, FRAME_attak4_6, supertank_frames_attack4, supertank_run};
mframe_t supertank_frames_attack3[]=
{
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL
};
mmove_t supertank_move_attack3 = {FRAME_attak3_1, FRAME_attak3_27, supertank_frames_attack3, supertank_run};
mframe_t supertank_frames_attack2[]=
{
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, supertankRocket,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, supertankRocket,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, supertankRocket,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL
};
mmove_t supertank_move_attack2 = {FRAME_attak2_1, FRAME_attak2_27, supertank_frames_attack2, supertank_run};
mframe_t supertank_frames_attack1[]=
{
ai_charge, 0, supertankMachineGun,
ai_charge, 0, supertankMachineGun,
ai_charge, 0, supertankMachineGun,
ai_charge, 0, supertankMachineGun,
ai_charge, 0, supertankMachineGun,
ai_charge, 0, supertankMachineGun,
};
mmove_t supertank_move_attack1 = {FRAME_attak1_1, FRAME_attak1_6, supertank_frames_attack1, supertank_reattack1};
mframe_t supertank_frames_end_attack1[]=
{
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL
};
mmove_t supertank_move_end_attack1 = {FRAME_attak1_7, FRAME_attak1_20, supertank_frames_end_attack1, supertank_run};
void supertank_reattack1(edict_t *self)
{
if (visible(self, self->enemy))
if (random() < 0.9)
self->monsterinfo.currentmove = &supertank_move_attack1;
else
self->monsterinfo.currentmove = &supertank_move_end_attack1;
else
self->monsterinfo.currentmove = &supertank_move_end_attack1;
}
void supertank_pain (edict_t *self, edict_t *other, float kick, int damage)
{
if (self->health < (self->max_health / 2))
self->s.skinnum = 1;
if (level.time < self->pain_debounce_time)
return;
// Lessen the chance of him going into his pain frames
if (damage <=25)
if (random()<0.2)
return;
// Don't go into pain if he's firing his rockets
if (skill->value >= 2)
if ( (self->s.frame >= FRAME_attak2_1) && (self->s.frame <= FRAME_attak2_14) )
return;
self->pain_debounce_time = level.time + 3;
if (skill->value == 3)
return; // no pain anims in nightmare
if (damage <= 10)
{
gi.sound (self, CHAN_VOICE, sound_pain1, 1, ATTN_NORM,0);
self->monsterinfo.currentmove = &supertank_move_pain1;
}
else if (damage <= 25)
{
gi.sound (self, CHAN_VOICE, sound_pain3, 1, ATTN_NORM,0);
self->monsterinfo.currentmove = &supertank_move_pain2;
}
else
{
gi.sound (self, CHAN_VOICE, sound_pain2, 1, ATTN_NORM,0);
self->monsterinfo.currentmove = &supertank_move_pain3;
}
};
void supertankRocket (edict_t *self)
{
vec3_t forward, right;
vec3_t start;
vec3_t dir;
vec3_t vec;
int flash_number;
if (self->s.frame == FRAME_attak2_8)
flash_number = MZ2_SUPERTANK_ROCKET_1;
else if (self->s.frame == FRAME_attak2_11)
flash_number = MZ2_SUPERTANK_ROCKET_2;
else // (self->s.frame == FRAME_attak2_14)
flash_number = MZ2_SUPERTANK_ROCKET_3;
AngleVectors (self->s.angles, forward, right, NULL);
G_ProjectSource (self->s.origin, monster_flash_offset[flash_number], forward, right, start);
VectorCopy (self->enemy->s.origin, vec);
vec[2] += self->enemy->viewheight;
VectorSubtract (vec, start, dir);
VectorNormalize (dir);
monster_fire_rocket (self, start, dir, 50, 500, flash_number);
}
void supertankMachineGun (edict_t *self)
{
vec3_t dir;
vec3_t vec;
vec3_t start;
vec3_t forward, right;
int flash_number;
flash_number = MZ2_SUPERTANK_MACHINEGUN_1 + (self->s.frame - FRAME_attak1_1);
//FIXME!!!
dir[0] = 0;
dir[1] = self->s.angles[1];
dir[2] = 0;
AngleVectors (dir, forward, right, NULL);
G_ProjectSource (self->s.origin, monster_flash_offset[flash_number], forward, right, start);
if (self->enemy)
{
VectorCopy (self->enemy->s.origin, vec);
VectorMA (vec, 0, self->enemy->velocity, vec);
vec[2] += self->enemy->viewheight;
VectorSubtract (vec, start, forward);
VectorNormalize (forward);
}
monster_fire_bullet (self, start, forward, 6, 4, DEFAULT_BULLET_HSPREAD, DEFAULT_BULLET_VSPREAD, flash_number);
}
void supertank_attack(edict_t *self)
{
vec3_t vec;
float range;
//float r;
VectorSubtract (self->enemy->s.origin, self->s.origin, vec);
range = VectorLength (vec);
//r = random();
// Attack 1 == Chaingun
// Attack 2 == Rocket Launcher
if (range <= 160)
{
self->monsterinfo.currentmove = &supertank_move_attack1;
}
else
{ // fire rockets more often at distance
if (random() < 0.3)
self->monsterinfo.currentmove = &supertank_move_attack1;
else
self->monsterinfo.currentmove = &supertank_move_attack2;
}
}
//
// death
//
void supertank_dead (edict_t *self)
{
VectorSet (self->mins, -60, -60, 0);
VectorSet (self->maxs, 60, 60, 72);
self->movetype = MOVETYPE_TOSS;
self->svflags |= SVF_DEADMONSTER;
self->nextthink = 0;
gi.linkentity (self);
}
void BossExplode (edict_t *self)
{
vec3_t org;
int n;
self->think = BossExplode;
VectorCopy (self->s.origin, org);
org[2] += 24 + (rand()&15);
switch (self->count++)
{
case 0:
org[0] -= 24;
org[1] -= 24;
break;
case 1:
org[0] += 24;
org[1] += 24;
break;
case 2:
org[0] += 24;
org[1] -= 24;
break;
case 3:
org[0] -= 24;
org[1] += 24;
break;
case 4:
org[0] -= 48;
org[1] -= 48;
break;
case 5:
org[0] += 48;
org[1] += 48;
break;
case 6:
org[0] -= 48;
org[1] += 48;
break;
case 7:
org[0] += 48;
org[1] -= 48;
break;
case 8:
self->s.sound = 0;
for (n= 0; n < 4; n++)
ThrowGib (self, "models/objects/gibs/sm_meat/tris.md2", 500, GIB_ORGANIC);
for (n= 0; n < 8; n++)
ThrowGib (self, "models/objects/gibs/sm_metal/tris.md2", 500, GIB_METALLIC);
ThrowGib (self, "models/objects/gibs/chest/tris.md2", 500, GIB_ORGANIC);
ThrowHead (self, "models/objects/gibs/gear/tris.md2", 500, GIB_METALLIC);
self->deadflag = DEAD_DEAD;
return;
}
gi.WriteByte (svc_temp_entity);
gi.WriteByte (TE_EXPLOSION1);
gi.WritePosition (org);
gi.multicast (self->s.origin, MULTICAST_PVS);
self->nextthink = level.time + 0.1;
}
void supertank_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
{
gi.sound (self, CHAN_VOICE, sound_death, 1, ATTN_NORM, 0);
self->deadflag = DEAD_DEAD;
self->takedamage = DAMAGE_NO;
self->count = 0;
self->monsterinfo.currentmove = &supertank_move_death;
}
//
// monster_supertank
//
/*QUAKED monster_supertank (1 .5 0) (-64 -64 0) (64 64 72) Ambush Trigger_Spawn Sight
*/
void SP_monster_supertank (edict_t *self)
{
if (deathmatch->value)
{
G_FreeEdict (self);
return;
}
sound_pain1 = gi.soundindex ("bosstank/btkpain1.wav");
sound_pain2 = gi.soundindex ("bosstank/btkpain2.wav");
sound_pain3 = gi.soundindex ("bosstank/btkpain3.wav");
sound_death = gi.soundindex ("bosstank/btkdeth1.wav");
sound_search1 = gi.soundindex ("bosstank/btkunqv1.wav");
sound_search2 = gi.soundindex ("bosstank/btkunqv2.wav");
// self->s.sound = gi.soundindex ("bosstank/btkengn1.wav");
tread_sound = gi.soundindex ("bosstank/btkengn1.wav");
self->movetype = MOVETYPE_STEP;
self->solid = SOLID_BBOX;
self->s.modelindex = gi.modelindex ("models/monsters/boss1/tris.md2");
VectorSet (self->mins, -64, -64, 0);
VectorSet (self->maxs, 64, 64, 112);
self->health = 1500;
self->gib_health = -500;
self->mass = 800;
self->pain = supertank_pain;
self->die = supertank_die;
self->monsterinfo.stand = supertank_stand;
self->monsterinfo.walk = supertank_walk;
self->monsterinfo.run = supertank_run;
self->monsterinfo.dodge = NULL;
self->monsterinfo.attack = supertank_attack;
self->monsterinfo.search = supertank_search;
self->monsterinfo.melee = NULL;
self->monsterinfo.sight = NULL;
gi.linkentity (self);
self->monsterinfo.currentmove = &supertank_move_stand;
self->monsterinfo.scale = MODEL_SCALE;
walkmonster_start(self);
}

279
game/m_supertank.h Normal file
View File

@ -0,0 +1,279 @@
/*
Copyright (C) 1997-2001 Id Software, Inc.
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 the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
// G:\quake2\baseq2\models/monsters/boss1/backup
// This file generated by ModelGen - Do NOT Modify
#define FRAME_attak1_1 0
#define FRAME_attak1_2 1
#define FRAME_attak1_3 2
#define FRAME_attak1_4 3
#define FRAME_attak1_5 4
#define FRAME_attak1_6 5
#define FRAME_attak1_7 6
#define FRAME_attak1_8 7
#define FRAME_attak1_9 8
#define FRAME_attak1_10 9
#define FRAME_attak1_11 10
#define FRAME_attak1_12 11
#define FRAME_attak1_13 12
#define FRAME_attak1_14 13
#define FRAME_attak1_15 14
#define FRAME_attak1_16 15
#define FRAME_attak1_17 16
#define FRAME_attak1_18 17
#define FRAME_attak1_19 18
#define FRAME_attak1_20 19
#define FRAME_attak2_1 20
#define FRAME_attak2_2 21
#define FRAME_attak2_3 22
#define FRAME_attak2_4 23
#define FRAME_attak2_5 24
#define FRAME_attak2_6 25
#define FRAME_attak2_7 26
#define FRAME_attak2_8 27
#define FRAME_attak2_9 28
#define FRAME_attak2_10 29
#define FRAME_attak2_11 30
#define FRAME_attak2_12 31
#define FRAME_attak2_13 32
#define FRAME_attak2_14 33
#define FRAME_attak2_15 34
#define FRAME_attak2_16 35
#define FRAME_attak2_17 36
#define FRAME_attak2_18 37
#define FRAME_attak2_19 38
#define FRAME_attak2_20 39
#define FRAME_attak2_21 40
#define FRAME_attak2_22 41
#define FRAME_attak2_23 42
#define FRAME_attak2_24 43
#define FRAME_attak2_25 44
#define FRAME_attak2_26 45
#define FRAME_attak2_27 46
#define FRAME_attak3_1 47
#define FRAME_attak3_2 48
#define FRAME_attak3_3 49
#define FRAME_attak3_4 50
#define FRAME_attak3_5 51
#define FRAME_attak3_6 52
#define FRAME_attak3_7 53
#define FRAME_attak3_8 54
#define FRAME_attak3_9 55
#define FRAME_attak3_10 56
#define FRAME_attak3_11 57
#define FRAME_attak3_12 58
#define FRAME_attak3_13 59
#define FRAME_attak3_14 60
#define FRAME_attak3_15 61
#define FRAME_attak3_16 62
#define FRAME_attak3_17 63
#define FRAME_attak3_18 64
#define FRAME_attak3_19 65
#define FRAME_attak3_20 66
#define FRAME_attak3_21 67
#define FRAME_attak3_22 68
#define FRAME_attak3_23 69
#define FRAME_attak3_24 70
#define FRAME_attak3_25 71
#define FRAME_attak3_26 72
#define FRAME_attak3_27 73
#define FRAME_attak4_1 74
#define FRAME_attak4_2 75
#define FRAME_attak4_3 76
#define FRAME_attak4_4 77
#define FRAME_attak4_5 78
#define FRAME_attak4_6 79
#define FRAME_backwd_1 80
#define FRAME_backwd_2 81
#define FRAME_backwd_3 82
#define FRAME_backwd_4 83
#define FRAME_backwd_5 84
#define FRAME_backwd_6 85
#define FRAME_backwd_7 86
#define FRAME_backwd_8 87
#define FRAME_backwd_9 88
#define FRAME_backwd_10 89
#define FRAME_backwd_11 90
#define FRAME_backwd_12 91
#define FRAME_backwd_13 92
#define FRAME_backwd_14 93
#define FRAME_backwd_15 94
#define FRAME_backwd_16 95
#define FRAME_backwd_17 96
#define FRAME_backwd_18 97
#define FRAME_death_1 98
#define FRAME_death_2 99
#define FRAME_death_3 100
#define FRAME_death_4 101
#define FRAME_death_5 102
#define FRAME_death_6 103
#define FRAME_death_7 104
#define FRAME_death_8 105
#define FRAME_death_9 106
#define FRAME_death_10 107
#define FRAME_death_11 108
#define FRAME_death_12 109
#define FRAME_death_13 110
#define FRAME_death_14 111
#define FRAME_death_15 112
#define FRAME_death_16 113
#define FRAME_death_17 114
#define FRAME_death_18 115
#define FRAME_death_19 116
#define FRAME_death_20 117
#define FRAME_death_21 118
#define FRAME_death_22 119
#define FRAME_death_23 120
#define FRAME_death_24 121
#define FRAME_death_31 122
#define FRAME_death_32 123
#define FRAME_death_33 124
#define FRAME_death_45 125
#define FRAME_death_46 126
#define FRAME_death_47 127
#define FRAME_forwrd_1 128
#define FRAME_forwrd_2 129
#define FRAME_forwrd_3 130
#define FRAME_forwrd_4 131
#define FRAME_forwrd_5 132
#define FRAME_forwrd_6 133
#define FRAME_forwrd_7 134
#define FRAME_forwrd_8 135
#define FRAME_forwrd_9 136
#define FRAME_forwrd_10 137
#define FRAME_forwrd_11 138
#define FRAME_forwrd_12 139
#define FRAME_forwrd_13 140
#define FRAME_forwrd_14 141
#define FRAME_forwrd_15 142
#define FRAME_forwrd_16 143
#define FRAME_forwrd_17 144
#define FRAME_forwrd_18 145
#define FRAME_left_1 146
#define FRAME_left_2 147
#define FRAME_left_3 148
#define FRAME_left_4 149
#define FRAME_left_5 150
#define FRAME_left_6 151
#define FRAME_left_7 152
#define FRAME_left_8 153
#define FRAME_left_9 154
#define FRAME_left_10 155
#define FRAME_left_11 156
#define FRAME_left_12 157
#define FRAME_left_13 158
#define FRAME_left_14 159
#define FRAME_left_15 160
#define FRAME_left_16 161
#define FRAME_left_17 162
#define FRAME_left_18 163
#define FRAME_pain1_1 164
#define FRAME_pain1_2 165
#define FRAME_pain1_3 166
#define FRAME_pain1_4 167
#define FRAME_pain2_5 168
#define FRAME_pain2_6 169
#define FRAME_pain2_7 170
#define FRAME_pain2_8 171
#define FRAME_pain3_9 172
#define FRAME_pain3_10 173
#define FRAME_pain3_11 174
#define FRAME_pain3_12 175
#define FRAME_right_1 176
#define FRAME_right_2 177
#define FRAME_right_3 178
#define FRAME_right_4 179
#define FRAME_right_5 180
#define FRAME_right_6 181
#define FRAME_right_7 182
#define FRAME_right_8 183
#define FRAME_right_9 184
#define FRAME_right_10 185
#define FRAME_right_11 186
#define FRAME_right_12 187
#define FRAME_right_13 188
#define FRAME_right_14 189
#define FRAME_right_15 190
#define FRAME_right_16 191
#define FRAME_right_17 192
#define FRAME_right_18 193
#define FRAME_stand_1 194
#define FRAME_stand_2 195
#define FRAME_stand_3 196
#define FRAME_stand_4 197
#define FRAME_stand_5 198
#define FRAME_stand_6 199
#define FRAME_stand_7 200
#define FRAME_stand_8 201
#define FRAME_stand_9 202
#define FRAME_stand_10 203
#define FRAME_stand_11 204
#define FRAME_stand_12 205
#define FRAME_stand_13 206
#define FRAME_stand_14 207
#define FRAME_stand_15 208
#define FRAME_stand_16 209
#define FRAME_stand_17 210
#define FRAME_stand_18 211
#define FRAME_stand_19 212
#define FRAME_stand_20 213
#define FRAME_stand_21 214
#define FRAME_stand_22 215
#define FRAME_stand_23 216
#define FRAME_stand_24 217
#define FRAME_stand_25 218
#define FRAME_stand_26 219
#define FRAME_stand_27 220
#define FRAME_stand_28 221
#define FRAME_stand_29 222
#define FRAME_stand_30 223
#define FRAME_stand_31 224
#define FRAME_stand_32 225
#define FRAME_stand_33 226
#define FRAME_stand_34 227
#define FRAME_stand_35 228
#define FRAME_stand_36 229
#define FRAME_stand_37 230
#define FRAME_stand_38 231
#define FRAME_stand_39 232
#define FRAME_stand_40 233
#define FRAME_stand_41 234
#define FRAME_stand_42 235
#define FRAME_stand_43 236
#define FRAME_stand_44 237
#define FRAME_stand_45 238
#define FRAME_stand_46 239
#define FRAME_stand_47 240
#define FRAME_stand_48 241
#define FRAME_stand_49 242
#define FRAME_stand_50 243
#define FRAME_stand_51 244
#define FRAME_stand_52 245
#define FRAME_stand_53 246
#define FRAME_stand_54 247
#define FRAME_stand_55 248
#define FRAME_stand_56 249
#define FRAME_stand_57 250
#define FRAME_stand_58 251
#define FRAME_stand_59 252
#define FRAME_stand_60 253
#define MODEL_SCALE 1.000000

856
game/m_tank.c Normal file
View File

@ -0,0 +1,856 @@
/*
Copyright (C) 1997-2001 Id Software, Inc.
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 the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/*
==============================================================================
TANK
==============================================================================
*/
#include "g_local.h"
#include "m_tank.h"
void tank_refire_rocket (edict_t *self);
void tank_doattack_rocket (edict_t *self);
void tank_reattack_blaster (edict_t *self);
static int sound_thud;
static int sound_pain;
static int sound_idle;
static int sound_die;
static int sound_step;
static int sound_sight;
static int sound_windup;
static int sound_strike;
//
// misc
//
void tank_sight (edict_t *self, edict_t *other)
{
gi.sound (self, CHAN_VOICE, sound_sight, 1, ATTN_NORM, 0);
}
void tank_footstep (edict_t *self)
{
gi.sound (self, CHAN_BODY, sound_step, 1, ATTN_NORM, 0);
}
void tank_thud (edict_t *self)
{
gi.sound (self, CHAN_BODY, sound_thud, 1, ATTN_NORM, 0);
}
void tank_windup (edict_t *self)
{
gi.sound (self, CHAN_WEAPON, sound_windup, 1, ATTN_NORM, 0);
}
void tank_idle (edict_t *self)
{
gi.sound (self, CHAN_VOICE, sound_idle, 1, ATTN_IDLE, 0);
}
//
// stand
//
mframe_t tank_frames_stand []=
{
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL
};
mmove_t tank_move_stand = {FRAME_stand01, FRAME_stand30, tank_frames_stand, NULL};
void tank_stand (edict_t *self)
{
self->monsterinfo.currentmove = &tank_move_stand;
}
//
// walk
//
void tank_walk (edict_t *self);
mframe_t tank_frames_start_walk [] =
{
ai_walk, 0, NULL,
ai_walk, 6, NULL,
ai_walk, 6, NULL,
ai_walk, 11, tank_footstep
};
mmove_t tank_move_start_walk = {FRAME_walk01, FRAME_walk04, tank_frames_start_walk, tank_walk};
mframe_t tank_frames_walk [] =
{
ai_walk, 4, NULL,
ai_walk, 5, NULL,
ai_walk, 3, NULL,
ai_walk, 2, NULL,
ai_walk, 5, NULL,
ai_walk, 5, NULL,
ai_walk, 4, NULL,
ai_walk, 4, tank_footstep,
ai_walk, 3, NULL,
ai_walk, 5, NULL,
ai_walk, 4, NULL,
ai_walk, 5, NULL,
ai_walk, 7, NULL,
ai_walk, 7, NULL,
ai_walk, 6, NULL,
ai_walk, 6, tank_footstep
};
mmove_t tank_move_walk = {FRAME_walk05, FRAME_walk20, tank_frames_walk, NULL};
mframe_t tank_frames_stop_walk [] =
{
ai_walk, 3, NULL,
ai_walk, 3, NULL,
ai_walk, 2, NULL,
ai_walk, 2, NULL,
ai_walk, 4, tank_footstep
};
mmove_t tank_move_stop_walk = {FRAME_walk21, FRAME_walk25, tank_frames_stop_walk, tank_stand};
void tank_walk (edict_t *self)
{
self->monsterinfo.currentmove = &tank_move_walk;
}
//
// run
//
void tank_run (edict_t *self);
mframe_t tank_frames_start_run [] =
{
ai_run, 0, NULL,
ai_run, 6, NULL,
ai_run, 6, NULL,
ai_run, 11, tank_footstep
};
mmove_t tank_move_start_run = {FRAME_walk01, FRAME_walk04, tank_frames_start_run, tank_run};
mframe_t tank_frames_run [] =
{
ai_run, 4, NULL,
ai_run, 5, NULL,
ai_run, 3, NULL,
ai_run, 2, NULL,
ai_run, 5, NULL,
ai_run, 5, NULL,
ai_run, 4, NULL,
ai_run, 4, tank_footstep,
ai_run, 3, NULL,
ai_run, 5, NULL,
ai_run, 4, NULL,
ai_run, 5, NULL,
ai_run, 7, NULL,
ai_run, 7, NULL,
ai_run, 6, NULL,
ai_run, 6, tank_footstep
};
mmove_t tank_move_run = {FRAME_walk05, FRAME_walk20, tank_frames_run, NULL};
mframe_t tank_frames_stop_run [] =
{
ai_run, 3, NULL,
ai_run, 3, NULL,
ai_run, 2, NULL,
ai_run, 2, NULL,
ai_run, 4, tank_footstep
};
mmove_t tank_move_stop_run = {FRAME_walk21, FRAME_walk25, tank_frames_stop_run, tank_walk};
void tank_run (edict_t *self)
{
if (self->enemy && self->enemy->client)
self->monsterinfo.aiflags |= AI_BRUTAL;
else
self->monsterinfo.aiflags &= ~AI_BRUTAL;
if (self->monsterinfo.aiflags & AI_STAND_GROUND)
{
self->monsterinfo.currentmove = &tank_move_stand;
return;
}
if (self->monsterinfo.currentmove == &tank_move_walk ||
self->monsterinfo.currentmove == &tank_move_start_run)
{
self->monsterinfo.currentmove = &tank_move_run;
}
else
{
self->monsterinfo.currentmove = &tank_move_start_run;
}
}
//
// pain
//
mframe_t tank_frames_pain1 [] =
{
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL
};
mmove_t tank_move_pain1 = {FRAME_pain101, FRAME_pain104, tank_frames_pain1, tank_run};
mframe_t tank_frames_pain2 [] =
{
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL
};
mmove_t tank_move_pain2 = {FRAME_pain201, FRAME_pain205, tank_frames_pain2, tank_run};
mframe_t tank_frames_pain3 [] =
{
ai_move, -7, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 2, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 3, NULL,
ai_move, 0, NULL,
ai_move, 2, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, tank_footstep
};
mmove_t tank_move_pain3 = {FRAME_pain301, FRAME_pain316, tank_frames_pain3, tank_run};
void tank_pain (edict_t *self, edict_t *other, float kick, int damage)
{
if (self->health < (self->max_health / 2))
self->s.skinnum |= 1;
if (damage <= 10)
return;
if (level.time < self->pain_debounce_time)
return;
if (damage <= 30)
if (random() > 0.2)
return;
// If hard or nightmare, don't go into pain while attacking
if ( skill->value >= 2)
{
if ( (self->s.frame >= FRAME_attak301) && (self->s.frame <= FRAME_attak330) )
return;
if ( (self->s.frame >= FRAME_attak101) && (self->s.frame <= FRAME_attak116) )
return;
}
self->pain_debounce_time = level.time + 3;
gi.sound (self, CHAN_VOICE, sound_pain, 1, ATTN_NORM, 0);
if (skill->value == 3)
return; // no pain anims in nightmare
if (damage <= 30)
self->monsterinfo.currentmove = &tank_move_pain1;
else if (damage <= 60)
self->monsterinfo.currentmove = &tank_move_pain2;
else
self->monsterinfo.currentmove = &tank_move_pain3;
};
//
// attacks
//
void TankBlaster (edict_t *self)
{
vec3_t forward, right;
vec3_t start;
vec3_t end;
vec3_t dir;
int flash_number;
if (self->s.frame == FRAME_attak110)
flash_number = MZ2_TANK_BLASTER_1;
else if (self->s.frame == FRAME_attak113)
flash_number = MZ2_TANK_BLASTER_2;
else // (self->s.frame == FRAME_attak116)
flash_number = MZ2_TANK_BLASTER_3;
AngleVectors (self->s.angles, forward, right, NULL);
G_ProjectSource (self->s.origin, monster_flash_offset[flash_number], forward, right, start);
VectorCopy (self->enemy->s.origin, end);
end[2] += self->enemy->viewheight;
VectorSubtract (end, start, dir);
monster_fire_blaster (self, start, dir, 30, 800, flash_number, EF_BLASTER);
}
void TankStrike (edict_t *self)
{
gi.sound (self, CHAN_WEAPON, sound_strike, 1, ATTN_NORM, 0);
}
void TankRocket (edict_t *self)
{
vec3_t forward, right;
vec3_t start;
vec3_t dir;
vec3_t vec;
int flash_number;
if (self->s.frame == FRAME_attak324)
flash_number = MZ2_TANK_ROCKET_1;
else if (self->s.frame == FRAME_attak327)
flash_number = MZ2_TANK_ROCKET_2;
else // (self->s.frame == FRAME_attak330)
flash_number = MZ2_TANK_ROCKET_3;
AngleVectors (self->s.angles, forward, right, NULL);
G_ProjectSource (self->s.origin, monster_flash_offset[flash_number], forward, right, start);
VectorCopy (self->enemy->s.origin, vec);
vec[2] += self->enemy->viewheight;
VectorSubtract (vec, start, dir);
VectorNormalize (dir);
monster_fire_rocket (self, start, dir, 50, 550, flash_number);
}
void TankMachineGun (edict_t *self)
{
vec3_t dir;
vec3_t vec;
vec3_t start;
vec3_t forward, right;
int flash_number;
flash_number = MZ2_TANK_MACHINEGUN_1 + (self->s.frame - FRAME_attak406);
AngleVectors (self->s.angles, forward, right, NULL);
G_ProjectSource (self->s.origin, monster_flash_offset[flash_number], forward, right, start);
if (self->enemy)
{
VectorCopy (self->enemy->s.origin, vec);
vec[2] += self->enemy->viewheight;
VectorSubtract (vec, start, vec);
vectoangles (vec, vec);
dir[0] = vec[0];
}
else
{
dir[0] = 0;
}
if (self->s.frame <= FRAME_attak415)
dir[1] = self->s.angles[1] - 8 * (self->s.frame - FRAME_attak411);
else
dir[1] = self->s.angles[1] + 8 * (self->s.frame - FRAME_attak419);
dir[2] = 0;
AngleVectors (dir, forward, NULL, NULL);
monster_fire_bullet (self, start, forward, 20, 4, DEFAULT_BULLET_HSPREAD, DEFAULT_BULLET_VSPREAD, flash_number);
}
mframe_t tank_frames_attack_blast [] =
{
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, -1, NULL,
ai_charge, -2, NULL,
ai_charge, -1, NULL,
ai_charge, -1, NULL,
ai_charge, 0, NULL,
ai_charge, 0, TankBlaster, // 10
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, TankBlaster,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, TankBlaster // 16
};
mmove_t tank_move_attack_blast = {FRAME_attak101, FRAME_attak116, tank_frames_attack_blast, tank_reattack_blaster};
mframe_t tank_frames_reattack_blast [] =
{
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, TankBlaster,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, TankBlaster // 16
};
mmove_t tank_move_reattack_blast = {FRAME_attak111, FRAME_attak116, tank_frames_reattack_blast, tank_reattack_blaster};
mframe_t tank_frames_attack_post_blast [] =
{
ai_move, 0, NULL, // 17
ai_move, 0, NULL,
ai_move, 2, NULL,
ai_move, 3, NULL,
ai_move, 2, NULL,
ai_move, -2, tank_footstep // 22
};
mmove_t tank_move_attack_post_blast = {FRAME_attak117, FRAME_attak122, tank_frames_attack_post_blast, tank_run};
void tank_reattack_blaster (edict_t *self)
{
if (skill->value >= 2)
if (visible (self, self->enemy))
if (self->enemy->health > 0)
if (random() <= 0.6)
{
self->monsterinfo.currentmove = &tank_move_reattack_blast;
return;
}
self->monsterinfo.currentmove = &tank_move_attack_post_blast;
}
void tank_poststrike (edict_t *self)
{
self->enemy = NULL;
tank_run (self);
}
mframe_t tank_frames_attack_strike [] =
{
ai_move, 3, NULL,
ai_move, 2, NULL,
ai_move, 2, NULL,
ai_move, 1, NULL,
ai_move, 6, NULL,
ai_move, 7, NULL,
ai_move, 9, tank_footstep,
ai_move, 2, NULL,
ai_move, 1, NULL,
ai_move, 2, NULL,
ai_move, 2, tank_footstep,
ai_move, 2, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, -2, NULL,
ai_move, -2, NULL,
ai_move, 0, tank_windup,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, TankStrike,
ai_move, 0, NULL,
ai_move, -1, NULL,
ai_move, -1, NULL,
ai_move, -1, NULL,
ai_move, -1, NULL,
ai_move, -1, NULL,
ai_move, -3, NULL,
ai_move, -10, NULL,
ai_move, -10, NULL,
ai_move, -2, NULL,
ai_move, -3, NULL,
ai_move, -2, tank_footstep
};
mmove_t tank_move_attack_strike = {FRAME_attak201, FRAME_attak238, tank_frames_attack_strike, tank_poststrike};
mframe_t tank_frames_attack_pre_rocket [] =
{
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL, // 10
ai_charge, 0, NULL,
ai_charge, 1, NULL,
ai_charge, 2, NULL,
ai_charge, 7, NULL,
ai_charge, 7, NULL,
ai_charge, 7, tank_footstep,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL, // 20
ai_charge, -3, NULL
};
mmove_t tank_move_attack_pre_rocket = {FRAME_attak301, FRAME_attak321, tank_frames_attack_pre_rocket, tank_doattack_rocket};
mframe_t tank_frames_attack_fire_rocket [] =
{
ai_charge, -3, NULL, // Loop Start 22
ai_charge, 0, NULL,
ai_charge, 0, TankRocket, // 24
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, TankRocket,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, -1, TankRocket // 30 Loop End
};
mmove_t tank_move_attack_fire_rocket = {FRAME_attak322, FRAME_attak330, tank_frames_attack_fire_rocket, tank_refire_rocket};
mframe_t tank_frames_attack_post_rocket [] =
{
ai_charge, 0, NULL, // 31
ai_charge, -1, NULL,
ai_charge, -1, NULL,
ai_charge, 0, NULL,
ai_charge, 2, NULL,
ai_charge, 3, NULL,
ai_charge, 4, NULL,
ai_charge, 2, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL, // 40
ai_charge, 0, NULL,
ai_charge, -9, NULL,
ai_charge, -8, NULL,
ai_charge, -7, NULL,
ai_charge, -1, NULL,
ai_charge, -1, tank_footstep,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL, // 50
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL
};
mmove_t tank_move_attack_post_rocket = {FRAME_attak331, FRAME_attak353, tank_frames_attack_post_rocket, tank_run};
mframe_t tank_frames_attack_chain [] =
{
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
NULL, 0, TankMachineGun,
NULL, 0, TankMachineGun,
NULL, 0, TankMachineGun,
NULL, 0, TankMachineGun,
NULL, 0, TankMachineGun,
NULL, 0, TankMachineGun,
NULL, 0, TankMachineGun,
NULL, 0, TankMachineGun,
NULL, 0, TankMachineGun,
NULL, 0, TankMachineGun,
NULL, 0, TankMachineGun,
NULL, 0, TankMachineGun,
NULL, 0, TankMachineGun,
NULL, 0, TankMachineGun,
NULL, 0, TankMachineGun,
NULL, 0, TankMachineGun,
NULL, 0, TankMachineGun,
NULL, 0, TankMachineGun,
NULL, 0, TankMachineGun,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL
};
mmove_t tank_move_attack_chain = {FRAME_attak401, FRAME_attak429, tank_frames_attack_chain, tank_run};
void tank_refire_rocket (edict_t *self)
{
// Only on hard or nightmare
if ( skill->value >= 2 )
if (self->enemy->health > 0)
if (visible(self, self->enemy) )
if (random() <= 0.4)
{
self->monsterinfo.currentmove = &tank_move_attack_fire_rocket;
return;
}
self->monsterinfo.currentmove = &tank_move_attack_post_rocket;
}
void tank_doattack_rocket (edict_t *self)
{
self->monsterinfo.currentmove = &tank_move_attack_fire_rocket;
}
void tank_attack(edict_t *self)
{
vec3_t vec;
float range;
float r;
if (self->enemy->health < 0)
{
self->monsterinfo.currentmove = &tank_move_attack_strike;
self->monsterinfo.aiflags &= ~AI_BRUTAL;
return;
}
VectorSubtract (self->enemy->s.origin, self->s.origin, vec);
range = VectorLength (vec);
r = random();
if (range <= 125)
{
if (r < 0.4)
self->monsterinfo.currentmove = &tank_move_attack_chain;
else
self->monsterinfo.currentmove = &tank_move_attack_blast;
}
else if (range <= 250)
{
if (r < 0.5)
self->monsterinfo.currentmove = &tank_move_attack_chain;
else
self->monsterinfo.currentmove = &tank_move_attack_blast;
}
else
{
if (r < 0.33)
self->monsterinfo.currentmove = &tank_move_attack_chain;
else if (r < 0.66)
{
self->monsterinfo.currentmove = &tank_move_attack_pre_rocket;
self->pain_debounce_time = level.time + 5.0; // no pain for a while
}
else
self->monsterinfo.currentmove = &tank_move_attack_blast;
}
}
//
// death
//
void tank_dead (edict_t *self)
{
VectorSet (self->mins, -16, -16, -16);
VectorSet (self->maxs, 16, 16, -0);
self->movetype = MOVETYPE_TOSS;
self->svflags |= SVF_DEADMONSTER;
self->nextthink = 0;
gi.linkentity (self);
}
mframe_t tank_frames_death1 [] =
{
ai_move, -7, NULL,
ai_move, -2, NULL,
ai_move, -2, NULL,
ai_move, 1, NULL,
ai_move, 3, NULL,
ai_move, 6, NULL,
ai_move, 1, NULL,
ai_move, 1, NULL,
ai_move, 2, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, -2, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, -3, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, -4, NULL,
ai_move, -6, NULL,
ai_move, -4, NULL,
ai_move, -5, NULL,
ai_move, -7, NULL,
ai_move, -15, tank_thud,
ai_move, -5, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL
};
mmove_t tank_move_death = {FRAME_death101, FRAME_death132, tank_frames_death1, tank_dead};
void tank_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
{
int n;
// check for gib
if (self->health <= self->gib_health)
{
gi.sound (self, CHAN_VOICE, gi.soundindex ("misc/udeath.wav"), 1, ATTN_NORM, 0);
for (n= 0; n < 1 /*4*/; n++)
ThrowGib (self, "models/objects/gibs/sm_meat/tris.md2", damage, GIB_ORGANIC);
for (n= 0; n < 4; n++)
ThrowGib (self, "models/objects/gibs/sm_metal/tris.md2", damage, GIB_METALLIC);
ThrowGib (self, "models/objects/gibs/chest/tris.md2", damage, GIB_ORGANIC);
ThrowHead (self, "models/objects/gibs/gear/tris.md2", damage, GIB_METALLIC);
self->deadflag = DEAD_DEAD;
return;
}
if (self->deadflag == DEAD_DEAD)
return;
// regular death
gi.sound (self, CHAN_VOICE, sound_die, 1, ATTN_NORM, 0);
self->deadflag = DEAD_DEAD;
self->takedamage = DAMAGE_YES;
self->monsterinfo.currentmove = &tank_move_death;
}
//
// monster_tank
//
/*QUAKED monster_tank (1 .5 0) (-32 -32 -16) (32 32 72) Ambush Trigger_Spawn Sight
*/
/*QUAKED monster_tank_commander (1 .5 0) (-32 -32 -16) (32 32 72) Ambush Trigger_Spawn Sight
*/
void SP_monster_tank (edict_t *self)
{
if (deathmatch->value)
{
G_FreeEdict (self);
return;
}
self->s.modelindex = gi.modelindex ("models/monsters/tank/tris.md2");
VectorSet (self->mins, -32, -32, -16);
VectorSet (self->maxs, 32, 32, 72);
self->movetype = MOVETYPE_STEP;
self->solid = SOLID_BBOX;
sound_pain = gi.soundindex ("tank/tnkpain2.wav");
sound_thud = gi.soundindex ("tank/tnkdeth2.wav");
sound_idle = gi.soundindex ("tank/tnkidle1.wav");
sound_die = gi.soundindex ("tank/death.wav");
sound_step = gi.soundindex ("tank/step.wav");
sound_windup = gi.soundindex ("tank/tnkatck4.wav");
sound_strike = gi.soundindex ("tank/tnkatck5.wav");
sound_sight = gi.soundindex ("tank/sight1.wav");
gi.soundindex ("tank/tnkatck1.wav");
gi.soundindex ("tank/tnkatk2a.wav");
gi.soundindex ("tank/tnkatk2b.wav");
gi.soundindex ("tank/tnkatk2c.wav");
gi.soundindex ("tank/tnkatk2d.wav");
gi.soundindex ("tank/tnkatk2e.wav");
gi.soundindex ("tank/tnkatck3.wav");
if (strcmp(self->classname, "monster_tank_commander") == 0)
{
self->health = 1000;
self->gib_health = -225;
}
else
{
self->health = 750;
self->gib_health = -200;
}
self->mass = 500;
self->pain = tank_pain;
self->die = tank_die;
self->monsterinfo.stand = tank_stand;
self->monsterinfo.walk = tank_walk;
self->monsterinfo.run = tank_run;
self->monsterinfo.dodge = NULL;
self->monsterinfo.attack = tank_attack;
self->monsterinfo.melee = NULL;
self->monsterinfo.sight = tank_sight;
self->monsterinfo.idle = tank_idle;
gi.linkentity (self);
self->monsterinfo.currentmove = &tank_move_stand;
self->monsterinfo.scale = MODEL_SCALE;
walkmonster_start(self);
if (strcmp(self->classname, "monster_tank_commander") == 0)
self->s.skinnum = 2;
}

319
game/m_tank.h Normal file
View File

@ -0,0 +1,319 @@
/*
Copyright (C) 1997-2001 Id Software, Inc.
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 the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
// G:\quake2\baseq2\models/monsters/tank
// This file generated by qdata - Do NOT Modify
#define FRAME_stand01 0
#define FRAME_stand02 1
#define FRAME_stand03 2
#define FRAME_stand04 3
#define FRAME_stand05 4
#define FRAME_stand06 5
#define FRAME_stand07 6
#define FRAME_stand08 7
#define FRAME_stand09 8
#define FRAME_stand10 9
#define FRAME_stand11 10
#define FRAME_stand12 11
#define FRAME_stand13 12
#define FRAME_stand14 13
#define FRAME_stand15 14
#define FRAME_stand16 15
#define FRAME_stand17 16
#define FRAME_stand18 17
#define FRAME_stand19 18
#define FRAME_stand20 19
#define FRAME_stand21 20
#define FRAME_stand22 21
#define FRAME_stand23 22
#define FRAME_stand24 23
#define FRAME_stand25 24
#define FRAME_stand26 25
#define FRAME_stand27 26
#define FRAME_stand28 27
#define FRAME_stand29 28
#define FRAME_stand30 29
#define FRAME_walk01 30
#define FRAME_walk02 31
#define FRAME_walk03 32
#define FRAME_walk04 33
#define FRAME_walk05 34
#define FRAME_walk06 35
#define FRAME_walk07 36
#define FRAME_walk08 37
#define FRAME_walk09 38
#define FRAME_walk10 39
#define FRAME_walk11 40
#define FRAME_walk12 41
#define FRAME_walk13 42
#define FRAME_walk14 43
#define FRAME_walk15 44
#define FRAME_walk16 45
#define FRAME_walk17 46
#define FRAME_walk18 47
#define FRAME_walk19 48
#define FRAME_walk20 49
#define FRAME_walk21 50
#define FRAME_walk22 51
#define FRAME_walk23 52
#define FRAME_walk24 53
#define FRAME_walk25 54
#define FRAME_attak101 55
#define FRAME_attak102 56
#define FRAME_attak103 57
#define FRAME_attak104 58
#define FRAME_attak105 59
#define FRAME_attak106 60
#define FRAME_attak107 61
#define FRAME_attak108 62
#define FRAME_attak109 63
#define FRAME_attak110 64
#define FRAME_attak111 65
#define FRAME_attak112 66
#define FRAME_attak113 67
#define FRAME_attak114 68
#define FRAME_attak115 69
#define FRAME_attak116 70
#define FRAME_attak117 71
#define FRAME_attak118 72
#define FRAME_attak119 73
#define FRAME_attak120 74
#define FRAME_attak121 75
#define FRAME_attak122 76
#define FRAME_attak201 77
#define FRAME_attak202 78
#define FRAME_attak203 79
#define FRAME_attak204 80
#define FRAME_attak205 81
#define FRAME_attak206 82
#define FRAME_attak207 83
#define FRAME_attak208 84
#define FRAME_attak209 85
#define FRAME_attak210 86
#define FRAME_attak211 87
#define FRAME_attak212 88
#define FRAME_attak213 89
#define FRAME_attak214 90
#define FRAME_attak215 91
#define FRAME_attak216 92
#define FRAME_attak217 93
#define FRAME_attak218 94
#define FRAME_attak219 95
#define FRAME_attak220 96
#define FRAME_attak221 97
#define FRAME_attak222 98
#define FRAME_attak223 99
#define FRAME_attak224 100
#define FRAME_attak225 101
#define FRAME_attak226 102
#define FRAME_attak227 103
#define FRAME_attak228 104
#define FRAME_attak229 105
#define FRAME_attak230 106
#define FRAME_attak231 107
#define FRAME_attak232 108
#define FRAME_attak233 109
#define FRAME_attak234 110
#define FRAME_attak235 111
#define FRAME_attak236 112
#define FRAME_attak237 113
#define FRAME_attak238 114
#define FRAME_attak301 115
#define FRAME_attak302 116
#define FRAME_attak303 117
#define FRAME_attak304 118
#define FRAME_attak305 119
#define FRAME_attak306 120
#define FRAME_attak307 121
#define FRAME_attak308 122
#define FRAME_attak309 123
#define FRAME_attak310 124
#define FRAME_attak311 125
#define FRAME_attak312 126
#define FRAME_attak313 127
#define FRAME_attak314 128
#define FRAME_attak315 129
#define FRAME_attak316 130
#define FRAME_attak317 131
#define FRAME_attak318 132
#define FRAME_attak319 133
#define FRAME_attak320 134
#define FRAME_attak321 135
#define FRAME_attak322 136
#define FRAME_attak323 137
#define FRAME_attak324 138
#define FRAME_attak325 139
#define FRAME_attak326 140
#define FRAME_attak327 141
#define FRAME_attak328 142
#define FRAME_attak329 143
#define FRAME_attak330 144
#define FRAME_attak331 145
#define FRAME_attak332 146
#define FRAME_attak333 147
#define FRAME_attak334 148
#define FRAME_attak335 149
#define FRAME_attak336 150
#define FRAME_attak337 151
#define FRAME_attak338 152
#define FRAME_attak339 153
#define FRAME_attak340 154
#define FRAME_attak341 155
#define FRAME_attak342 156
#define FRAME_attak343 157
#define FRAME_attak344 158
#define FRAME_attak345 159
#define FRAME_attak346 160
#define FRAME_attak347 161
#define FRAME_attak348 162
#define FRAME_attak349 163
#define FRAME_attak350 164
#define FRAME_attak351 165
#define FRAME_attak352 166
#define FRAME_attak353 167
#define FRAME_attak401 168
#define FRAME_attak402 169
#define FRAME_attak403 170
#define FRAME_attak404 171
#define FRAME_attak405 172
#define FRAME_attak406 173
#define FRAME_attak407 174
#define FRAME_attak408 175
#define FRAME_attak409 176
#define FRAME_attak410 177
#define FRAME_attak411 178
#define FRAME_attak412 179
#define FRAME_attak413 180
#define FRAME_attak414 181
#define FRAME_attak415 182
#define FRAME_attak416 183
#define FRAME_attak417 184
#define FRAME_attak418 185
#define FRAME_attak419 186
#define FRAME_attak420 187
#define FRAME_attak421 188
#define FRAME_attak422 189
#define FRAME_attak423 190
#define FRAME_attak424 191
#define FRAME_attak425 192
#define FRAME_attak426 193
#define FRAME_attak427 194
#define FRAME_attak428 195
#define FRAME_attak429 196
#define FRAME_pain101 197
#define FRAME_pain102 198
#define FRAME_pain103 199
#define FRAME_pain104 200
#define FRAME_pain201 201
#define FRAME_pain202 202
#define FRAME_pain203 203
#define FRAME_pain204 204
#define FRAME_pain205 205
#define FRAME_pain301 206
#define FRAME_pain302 207
#define FRAME_pain303 208
#define FRAME_pain304 209
#define FRAME_pain305 210
#define FRAME_pain306 211
#define FRAME_pain307 212
#define FRAME_pain308 213
#define FRAME_pain309 214
#define FRAME_pain310 215
#define FRAME_pain311 216
#define FRAME_pain312 217
#define FRAME_pain313 218
#define FRAME_pain314 219
#define FRAME_pain315 220
#define FRAME_pain316 221
#define FRAME_death101 222
#define FRAME_death102 223
#define FRAME_death103 224
#define FRAME_death104 225
#define FRAME_death105 226
#define FRAME_death106 227
#define FRAME_death107 228
#define FRAME_death108 229
#define FRAME_death109 230
#define FRAME_death110 231
#define FRAME_death111 232
#define FRAME_death112 233
#define FRAME_death113 234
#define FRAME_death114 235
#define FRAME_death115 236
#define FRAME_death116 237
#define FRAME_death117 238
#define FRAME_death118 239
#define FRAME_death119 240
#define FRAME_death120 241
#define FRAME_death121 242
#define FRAME_death122 243
#define FRAME_death123 244
#define FRAME_death124 245
#define FRAME_death125 246
#define FRAME_death126 247
#define FRAME_death127 248
#define FRAME_death128 249
#define FRAME_death129 250
#define FRAME_death130 251
#define FRAME_death131 252
#define FRAME_death132 253
#define FRAME_recln101 254
#define FRAME_recln102 255
#define FRAME_recln103 256
#define FRAME_recln104 257
#define FRAME_recln105 258
#define FRAME_recln106 259
#define FRAME_recln107 260
#define FRAME_recln108 261
#define FRAME_recln109 262
#define FRAME_recln110 263
#define FRAME_recln111 264
#define FRAME_recln112 265
#define FRAME_recln113 266
#define FRAME_recln114 267
#define FRAME_recln115 268
#define FRAME_recln116 269
#define FRAME_recln117 270
#define FRAME_recln118 271
#define FRAME_recln119 272
#define FRAME_recln120 273
#define FRAME_recln121 274
#define FRAME_recln122 275
#define FRAME_recln123 276
#define FRAME_recln124 277
#define FRAME_recln125 278
#define FRAME_recln126 279
#define FRAME_recln127 280
#define FRAME_recln128 281
#define FRAME_recln129 282
#define FRAME_recln130 283
#define FRAME_recln131 284
#define FRAME_recln132 285
#define FRAME_recln133 286
#define FRAME_recln134 287
#define FRAME_recln135 288
#define FRAME_recln136 289
#define FRAME_recln137 290
#define FRAME_recln138 291
#define FRAME_recln139 292
#define FRAME_recln140 293
#define MODEL_SCALE 1.000000

1805
game/p_client.c Normal file

File diff suppressed because it is too large Load Diff

571
game/p_hud.c Normal file
View File

@ -0,0 +1,571 @@
/*
Copyright (C) 1997-2001 Id Software, Inc.
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 the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "g_local.h"
/*
======================================================================
INTERMISSION
======================================================================
*/
void MoveClientToIntermission (edict_t *ent)
{
if (deathmatch->value || coop->value)
ent->client->showscores = true;
VectorCopy (level.intermission_origin, ent->s.origin);
ent->client->ps.pmove.origin[0] = level.intermission_origin[0]*8;
ent->client->ps.pmove.origin[1] = level.intermission_origin[1]*8;
ent->client->ps.pmove.origin[2] = level.intermission_origin[2]*8;
VectorCopy (level.intermission_angle, ent->client->ps.viewangles);
ent->client->ps.pmove.pm_type = PM_FREEZE;
ent->client->ps.gunindex = 0;
ent->client->ps.blend[3] = 0;
ent->client->ps.rdflags &= ~RDF_UNDERWATER;
// clean up powerup info
ent->client->quad_framenum = 0;
ent->client->invincible_framenum = 0;
ent->client->breather_framenum = 0;
ent->client->enviro_framenum = 0;
ent->client->grenade_blew_up = false;
ent->client->grenade_time = 0;
ent->viewheight = 0;
ent->s.modelindex = 0;
ent->s.modelindex2 = 0;
ent->s.modelindex3 = 0;
ent->s.modelindex = 0;
ent->s.effects = 0;
ent->s.sound = 0;
ent->solid = SOLID_NOT;
// add the layout
if (deathmatch->value || coop->value)
{
DeathmatchScoreboardMessage (ent, NULL);
gi.unicast (ent, true);
}
}
void BeginIntermission (edict_t *targ)
{
int i, n;
edict_t *ent, *client;
if (level.intermissiontime)
return; // already activated
game.autosaved = false;
// respawn any dead clients
for (i=0 ; i<maxclients->value ; i++)
{
client = g_edicts + 1 + i;
if (!client->inuse)
continue;
if (client->health <= 0)
respawn(client);
}
level.intermissiontime = level.time;
level.changemap = targ->map;
if (strstr(level.changemap, "*"))
{
if (coop->value)
{
for (i=0 ; i<maxclients->value ; i++)
{
client = g_edicts + 1 + i;
if (!client->inuse)
continue;
// strip players of all keys between units
for (n = 0; n < MAX_ITEMS; n++)
{
if (itemlist[n].flags & IT_KEY)
client->client->pers.inventory[n] = 0;
}
}
}
}
else
{
if (!deathmatch->value)
{
level.exitintermission = 1; // go immediately to the next level
return;
}
}
level.exitintermission = 0;
// find an intermission spot
ent = G_Find (NULL, FOFS(classname), "info_player_intermission");
if (!ent)
{ // the map creator forgot to put in an intermission point...
ent = G_Find (NULL, FOFS(classname), "info_player_start");
if (!ent)
ent = G_Find (NULL, FOFS(classname), "info_player_deathmatch");
}
else
{ // chose one of four spots
i = rand() & 3;
while (i--)
{
ent = G_Find (ent, FOFS(classname), "info_player_intermission");
if (!ent) // wrap around the list
ent = G_Find (ent, FOFS(classname), "info_player_intermission");
}
}
VectorCopy (ent->s.origin, level.intermission_origin);
VectorCopy (ent->s.angles, level.intermission_angle);
// move all clients to the intermission point
for (i=0 ; i<maxclients->value ; i++)
{
client = g_edicts + 1 + i;
if (!client->inuse)
continue;
MoveClientToIntermission (client);
}
}
/*
==================
DeathmatchScoreboardMessage
==================
*/
void DeathmatchScoreboardMessage (edict_t *ent, edict_t *killer)
{
char entry[1024];
char string[1400];
int stringlength;
int i, j, k;
int sorted[MAX_CLIENTS];
int sortedscores[MAX_CLIENTS];
int score, total;
int picnum;
int x, y;
gclient_t *cl;
edict_t *cl_ent;
char *tag;
// sort the clients by score
total = 0;
for (i=0 ; i<game.maxclients ; i++)
{
cl_ent = g_edicts + 1 + i;
if (!cl_ent->inuse || game.clients[i].resp.spectator)
continue;
score = game.clients[i].resp.score;
for (j=0 ; j<total ; j++)
{
if (score > sortedscores[j])
break;
}
for (k=total ; k>j ; k--)
{
sorted[k] = sorted[k-1];
sortedscores[k] = sortedscores[k-1];
}
sorted[j] = i;
sortedscores[j] = score;
total++;
}
// print level name and exit rules
string[0] = 0;
stringlength = strlen(string);
// add the clients in sorted order
if (total > 12)
total = 12;
for (i=0 ; i<total ; i++)
{
cl = &game.clients[sorted[i]];
cl_ent = g_edicts + 1 + sorted[i];
picnum = gi.imageindex ("i_fixme");
x = (i>=6) ? 160 : 0;
y = 32 + 32 * (i%6);
// add a dogtag
if (cl_ent == ent)
tag = "tag1";
else if (cl_ent == killer)
tag = "tag2";
else
tag = NULL;
if (tag)
{
Com_sprintf (entry, sizeof(entry),
"xv %i yv %i picn %s ",x+32, y, tag);
j = strlen(entry);
if (stringlength + j > 1024)
break;
strcpy (string + stringlength, entry);
stringlength += j;
}
// send the layout
Com_sprintf (entry, sizeof(entry),
"client %i %i %i %i %i %i ",
x, y, sorted[i], cl->resp.score, cl->ping, (level.framenum - cl->resp.enterframe)/600);
j = strlen(entry);
if (stringlength + j > 1024)
break;
strcpy (string + stringlength, entry);
stringlength += j;
}
gi.WriteByte (svc_layout);
gi.WriteString (string);
}
/*
==================
DeathmatchScoreboard
Draw instead of help message.
Note that it isn't that hard to overflow the 1400 byte message limit!
==================
*/
void DeathmatchScoreboard (edict_t *ent)
{
DeathmatchScoreboardMessage (ent, ent->enemy);
gi.unicast (ent, true);
}
/*
==================
Cmd_Score_f
Display the scoreboard
==================
*/
void Cmd_Score_f (edict_t *ent)
{
ent->client->showinventory = false;
ent->client->showhelp = false;
if (!deathmatch->value && !coop->value)
return;
if (ent->client->showscores)
{
ent->client->showscores = false;
return;
}
ent->client->showscores = true;
DeathmatchScoreboard (ent);
}
/*
==================
HelpComputer
Draw help computer.
==================
*/
void HelpComputer (edict_t *ent)
{
char string[1024];
char *sk;
if (skill->value == 0)
sk = "easy";
else if (skill->value == 1)
sk = "medium";
else if (skill->value == 2)
sk = "hard";
else
sk = "hard+";
// send the layout
Com_sprintf (string, sizeof(string),
"xv 32 yv 8 picn help " // background
"xv 202 yv 12 string2 \"%s\" " // skill
"xv 0 yv 24 cstring2 \"%s\" " // level name
"xv 0 yv 54 cstring2 \"%s\" " // help 1
"xv 0 yv 110 cstring2 \"%s\" " // help 2
"xv 50 yv 164 string2 \" kills goals secrets\" "
"xv 50 yv 172 string2 \"%3i/%3i %i/%i %i/%i\" ",
sk,
level.level_name,
game.helpmessage1,
game.helpmessage2,
level.killed_monsters, level.total_monsters,
level.found_goals, level.total_goals,
level.found_secrets, level.total_secrets);
gi.WriteByte (svc_layout);
gi.WriteString (string);
gi.unicast (ent, true);
}
/*
==================
Cmd_Help_f
Display the current help message
==================
*/
void Cmd_Help_f (edict_t *ent)
{
// this is for backwards compatability
if (deathmatch->value)
{
Cmd_Score_f (ent);
return;
}
ent->client->showinventory = false;
ent->client->showscores = false;
if (ent->client->showhelp && (ent->client->pers.game_helpchanged == game.helpchanged))
{
ent->client->showhelp = false;
return;
}
ent->client->showhelp = true;
ent->client->pers.helpchanged = 0;
HelpComputer (ent);
}
//=======================================================================
/*
===============
G_SetStats
===============
*/
void G_SetStats (edict_t *ent)
{
gitem_t *item;
int index, cells;
int power_armor_type;
//
// health
//
ent->client->ps.stats[STAT_HEALTH_ICON] = level.pic_health;
ent->client->ps.stats[STAT_HEALTH] = ent->health;
//
// ammo
//
if (!ent->client->ammo_index /* || !ent->client->pers.inventory[ent->client->ammo_index] */)
{
ent->client->ps.stats[STAT_AMMO_ICON] = 0;
ent->client->ps.stats[STAT_AMMO] = 0;
}
else
{
item = &itemlist[ent->client->ammo_index];
ent->client->ps.stats[STAT_AMMO_ICON] = gi.imageindex (item->icon);
ent->client->ps.stats[STAT_AMMO] = ent->client->pers.inventory[ent->client->ammo_index];
}
//
// armor
//
power_armor_type = PowerArmorType (ent);
if (power_armor_type)
{
cells = ent->client->pers.inventory[ITEM_INDEX(FindItem ("cells"))];
if (cells == 0)
{ // ran out of cells for power armor
ent->flags &= ~FL_POWER_ARMOR;
gi.sound(ent, CHAN_ITEM, gi.soundindex("misc/power2.wav"), 1, ATTN_NORM, 0);
power_armor_type = 0;;
}
}
index = ArmorIndex (ent);
if (power_armor_type && (!index || (level.framenum & 8) ) )
{ // flash between power armor and other armor icon
ent->client->ps.stats[STAT_ARMOR_ICON] = gi.imageindex ("i_powershield");
ent->client->ps.stats[STAT_ARMOR] = cells;
}
else if (index)
{
item = GetItemByIndex (index);
ent->client->ps.stats[STAT_ARMOR_ICON] = gi.imageindex (item->icon);
ent->client->ps.stats[STAT_ARMOR] = ent->client->pers.inventory[index];
}
else
{
ent->client->ps.stats[STAT_ARMOR_ICON] = 0;
ent->client->ps.stats[STAT_ARMOR] = 0;
}
//
// pickup message
//
if (level.time > ent->client->pickup_msg_time)
{
ent->client->ps.stats[STAT_PICKUP_ICON] = 0;
ent->client->ps.stats[STAT_PICKUP_STRING] = 0;
}
//
// timers
//
if (ent->client->quad_framenum > level.framenum)
{
ent->client->ps.stats[STAT_TIMER_ICON] = gi.imageindex ("p_quad");
ent->client->ps.stats[STAT_TIMER] = (ent->client->quad_framenum - level.framenum)/10;
}
else if (ent->client->invincible_framenum > level.framenum)
{
ent->client->ps.stats[STAT_TIMER_ICON] = gi.imageindex ("p_invulnerability");
ent->client->ps.stats[STAT_TIMER] = (ent->client->invincible_framenum - level.framenum)/10;
}
else if (ent->client->enviro_framenum > level.framenum)
{
ent->client->ps.stats[STAT_TIMER_ICON] = gi.imageindex ("p_envirosuit");
ent->client->ps.stats[STAT_TIMER] = (ent->client->enviro_framenum - level.framenum)/10;
}
else if (ent->client->breather_framenum > level.framenum)
{
ent->client->ps.stats[STAT_TIMER_ICON] = gi.imageindex ("p_rebreather");
ent->client->ps.stats[STAT_TIMER] = (ent->client->breather_framenum - level.framenum)/10;
}
else
{
ent->client->ps.stats[STAT_TIMER_ICON] = 0;
ent->client->ps.stats[STAT_TIMER] = 0;
}
//
// selected item
//
if (ent->client->pers.selected_item == -1)
ent->client->ps.stats[STAT_SELECTED_ICON] = 0;
else
ent->client->ps.stats[STAT_SELECTED_ICON] = gi.imageindex (itemlist[ent->client->pers.selected_item].icon);
ent->client->ps.stats[STAT_SELECTED_ITEM] = ent->client->pers.selected_item;
//
// layouts
//
ent->client->ps.stats[STAT_LAYOUTS] = 0;
if (deathmatch->value)
{
if (ent->client->pers.health <= 0 || level.intermissiontime
|| ent->client->showscores)
ent->client->ps.stats[STAT_LAYOUTS] |= 1;
if (ent->client->showinventory && ent->client->pers.health > 0)
ent->client->ps.stats[STAT_LAYOUTS] |= 2;
}
else
{
if (ent->client->showscores || ent->client->showhelp)
ent->client->ps.stats[STAT_LAYOUTS] |= 1;
if (ent->client->showinventory && ent->client->pers.health > 0)
ent->client->ps.stats[STAT_LAYOUTS] |= 2;
}
//
// frags
//
ent->client->ps.stats[STAT_FRAGS] = ent->client->resp.score;
//
// help icon / current weapon if not shown
//
if (ent->client->pers.helpchanged && (level.framenum&8) )
ent->client->ps.stats[STAT_HELPICON] = gi.imageindex ("i_help");
else if ( (ent->client->pers.hand == CENTER_HANDED || ent->client->ps.fov > 91)
&& ent->client->pers.weapon)
ent->client->ps.stats[STAT_HELPICON] = gi.imageindex (ent->client->pers.weapon->icon);
else
ent->client->ps.stats[STAT_HELPICON] = 0;
ent->client->ps.stats[STAT_SPECTATOR] = 0;
}
/*
===============
G_CheckChaseStats
===============
*/
void G_CheckChaseStats (edict_t *ent)
{
int i;
gclient_t *cl;
for (i = 1; i <= maxclients->value; i++) {
cl = g_edicts[i].client;
if (!g_edicts[i].inuse || cl->chase_target != ent)
continue;
memcpy(cl->ps.stats, ent->client->ps.stats, sizeof(cl->ps.stats));
G_SetSpectatorStats(g_edicts + i);
}
}
/*
===============
G_SetSpectatorStats
===============
*/
void G_SetSpectatorStats (edict_t *ent)
{
gclient_t *cl = ent->client;
if (!cl->chase_target)
G_SetStats (ent);
cl->ps.stats[STAT_SPECTATOR] = 1;
// layouts are independant in spectator
cl->ps.stats[STAT_LAYOUTS] = 0;
if (cl->pers.health <= 0 || level.intermissiontime || cl->showscores)
cl->ps.stats[STAT_LAYOUTS] |= 1;
if (cl->showinventory && cl->pers.health > 0)
cl->ps.stats[STAT_LAYOUTS] |= 2;
if (cl->chase_target && cl->chase_target->inuse)
cl->ps.stats[STAT_CHASE] = CS_PLAYERSKINS +
(cl->chase_target - g_edicts) - 1;
else
cl->ps.stats[STAT_CHASE] = 0;
}

146
game/p_trail.c Normal file
View File

@ -0,0 +1,146 @@
/*
Copyright (C) 1997-2001 Id Software, Inc.
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 the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "g_local.h"
/*
==============================================================================
PLAYER TRAIL
==============================================================================
This is a circular list containing the a list of points of where
the player has been recently. It is used by monsters for pursuit.
.origin the spot
.owner forward link
.aiment backward link
*/
#define TRAIL_LENGTH 8
edict_t *trail[TRAIL_LENGTH];
int trail_head;
qboolean trail_active = false;
#define NEXT(n) (((n) + 1) & (TRAIL_LENGTH - 1))
#define PREV(n) (((n) - 1) & (TRAIL_LENGTH - 1))
void PlayerTrail_Init (void)
{
int n;
if (deathmatch->value /* FIXME || coop */)
return;
for (n = 0; n < TRAIL_LENGTH; n++)
{
trail[n] = G_Spawn();
trail[n]->classname = "player_trail";
}
trail_head = 0;
trail_active = true;
}
void PlayerTrail_Add (vec3_t spot)
{
vec3_t temp;
if (!trail_active)
return;
VectorCopy (spot, trail[trail_head]->s.origin);
trail[trail_head]->timestamp = level.time;
VectorSubtract (spot, trail[PREV(trail_head)]->s.origin, temp);
trail[trail_head]->s.angles[1] = vectoyaw (temp);
trail_head = NEXT(trail_head);
}
void PlayerTrail_New (vec3_t spot)
{
if (!trail_active)
return;
PlayerTrail_Init ();
PlayerTrail_Add (spot);
}
edict_t *PlayerTrail_PickFirst (edict_t *self)
{
int marker;
int n;
if (!trail_active)
return NULL;
for (marker = trail_head, n = TRAIL_LENGTH; n; n--)
{
if(trail[marker]->timestamp <= self->monsterinfo.trail_time)
marker = NEXT(marker);
else
break;
}
if (visible(self, trail[marker]))
{
return trail[marker];
}
if (visible(self, trail[PREV(marker)]))
{
return trail[PREV(marker)];
}
return trail[marker];
}
edict_t *PlayerTrail_PickNext (edict_t *self)
{
int marker;
int n;
if (!trail_active)
return NULL;
for (marker = trail_head, n = TRAIL_LENGTH; n; n--)
{
if(trail[marker]->timestamp <= self->monsterinfo.trail_time)
marker = NEXT(marker);
else
break;
}
return trail[marker];
}
edict_t *PlayerTrail_LastSpot (void)
{
return trail[PREV(trail_head)];
}

1087
game/p_view.c Normal file

File diff suppressed because it is too large Load Diff

1434
game/p_weapon.c Normal file

File diff suppressed because it is too large Load Diff

1418
game/q_shared.c Normal file

File diff suppressed because it is too large Load Diff

1200
game/q_shared.h Normal file

File diff suppressed because it is too large Load Diff