mirror of
https://github.com/id-Software/quake2-rerelease-dll.git
synced 2026-03-19 16:39:46 +01:00
Initial commit
This commit is contained in:
1117
original/baseq2/g_ai.c
Normal file
1117
original/baseq2/g_ai.c
Normal file
File diff suppressed because it is too large
Load Diff
175
original/baseq2/g_chase.c
Normal file
175
original/baseq2/g_chase.c
Normal file
@@ -0,0 +1,175 @@
|
||||
/*
|
||||
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 UpdateChaseCam(edict_t *ent)
|
||||
{
|
||||
vec3_t o, ownerv, goal;
|
||||
edict_t *targ;
|
||||
vec3_t forward, right;
|
||||
trace_t trace;
|
||||
int i;
|
||||
vec3_t oldgoal;
|
||||
vec3_t angles;
|
||||
|
||||
// is our chase target gone?
|
||||
if (!ent->client->chase_target->inuse
|
||||
|| ent->client->chase_target->client->resp.spectator) {
|
||||
edict_t *old = ent->client->chase_target;
|
||||
ChaseNext(ent);
|
||||
if (ent->client->chase_target == old) {
|
||||
ent->client->chase_target = NULL;
|
||||
ent->client->ps.pmove.pm_flags &= ~PMF_NO_PREDICTION;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
targ = ent->client->chase_target;
|
||||
|
||||
VectorCopy(targ->s.origin, ownerv);
|
||||
VectorCopy(ent->s.origin, oldgoal);
|
||||
|
||||
ownerv[2] += targ->viewheight;
|
||||
|
||||
VectorCopy(targ->client->v_angle, angles);
|
||||
if (angles[PITCH] > 56)
|
||||
angles[PITCH] = 56;
|
||||
AngleVectors (angles, forward, right, NULL);
|
||||
VectorNormalize(forward);
|
||||
VectorMA(ownerv, -30, forward, o);
|
||||
|
||||
if (o[2] < targ->s.origin[2] + 20)
|
||||
o[2] = targ->s.origin[2] + 20;
|
||||
|
||||
// jump animation lifts
|
||||
if (!targ->groundentity)
|
||||
o[2] += 16;
|
||||
|
||||
trace = gi.trace(ownerv, vec3_origin, vec3_origin, o, targ, MASK_SOLID);
|
||||
|
||||
VectorCopy(trace.endpos, goal);
|
||||
|
||||
VectorMA(goal, 2, forward, goal);
|
||||
|
||||
// pad for floors and ceilings
|
||||
VectorCopy(goal, o);
|
||||
o[2] += 6;
|
||||
trace = gi.trace(goal, vec3_origin, vec3_origin, o, targ, MASK_SOLID);
|
||||
if (trace.fraction < 1) {
|
||||
VectorCopy(trace.endpos, goal);
|
||||
goal[2] -= 6;
|
||||
}
|
||||
|
||||
VectorCopy(goal, o);
|
||||
o[2] -= 6;
|
||||
trace = gi.trace(goal, vec3_origin, vec3_origin, o, targ, MASK_SOLID);
|
||||
if (trace.fraction < 1) {
|
||||
VectorCopy(trace.endpos, goal);
|
||||
goal[2] += 6;
|
||||
}
|
||||
|
||||
if (targ->deadflag)
|
||||
ent->client->ps.pmove.pm_type = PM_DEAD;
|
||||
else
|
||||
ent->client->ps.pmove.pm_type = PM_FREEZE;
|
||||
|
||||
VectorCopy(goal, ent->s.origin);
|
||||
for (i=0 ; i<3 ; i++)
|
||||
ent->client->ps.pmove.delta_angles[i] = ANGLE2SHORT(targ->client->v_angle[i] - ent->client->resp.cmd_angles[i]);
|
||||
|
||||
if (targ->deadflag) {
|
||||
ent->client->ps.viewangles[ROLL] = 40;
|
||||
ent->client->ps.viewangles[PITCH] = -15;
|
||||
ent->client->ps.viewangles[YAW] = targ->client->killer_yaw;
|
||||
} else {
|
||||
VectorCopy(targ->client->v_angle, ent->client->ps.viewangles);
|
||||
VectorCopy(targ->client->v_angle, ent->client->v_angle);
|
||||
}
|
||||
|
||||
ent->viewheight = 0;
|
||||
ent->client->ps.pmove.pm_flags |= PMF_NO_PREDICTION;
|
||||
gi.linkentity(ent);
|
||||
}
|
||||
|
||||
void ChaseNext(edict_t *ent)
|
||||
{
|
||||
int i;
|
||||
edict_t *e;
|
||||
|
||||
if (!ent->client->chase_target)
|
||||
return;
|
||||
|
||||
i = ent->client->chase_target - g_edicts;
|
||||
do {
|
||||
i++;
|
||||
if (i > maxclients->value)
|
||||
i = 1;
|
||||
e = g_edicts + i;
|
||||
if (!e->inuse)
|
||||
continue;
|
||||
if (!e->client->resp.spectator)
|
||||
break;
|
||||
} while (e != ent->client->chase_target);
|
||||
|
||||
ent->client->chase_target = e;
|
||||
ent->client->update_chase = true;
|
||||
}
|
||||
|
||||
void ChasePrev(edict_t *ent)
|
||||
{
|
||||
int i;
|
||||
edict_t *e;
|
||||
|
||||
if (!ent->client->chase_target)
|
||||
return;
|
||||
|
||||
i = ent->client->chase_target - g_edicts;
|
||||
do {
|
||||
i--;
|
||||
if (i < 1)
|
||||
i = maxclients->value;
|
||||
e = g_edicts + i;
|
||||
if (!e->inuse)
|
||||
continue;
|
||||
if (!e->client->resp.spectator)
|
||||
break;
|
||||
} while (e != ent->client->chase_target);
|
||||
|
||||
ent->client->chase_target = e;
|
||||
ent->client->update_chase = true;
|
||||
}
|
||||
|
||||
void GetChaseTarget(edict_t *ent)
|
||||
{
|
||||
int i;
|
||||
edict_t *other;
|
||||
|
||||
for (i = 1; i <= maxclients->value; i++) {
|
||||
other = g_edicts + i;
|
||||
if (other->inuse && !other->client->resp.spectator) {
|
||||
ent->client->chase_target = other;
|
||||
ent->client->update_chase = true;
|
||||
UpdateChaseCam(ent);
|
||||
return;
|
||||
}
|
||||
}
|
||||
gi.centerprintf(ent, "No other players to chase.");
|
||||
}
|
||||
|
||||
992
original/baseq2/g_cmds.c
Normal file
992
original/baseq2/g_cmds.c
Normal file
@@ -0,0 +1,992 @@
|
||||
/*
|
||||
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"
|
||||
#include "m_player.h"
|
||||
|
||||
|
||||
char *ClientTeam (edict_t *ent)
|
||||
{
|
||||
char *p;
|
||||
static char value[512];
|
||||
|
||||
value[0] = 0;
|
||||
|
||||
if (!ent->client)
|
||||
return value;
|
||||
|
||||
strcpy(value, Info_ValueForKey (ent->client->pers.userinfo, "skin"));
|
||||
p = strchr(value, '/');
|
||||
if (!p)
|
||||
return value;
|
||||
|
||||
if ((int)(dmflags->value) & DF_MODELTEAMS)
|
||||
{
|
||||
*p = 0;
|
||||
return value;
|
||||
}
|
||||
|
||||
// if ((int)(dmflags->value) & DF_SKINTEAMS)
|
||||
return ++p;
|
||||
}
|
||||
|
||||
qboolean OnSameTeam (edict_t *ent1, edict_t *ent2)
|
||||
{
|
||||
char ent1Team [512];
|
||||
char ent2Team [512];
|
||||
|
||||
if (!((int)(dmflags->value) & (DF_MODELTEAMS | DF_SKINTEAMS)))
|
||||
return false;
|
||||
|
||||
strcpy (ent1Team, ClientTeam (ent1));
|
||||
strcpy (ent2Team, ClientTeam (ent2));
|
||||
|
||||
if (strcmp(ent1Team, ent2Team) == 0)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void SelectNextItem (edict_t *ent, int itflags)
|
||||
{
|
||||
gclient_t *cl;
|
||||
int i, index;
|
||||
gitem_t *it;
|
||||
|
||||
cl = ent->client;
|
||||
|
||||
if (cl->chase_target) {
|
||||
ChaseNext(ent);
|
||||
return;
|
||||
}
|
||||
|
||||
// scan for the next valid one
|
||||
for (i=1 ; i<=MAX_ITEMS ; i++)
|
||||
{
|
||||
index = (cl->pers.selected_item + i)%MAX_ITEMS;
|
||||
if (!cl->pers.inventory[index])
|
||||
continue;
|
||||
it = &itemlist[index];
|
||||
if (!it->use)
|
||||
continue;
|
||||
if (!(it->flags & itflags))
|
||||
continue;
|
||||
|
||||
cl->pers.selected_item = index;
|
||||
return;
|
||||
}
|
||||
|
||||
cl->pers.selected_item = -1;
|
||||
}
|
||||
|
||||
void SelectPrevItem (edict_t *ent, int itflags)
|
||||
{
|
||||
gclient_t *cl;
|
||||
int i, index;
|
||||
gitem_t *it;
|
||||
|
||||
cl = ent->client;
|
||||
|
||||
if (cl->chase_target) {
|
||||
ChasePrev(ent);
|
||||
return;
|
||||
}
|
||||
|
||||
// scan for the next valid one
|
||||
for (i=1 ; i<=MAX_ITEMS ; i++)
|
||||
{
|
||||
index = (cl->pers.selected_item + MAX_ITEMS - i)%MAX_ITEMS;
|
||||
if (!cl->pers.inventory[index])
|
||||
continue;
|
||||
it = &itemlist[index];
|
||||
if (!it->use)
|
||||
continue;
|
||||
if (!(it->flags & itflags))
|
||||
continue;
|
||||
|
||||
cl->pers.selected_item = index;
|
||||
return;
|
||||
}
|
||||
|
||||
cl->pers.selected_item = -1;
|
||||
}
|
||||
|
||||
void ValidateSelectedItem (edict_t *ent)
|
||||
{
|
||||
gclient_t *cl;
|
||||
|
||||
cl = ent->client;
|
||||
|
||||
if (cl->pers.inventory[cl->pers.selected_item])
|
||||
return; // valid
|
||||
|
||||
SelectNextItem (ent, -1);
|
||||
}
|
||||
|
||||
|
||||
//=================================================================================
|
||||
|
||||
/*
|
||||
==================
|
||||
Cmd_Give_f
|
||||
|
||||
Give items to a client
|
||||
==================
|
||||
*/
|
||||
void Cmd_Give_f (edict_t *ent)
|
||||
{
|
||||
char *name;
|
||||
gitem_t *it;
|
||||
int index;
|
||||
int i;
|
||||
qboolean give_all;
|
||||
edict_t *it_ent;
|
||||
|
||||
if (deathmatch->value && !sv_cheats->value)
|
||||
{
|
||||
gi.cprintf (ent, PRINT_HIGH, "You must run the server with '+set cheats 1' to enable this command.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
name = gi.args();
|
||||
|
||||
if (Q_stricmp(name, "all") == 0)
|
||||
give_all = true;
|
||||
else
|
||||
give_all = false;
|
||||
|
||||
if (give_all || Q_stricmp(gi.argv(1), "health") == 0)
|
||||
{
|
||||
if (gi.argc() == 3)
|
||||
ent->health = atoi(gi.argv(2));
|
||||
else
|
||||
ent->health = ent->max_health;
|
||||
if (!give_all)
|
||||
return;
|
||||
}
|
||||
|
||||
if (give_all || Q_stricmp(name, "weapons") == 0)
|
||||
{
|
||||
for (i=0 ; i<game.num_items ; i++)
|
||||
{
|
||||
it = itemlist + i;
|
||||
if (!it->pickup)
|
||||
continue;
|
||||
if (!(it->flags & IT_WEAPON))
|
||||
continue;
|
||||
ent->client->pers.inventory[i] += 1;
|
||||
}
|
||||
if (!give_all)
|
||||
return;
|
||||
}
|
||||
|
||||
if (give_all || Q_stricmp(name, "ammo") == 0)
|
||||
{
|
||||
for (i=0 ; i<game.num_items ; i++)
|
||||
{
|
||||
it = itemlist + i;
|
||||
if (!it->pickup)
|
||||
continue;
|
||||
if (!(it->flags & IT_AMMO))
|
||||
continue;
|
||||
Add_Ammo (ent, it, 1000);
|
||||
}
|
||||
if (!give_all)
|
||||
return;
|
||||
}
|
||||
|
||||
if (give_all || Q_stricmp(name, "armor") == 0)
|
||||
{
|
||||
gitem_armor_t *info;
|
||||
|
||||
it = FindItem("Jacket Armor");
|
||||
ent->client->pers.inventory[ITEM_INDEX(it)] = 0;
|
||||
|
||||
it = FindItem("Combat Armor");
|
||||
ent->client->pers.inventory[ITEM_INDEX(it)] = 0;
|
||||
|
||||
it = FindItem("Body Armor");
|
||||
info = (gitem_armor_t *)it->info;
|
||||
ent->client->pers.inventory[ITEM_INDEX(it)] = info->max_count;
|
||||
|
||||
if (!give_all)
|
||||
return;
|
||||
}
|
||||
|
||||
if (give_all || Q_stricmp(name, "Power Shield") == 0)
|
||||
{
|
||||
it = FindItem("Power Shield");
|
||||
it_ent = G_Spawn();
|
||||
it_ent->classname = it->classname;
|
||||
SpawnItem (it_ent, it);
|
||||
Touch_Item (it_ent, ent, NULL, NULL);
|
||||
if (it_ent->inuse)
|
||||
G_FreeEdict(it_ent);
|
||||
|
||||
if (!give_all)
|
||||
return;
|
||||
}
|
||||
|
||||
if (give_all)
|
||||
{
|
||||
for (i=0 ; i<game.num_items ; i++)
|
||||
{
|
||||
it = itemlist + i;
|
||||
if (!it->pickup)
|
||||
continue;
|
||||
if (it->flags & (IT_ARMOR|IT_WEAPON|IT_AMMO))
|
||||
continue;
|
||||
ent->client->pers.inventory[i] = 1;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
it = FindItem (name);
|
||||
if (!it)
|
||||
{
|
||||
name = gi.argv(1);
|
||||
it = FindItem (name);
|
||||
if (!it)
|
||||
{
|
||||
gi.cprintf (ent, PRINT_HIGH, "unknown item\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!it->pickup)
|
||||
{
|
||||
gi.cprintf (ent, PRINT_HIGH, "non-pickup item\n");
|
||||
return;
|
||||
}
|
||||
|
||||
index = ITEM_INDEX(it);
|
||||
|
||||
if (it->flags & IT_AMMO)
|
||||
{
|
||||
if (gi.argc() == 3)
|
||||
ent->client->pers.inventory[index] = atoi(gi.argv(2));
|
||||
else
|
||||
ent->client->pers.inventory[index] += it->quantity;
|
||||
}
|
||||
else
|
||||
{
|
||||
it_ent = G_Spawn();
|
||||
it_ent->classname = it->classname;
|
||||
SpawnItem (it_ent, it);
|
||||
Touch_Item (it_ent, ent, NULL, NULL);
|
||||
if (it_ent->inuse)
|
||||
G_FreeEdict(it_ent);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
==================
|
||||
Cmd_God_f
|
||||
|
||||
Sets client to godmode
|
||||
|
||||
argv(0) god
|
||||
==================
|
||||
*/
|
||||
void Cmd_God_f (edict_t *ent)
|
||||
{
|
||||
char *msg;
|
||||
|
||||
if (deathmatch->value && !sv_cheats->value)
|
||||
{
|
||||
gi.cprintf (ent, PRINT_HIGH, "You must run the server with '+set cheats 1' to enable this command.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
ent->flags ^= FL_GODMODE;
|
||||
if (!(ent->flags & FL_GODMODE) )
|
||||
msg = "godmode OFF\n";
|
||||
else
|
||||
msg = "godmode ON\n";
|
||||
|
||||
gi.cprintf (ent, PRINT_HIGH, msg);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
==================
|
||||
Cmd_Notarget_f
|
||||
|
||||
Sets client to notarget
|
||||
|
||||
argv(0) notarget
|
||||
==================
|
||||
*/
|
||||
void Cmd_Notarget_f (edict_t *ent)
|
||||
{
|
||||
char *msg;
|
||||
|
||||
if (deathmatch->value && !sv_cheats->value)
|
||||
{
|
||||
gi.cprintf (ent, PRINT_HIGH, "You must run the server with '+set cheats 1' to enable this command.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
ent->flags ^= FL_NOTARGET;
|
||||
if (!(ent->flags & FL_NOTARGET) )
|
||||
msg = "notarget OFF\n";
|
||||
else
|
||||
msg = "notarget ON\n";
|
||||
|
||||
gi.cprintf (ent, PRINT_HIGH, msg);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
==================
|
||||
Cmd_Noclip_f
|
||||
|
||||
argv(0) noclip
|
||||
==================
|
||||
*/
|
||||
void Cmd_Noclip_f (edict_t *ent)
|
||||
{
|
||||
char *msg;
|
||||
|
||||
if (deathmatch->value && !sv_cheats->value)
|
||||
{
|
||||
gi.cprintf (ent, PRINT_HIGH, "You must run the server with '+set cheats 1' to enable this command.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (ent->movetype == MOVETYPE_NOCLIP)
|
||||
{
|
||||
ent->movetype = MOVETYPE_WALK;
|
||||
msg = "noclip OFF\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
ent->movetype = MOVETYPE_NOCLIP;
|
||||
msg = "noclip ON\n";
|
||||
}
|
||||
|
||||
gi.cprintf (ent, PRINT_HIGH, msg);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
==================
|
||||
Cmd_Use_f
|
||||
|
||||
Use an inventory item
|
||||
==================
|
||||
*/
|
||||
void Cmd_Use_f (edict_t *ent)
|
||||
{
|
||||
int index;
|
||||
gitem_t *it;
|
||||
char *s;
|
||||
|
||||
s = gi.args();
|
||||
it = FindItem (s);
|
||||
if (!it)
|
||||
{
|
||||
gi.cprintf (ent, PRINT_HIGH, "unknown item: %s\n", s);
|
||||
return;
|
||||
}
|
||||
if (!it->use)
|
||||
{
|
||||
gi.cprintf (ent, PRINT_HIGH, "Item is not usable.\n");
|
||||
return;
|
||||
}
|
||||
index = ITEM_INDEX(it);
|
||||
if (!ent->client->pers.inventory[index])
|
||||
{
|
||||
gi.cprintf (ent, PRINT_HIGH, "Out of item: %s\n", s);
|
||||
return;
|
||||
}
|
||||
|
||||
it->use (ent, it);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
==================
|
||||
Cmd_Drop_f
|
||||
|
||||
Drop an inventory item
|
||||
==================
|
||||
*/
|
||||
void Cmd_Drop_f (edict_t *ent)
|
||||
{
|
||||
int index;
|
||||
gitem_t *it;
|
||||
char *s;
|
||||
|
||||
s = gi.args();
|
||||
it = FindItem (s);
|
||||
if (!it)
|
||||
{
|
||||
gi.cprintf (ent, PRINT_HIGH, "unknown item: %s\n", s);
|
||||
return;
|
||||
}
|
||||
if (!it->drop)
|
||||
{
|
||||
gi.cprintf (ent, PRINT_HIGH, "Item is not dropable.\n");
|
||||
return;
|
||||
}
|
||||
index = ITEM_INDEX(it);
|
||||
if (!ent->client->pers.inventory[index])
|
||||
{
|
||||
gi.cprintf (ent, PRINT_HIGH, "Out of item: %s\n", s);
|
||||
return;
|
||||
}
|
||||
|
||||
it->drop (ent, it);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=================
|
||||
Cmd_Inven_f
|
||||
=================
|
||||
*/
|
||||
void Cmd_Inven_f (edict_t *ent)
|
||||
{
|
||||
int i;
|
||||
gclient_t *cl;
|
||||
|
||||
cl = ent->client;
|
||||
|
||||
cl->showscores = false;
|
||||
cl->showhelp = false;
|
||||
|
||||
if (cl->showinventory)
|
||||
{
|
||||
cl->showinventory = false;
|
||||
return;
|
||||
}
|
||||
|
||||
cl->showinventory = true;
|
||||
|
||||
gi.WriteByte (svc_inventory);
|
||||
for (i=0 ; i<MAX_ITEMS ; i++)
|
||||
{
|
||||
gi.WriteShort (cl->pers.inventory[i]);
|
||||
}
|
||||
gi.unicast (ent, true);
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
Cmd_InvUse_f
|
||||
=================
|
||||
*/
|
||||
void Cmd_InvUse_f (edict_t *ent)
|
||||
{
|
||||
gitem_t *it;
|
||||
|
||||
ValidateSelectedItem (ent);
|
||||
|
||||
if (ent->client->pers.selected_item == -1)
|
||||
{
|
||||
gi.cprintf (ent, PRINT_HIGH, "No item to use.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
it = &itemlist[ent->client->pers.selected_item];
|
||||
if (!it->use)
|
||||
{
|
||||
gi.cprintf (ent, PRINT_HIGH, "Item is not usable.\n");
|
||||
return;
|
||||
}
|
||||
it->use (ent, it);
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
Cmd_WeapPrev_f
|
||||
=================
|
||||
*/
|
||||
void Cmd_WeapPrev_f (edict_t *ent)
|
||||
{
|
||||
gclient_t *cl;
|
||||
int i, index;
|
||||
gitem_t *it;
|
||||
int selected_weapon;
|
||||
|
||||
cl = ent->client;
|
||||
|
||||
if (!cl->pers.weapon)
|
||||
return;
|
||||
|
||||
selected_weapon = ITEM_INDEX(cl->pers.weapon);
|
||||
|
||||
// scan for the next valid one
|
||||
for (i=1 ; i<=MAX_ITEMS ; i++)
|
||||
{
|
||||
index = (selected_weapon + i)%MAX_ITEMS;
|
||||
if (!cl->pers.inventory[index])
|
||||
continue;
|
||||
it = &itemlist[index];
|
||||
if (!it->use)
|
||||
continue;
|
||||
if (! (it->flags & IT_WEAPON) )
|
||||
continue;
|
||||
it->use (ent, it);
|
||||
if (cl->pers.weapon == it)
|
||||
return; // successful
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
Cmd_WeapNext_f
|
||||
=================
|
||||
*/
|
||||
void Cmd_WeapNext_f (edict_t *ent)
|
||||
{
|
||||
gclient_t *cl;
|
||||
int i, index;
|
||||
gitem_t *it;
|
||||
int selected_weapon;
|
||||
|
||||
cl = ent->client;
|
||||
|
||||
if (!cl->pers.weapon)
|
||||
return;
|
||||
|
||||
selected_weapon = ITEM_INDEX(cl->pers.weapon);
|
||||
|
||||
// scan for the next valid one
|
||||
for (i=1 ; i<=MAX_ITEMS ; i++)
|
||||
{
|
||||
index = (selected_weapon + MAX_ITEMS - i)%MAX_ITEMS;
|
||||
if (!cl->pers.inventory[index])
|
||||
continue;
|
||||
it = &itemlist[index];
|
||||
if (!it->use)
|
||||
continue;
|
||||
if (! (it->flags & IT_WEAPON) )
|
||||
continue;
|
||||
it->use (ent, it);
|
||||
if (cl->pers.weapon == it)
|
||||
return; // successful
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
Cmd_WeapLast_f
|
||||
=================
|
||||
*/
|
||||
void Cmd_WeapLast_f (edict_t *ent)
|
||||
{
|
||||
gclient_t *cl;
|
||||
int index;
|
||||
gitem_t *it;
|
||||
|
||||
cl = ent->client;
|
||||
|
||||
if (!cl->pers.weapon || !cl->pers.lastweapon)
|
||||
return;
|
||||
|
||||
index = ITEM_INDEX(cl->pers.lastweapon);
|
||||
if (!cl->pers.inventory[index])
|
||||
return;
|
||||
it = &itemlist[index];
|
||||
if (!it->use)
|
||||
return;
|
||||
if (! (it->flags & IT_WEAPON) )
|
||||
return;
|
||||
it->use (ent, it);
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
Cmd_InvDrop_f
|
||||
=================
|
||||
*/
|
||||
void Cmd_InvDrop_f (edict_t *ent)
|
||||
{
|
||||
gitem_t *it;
|
||||
|
||||
ValidateSelectedItem (ent);
|
||||
|
||||
if (ent->client->pers.selected_item == -1)
|
||||
{
|
||||
gi.cprintf (ent, PRINT_HIGH, "No item to drop.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
it = &itemlist[ent->client->pers.selected_item];
|
||||
if (!it->drop)
|
||||
{
|
||||
gi.cprintf (ent, PRINT_HIGH, "Item is not dropable.\n");
|
||||
return;
|
||||
}
|
||||
it->drop (ent, it);
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
Cmd_Kill_f
|
||||
=================
|
||||
*/
|
||||
void Cmd_Kill_f (edict_t *ent)
|
||||
{
|
||||
if((level.time - ent->client->respawn_time) < 5)
|
||||
return;
|
||||
ent->flags &= ~FL_GODMODE;
|
||||
ent->health = 0;
|
||||
meansOfDeath = MOD_SUICIDE;
|
||||
player_die (ent, ent, ent, 100000, vec3_origin);
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
Cmd_PutAway_f
|
||||
=================
|
||||
*/
|
||||
void Cmd_PutAway_f (edict_t *ent)
|
||||
{
|
||||
ent->client->showscores = false;
|
||||
ent->client->showhelp = false;
|
||||
ent->client->showinventory = false;
|
||||
}
|
||||
|
||||
|
||||
int PlayerSort (void const *a, void const *b)
|
||||
{
|
||||
int anum, bnum;
|
||||
|
||||
anum = *(int *)a;
|
||||
bnum = *(int *)b;
|
||||
|
||||
anum = game.clients[anum].ps.stats[STAT_FRAGS];
|
||||
bnum = game.clients[bnum].ps.stats[STAT_FRAGS];
|
||||
|
||||
if (anum < bnum)
|
||||
return -1;
|
||||
if (anum > bnum)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
Cmd_Players_f
|
||||
=================
|
||||
*/
|
||||
void Cmd_Players_f (edict_t *ent)
|
||||
{
|
||||
int i;
|
||||
int count;
|
||||
char small[64];
|
||||
char large[1280];
|
||||
int index[256];
|
||||
|
||||
count = 0;
|
||||
for (i = 0 ; i < maxclients->value ; i++)
|
||||
if (game.clients[i].pers.connected)
|
||||
{
|
||||
index[count] = i;
|
||||
count++;
|
||||
}
|
||||
|
||||
// sort by frags
|
||||
qsort (index, count, sizeof(index[0]), PlayerSort);
|
||||
|
||||
// print information
|
||||
large[0] = 0;
|
||||
|
||||
for (i = 0 ; i < count ; i++)
|
||||
{
|
||||
Com_sprintf (small, sizeof(small), "%3i %s\n",
|
||||
game.clients[index[i]].ps.stats[STAT_FRAGS],
|
||||
game.clients[index[i]].pers.netname);
|
||||
if (strlen (small) + strlen(large) > sizeof(large) - 100 )
|
||||
{ // can't print all of them in one packet
|
||||
strcat (large, "...\n");
|
||||
break;
|
||||
}
|
||||
strcat (large, small);
|
||||
}
|
||||
|
||||
gi.cprintf (ent, PRINT_HIGH, "%s\n%i players\n", large, count);
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
Cmd_Wave_f
|
||||
=================
|
||||
*/
|
||||
void Cmd_Wave_f (edict_t *ent)
|
||||
{
|
||||
int i;
|
||||
|
||||
i = atoi (gi.argv(1));
|
||||
|
||||
// can't wave when ducked
|
||||
if (ent->client->ps.pmove.pm_flags & PMF_DUCKED)
|
||||
return;
|
||||
|
||||
if (ent->client->anim_priority > ANIM_WAVE)
|
||||
return;
|
||||
|
||||
ent->client->anim_priority = ANIM_WAVE;
|
||||
|
||||
switch (i)
|
||||
{
|
||||
case 0:
|
||||
gi.cprintf (ent, PRINT_HIGH, "flipoff\n");
|
||||
ent->s.frame = FRAME_flip01-1;
|
||||
ent->client->anim_end = FRAME_flip12;
|
||||
break;
|
||||
case 1:
|
||||
gi.cprintf (ent, PRINT_HIGH, "salute\n");
|
||||
ent->s.frame = FRAME_salute01-1;
|
||||
ent->client->anim_end = FRAME_salute11;
|
||||
break;
|
||||
case 2:
|
||||
gi.cprintf (ent, PRINT_HIGH, "taunt\n");
|
||||
ent->s.frame = FRAME_taunt01-1;
|
||||
ent->client->anim_end = FRAME_taunt17;
|
||||
break;
|
||||
case 3:
|
||||
gi.cprintf (ent, PRINT_HIGH, "wave\n");
|
||||
ent->s.frame = FRAME_wave01-1;
|
||||
ent->client->anim_end = FRAME_wave11;
|
||||
break;
|
||||
case 4:
|
||||
default:
|
||||
gi.cprintf (ent, PRINT_HIGH, "point\n");
|
||||
ent->s.frame = FRAME_point01-1;
|
||||
ent->client->anim_end = FRAME_point12;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
Cmd_Say_f
|
||||
==================
|
||||
*/
|
||||
void Cmd_Say_f (edict_t *ent, qboolean team, qboolean arg0)
|
||||
{
|
||||
int i, j;
|
||||
edict_t *other;
|
||||
char *p;
|
||||
char text[2048];
|
||||
gclient_t *cl;
|
||||
|
||||
if (gi.argc () < 2 && !arg0)
|
||||
return;
|
||||
|
||||
if (!((int)(dmflags->value) & (DF_MODELTEAMS | DF_SKINTEAMS)))
|
||||
team = false;
|
||||
|
||||
if (team)
|
||||
Com_sprintf (text, sizeof(text), "(%s): ", ent->client->pers.netname);
|
||||
else
|
||||
Com_sprintf (text, sizeof(text), "%s: ", ent->client->pers.netname);
|
||||
|
||||
if (arg0)
|
||||
{
|
||||
strcat (text, gi.argv(0));
|
||||
strcat (text, " ");
|
||||
strcat (text, gi.args());
|
||||
}
|
||||
else
|
||||
{
|
||||
p = gi.args();
|
||||
|
||||
if (*p == '"')
|
||||
{
|
||||
p++;
|
||||
p[strlen(p)-1] = 0;
|
||||
}
|
||||
strcat(text, p);
|
||||
}
|
||||
|
||||
// don't let text be too long for malicious reasons
|
||||
if (strlen(text) > 150)
|
||||
text[150] = 0;
|
||||
|
||||
strcat(text, "\n");
|
||||
|
||||
if (flood_msgs->value) {
|
||||
cl = ent->client;
|
||||
|
||||
if (level.time < cl->flood_locktill) {
|
||||
gi.cprintf(ent, PRINT_HIGH, "You can't talk for %d more seconds\n",
|
||||
(int)(cl->flood_locktill - level.time));
|
||||
return;
|
||||
}
|
||||
i = cl->flood_whenhead - flood_msgs->value + 1;
|
||||
if (i < 0)
|
||||
i = (sizeof(cl->flood_when)/sizeof(cl->flood_when[0])) + i;
|
||||
if (cl->flood_when[i] &&
|
||||
level.time - cl->flood_when[i] < flood_persecond->value) {
|
||||
cl->flood_locktill = level.time + flood_waitdelay->value;
|
||||
gi.cprintf(ent, PRINT_CHAT, "Flood protection: You can't talk for %d seconds.\n",
|
||||
(int)flood_waitdelay->value);
|
||||
return;
|
||||
}
|
||||
cl->flood_whenhead = (cl->flood_whenhead + 1) %
|
||||
(sizeof(cl->flood_when)/sizeof(cl->flood_when[0]));
|
||||
cl->flood_when[cl->flood_whenhead] = level.time;
|
||||
}
|
||||
|
||||
if (dedicated->value)
|
||||
gi.cprintf(NULL, PRINT_CHAT, "%s", text);
|
||||
|
||||
for (j = 1; j <= game.maxclients; j++)
|
||||
{
|
||||
other = &g_edicts[j];
|
||||
if (!other->inuse)
|
||||
continue;
|
||||
if (!other->client)
|
||||
continue;
|
||||
if (team)
|
||||
{
|
||||
if (!OnSameTeam(ent, other))
|
||||
continue;
|
||||
}
|
||||
gi.cprintf(other, PRINT_CHAT, "%s", text);
|
||||
}
|
||||
}
|
||||
|
||||
void Cmd_PlayerList_f(edict_t *ent)
|
||||
{
|
||||
int i;
|
||||
char st[80];
|
||||
char text[1400];
|
||||
edict_t *e2;
|
||||
|
||||
// connect time, ping, score, name
|
||||
*text = 0;
|
||||
for (i = 0, e2 = g_edicts + 1; i < maxclients->value; i++, e2++) {
|
||||
if (!e2->inuse)
|
||||
continue;
|
||||
|
||||
Com_sprintf(st, sizeof(st), "%02d:%02d %4d %3d %s%s\n",
|
||||
(level.framenum - e2->client->resp.enterframe) / 600,
|
||||
((level.framenum - e2->client->resp.enterframe) % 600)/10,
|
||||
e2->client->ping,
|
||||
e2->client->resp.score,
|
||||
e2->client->pers.netname,
|
||||
e2->client->resp.spectator ? " (spectator)" : "");
|
||||
if (strlen(text) + strlen(st) > sizeof(text) - 50) {
|
||||
sprintf(text+strlen(text), "And more...\n");
|
||||
gi.cprintf(ent, PRINT_HIGH, "%s", text);
|
||||
return;
|
||||
}
|
||||
strcat(text, st);
|
||||
}
|
||||
gi.cprintf(ent, PRINT_HIGH, "%s", text);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=================
|
||||
ClientCommand
|
||||
=================
|
||||
*/
|
||||
void ClientCommand (edict_t *ent)
|
||||
{
|
||||
char *cmd;
|
||||
|
||||
if (!ent->client)
|
||||
return; // not fully in game yet
|
||||
|
||||
cmd = gi.argv(0);
|
||||
|
||||
if (Q_stricmp (cmd, "players") == 0)
|
||||
{
|
||||
Cmd_Players_f (ent);
|
||||
return;
|
||||
}
|
||||
if (Q_stricmp (cmd, "say") == 0)
|
||||
{
|
||||
Cmd_Say_f (ent, false, false);
|
||||
return;
|
||||
}
|
||||
if (Q_stricmp (cmd, "say_team") == 0)
|
||||
{
|
||||
Cmd_Say_f (ent, true, false);
|
||||
return;
|
||||
}
|
||||
if (Q_stricmp (cmd, "score") == 0)
|
||||
{
|
||||
Cmd_Score_f (ent);
|
||||
return;
|
||||
}
|
||||
if (Q_stricmp (cmd, "help") == 0)
|
||||
{
|
||||
Cmd_Help_f (ent);
|
||||
return;
|
||||
}
|
||||
|
||||
if (level.intermissiontime)
|
||||
return;
|
||||
|
||||
if (Q_stricmp (cmd, "use") == 0)
|
||||
Cmd_Use_f (ent);
|
||||
else if (Q_stricmp (cmd, "drop") == 0)
|
||||
Cmd_Drop_f (ent);
|
||||
else if (Q_stricmp (cmd, "give") == 0)
|
||||
Cmd_Give_f (ent);
|
||||
else if (Q_stricmp (cmd, "god") == 0)
|
||||
Cmd_God_f (ent);
|
||||
else if (Q_stricmp (cmd, "notarget") == 0)
|
||||
Cmd_Notarget_f (ent);
|
||||
else if (Q_stricmp (cmd, "noclip") == 0)
|
||||
Cmd_Noclip_f (ent);
|
||||
else if (Q_stricmp (cmd, "inven") == 0)
|
||||
Cmd_Inven_f (ent);
|
||||
else if (Q_stricmp (cmd, "invnext") == 0)
|
||||
SelectNextItem (ent, -1);
|
||||
else if (Q_stricmp (cmd, "invprev") == 0)
|
||||
SelectPrevItem (ent, -1);
|
||||
else if (Q_stricmp (cmd, "invnextw") == 0)
|
||||
SelectNextItem (ent, IT_WEAPON);
|
||||
else if (Q_stricmp (cmd, "invprevw") == 0)
|
||||
SelectPrevItem (ent, IT_WEAPON);
|
||||
else if (Q_stricmp (cmd, "invnextp") == 0)
|
||||
SelectNextItem (ent, IT_POWERUP);
|
||||
else if (Q_stricmp (cmd, "invprevp") == 0)
|
||||
SelectPrevItem (ent, IT_POWERUP);
|
||||
else if (Q_stricmp (cmd, "invuse") == 0)
|
||||
Cmd_InvUse_f (ent);
|
||||
else if (Q_stricmp (cmd, "invdrop") == 0)
|
||||
Cmd_InvDrop_f (ent);
|
||||
else if (Q_stricmp (cmd, "weapprev") == 0)
|
||||
Cmd_WeapPrev_f (ent);
|
||||
else if (Q_stricmp (cmd, "weapnext") == 0)
|
||||
Cmd_WeapNext_f (ent);
|
||||
else if (Q_stricmp (cmd, "weaplast") == 0)
|
||||
Cmd_WeapLast_f (ent);
|
||||
else if (Q_stricmp (cmd, "kill") == 0)
|
||||
Cmd_Kill_f (ent);
|
||||
else if (Q_stricmp (cmd, "putaway") == 0)
|
||||
Cmd_PutAway_f (ent);
|
||||
else if (Q_stricmp (cmd, "wave") == 0)
|
||||
Cmd_Wave_f (ent);
|
||||
else if (Q_stricmp(cmd, "playerlist") == 0)
|
||||
Cmd_PlayerList_f(ent);
|
||||
else // anything that doesn't match a command will be a chat
|
||||
Cmd_Say_f (ent, false, true);
|
||||
}
|
||||
576
original/baseq2/g_combat.c
Normal file
576
original/baseq2/g_combat.c
Normal file
@@ -0,0 +1,576 @@
|
||||
/*
|
||||
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_combat.c
|
||||
|
||||
#include "g_local.h"
|
||||
|
||||
/*
|
||||
============
|
||||
CanDamage
|
||||
|
||||
Returns true if the inflictor can directly damage the target. Used for
|
||||
explosions and melee attacks.
|
||||
============
|
||||
*/
|
||||
qboolean CanDamage (edict_t *targ, edict_t *inflictor)
|
||||
{
|
||||
vec3_t dest;
|
||||
trace_t trace;
|
||||
|
||||
// bmodels need special checking because their origin is 0,0,0
|
||||
if (targ->movetype == MOVETYPE_PUSH)
|
||||
{
|
||||
VectorAdd (targ->absmin, targ->absmax, dest);
|
||||
VectorScale (dest, 0.5, dest);
|
||||
trace = gi.trace (inflictor->s.origin, vec3_origin, vec3_origin, dest, inflictor, MASK_SOLID);
|
||||
if (trace.fraction == 1.0)
|
||||
return true;
|
||||
if (trace.ent == targ)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
trace = gi.trace (inflictor->s.origin, vec3_origin, vec3_origin, targ->s.origin, inflictor, MASK_SOLID);
|
||||
if (trace.fraction == 1.0)
|
||||
return true;
|
||||
|
||||
VectorCopy (targ->s.origin, dest);
|
||||
dest[0] += 15.0;
|
||||
dest[1] += 15.0;
|
||||
trace = gi.trace (inflictor->s.origin, vec3_origin, vec3_origin, dest, inflictor, MASK_SOLID);
|
||||
if (trace.fraction == 1.0)
|
||||
return true;
|
||||
|
||||
VectorCopy (targ->s.origin, dest);
|
||||
dest[0] += 15.0;
|
||||
dest[1] -= 15.0;
|
||||
trace = gi.trace (inflictor->s.origin, vec3_origin, vec3_origin, dest, inflictor, MASK_SOLID);
|
||||
if (trace.fraction == 1.0)
|
||||
return true;
|
||||
|
||||
VectorCopy (targ->s.origin, dest);
|
||||
dest[0] -= 15.0;
|
||||
dest[1] += 15.0;
|
||||
trace = gi.trace (inflictor->s.origin, vec3_origin, vec3_origin, dest, inflictor, MASK_SOLID);
|
||||
if (trace.fraction == 1.0)
|
||||
return true;
|
||||
|
||||
VectorCopy (targ->s.origin, dest);
|
||||
dest[0] -= 15.0;
|
||||
dest[1] -= 15.0;
|
||||
trace = gi.trace (inflictor->s.origin, vec3_origin, vec3_origin, dest, inflictor, MASK_SOLID);
|
||||
if (trace.fraction == 1.0)
|
||||
return true;
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
============
|
||||
Killed
|
||||
============
|
||||
*/
|
||||
void Killed (edict_t *targ, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
|
||||
{
|
||||
if (targ->health < -999)
|
||||
targ->health = -999;
|
||||
|
||||
targ->enemy = attacker;
|
||||
|
||||
if ((targ->svflags & SVF_MONSTER) && (targ->deadflag != DEAD_DEAD))
|
||||
{
|
||||
// targ->svflags |= SVF_DEADMONSTER; // now treat as a different content type
|
||||
if (!(targ->monsterinfo.aiflags & AI_GOOD_GUY))
|
||||
{
|
||||
level.killed_monsters++;
|
||||
if (coop->value && attacker->client)
|
||||
attacker->client->resp.score++;
|
||||
// medics won't heal monsters that they kill themselves
|
||||
if (strcmp(attacker->classname, "monster_medic") == 0)
|
||||
targ->owner = attacker;
|
||||
}
|
||||
}
|
||||
|
||||
if (targ->movetype == MOVETYPE_PUSH || targ->movetype == MOVETYPE_STOP || targ->movetype == MOVETYPE_NONE)
|
||||
{ // doors, triggers, etc
|
||||
targ->die (targ, inflictor, attacker, damage, point);
|
||||
return;
|
||||
}
|
||||
|
||||
if ((targ->svflags & SVF_MONSTER) && (targ->deadflag != DEAD_DEAD))
|
||||
{
|
||||
targ->touch = NULL;
|
||||
monster_death_use (targ);
|
||||
}
|
||||
|
||||
targ->die (targ, inflictor, attacker, damage, point);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
SpawnDamage
|
||||
================
|
||||
*/
|
||||
void SpawnDamage (int type, vec3_t origin, vec3_t normal, int damage)
|
||||
{
|
||||
if (damage > 255)
|
||||
damage = 255;
|
||||
gi.WriteByte (svc_temp_entity);
|
||||
gi.WriteByte (type);
|
||||
// gi.WriteByte (damage);
|
||||
gi.WritePosition (origin);
|
||||
gi.WriteDir (normal);
|
||||
gi.multicast (origin, MULTICAST_PVS);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
============
|
||||
T_Damage
|
||||
|
||||
targ entity that is being damaged
|
||||
inflictor entity that is causing the damage
|
||||
attacker entity that caused the inflictor to damage targ
|
||||
example: targ=monster, inflictor=rocket, attacker=player
|
||||
|
||||
dir direction of the attack
|
||||
point point at which the damage is being inflicted
|
||||
normal normal vector from that point
|
||||
damage amount of damage being inflicted
|
||||
knockback force to be applied against targ as a result of the damage
|
||||
|
||||
dflags these flags are used to control how T_Damage works
|
||||
DAMAGE_RADIUS damage was indirect (from a nearby explosion)
|
||||
DAMAGE_NO_ARMOR armor does not protect from this damage
|
||||
DAMAGE_ENERGY damage is from an energy based weapon
|
||||
DAMAGE_NO_KNOCKBACK do not affect velocity, just view angles
|
||||
DAMAGE_BULLET damage is from a bullet (used for ricochets)
|
||||
DAMAGE_NO_PROTECTION kills godmode, armor, everything
|
||||
============
|
||||
*/
|
||||
static int CheckPowerArmor (edict_t *ent, vec3_t point, vec3_t normal, int damage, int dflags)
|
||||
{
|
||||
gclient_t *client;
|
||||
int save;
|
||||
int power_armor_type;
|
||||
int index;
|
||||
int damagePerCell;
|
||||
int pa_te_type;
|
||||
int power;
|
||||
int power_used;
|
||||
|
||||
if (!damage)
|
||||
return 0;
|
||||
|
||||
client = ent->client;
|
||||
|
||||
if (dflags & DAMAGE_NO_ARMOR)
|
||||
return 0;
|
||||
|
||||
if (client)
|
||||
{
|
||||
power_armor_type = PowerArmorType (ent);
|
||||
if (power_armor_type != POWER_ARMOR_NONE)
|
||||
{
|
||||
index = ITEM_INDEX(FindItem("Cells"));
|
||||
power = client->pers.inventory[index];
|
||||
}
|
||||
}
|
||||
else if (ent->svflags & SVF_MONSTER)
|
||||
{
|
||||
power_armor_type = ent->monsterinfo.power_armor_type;
|
||||
power = ent->monsterinfo.power_armor_power;
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
|
||||
if (power_armor_type == POWER_ARMOR_NONE)
|
||||
return 0;
|
||||
if (!power)
|
||||
return 0;
|
||||
|
||||
if (power_armor_type == POWER_ARMOR_SCREEN)
|
||||
{
|
||||
vec3_t vec;
|
||||
float dot;
|
||||
vec3_t forward;
|
||||
|
||||
// only works if damage point is in front
|
||||
AngleVectors (ent->s.angles, forward, NULL, NULL);
|
||||
VectorSubtract (point, ent->s.origin, vec);
|
||||
VectorNormalize (vec);
|
||||
dot = DotProduct (vec, forward);
|
||||
if (dot <= 0.3)
|
||||
return 0;
|
||||
|
||||
damagePerCell = 1;
|
||||
pa_te_type = TE_SCREEN_SPARKS;
|
||||
damage = damage / 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
damagePerCell = 2;
|
||||
pa_te_type = TE_SHIELD_SPARKS;
|
||||
damage = (2 * damage) / 3;
|
||||
}
|
||||
|
||||
save = power * damagePerCell;
|
||||
if (!save)
|
||||
return 0;
|
||||
if (save > damage)
|
||||
save = damage;
|
||||
|
||||
SpawnDamage (pa_te_type, point, normal, save);
|
||||
ent->powerarmor_time = level.time + 0.2;
|
||||
|
||||
power_used = save / damagePerCell;
|
||||
|
||||
if (client)
|
||||
client->pers.inventory[index] -= power_used;
|
||||
else
|
||||
ent->monsterinfo.power_armor_power -= power_used;
|
||||
return save;
|
||||
}
|
||||
|
||||
static int CheckArmor (edict_t *ent, vec3_t point, vec3_t normal, int damage, int te_sparks, int dflags)
|
||||
{
|
||||
gclient_t *client;
|
||||
int save;
|
||||
int index;
|
||||
gitem_t *armor;
|
||||
|
||||
if (!damage)
|
||||
return 0;
|
||||
|
||||
client = ent->client;
|
||||
|
||||
if (!client)
|
||||
return 0;
|
||||
|
||||
if (dflags & DAMAGE_NO_ARMOR)
|
||||
return 0;
|
||||
|
||||
index = ArmorIndex (ent);
|
||||
if (!index)
|
||||
return 0;
|
||||
|
||||
armor = GetItemByIndex (index);
|
||||
|
||||
if (dflags & DAMAGE_ENERGY)
|
||||
save = ceil(((gitem_armor_t *)armor->info)->energy_protection*damage);
|
||||
else
|
||||
save = ceil(((gitem_armor_t *)armor->info)->normal_protection*damage);
|
||||
if (save >= client->pers.inventory[index])
|
||||
save = client->pers.inventory[index];
|
||||
|
||||
if (!save)
|
||||
return 0;
|
||||
|
||||
client->pers.inventory[index] -= save;
|
||||
SpawnDamage (te_sparks, point, normal, save);
|
||||
|
||||
return save;
|
||||
}
|
||||
|
||||
void M_ReactToDamage (edict_t *targ, edict_t *attacker)
|
||||
{
|
||||
if (!(attacker->client) && !(attacker->svflags & SVF_MONSTER))
|
||||
return;
|
||||
|
||||
if (attacker == targ || attacker == targ->enemy)
|
||||
return;
|
||||
|
||||
// if we are a good guy monster and our attacker is a player
|
||||
// or another good guy, do not get mad at them
|
||||
if (targ->monsterinfo.aiflags & AI_GOOD_GUY)
|
||||
{
|
||||
if (attacker->client || (attacker->monsterinfo.aiflags & AI_GOOD_GUY))
|
||||
return;
|
||||
}
|
||||
|
||||
// we now know that we are not both good guys
|
||||
|
||||
// if attacker is a client, get mad at them because he's good and we're not
|
||||
if (attacker->client)
|
||||
{
|
||||
targ->monsterinfo.aiflags &= ~AI_SOUND_TARGET;
|
||||
|
||||
// this can only happen in coop (both new and old enemies are clients)
|
||||
// only switch if can't see the current enemy
|
||||
if (targ->enemy && targ->enemy->client)
|
||||
{
|
||||
if (visible(targ, targ->enemy))
|
||||
{
|
||||
targ->oldenemy = attacker;
|
||||
return;
|
||||
}
|
||||
targ->oldenemy = targ->enemy;
|
||||
}
|
||||
targ->enemy = attacker;
|
||||
if (!(targ->monsterinfo.aiflags & AI_DUCKED))
|
||||
FoundTarget (targ);
|
||||
return;
|
||||
}
|
||||
|
||||
// it's the same base (walk/swim/fly) type and a different classname and it's not a tank
|
||||
// (they spray too much), get mad at them
|
||||
if (((targ->flags & (FL_FLY|FL_SWIM)) == (attacker->flags & (FL_FLY|FL_SWIM))) &&
|
||||
(strcmp (targ->classname, attacker->classname) != 0) &&
|
||||
(strcmp(attacker->classname, "monster_tank") != 0) &&
|
||||
(strcmp(attacker->classname, "monster_supertank") != 0) &&
|
||||
(strcmp(attacker->classname, "monster_makron") != 0) &&
|
||||
(strcmp(attacker->classname, "monster_jorg") != 0) )
|
||||
{
|
||||
if (targ->enemy && targ->enemy->client)
|
||||
targ->oldenemy = targ->enemy;
|
||||
targ->enemy = attacker;
|
||||
if (!(targ->monsterinfo.aiflags & AI_DUCKED))
|
||||
FoundTarget (targ);
|
||||
}
|
||||
// if they *meant* to shoot us, then shoot back
|
||||
else if (attacker->enemy == targ)
|
||||
{
|
||||
if (targ->enemy && targ->enemy->client)
|
||||
targ->oldenemy = targ->enemy;
|
||||
targ->enemy = attacker;
|
||||
if (!(targ->monsterinfo.aiflags & AI_DUCKED))
|
||||
FoundTarget (targ);
|
||||
}
|
||||
// otherwise get mad at whoever they are mad at (help our buddy) unless it is us!
|
||||
else if (attacker->enemy && attacker->enemy != targ)
|
||||
{
|
||||
if (targ->enemy && targ->enemy->client)
|
||||
targ->oldenemy = targ->enemy;
|
||||
targ->enemy = attacker->enemy;
|
||||
if (!(targ->monsterinfo.aiflags & AI_DUCKED))
|
||||
FoundTarget (targ);
|
||||
}
|
||||
}
|
||||
|
||||
qboolean CheckTeamDamage (edict_t *targ, edict_t *attacker)
|
||||
{
|
||||
//FIXME make the next line real and uncomment this block
|
||||
// if ((ability to damage a teammate == OFF) && (targ's team == attacker's team))
|
||||
return false;
|
||||
}
|
||||
|
||||
void T_Damage (edict_t *targ, edict_t *inflictor, edict_t *attacker, vec3_t dir, vec3_t point, vec3_t normal, int damage, int knockback, int dflags, int mod)
|
||||
{
|
||||
gclient_t *client;
|
||||
int take;
|
||||
int save;
|
||||
int asave;
|
||||
int psave;
|
||||
int te_sparks;
|
||||
|
||||
if (!targ->takedamage)
|
||||
return;
|
||||
|
||||
// friendly fire avoidance
|
||||
// if enabled you can't hurt teammates (but you can hurt yourself)
|
||||
// knockback still occurs
|
||||
if ((targ != attacker) && ((deathmatch->value && ((int)(dmflags->value) & (DF_MODELTEAMS | DF_SKINTEAMS))) || coop->value))
|
||||
{
|
||||
if (OnSameTeam (targ, attacker))
|
||||
{
|
||||
if ((int)(dmflags->value) & DF_NO_FRIENDLY_FIRE)
|
||||
damage = 0;
|
||||
else
|
||||
mod |= MOD_FRIENDLY_FIRE;
|
||||
}
|
||||
}
|
||||
meansOfDeath = mod;
|
||||
|
||||
// easy mode takes half damage
|
||||
if (skill->value == 0 && deathmatch->value == 0 && targ->client)
|
||||
{
|
||||
damage *= 0.5;
|
||||
if (!damage)
|
||||
damage = 1;
|
||||
}
|
||||
|
||||
client = targ->client;
|
||||
|
||||
if (dflags & DAMAGE_BULLET)
|
||||
te_sparks = TE_BULLET_SPARKS;
|
||||
else
|
||||
te_sparks = TE_SPARKS;
|
||||
|
||||
VectorNormalize(dir);
|
||||
|
||||
// bonus damage for suprising a monster
|
||||
if (!(dflags & DAMAGE_RADIUS) && (targ->svflags & SVF_MONSTER) && (attacker->client) && (!targ->enemy) && (targ->health > 0))
|
||||
damage *= 2;
|
||||
|
||||
if (targ->flags & FL_NO_KNOCKBACK)
|
||||
knockback = 0;
|
||||
|
||||
// figure momentum add
|
||||
if (!(dflags & DAMAGE_NO_KNOCKBACK))
|
||||
{
|
||||
if ((knockback) && (targ->movetype != MOVETYPE_NONE) && (targ->movetype != MOVETYPE_BOUNCE) && (targ->movetype != MOVETYPE_PUSH) && (targ->movetype != MOVETYPE_STOP))
|
||||
{
|
||||
vec3_t kvel;
|
||||
float mass;
|
||||
|
||||
if (targ->mass < 50)
|
||||
mass = 50;
|
||||
else
|
||||
mass = targ->mass;
|
||||
|
||||
if (targ->client && attacker == targ)
|
||||
VectorScale (dir, 1600.0 * (float)knockback / mass, kvel); // the rocket jump hack...
|
||||
else
|
||||
VectorScale (dir, 500.0 * (float)knockback / mass, kvel);
|
||||
|
||||
VectorAdd (targ->velocity, kvel, targ->velocity);
|
||||
}
|
||||
}
|
||||
|
||||
take = damage;
|
||||
save = 0;
|
||||
|
||||
// check for godmode
|
||||
if ( (targ->flags & FL_GODMODE) && !(dflags & DAMAGE_NO_PROTECTION) )
|
||||
{
|
||||
take = 0;
|
||||
save = damage;
|
||||
SpawnDamage (te_sparks, point, normal, save);
|
||||
}
|
||||
|
||||
// check for invincibility
|
||||
if ((client && client->invincible_framenum > level.framenum ) && !(dflags & DAMAGE_NO_PROTECTION))
|
||||
{
|
||||
if (targ->pain_debounce_time < level.time)
|
||||
{
|
||||
gi.sound(targ, CHAN_ITEM, gi.soundindex("items/protect4.wav"), 1, ATTN_NORM, 0);
|
||||
targ->pain_debounce_time = level.time + 2;
|
||||
}
|
||||
take = 0;
|
||||
save = damage;
|
||||
}
|
||||
|
||||
psave = CheckPowerArmor (targ, point, normal, take, dflags);
|
||||
take -= psave;
|
||||
|
||||
asave = CheckArmor (targ, point, normal, take, te_sparks, dflags);
|
||||
take -= asave;
|
||||
|
||||
//treat cheat/powerup savings the same as armor
|
||||
asave += save;
|
||||
|
||||
// team damage avoidance
|
||||
if (!(dflags & DAMAGE_NO_PROTECTION) && CheckTeamDamage (targ, attacker))
|
||||
return;
|
||||
|
||||
// do the damage
|
||||
if (take)
|
||||
{
|
||||
if ((targ->svflags & SVF_MONSTER) || (client))
|
||||
SpawnDamage (TE_BLOOD, point, normal, take);
|
||||
else
|
||||
SpawnDamage (te_sparks, point, normal, take);
|
||||
|
||||
|
||||
targ->health = targ->health - take;
|
||||
|
||||
if (targ->health <= 0)
|
||||
{
|
||||
if ((targ->svflags & SVF_MONSTER) || (client))
|
||||
targ->flags |= FL_NO_KNOCKBACK;
|
||||
Killed (targ, inflictor, attacker, take, point);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (targ->svflags & SVF_MONSTER)
|
||||
{
|
||||
M_ReactToDamage (targ, attacker);
|
||||
if (!(targ->monsterinfo.aiflags & AI_DUCKED) && (take))
|
||||
{
|
||||
targ->pain (targ, attacker, knockback, take);
|
||||
// nightmare mode monsters don't go into pain frames often
|
||||
if (skill->value == 3)
|
||||
targ->pain_debounce_time = level.time + 5;
|
||||
}
|
||||
}
|
||||
else if (client)
|
||||
{
|
||||
if (!(targ->flags & FL_GODMODE) && (take))
|
||||
targ->pain (targ, attacker, knockback, take);
|
||||
}
|
||||
else if (take)
|
||||
{
|
||||
if (targ->pain)
|
||||
targ->pain (targ, attacker, knockback, take);
|
||||
}
|
||||
|
||||
// add to the damage inflicted on a player this frame
|
||||
// the total will be turned into screen blends and view angle kicks
|
||||
// at the end of the frame
|
||||
if (client)
|
||||
{
|
||||
client->damage_parmor += psave;
|
||||
client->damage_armor += asave;
|
||||
client->damage_blood += take;
|
||||
client->damage_knockback += knockback;
|
||||
VectorCopy (point, client->damage_from);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
============
|
||||
T_RadiusDamage
|
||||
============
|
||||
*/
|
||||
void T_RadiusDamage (edict_t *inflictor, edict_t *attacker, float damage, edict_t *ignore, float radius, int mod)
|
||||
{
|
||||
float points;
|
||||
edict_t *ent = NULL;
|
||||
vec3_t v;
|
||||
vec3_t dir;
|
||||
|
||||
while ((ent = findradius(ent, inflictor->s.origin, radius)) != NULL)
|
||||
{
|
||||
if (ent == ignore)
|
||||
continue;
|
||||
if (!ent->takedamage)
|
||||
continue;
|
||||
|
||||
VectorAdd (ent->mins, ent->maxs, v);
|
||||
VectorMA (ent->s.origin, 0.5, v, v);
|
||||
VectorSubtract (inflictor->s.origin, v, v);
|
||||
points = damage - 0.5 * VectorLength (v);
|
||||
if (ent == attacker)
|
||||
points = points * 0.5;
|
||||
if (points > 0)
|
||||
{
|
||||
if (CanDamage (ent, inflictor))
|
||||
{
|
||||
VectorSubtract (ent->s.origin, inflictor->s.origin, dir);
|
||||
T_Damage (ent, inflictor, attacker, dir, inflictor->s.origin, vec3_origin, (int)points, (int)points, DAMAGE_RADIUS, mod);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
2048
original/baseq2/g_func.c
Normal file
2048
original/baseq2/g_func.c
Normal file
File diff suppressed because it is too large
Load Diff
2216
original/baseq2/g_items.c
Normal file
2216
original/baseq2/g_items.c
Normal file
File diff suppressed because it is too large
Load Diff
1114
original/baseq2/g_local.h
Normal file
1114
original/baseq2/g_local.h
Normal file
File diff suppressed because it is too large
Load Diff
442
original/baseq2/g_main.c
Normal file
442
original/baseq2/g_main.c
Normal file
@@ -0,0 +1,442 @@
|
||||
/*
|
||||
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"
|
||||
|
||||
game_locals_t game;
|
||||
level_locals_t level;
|
||||
game_import_t gi;
|
||||
game_export_t globals;
|
||||
spawn_temp_t st;
|
||||
|
||||
int sm_meat_index;
|
||||
int snd_fry;
|
||||
int meansOfDeath;
|
||||
|
||||
edict_t *g_edicts;
|
||||
|
||||
cvar_t *deathmatch;
|
||||
cvar_t *coop;
|
||||
cvar_t *dmflags;
|
||||
cvar_t *skill;
|
||||
cvar_t *fraglimit;
|
||||
cvar_t *timelimit;
|
||||
cvar_t *password;
|
||||
cvar_t *spectator_password;
|
||||
cvar_t *needpass;
|
||||
cvar_t *maxclients;
|
||||
cvar_t *maxspectators;
|
||||
cvar_t *maxentities;
|
||||
cvar_t *g_select_empty;
|
||||
cvar_t *dedicated;
|
||||
|
||||
cvar_t *filterban;
|
||||
|
||||
cvar_t *sv_maxvelocity;
|
||||
cvar_t *sv_gravity;
|
||||
|
||||
cvar_t *sv_rollspeed;
|
||||
cvar_t *sv_rollangle;
|
||||
cvar_t *gun_x;
|
||||
cvar_t *gun_y;
|
||||
cvar_t *gun_z;
|
||||
|
||||
cvar_t *run_pitch;
|
||||
cvar_t *run_roll;
|
||||
cvar_t *bob_up;
|
||||
cvar_t *bob_pitch;
|
||||
cvar_t *bob_roll;
|
||||
|
||||
cvar_t *sv_cheats;
|
||||
|
||||
cvar_t *flood_msgs;
|
||||
cvar_t *flood_persecond;
|
||||
cvar_t *flood_waitdelay;
|
||||
|
||||
cvar_t *sv_maplist;
|
||||
|
||||
void SpawnEntities (char *mapname, char *entities, char *spawnpoint);
|
||||
void ClientThink (edict_t *ent, usercmd_t *cmd);
|
||||
qboolean ClientConnect (edict_t *ent, char *userinfo);
|
||||
void ClientUserinfoChanged (edict_t *ent, char *userinfo);
|
||||
void ClientDisconnect (edict_t *ent);
|
||||
void ClientBegin (edict_t *ent);
|
||||
void ClientCommand (edict_t *ent);
|
||||
void RunEntity (edict_t *ent);
|
||||
void WriteGame (char *filename, qboolean autosave);
|
||||
void ReadGame (char *filename);
|
||||
void WriteLevel (char *filename);
|
||||
void ReadLevel (char *filename);
|
||||
void InitGame (void);
|
||||
void G_RunFrame (void);
|
||||
|
||||
|
||||
//===================================================================
|
||||
|
||||
|
||||
void ShutdownGame (void)
|
||||
{
|
||||
gi.dprintf ("==== ShutdownGame ====\n");
|
||||
|
||||
gi.FreeTags (TAG_LEVEL);
|
||||
gi.FreeTags (TAG_GAME);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=================
|
||||
GetGameAPI
|
||||
|
||||
Returns a pointer to the structure with all entry points
|
||||
and global variables
|
||||
=================
|
||||
*/
|
||||
game_export_t *GetGameAPI (game_import_t *import)
|
||||
{
|
||||
gi = *import;
|
||||
|
||||
globals.apiversion = GAME_API_VERSION;
|
||||
globals.Init = InitGame;
|
||||
globals.Shutdown = ShutdownGame;
|
||||
globals.SpawnEntities = SpawnEntities;
|
||||
|
||||
globals.WriteGame = WriteGame;
|
||||
globals.ReadGame = ReadGame;
|
||||
globals.WriteLevel = WriteLevel;
|
||||
globals.ReadLevel = ReadLevel;
|
||||
|
||||
globals.ClientThink = ClientThink;
|
||||
globals.ClientConnect = ClientConnect;
|
||||
globals.ClientUserinfoChanged = ClientUserinfoChanged;
|
||||
globals.ClientDisconnect = ClientDisconnect;
|
||||
globals.ClientBegin = ClientBegin;
|
||||
globals.ClientCommand = ClientCommand;
|
||||
|
||||
globals.RunFrame = G_RunFrame;
|
||||
|
||||
globals.ServerCommand = ServerCommand;
|
||||
|
||||
globals.edict_size = sizeof(edict_t);
|
||||
|
||||
return &globals;
|
||||
}
|
||||
|
||||
#ifndef GAME_HARD_LINKED
|
||||
// this is only here so the functions in q_shared.c and q_shwin.c can link
|
||||
void Sys_Error (char *error, ...)
|
||||
{
|
||||
va_list argptr;
|
||||
char text[1024];
|
||||
|
||||
va_start (argptr, error);
|
||||
vsprintf (text, error, argptr);
|
||||
va_end (argptr);
|
||||
|
||||
gi.error (ERR_FATAL, "%s", text);
|
||||
}
|
||||
|
||||
void Com_Printf (char *msg, ...)
|
||||
{
|
||||
va_list argptr;
|
||||
char text[1024];
|
||||
|
||||
va_start (argptr, msg);
|
||||
vsprintf (text, msg, argptr);
|
||||
va_end (argptr);
|
||||
|
||||
gi.dprintf ("%s", text);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
//======================================================================
|
||||
|
||||
|
||||
/*
|
||||
=================
|
||||
ClientEndServerFrames
|
||||
=================
|
||||
*/
|
||||
void ClientEndServerFrames (void)
|
||||
{
|
||||
int i;
|
||||
edict_t *ent;
|
||||
|
||||
// calc the player views now that all pushing
|
||||
// and damage has been added
|
||||
for (i=0 ; i<maxclients->value ; i++)
|
||||
{
|
||||
ent = g_edicts + 1 + i;
|
||||
if (!ent->inuse || !ent->client)
|
||||
continue;
|
||||
ClientEndServerFrame (ent);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
CreateTargetChangeLevel
|
||||
|
||||
Returns the created target changelevel
|
||||
=================
|
||||
*/
|
||||
edict_t *CreateTargetChangeLevel(char *map)
|
||||
{
|
||||
edict_t *ent;
|
||||
|
||||
ent = G_Spawn ();
|
||||
ent->classname = "target_changelevel";
|
||||
Com_sprintf(level.nextmap, sizeof(level.nextmap), "%s", map);
|
||||
ent->map = level.nextmap;
|
||||
return ent;
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
EndDMLevel
|
||||
|
||||
The timelimit or fraglimit has been exceeded
|
||||
=================
|
||||
*/
|
||||
void EndDMLevel (void)
|
||||
{
|
||||
edict_t *ent;
|
||||
char *s, *t, *f;
|
||||
static const char *seps = " ,\n\r";
|
||||
|
||||
// stay on same level flag
|
||||
if ((int)dmflags->value & DF_SAME_LEVEL)
|
||||
{
|
||||
BeginIntermission (CreateTargetChangeLevel (level.mapname) );
|
||||
return;
|
||||
}
|
||||
|
||||
// see if it's in the map list
|
||||
if (*sv_maplist->string) {
|
||||
s = strdup(sv_maplist->string);
|
||||
f = NULL;
|
||||
t = strtok(s, seps);
|
||||
while (t != NULL) {
|
||||
if (Q_stricmp(t, level.mapname) == 0) {
|
||||
// it's in the list, go to the next one
|
||||
t = strtok(NULL, seps);
|
||||
if (t == NULL) { // end of list, go to first one
|
||||
if (f == NULL) // there isn't a first one, same level
|
||||
BeginIntermission (CreateTargetChangeLevel (level.mapname) );
|
||||
else
|
||||
BeginIntermission (CreateTargetChangeLevel (f) );
|
||||
} else
|
||||
BeginIntermission (CreateTargetChangeLevel (t) );
|
||||
free(s);
|
||||
return;
|
||||
}
|
||||
if (!f)
|
||||
f = t;
|
||||
t = strtok(NULL, seps);
|
||||
}
|
||||
free(s);
|
||||
}
|
||||
|
||||
if (level.nextmap[0]) // go to a specific map
|
||||
BeginIntermission (CreateTargetChangeLevel (level.nextmap) );
|
||||
else { // search for a changelevel
|
||||
ent = G_Find (NULL, FOFS(classname), "target_changelevel");
|
||||
if (!ent)
|
||||
{ // the map designer didn't include a changelevel,
|
||||
// so create a fake ent that goes back to the same level
|
||||
BeginIntermission (CreateTargetChangeLevel (level.mapname) );
|
||||
return;
|
||||
}
|
||||
BeginIntermission (ent);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=================
|
||||
CheckNeedPass
|
||||
=================
|
||||
*/
|
||||
void CheckNeedPass (void)
|
||||
{
|
||||
int need;
|
||||
|
||||
// if password or spectator_password has changed, update needpass
|
||||
// as needed
|
||||
if (password->modified || spectator_password->modified)
|
||||
{
|
||||
password->modified = spectator_password->modified = false;
|
||||
|
||||
need = 0;
|
||||
|
||||
if (*password->string && Q_stricmp(password->string, "none"))
|
||||
need |= 1;
|
||||
if (*spectator_password->string && Q_stricmp(spectator_password->string, "none"))
|
||||
need |= 2;
|
||||
|
||||
gi.cvar_set("needpass", va("%d", need));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
CheckDMRules
|
||||
=================
|
||||
*/
|
||||
void CheckDMRules (void)
|
||||
{
|
||||
int i;
|
||||
gclient_t *cl;
|
||||
|
||||
if (level.intermissiontime)
|
||||
return;
|
||||
|
||||
if (!deathmatch->value)
|
||||
return;
|
||||
|
||||
if (timelimit->value)
|
||||
{
|
||||
if (level.time >= timelimit->value*60)
|
||||
{
|
||||
gi.bprintf (PRINT_HIGH, "Timelimit hit.\n");
|
||||
EndDMLevel ();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (fraglimit->value)
|
||||
{
|
||||
for (i=0 ; i<maxclients->value ; i++)
|
||||
{
|
||||
cl = game.clients + i;
|
||||
if (!g_edicts[i+1].inuse)
|
||||
continue;
|
||||
|
||||
if (cl->resp.score >= fraglimit->value)
|
||||
{
|
||||
gi.bprintf (PRINT_HIGH, "Fraglimit hit.\n");
|
||||
EndDMLevel ();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=============
|
||||
ExitLevel
|
||||
=============
|
||||
*/
|
||||
void ExitLevel (void)
|
||||
{
|
||||
int i;
|
||||
edict_t *ent;
|
||||
char command [256];
|
||||
|
||||
Com_sprintf (command, sizeof(command), "gamemap \"%s\"\n", level.changemap);
|
||||
gi.AddCommandString (command);
|
||||
level.changemap = NULL;
|
||||
level.exitintermission = 0;
|
||||
level.intermissiontime = 0;
|
||||
ClientEndServerFrames ();
|
||||
|
||||
// clear some things before going to next level
|
||||
for (i=0 ; i<maxclients->value ; i++)
|
||||
{
|
||||
ent = g_edicts + 1 + i;
|
||||
if (!ent->inuse)
|
||||
continue;
|
||||
if (ent->health > ent->client->pers.max_health)
|
||||
ent->health = ent->client->pers.max_health;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
G_RunFrame
|
||||
|
||||
Advances the world by 0.1 seconds
|
||||
================
|
||||
*/
|
||||
void G_RunFrame (void)
|
||||
{
|
||||
int i;
|
||||
edict_t *ent;
|
||||
|
||||
level.framenum++;
|
||||
level.time = level.framenum*FRAMETIME;
|
||||
|
||||
// choose a client for monsters to target this frame
|
||||
AI_SetSightClient ();
|
||||
|
||||
// exit intermissions
|
||||
|
||||
if (level.exitintermission)
|
||||
{
|
||||
ExitLevel ();
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
// treat each object in turn
|
||||
// even the world gets a chance to think
|
||||
//
|
||||
ent = &g_edicts[0];
|
||||
for (i=0 ; i<globals.num_edicts ; i++, ent++)
|
||||
{
|
||||
if (!ent->inuse)
|
||||
continue;
|
||||
|
||||
level.current_entity = ent;
|
||||
|
||||
VectorCopy (ent->s.origin, ent->s.old_origin);
|
||||
|
||||
// if the ground entity moved, make sure we are still on it
|
||||
if ((ent->groundentity) && (ent->groundentity->linkcount != ent->groundentity_linkcount))
|
||||
{
|
||||
ent->groundentity = NULL;
|
||||
if ( !(ent->flags & (FL_SWIM|FL_FLY)) && (ent->svflags & SVF_MONSTER) )
|
||||
{
|
||||
M_CheckGround (ent);
|
||||
}
|
||||
}
|
||||
|
||||
if (i > 0 && i <= maxclients->value)
|
||||
{
|
||||
ClientBeginServerFrame (ent);
|
||||
continue;
|
||||
}
|
||||
|
||||
G_RunEntity (ent);
|
||||
}
|
||||
|
||||
// see if it is time to end a deathmatch
|
||||
CheckDMRules ();
|
||||
|
||||
// see if needpass needs updated
|
||||
CheckNeedPass ();
|
||||
|
||||
// build the playerstate_t structures for all players
|
||||
ClientEndServerFrames ();
|
||||
}
|
||||
|
||||
1878
original/baseq2/g_misc.c
Normal file
1878
original/baseq2/g_misc.c
Normal file
File diff suppressed because it is too large
Load Diff
740
original/baseq2/g_monster.c
Normal file
740
original/baseq2/g_monster.c
Normal file
@@ -0,0 +1,740 @@
|
||||
/*
|
||||
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"
|
||||
|
||||
|
||||
//
|
||||
// monster weapons
|
||||
//
|
||||
|
||||
//FIXME mosnters should call these with a totally accurate direction
|
||||
// and we can mess it up based on skill. Spread should be for normal
|
||||
// and we can tighten or loosen based on skill. We could muck with
|
||||
// the damages too, but I'm not sure that's such a good idea.
|
||||
void monster_fire_bullet (edict_t *self, vec3_t start, vec3_t dir, int damage, int kick, int hspread, int vspread, int flashtype)
|
||||
{
|
||||
fire_bullet (self, start, dir, damage, kick, hspread, vspread, MOD_UNKNOWN);
|
||||
|
||||
gi.WriteByte (svc_muzzleflash2);
|
||||
gi.WriteShort (self - g_edicts);
|
||||
gi.WriteByte (flashtype);
|
||||
gi.multicast (start, MULTICAST_PVS);
|
||||
}
|
||||
|
||||
void monster_fire_shotgun (edict_t *self, vec3_t start, vec3_t aimdir, int damage, int kick, int hspread, int vspread, int count, int flashtype)
|
||||
{
|
||||
fire_shotgun (self, start, aimdir, damage, kick, hspread, vspread, count, MOD_UNKNOWN);
|
||||
|
||||
gi.WriteByte (svc_muzzleflash2);
|
||||
gi.WriteShort (self - g_edicts);
|
||||
gi.WriteByte (flashtype);
|
||||
gi.multicast (start, MULTICAST_PVS);
|
||||
}
|
||||
|
||||
void monster_fire_blaster (edict_t *self, vec3_t start, vec3_t dir, int damage, int speed, int flashtype, int effect)
|
||||
{
|
||||
fire_blaster (self, start, dir, damage, speed, effect, false);
|
||||
|
||||
gi.WriteByte (svc_muzzleflash2);
|
||||
gi.WriteShort (self - g_edicts);
|
||||
gi.WriteByte (flashtype);
|
||||
gi.multicast (start, MULTICAST_PVS);
|
||||
}
|
||||
|
||||
void monster_fire_grenade (edict_t *self, vec3_t start, vec3_t aimdir, int damage, int speed, int flashtype)
|
||||
{
|
||||
fire_grenade (self, start, aimdir, damage, speed, 2.5, damage+40);
|
||||
|
||||
gi.WriteByte (svc_muzzleflash2);
|
||||
gi.WriteShort (self - g_edicts);
|
||||
gi.WriteByte (flashtype);
|
||||
gi.multicast (start, MULTICAST_PVS);
|
||||
}
|
||||
|
||||
void monster_fire_rocket (edict_t *self, vec3_t start, vec3_t dir, int damage, int speed, int flashtype)
|
||||
{
|
||||
fire_rocket (self, start, dir, damage, speed, damage+20, damage);
|
||||
|
||||
gi.WriteByte (svc_muzzleflash2);
|
||||
gi.WriteShort (self - g_edicts);
|
||||
gi.WriteByte (flashtype);
|
||||
gi.multicast (start, MULTICAST_PVS);
|
||||
}
|
||||
|
||||
void monster_fire_railgun (edict_t *self, vec3_t start, vec3_t aimdir, int damage, int kick, int flashtype)
|
||||
{
|
||||
fire_rail (self, start, aimdir, damage, kick);
|
||||
|
||||
gi.WriteByte (svc_muzzleflash2);
|
||||
gi.WriteShort (self - g_edicts);
|
||||
gi.WriteByte (flashtype);
|
||||
gi.multicast (start, MULTICAST_PVS);
|
||||
}
|
||||
|
||||
void monster_fire_bfg (edict_t *self, vec3_t start, vec3_t aimdir, int damage, int speed, int kick, float damage_radius, int flashtype)
|
||||
{
|
||||
fire_bfg (self, start, aimdir, damage, speed, damage_radius);
|
||||
|
||||
gi.WriteByte (svc_muzzleflash2);
|
||||
gi.WriteShort (self - g_edicts);
|
||||
gi.WriteByte (flashtype);
|
||||
gi.multicast (start, MULTICAST_PVS);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//
|
||||
// Monster utility functions
|
||||
//
|
||||
|
||||
static void M_FliesOff (edict_t *self)
|
||||
{
|
||||
self->s.effects &= ~EF_FLIES;
|
||||
self->s.sound = 0;
|
||||
}
|
||||
|
||||
static void M_FliesOn (edict_t *self)
|
||||
{
|
||||
if (self->waterlevel)
|
||||
return;
|
||||
self->s.effects |= EF_FLIES;
|
||||
self->s.sound = gi.soundindex ("infantry/inflies1.wav");
|
||||
self->think = M_FliesOff;
|
||||
self->nextthink = level.time + 60;
|
||||
}
|
||||
|
||||
void M_FlyCheck (edict_t *self)
|
||||
{
|
||||
if (self->waterlevel)
|
||||
return;
|
||||
|
||||
if (random() > 0.5)
|
||||
return;
|
||||
|
||||
self->think = M_FliesOn;
|
||||
self->nextthink = level.time + 5 + 10 * random();
|
||||
}
|
||||
|
||||
void AttackFinished (edict_t *self, float time)
|
||||
{
|
||||
self->monsterinfo.attack_finished = level.time + time;
|
||||
}
|
||||
|
||||
|
||||
void M_CheckGround (edict_t *ent)
|
||||
{
|
||||
vec3_t point;
|
||||
trace_t trace;
|
||||
|
||||
if (ent->flags & (FL_SWIM|FL_FLY))
|
||||
return;
|
||||
|
||||
if (ent->velocity[2] > 100)
|
||||
{
|
||||
ent->groundentity = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
// if the hull point one-quarter unit down is solid the entity is on ground
|
||||
point[0] = ent->s.origin[0];
|
||||
point[1] = ent->s.origin[1];
|
||||
point[2] = ent->s.origin[2] - 0.25;
|
||||
|
||||
trace = gi.trace (ent->s.origin, ent->mins, ent->maxs, point, ent, MASK_MONSTERSOLID);
|
||||
|
||||
// check steepness
|
||||
if ( trace.plane.normal[2] < 0.7 && !trace.startsolid)
|
||||
{
|
||||
ent->groundentity = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
// ent->groundentity = trace.ent;
|
||||
// ent->groundentity_linkcount = trace.ent->linkcount;
|
||||
// if (!trace.startsolid && !trace.allsolid)
|
||||
// VectorCopy (trace.endpos, ent->s.origin);
|
||||
if (!trace.startsolid && !trace.allsolid)
|
||||
{
|
||||
VectorCopy (trace.endpos, ent->s.origin);
|
||||
ent->groundentity = trace.ent;
|
||||
ent->groundentity_linkcount = trace.ent->linkcount;
|
||||
ent->velocity[2] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void M_CatagorizePosition (edict_t *ent)
|
||||
{
|
||||
vec3_t point;
|
||||
int cont;
|
||||
|
||||
//
|
||||
// get waterlevel
|
||||
//
|
||||
point[0] = ent->s.origin[0];
|
||||
point[1] = ent->s.origin[1];
|
||||
point[2] = ent->s.origin[2] + ent->mins[2] + 1;
|
||||
cont = gi.pointcontents (point);
|
||||
|
||||
if (!(cont & MASK_WATER))
|
||||
{
|
||||
ent->waterlevel = 0;
|
||||
ent->watertype = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
ent->watertype = cont;
|
||||
ent->waterlevel = 1;
|
||||
point[2] += 26;
|
||||
cont = gi.pointcontents (point);
|
||||
if (!(cont & MASK_WATER))
|
||||
return;
|
||||
|
||||
ent->waterlevel = 2;
|
||||
point[2] += 22;
|
||||
cont = gi.pointcontents (point);
|
||||
if (cont & MASK_WATER)
|
||||
ent->waterlevel = 3;
|
||||
}
|
||||
|
||||
|
||||
void M_WorldEffects (edict_t *ent)
|
||||
{
|
||||
int dmg;
|
||||
|
||||
if (ent->health > 0)
|
||||
{
|
||||
if (!(ent->flags & FL_SWIM))
|
||||
{
|
||||
if (ent->waterlevel < 3)
|
||||
{
|
||||
ent->air_finished = level.time + 12;
|
||||
}
|
||||
else if (ent->air_finished < level.time)
|
||||
{ // drown!
|
||||
if (ent->pain_debounce_time < level.time)
|
||||
{
|
||||
dmg = 2 + 2 * floor(level.time - ent->air_finished);
|
||||
if (dmg > 15)
|
||||
dmg = 15;
|
||||
T_Damage (ent, world, world, vec3_origin, ent->s.origin, vec3_origin, dmg, 0, DAMAGE_NO_ARMOR, MOD_WATER);
|
||||
ent->pain_debounce_time = level.time + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ent->waterlevel > 0)
|
||||
{
|
||||
ent->air_finished = level.time + 9;
|
||||
}
|
||||
else if (ent->air_finished < level.time)
|
||||
{ // suffocate!
|
||||
if (ent->pain_debounce_time < level.time)
|
||||
{
|
||||
dmg = 2 + 2 * floor(level.time - ent->air_finished);
|
||||
if (dmg > 15)
|
||||
dmg = 15;
|
||||
T_Damage (ent, world, world, vec3_origin, ent->s.origin, vec3_origin, dmg, 0, DAMAGE_NO_ARMOR, MOD_WATER);
|
||||
ent->pain_debounce_time = level.time + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ent->waterlevel == 0)
|
||||
{
|
||||
if (ent->flags & FL_INWATER)
|
||||
{
|
||||
gi.sound (ent, CHAN_BODY, gi.soundindex("player/watr_out.wav"), 1, ATTN_NORM, 0);
|
||||
ent->flags &= ~FL_INWATER;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if ((ent->watertype & CONTENTS_LAVA) && !(ent->flags & FL_IMMUNE_LAVA))
|
||||
{
|
||||
if (ent->damage_debounce_time < level.time)
|
||||
{
|
||||
ent->damage_debounce_time = level.time + 0.2;
|
||||
T_Damage (ent, world, world, vec3_origin, ent->s.origin, vec3_origin, 10*ent->waterlevel, 0, 0, MOD_LAVA);
|
||||
}
|
||||
}
|
||||
if ((ent->watertype & CONTENTS_SLIME) && !(ent->flags & FL_IMMUNE_SLIME))
|
||||
{
|
||||
if (ent->damage_debounce_time < level.time)
|
||||
{
|
||||
ent->damage_debounce_time = level.time + 1;
|
||||
T_Damage (ent, world, world, vec3_origin, ent->s.origin, vec3_origin, 4*ent->waterlevel, 0, 0, MOD_SLIME);
|
||||
}
|
||||
}
|
||||
|
||||
if ( !(ent->flags & FL_INWATER) )
|
||||
{
|
||||
if (!(ent->svflags & SVF_DEADMONSTER))
|
||||
{
|
||||
if (ent->watertype & CONTENTS_LAVA)
|
||||
if (random() <= 0.5)
|
||||
gi.sound (ent, CHAN_BODY, gi.soundindex("player/lava1.wav"), 1, ATTN_NORM, 0);
|
||||
else
|
||||
gi.sound (ent, CHAN_BODY, gi.soundindex("player/lava2.wav"), 1, ATTN_NORM, 0);
|
||||
else if (ent->watertype & CONTENTS_SLIME)
|
||||
gi.sound (ent, CHAN_BODY, gi.soundindex("player/watr_in.wav"), 1, ATTN_NORM, 0);
|
||||
else if (ent->watertype & CONTENTS_WATER)
|
||||
gi.sound (ent, CHAN_BODY, gi.soundindex("player/watr_in.wav"), 1, ATTN_NORM, 0);
|
||||
}
|
||||
|
||||
ent->flags |= FL_INWATER;
|
||||
ent->damage_debounce_time = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void M_droptofloor (edict_t *ent)
|
||||
{
|
||||
vec3_t end;
|
||||
trace_t trace;
|
||||
|
||||
ent->s.origin[2] += 1;
|
||||
VectorCopy (ent->s.origin, end);
|
||||
end[2] -= 256;
|
||||
|
||||
trace = gi.trace (ent->s.origin, ent->mins, ent->maxs, end, ent, MASK_MONSTERSOLID);
|
||||
|
||||
if (trace.fraction == 1 || trace.allsolid)
|
||||
return;
|
||||
|
||||
VectorCopy (trace.endpos, ent->s.origin);
|
||||
|
||||
gi.linkentity (ent);
|
||||
M_CheckGround (ent);
|
||||
M_CatagorizePosition (ent);
|
||||
}
|
||||
|
||||
|
||||
void M_SetEffects (edict_t *ent)
|
||||
{
|
||||
ent->s.effects &= ~(EF_COLOR_SHELL|EF_POWERSCREEN);
|
||||
ent->s.renderfx &= ~(RF_SHELL_RED|RF_SHELL_GREEN|RF_SHELL_BLUE);
|
||||
|
||||
if (ent->monsterinfo.aiflags & AI_RESURRECTING)
|
||||
{
|
||||
ent->s.effects |= EF_COLOR_SHELL;
|
||||
ent->s.renderfx |= RF_SHELL_RED;
|
||||
}
|
||||
|
||||
if (ent->health <= 0)
|
||||
return;
|
||||
|
||||
if (ent->powerarmor_time > level.time)
|
||||
{
|
||||
if (ent->monsterinfo.power_armor_type == POWER_ARMOR_SCREEN)
|
||||
{
|
||||
ent->s.effects |= EF_POWERSCREEN;
|
||||
}
|
||||
else if (ent->monsterinfo.power_armor_type == POWER_ARMOR_SHIELD)
|
||||
{
|
||||
ent->s.effects |= EF_COLOR_SHELL;
|
||||
ent->s.renderfx |= RF_SHELL_GREEN;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void M_MoveFrame (edict_t *self)
|
||||
{
|
||||
mmove_t *move;
|
||||
int index;
|
||||
|
||||
move = self->monsterinfo.currentmove;
|
||||
self->nextthink = level.time + FRAMETIME;
|
||||
|
||||
if ((self->monsterinfo.nextframe) && (self->monsterinfo.nextframe >= move->firstframe) && (self->monsterinfo.nextframe <= move->lastframe))
|
||||
{
|
||||
self->s.frame = self->monsterinfo.nextframe;
|
||||
self->monsterinfo.nextframe = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (self->s.frame == move->lastframe)
|
||||
{
|
||||
if (move->endfunc)
|
||||
{
|
||||
move->endfunc (self);
|
||||
|
||||
// regrab move, endfunc is very likely to change it
|
||||
move = self->monsterinfo.currentmove;
|
||||
|
||||
// check for death
|
||||
if (self->svflags & SVF_DEADMONSTER)
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (self->s.frame < move->firstframe || self->s.frame > move->lastframe)
|
||||
{
|
||||
self->monsterinfo.aiflags &= ~AI_HOLD_FRAME;
|
||||
self->s.frame = move->firstframe;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!(self->monsterinfo.aiflags & AI_HOLD_FRAME))
|
||||
{
|
||||
self->s.frame++;
|
||||
if (self->s.frame > move->lastframe)
|
||||
self->s.frame = move->firstframe;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
index = self->s.frame - move->firstframe;
|
||||
if (move->frame[index].aifunc)
|
||||
if (!(self->monsterinfo.aiflags & AI_HOLD_FRAME))
|
||||
move->frame[index].aifunc (self, move->frame[index].dist * self->monsterinfo.scale);
|
||||
else
|
||||
move->frame[index].aifunc (self, 0);
|
||||
|
||||
if (move->frame[index].thinkfunc)
|
||||
move->frame[index].thinkfunc (self);
|
||||
}
|
||||
|
||||
|
||||
void monster_think (edict_t *self)
|
||||
{
|
||||
M_MoveFrame (self);
|
||||
if (self->linkcount != self->monsterinfo.linkcount)
|
||||
{
|
||||
self->monsterinfo.linkcount = self->linkcount;
|
||||
M_CheckGround (self);
|
||||
}
|
||||
M_CatagorizePosition (self);
|
||||
M_WorldEffects (self);
|
||||
M_SetEffects (self);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
monster_use
|
||||
|
||||
Using a monster makes it angry at the current activator
|
||||
================
|
||||
*/
|
||||
void monster_use (edict_t *self, edict_t *other, edict_t *activator)
|
||||
{
|
||||
if (self->enemy)
|
||||
return;
|
||||
if (self->health <= 0)
|
||||
return;
|
||||
if (activator->flags & FL_NOTARGET)
|
||||
return;
|
||||
if (!(activator->client) && !(activator->monsterinfo.aiflags & AI_GOOD_GUY))
|
||||
return;
|
||||
|
||||
// delay reaction so if the monster is teleported, its sound is still heard
|
||||
self->enemy = activator;
|
||||
FoundTarget (self);
|
||||
}
|
||||
|
||||
|
||||
void monster_start_go (edict_t *self);
|
||||
|
||||
|
||||
void monster_triggered_spawn (edict_t *self)
|
||||
{
|
||||
self->s.origin[2] += 1;
|
||||
KillBox (self);
|
||||
|
||||
self->solid = SOLID_BBOX;
|
||||
self->movetype = MOVETYPE_STEP;
|
||||
self->svflags &= ~SVF_NOCLIENT;
|
||||
self->air_finished = level.time + 12;
|
||||
gi.linkentity (self);
|
||||
|
||||
monster_start_go (self);
|
||||
|
||||
if (self->enemy && !(self->spawnflags & 1) && !(self->enemy->flags & FL_NOTARGET))
|
||||
{
|
||||
FoundTarget (self);
|
||||
}
|
||||
else
|
||||
{
|
||||
self->enemy = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void monster_triggered_spawn_use (edict_t *self, edict_t *other, edict_t *activator)
|
||||
{
|
||||
// we have a one frame delay here so we don't telefrag the guy who activated us
|
||||
self->think = monster_triggered_spawn;
|
||||
self->nextthink = level.time + FRAMETIME;
|
||||
if (activator->client)
|
||||
self->enemy = activator;
|
||||
self->use = monster_use;
|
||||
}
|
||||
|
||||
void monster_triggered_start (edict_t *self)
|
||||
{
|
||||
self->solid = SOLID_NOT;
|
||||
self->movetype = MOVETYPE_NONE;
|
||||
self->svflags |= SVF_NOCLIENT;
|
||||
self->nextthink = 0;
|
||||
self->use = monster_triggered_spawn_use;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
monster_death_use
|
||||
|
||||
When a monster dies, it fires all of its targets with the current
|
||||
enemy as activator.
|
||||
================
|
||||
*/
|
||||
void monster_death_use (edict_t *self)
|
||||
{
|
||||
self->flags &= ~(FL_FLY|FL_SWIM);
|
||||
self->monsterinfo.aiflags &= AI_GOOD_GUY;
|
||||
|
||||
if (self->item)
|
||||
{
|
||||
Drop_Item (self, self->item);
|
||||
self->item = NULL;
|
||||
}
|
||||
|
||||
if (self->deathtarget)
|
||||
self->target = self->deathtarget;
|
||||
|
||||
if (!self->target)
|
||||
return;
|
||||
|
||||
G_UseTargets (self, self->enemy);
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
|
||||
qboolean monster_start (edict_t *self)
|
||||
{
|
||||
if (deathmatch->value)
|
||||
{
|
||||
G_FreeEdict (self);
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((self->spawnflags & 4) && !(self->monsterinfo.aiflags & AI_GOOD_GUY))
|
||||
{
|
||||
self->spawnflags &= ~4;
|
||||
self->spawnflags |= 1;
|
||||
// gi.dprintf("fixed spawnflags on %s at %s\n", self->classname, vtos(self->s.origin));
|
||||
}
|
||||
|
||||
if (!(self->monsterinfo.aiflags & AI_GOOD_GUY))
|
||||
level.total_monsters++;
|
||||
|
||||
self->nextthink = level.time + FRAMETIME;
|
||||
self->svflags |= SVF_MONSTER;
|
||||
self->s.renderfx |= RF_FRAMELERP;
|
||||
self->takedamage = DAMAGE_AIM;
|
||||
self->air_finished = level.time + 12;
|
||||
self->use = monster_use;
|
||||
self->max_health = self->health;
|
||||
self->clipmask = MASK_MONSTERSOLID;
|
||||
|
||||
self->s.skinnum = 0;
|
||||
self->deadflag = DEAD_NO;
|
||||
self->svflags &= ~SVF_DEADMONSTER;
|
||||
|
||||
if (!self->monsterinfo.checkattack)
|
||||
self->monsterinfo.checkattack = M_CheckAttack;
|
||||
VectorCopy (self->s.origin, self->s.old_origin);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
// randomize what frame they start on
|
||||
if (self->monsterinfo.currentmove)
|
||||
self->s.frame = self->monsterinfo.currentmove->firstframe + (rand() % (self->monsterinfo.currentmove->lastframe - self->monsterinfo.currentmove->firstframe + 1));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void monster_start_go (edict_t *self)
|
||||
{
|
||||
vec3_t v;
|
||||
|
||||
if (self->health <= 0)
|
||||
return;
|
||||
|
||||
// check for target to combat_point and change to combattarget
|
||||
if (self->target)
|
||||
{
|
||||
qboolean notcombat;
|
||||
qboolean fixup;
|
||||
edict_t *target;
|
||||
|
||||
target = NULL;
|
||||
notcombat = false;
|
||||
fixup = false;
|
||||
while ((target = G_Find (target, FOFS(targetname), self->target)) != NULL)
|
||||
{
|
||||
if (strcmp(target->classname, "point_combat") == 0)
|
||||
{
|
||||
self->combattarget = self->target;
|
||||
fixup = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
notcombat = true;
|
||||
}
|
||||
}
|
||||
if (notcombat && self->combattarget)
|
||||
gi.dprintf("%s at %s has target with mixed types\n", self->classname, vtos(self->s.origin));
|
||||
if (fixup)
|
||||
self->target = NULL;
|
||||
}
|
||||
|
||||
// validate combattarget
|
||||
if (self->combattarget)
|
||||
{
|
||||
edict_t *target;
|
||||
|
||||
target = NULL;
|
||||
while ((target = G_Find (target, FOFS(targetname), self->combattarget)) != NULL)
|
||||
{
|
||||
if (strcmp(target->classname, "point_combat") != 0)
|
||||
{
|
||||
gi.dprintf("%s at (%i %i %i) has a bad combattarget %s : %s at (%i %i %i)\n",
|
||||
self->classname, (int)self->s.origin[0], (int)self->s.origin[1], (int)self->s.origin[2],
|
||||
self->combattarget, target->classname, (int)target->s.origin[0], (int)target->s.origin[1],
|
||||
(int)target->s.origin[2]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (self->target)
|
||||
{
|
||||
self->goalentity = self->movetarget = G_PickTarget(self->target);
|
||||
if (!self->movetarget)
|
||||
{
|
||||
gi.dprintf ("%s can't find target %s at %s\n", self->classname, self->target, vtos(self->s.origin));
|
||||
self->target = NULL;
|
||||
self->monsterinfo.pausetime = 100000000;
|
||||
self->monsterinfo.stand (self);
|
||||
}
|
||||
else if (strcmp (self->movetarget->classname, "path_corner") == 0)
|
||||
{
|
||||
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;
|
||||
}
|
||||
else
|
||||
{
|
||||
self->goalentity = self->movetarget = NULL;
|
||||
self->monsterinfo.pausetime = 100000000;
|
||||
self->monsterinfo.stand (self);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
self->monsterinfo.pausetime = 100000000;
|
||||
self->monsterinfo.stand (self);
|
||||
}
|
||||
|
||||
self->think = monster_think;
|
||||
self->nextthink = level.time + FRAMETIME;
|
||||
}
|
||||
|
||||
|
||||
void walkmonster_start_go (edict_t *self)
|
||||
{
|
||||
if (!(self->spawnflags & 2) && level.time < 1)
|
||||
{
|
||||
M_droptofloor (self);
|
||||
|
||||
if (self->groundentity)
|
||||
if (!M_walkmove (self, 0, 0))
|
||||
gi.dprintf ("%s in solid at %s\n", self->classname, vtos(self->s.origin));
|
||||
}
|
||||
|
||||
if (!self->yaw_speed)
|
||||
self->yaw_speed = 20;
|
||||
self->viewheight = 25;
|
||||
|
||||
monster_start_go (self);
|
||||
|
||||
if (self->spawnflags & 2)
|
||||
monster_triggered_start (self);
|
||||
}
|
||||
|
||||
void walkmonster_start (edict_t *self)
|
||||
{
|
||||
self->think = walkmonster_start_go;
|
||||
monster_start (self);
|
||||
}
|
||||
|
||||
|
||||
void flymonster_start_go (edict_t *self)
|
||||
{
|
||||
if (!M_walkmove (self, 0, 0))
|
||||
gi.dprintf ("%s in solid at %s\n", self->classname, vtos(self->s.origin));
|
||||
|
||||
if (!self->yaw_speed)
|
||||
self->yaw_speed = 10;
|
||||
self->viewheight = 25;
|
||||
|
||||
monster_start_go (self);
|
||||
|
||||
if (self->spawnflags & 2)
|
||||
monster_triggered_start (self);
|
||||
}
|
||||
|
||||
|
||||
void flymonster_start (edict_t *self)
|
||||
{
|
||||
self->flags |= FL_FLY;
|
||||
self->think = flymonster_start_go;
|
||||
monster_start (self);
|
||||
}
|
||||
|
||||
|
||||
void swimmonster_start_go (edict_t *self)
|
||||
{
|
||||
if (!self->yaw_speed)
|
||||
self->yaw_speed = 10;
|
||||
self->viewheight = 10;
|
||||
|
||||
monster_start_go (self);
|
||||
|
||||
if (self->spawnflags & 2)
|
||||
monster_triggered_start (self);
|
||||
}
|
||||
|
||||
void swimmonster_start (edict_t *self)
|
||||
{
|
||||
self->flags |= FL_SWIM;
|
||||
self->think = swimmonster_start_go;
|
||||
monster_start (self);
|
||||
}
|
||||
961
original/baseq2/g_phys.c
Normal file
961
original/baseq2/g_phys.c
Normal file
@@ -0,0 +1,961 @@
|
||||
/*
|
||||
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_phys.c
|
||||
|
||||
#include "g_local.h"
|
||||
|
||||
/*
|
||||
|
||||
|
||||
pushmove objects do not obey gravity, and do not interact with each other or trigger fields, but block normal movement and push normal objects when they move.
|
||||
|
||||
onground is set for toss objects when they come to a complete rest. it is set for steping or walking objects
|
||||
|
||||
doors, plats, etc are SOLID_BSP, and MOVETYPE_PUSH
|
||||
bonus items are SOLID_TRIGGER touch, and MOVETYPE_TOSS
|
||||
corpses are SOLID_NOT and MOVETYPE_TOSS
|
||||
crates are SOLID_BBOX and MOVETYPE_TOSS
|
||||
walking monsters are SOLID_SLIDEBOX and MOVETYPE_STEP
|
||||
flying/floating monsters are SOLID_SLIDEBOX and MOVETYPE_FLY
|
||||
|
||||
solid_edge items only clip against bsp models.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
============
|
||||
SV_TestEntityPosition
|
||||
|
||||
============
|
||||
*/
|
||||
edict_t *SV_TestEntityPosition (edict_t *ent)
|
||||
{
|
||||
trace_t trace;
|
||||
int mask;
|
||||
|
||||
if (ent->clipmask)
|
||||
mask = ent->clipmask;
|
||||
else
|
||||
mask = MASK_SOLID;
|
||||
trace = gi.trace (ent->s.origin, ent->mins, ent->maxs, ent->s.origin, ent, mask);
|
||||
|
||||
if (trace.startsolid)
|
||||
return g_edicts;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
SV_CheckVelocity
|
||||
================
|
||||
*/
|
||||
void SV_CheckVelocity (edict_t *ent)
|
||||
{
|
||||
int i;
|
||||
|
||||
//
|
||||
// bound velocity
|
||||
//
|
||||
for (i=0 ; i<3 ; i++)
|
||||
{
|
||||
if (ent->velocity[i] > sv_maxvelocity->value)
|
||||
ent->velocity[i] = sv_maxvelocity->value;
|
||||
else if (ent->velocity[i] < -sv_maxvelocity->value)
|
||||
ent->velocity[i] = -sv_maxvelocity->value;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
SV_RunThink
|
||||
|
||||
Runs thinking code for this frame if necessary
|
||||
=============
|
||||
*/
|
||||
qboolean SV_RunThink (edict_t *ent)
|
||||
{
|
||||
float thinktime;
|
||||
|
||||
thinktime = ent->nextthink;
|
||||
if (thinktime <= 0)
|
||||
return true;
|
||||
if (thinktime > level.time+0.001)
|
||||
return true;
|
||||
|
||||
ent->nextthink = 0;
|
||||
if (!ent->think)
|
||||
gi.error ("NULL ent->think");
|
||||
ent->think (ent);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
SV_Impact
|
||||
|
||||
Two entities have touched, so run their touch functions
|
||||
==================
|
||||
*/
|
||||
void SV_Impact (edict_t *e1, trace_t *trace)
|
||||
{
|
||||
edict_t *e2;
|
||||
// cplane_t backplane;
|
||||
|
||||
e2 = trace->ent;
|
||||
|
||||
if (e1->touch && e1->solid != SOLID_NOT)
|
||||
e1->touch (e1, e2, &trace->plane, trace->surface);
|
||||
|
||||
if (e2->touch && e2->solid != SOLID_NOT)
|
||||
e2->touch (e2, e1, NULL, NULL);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
==================
|
||||
ClipVelocity
|
||||
|
||||
Slide off of the impacting object
|
||||
returns the blocked flags (1 = floor, 2 = step / wall)
|
||||
==================
|
||||
*/
|
||||
#define STOP_EPSILON 0.1
|
||||
|
||||
int ClipVelocity (vec3_t in, vec3_t normal, vec3_t out, float overbounce)
|
||||
{
|
||||
float backoff;
|
||||
float change;
|
||||
int i, blocked;
|
||||
|
||||
blocked = 0;
|
||||
if (normal[2] > 0)
|
||||
blocked |= 1; // floor
|
||||
if (!normal[2])
|
||||
blocked |= 2; // step
|
||||
|
||||
backoff = DotProduct (in, normal) * overbounce;
|
||||
|
||||
for (i=0 ; i<3 ; i++)
|
||||
{
|
||||
change = normal[i]*backoff;
|
||||
out[i] = in[i] - change;
|
||||
if (out[i] > -STOP_EPSILON && out[i] < STOP_EPSILON)
|
||||
out[i] = 0;
|
||||
}
|
||||
|
||||
return blocked;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
============
|
||||
SV_FlyMove
|
||||
|
||||
The basic solid body movement clip that slides along multiple planes
|
||||
Returns the clipflags if the velocity was modified (hit something solid)
|
||||
1 = floor
|
||||
2 = wall / step
|
||||
4 = dead stop
|
||||
============
|
||||
*/
|
||||
#define MAX_CLIP_PLANES 5
|
||||
int SV_FlyMove (edict_t *ent, float time, int mask)
|
||||
{
|
||||
edict_t *hit;
|
||||
int bumpcount, numbumps;
|
||||
vec3_t dir;
|
||||
float d;
|
||||
int numplanes;
|
||||
vec3_t planes[MAX_CLIP_PLANES];
|
||||
vec3_t primal_velocity, original_velocity, new_velocity;
|
||||
int i, j;
|
||||
trace_t trace;
|
||||
vec3_t end;
|
||||
float time_left;
|
||||
int blocked;
|
||||
|
||||
numbumps = 4;
|
||||
|
||||
blocked = 0;
|
||||
VectorCopy (ent->velocity, original_velocity);
|
||||
VectorCopy (ent->velocity, primal_velocity);
|
||||
numplanes = 0;
|
||||
|
||||
time_left = time;
|
||||
|
||||
ent->groundentity = NULL;
|
||||
for (bumpcount=0 ; bumpcount<numbumps ; bumpcount++)
|
||||
{
|
||||
for (i=0 ; i<3 ; i++)
|
||||
end[i] = ent->s.origin[i] + time_left * ent->velocity[i];
|
||||
|
||||
trace = gi.trace (ent->s.origin, ent->mins, ent->maxs, end, ent, mask);
|
||||
|
||||
if (trace.allsolid)
|
||||
{ // entity is trapped in another solid
|
||||
VectorCopy (vec3_origin, ent->velocity);
|
||||
return 3;
|
||||
}
|
||||
|
||||
if (trace.fraction > 0)
|
||||
{ // actually covered some distance
|
||||
VectorCopy (trace.endpos, ent->s.origin);
|
||||
VectorCopy (ent->velocity, original_velocity);
|
||||
numplanes = 0;
|
||||
}
|
||||
|
||||
if (trace.fraction == 1)
|
||||
break; // moved the entire distance
|
||||
|
||||
hit = trace.ent;
|
||||
|
||||
if (trace.plane.normal[2] > 0.7)
|
||||
{
|
||||
blocked |= 1; // floor
|
||||
if ( hit->solid == SOLID_BSP)
|
||||
{
|
||||
ent->groundentity = hit;
|
||||
ent->groundentity_linkcount = hit->linkcount;
|
||||
}
|
||||
}
|
||||
if (!trace.plane.normal[2])
|
||||
{
|
||||
blocked |= 2; // step
|
||||
}
|
||||
|
||||
//
|
||||
// run the impact function
|
||||
//
|
||||
SV_Impact (ent, &trace);
|
||||
if (!ent->inuse)
|
||||
break; // removed by the impact function
|
||||
|
||||
|
||||
time_left -= time_left * trace.fraction;
|
||||
|
||||
// cliped to another plane
|
||||
if (numplanes >= MAX_CLIP_PLANES)
|
||||
{ // this shouldn't really happen
|
||||
VectorCopy (vec3_origin, ent->velocity);
|
||||
return 3;
|
||||
}
|
||||
|
||||
VectorCopy (trace.plane.normal, planes[numplanes]);
|
||||
numplanes++;
|
||||
|
||||
//
|
||||
// modify original_velocity so it parallels all of the clip planes
|
||||
//
|
||||
for (i=0 ; i<numplanes ; i++)
|
||||
{
|
||||
ClipVelocity (original_velocity, planes[i], new_velocity, 1);
|
||||
|
||||
for (j=0 ; j<numplanes ; j++)
|
||||
if ((j != i) && !VectorCompare (planes[i], planes[j]))
|
||||
{
|
||||
if (DotProduct (new_velocity, planes[j]) < 0)
|
||||
break; // not ok
|
||||
}
|
||||
if (j == numplanes)
|
||||
break;
|
||||
}
|
||||
|
||||
if (i != numplanes)
|
||||
{ // go along this plane
|
||||
VectorCopy (new_velocity, ent->velocity);
|
||||
}
|
||||
else
|
||||
{ // go along the crease
|
||||
if (numplanes != 2)
|
||||
{
|
||||
// gi.dprintf ("clip velocity, numplanes == %i\n",numplanes);
|
||||
VectorCopy (vec3_origin, ent->velocity);
|
||||
return 7;
|
||||
}
|
||||
CrossProduct (planes[0], planes[1], dir);
|
||||
d = DotProduct (dir, ent->velocity);
|
||||
VectorScale (dir, d, ent->velocity);
|
||||
}
|
||||
|
||||
//
|
||||
// if original velocity is against the original velocity, stop dead
|
||||
// to avoid tiny occilations in sloping corners
|
||||
//
|
||||
if (DotProduct (ent->velocity, primal_velocity) <= 0)
|
||||
{
|
||||
VectorCopy (vec3_origin, ent->velocity);
|
||||
return blocked;
|
||||
}
|
||||
}
|
||||
|
||||
return blocked;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
============
|
||||
SV_AddGravity
|
||||
|
||||
============
|
||||
*/
|
||||
void SV_AddGravity (edict_t *ent)
|
||||
{
|
||||
ent->velocity[2] -= ent->gravity * sv_gravity->value * FRAMETIME;
|
||||
}
|
||||
|
||||
/*
|
||||
===============================================================================
|
||||
|
||||
PUSHMOVE
|
||||
|
||||
===============================================================================
|
||||
*/
|
||||
|
||||
/*
|
||||
============
|
||||
SV_PushEntity
|
||||
|
||||
Does not change the entities velocity at all
|
||||
============
|
||||
*/
|
||||
trace_t SV_PushEntity (edict_t *ent, vec3_t push)
|
||||
{
|
||||
trace_t trace;
|
||||
vec3_t start;
|
||||
vec3_t end;
|
||||
int mask;
|
||||
|
||||
VectorCopy (ent->s.origin, start);
|
||||
VectorAdd (start, push, end);
|
||||
|
||||
retry:
|
||||
if (ent->clipmask)
|
||||
mask = ent->clipmask;
|
||||
else
|
||||
mask = MASK_SOLID;
|
||||
|
||||
trace = gi.trace (start, ent->mins, ent->maxs, end, ent, mask);
|
||||
|
||||
VectorCopy (trace.endpos, ent->s.origin);
|
||||
gi.linkentity (ent);
|
||||
|
||||
if (trace.fraction != 1.0)
|
||||
{
|
||||
SV_Impact (ent, &trace);
|
||||
|
||||
// if the pushed entity went away and the pusher is still there
|
||||
if (!trace.ent->inuse && ent->inuse)
|
||||
{
|
||||
// move the pusher back and try again
|
||||
VectorCopy (start, ent->s.origin);
|
||||
gi.linkentity (ent);
|
||||
goto retry;
|
||||
}
|
||||
}
|
||||
|
||||
if (ent->inuse)
|
||||
G_TouchTriggers (ent);
|
||||
|
||||
return trace;
|
||||
}
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
edict_t *ent;
|
||||
vec3_t origin;
|
||||
vec3_t angles;
|
||||
float deltayaw;
|
||||
} pushed_t;
|
||||
pushed_t pushed[MAX_EDICTS], *pushed_p;
|
||||
|
||||
edict_t *obstacle;
|
||||
|
||||
/*
|
||||
============
|
||||
SV_Push
|
||||
|
||||
Objects need to be moved back on a failed push,
|
||||
otherwise riders would continue to slide.
|
||||
============
|
||||
*/
|
||||
qboolean SV_Push (edict_t *pusher, vec3_t move, vec3_t amove)
|
||||
{
|
||||
int i, e;
|
||||
edict_t *check, *block;
|
||||
vec3_t mins, maxs;
|
||||
pushed_t *p;
|
||||
vec3_t org, org2, move2, forward, right, up;
|
||||
|
||||
// clamp the move to 1/8 units, so the position will
|
||||
// be accurate for client side prediction
|
||||
for (i=0 ; i<3 ; i++)
|
||||
{
|
||||
float temp;
|
||||
temp = move[i]*8.0;
|
||||
if (temp > 0.0)
|
||||
temp += 0.5;
|
||||
else
|
||||
temp -= 0.5;
|
||||
move[i] = 0.125 * (int)temp;
|
||||
}
|
||||
|
||||
// find the bounding box
|
||||
for (i=0 ; i<3 ; i++)
|
||||
{
|
||||
mins[i] = pusher->absmin[i] + move[i];
|
||||
maxs[i] = pusher->absmax[i] + move[i];
|
||||
}
|
||||
|
||||
// we need this for pushing things later
|
||||
VectorSubtract (vec3_origin, amove, org);
|
||||
AngleVectors (org, forward, right, up);
|
||||
|
||||
// save the pusher's original position
|
||||
pushed_p->ent = pusher;
|
||||
VectorCopy (pusher->s.origin, pushed_p->origin);
|
||||
VectorCopy (pusher->s.angles, pushed_p->angles);
|
||||
if (pusher->client)
|
||||
pushed_p->deltayaw = pusher->client->ps.pmove.delta_angles[YAW];
|
||||
pushed_p++;
|
||||
|
||||
// move the pusher to it's final position
|
||||
VectorAdd (pusher->s.origin, move, pusher->s.origin);
|
||||
VectorAdd (pusher->s.angles, amove, pusher->s.angles);
|
||||
gi.linkentity (pusher);
|
||||
|
||||
// see if any solid entities are inside the final position
|
||||
check = g_edicts+1;
|
||||
for (e = 1; e < globals.num_edicts; e++, check++)
|
||||
{
|
||||
if (!check->inuse)
|
||||
continue;
|
||||
if (check->movetype == MOVETYPE_PUSH
|
||||
|| check->movetype == MOVETYPE_STOP
|
||||
|| check->movetype == MOVETYPE_NONE
|
||||
|| check->movetype == MOVETYPE_NOCLIP)
|
||||
continue;
|
||||
|
||||
if (!check->area.prev)
|
||||
continue; // not linked in anywhere
|
||||
|
||||
// if the entity is standing on the pusher, it will definitely be moved
|
||||
if (check->groundentity != pusher)
|
||||
{
|
||||
// see if the ent needs to be tested
|
||||
if ( check->absmin[0] >= maxs[0]
|
||||
|| check->absmin[1] >= maxs[1]
|
||||
|| check->absmin[2] >= maxs[2]
|
||||
|| check->absmax[0] <= mins[0]
|
||||
|| check->absmax[1] <= mins[1]
|
||||
|| check->absmax[2] <= mins[2] )
|
||||
continue;
|
||||
|
||||
// see if the ent's bbox is inside the pusher's final position
|
||||
if (!SV_TestEntityPosition (check))
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((pusher->movetype == MOVETYPE_PUSH) || (check->groundentity == pusher))
|
||||
{
|
||||
// move this entity
|
||||
pushed_p->ent = check;
|
||||
VectorCopy (check->s.origin, pushed_p->origin);
|
||||
VectorCopy (check->s.angles, pushed_p->angles);
|
||||
pushed_p++;
|
||||
|
||||
// try moving the contacted entity
|
||||
VectorAdd (check->s.origin, move, check->s.origin);
|
||||
if (check->client)
|
||||
{ // FIXME: doesn't rotate monsters?
|
||||
check->client->ps.pmove.delta_angles[YAW] += amove[YAW];
|
||||
}
|
||||
|
||||
// figure movement due to the pusher's amove
|
||||
VectorSubtract (check->s.origin, pusher->s.origin, org);
|
||||
org2[0] = DotProduct (org, forward);
|
||||
org2[1] = -DotProduct (org, right);
|
||||
org2[2] = DotProduct (org, up);
|
||||
VectorSubtract (org2, org, move2);
|
||||
VectorAdd (check->s.origin, move2, check->s.origin);
|
||||
|
||||
// may have pushed them off an edge
|
||||
if (check->groundentity != pusher)
|
||||
check->groundentity = NULL;
|
||||
|
||||
block = SV_TestEntityPosition (check);
|
||||
if (!block)
|
||||
{ // pushed ok
|
||||
gi.linkentity (check);
|
||||
// impact?
|
||||
continue;
|
||||
}
|
||||
|
||||
// if it is ok to leave in the old position, do it
|
||||
// this is only relevent for riding entities, not pushed
|
||||
// FIXME: this doesn't acount for rotation
|
||||
VectorSubtract (check->s.origin, move, check->s.origin);
|
||||
block = SV_TestEntityPosition (check);
|
||||
if (!block)
|
||||
{
|
||||
pushed_p--;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// save off the obstacle so we can call the block function
|
||||
obstacle = check;
|
||||
|
||||
// move back any entities we already moved
|
||||
// go backwards, so if the same entity was pushed
|
||||
// twice, it goes back to the original position
|
||||
for (p=pushed_p-1 ; p>=pushed ; p--)
|
||||
{
|
||||
VectorCopy (p->origin, p->ent->s.origin);
|
||||
VectorCopy (p->angles, p->ent->s.angles);
|
||||
if (p->ent->client)
|
||||
{
|
||||
p->ent->client->ps.pmove.delta_angles[YAW] = p->deltayaw;
|
||||
}
|
||||
gi.linkentity (p->ent);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//FIXME: is there a better way to handle this?
|
||||
// see if anything we moved has touched a trigger
|
||||
for (p=pushed_p-1 ; p>=pushed ; p--)
|
||||
G_TouchTriggers (p->ent);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
SV_Physics_Pusher
|
||||
|
||||
Bmodel objects don't interact with each other, but
|
||||
push all box objects
|
||||
================
|
||||
*/
|
||||
void SV_Physics_Pusher (edict_t *ent)
|
||||
{
|
||||
vec3_t move, amove;
|
||||
edict_t *part, *mv;
|
||||
|
||||
// if not a team captain, so movement will be handled elsewhere
|
||||
if ( ent->flags & FL_TEAMSLAVE)
|
||||
return;
|
||||
|
||||
// make sure all team slaves can move before commiting
|
||||
// any moves or calling any think functions
|
||||
// if the move is blocked, all moved objects will be backed out
|
||||
//retry:
|
||||
pushed_p = pushed;
|
||||
for (part = ent ; part ; part=part->teamchain)
|
||||
{
|
||||
if (part->velocity[0] || part->velocity[1] || part->velocity[2] ||
|
||||
part->avelocity[0] || part->avelocity[1] || part->avelocity[2]
|
||||
)
|
||||
{ // object is moving
|
||||
VectorScale (part->velocity, FRAMETIME, move);
|
||||
VectorScale (part->avelocity, FRAMETIME, amove);
|
||||
|
||||
if (!SV_Push (part, move, amove))
|
||||
break; // move was blocked
|
||||
}
|
||||
}
|
||||
if (pushed_p > &pushed[MAX_EDICTS])
|
||||
gi.error (ERR_FATAL, "pushed_p > &pushed[MAX_EDICTS], memory corrupted");
|
||||
|
||||
if (part)
|
||||
{
|
||||
// the move failed, bump all nextthink times and back out moves
|
||||
for (mv = ent ; mv ; mv=mv->teamchain)
|
||||
{
|
||||
if (mv->nextthink > 0)
|
||||
mv->nextthink += FRAMETIME;
|
||||
}
|
||||
|
||||
// if the pusher has a "blocked" function, call it
|
||||
// otherwise, just stay in place until the obstacle is gone
|
||||
if (part->blocked)
|
||||
part->blocked (part, obstacle);
|
||||
#if 0
|
||||
// if the pushed entity went away and the pusher is still there
|
||||
if (!obstacle->inuse && part->inuse)
|
||||
goto retry;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
// the move succeeded, so call all think functions
|
||||
for (part = ent ; part ; part=part->teamchain)
|
||||
{
|
||||
SV_RunThink (part);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//==================================================================
|
||||
|
||||
/*
|
||||
=============
|
||||
SV_Physics_None
|
||||
|
||||
Non moving objects can only think
|
||||
=============
|
||||
*/
|
||||
void SV_Physics_None (edict_t *ent)
|
||||
{
|
||||
// regular thinking
|
||||
SV_RunThink (ent);
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
SV_Physics_Noclip
|
||||
|
||||
A moving object that doesn't obey physics
|
||||
=============
|
||||
*/
|
||||
void SV_Physics_Noclip (edict_t *ent)
|
||||
{
|
||||
// regular thinking
|
||||
if (!SV_RunThink (ent))
|
||||
return;
|
||||
|
||||
VectorMA (ent->s.angles, FRAMETIME, ent->avelocity, ent->s.angles);
|
||||
VectorMA (ent->s.origin, FRAMETIME, ent->velocity, ent->s.origin);
|
||||
|
||||
gi.linkentity (ent);
|
||||
}
|
||||
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
TOSS / BOUNCE
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
/*
|
||||
=============
|
||||
SV_Physics_Toss
|
||||
|
||||
Toss, bounce, and fly movement. When onground, do nothing.
|
||||
=============
|
||||
*/
|
||||
void SV_Physics_Toss (edict_t *ent)
|
||||
{
|
||||
trace_t trace;
|
||||
vec3_t move;
|
||||
float backoff;
|
||||
edict_t *slave;
|
||||
qboolean wasinwater;
|
||||
qboolean isinwater;
|
||||
vec3_t old_origin;
|
||||
|
||||
// regular thinking
|
||||
SV_RunThink (ent);
|
||||
|
||||
// if not a team captain, so movement will be handled elsewhere
|
||||
if ( ent->flags & FL_TEAMSLAVE)
|
||||
return;
|
||||
|
||||
if (ent->velocity[2] > 0)
|
||||
ent->groundentity = NULL;
|
||||
|
||||
// check for the groundentity going away
|
||||
if (ent->groundentity)
|
||||
if (!ent->groundentity->inuse)
|
||||
ent->groundentity = NULL;
|
||||
|
||||
// if onground, return without moving
|
||||
if ( ent->groundentity )
|
||||
return;
|
||||
|
||||
VectorCopy (ent->s.origin, old_origin);
|
||||
|
||||
SV_CheckVelocity (ent);
|
||||
|
||||
// add gravity
|
||||
if (ent->movetype != MOVETYPE_FLY
|
||||
&& ent->movetype != MOVETYPE_FLYMISSILE)
|
||||
SV_AddGravity (ent);
|
||||
|
||||
// move angles
|
||||
VectorMA (ent->s.angles, FRAMETIME, ent->avelocity, ent->s.angles);
|
||||
|
||||
// move origin
|
||||
VectorScale (ent->velocity, FRAMETIME, move);
|
||||
trace = SV_PushEntity (ent, move);
|
||||
if (!ent->inuse)
|
||||
return;
|
||||
|
||||
if (trace.fraction < 1)
|
||||
{
|
||||
if (ent->movetype == MOVETYPE_BOUNCE)
|
||||
backoff = 1.5;
|
||||
else
|
||||
backoff = 1;
|
||||
|
||||
ClipVelocity (ent->velocity, trace.plane.normal, ent->velocity, backoff);
|
||||
|
||||
// stop if on ground
|
||||
if (trace.plane.normal[2] > 0.7)
|
||||
{
|
||||
if (ent->velocity[2] < 60 || ent->movetype != MOVETYPE_BOUNCE )
|
||||
{
|
||||
ent->groundentity = trace.ent;
|
||||
ent->groundentity_linkcount = trace.ent->linkcount;
|
||||
VectorCopy (vec3_origin, ent->velocity);
|
||||
VectorCopy (vec3_origin, ent->avelocity);
|
||||
}
|
||||
}
|
||||
|
||||
// if (ent->touch)
|
||||
// ent->touch (ent, trace.ent, &trace.plane, trace.surface);
|
||||
}
|
||||
|
||||
// check for water transition
|
||||
wasinwater = (ent->watertype & MASK_WATER);
|
||||
ent->watertype = gi.pointcontents (ent->s.origin);
|
||||
isinwater = ent->watertype & MASK_WATER;
|
||||
|
||||
if (isinwater)
|
||||
ent->waterlevel = 1;
|
||||
else
|
||||
ent->waterlevel = 0;
|
||||
|
||||
if (!wasinwater && isinwater)
|
||||
gi.positioned_sound (old_origin, g_edicts, CHAN_AUTO, gi.soundindex("misc/h2ohit1.wav"), 1, 1, 0);
|
||||
else if (wasinwater && !isinwater)
|
||||
gi.positioned_sound (ent->s.origin, g_edicts, CHAN_AUTO, gi.soundindex("misc/h2ohit1.wav"), 1, 1, 0);
|
||||
|
||||
// move teamslaves
|
||||
for (slave = ent->teamchain; slave; slave = slave->teamchain)
|
||||
{
|
||||
VectorCopy (ent->s.origin, slave->s.origin);
|
||||
gi.linkentity (slave);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
===============================================================================
|
||||
|
||||
STEPPING MOVEMENT
|
||||
|
||||
===============================================================================
|
||||
*/
|
||||
|
||||
/*
|
||||
=============
|
||||
SV_Physics_Step
|
||||
|
||||
Monsters freefall when they don't have a ground entity, otherwise
|
||||
all movement is done with discrete steps.
|
||||
|
||||
This is also used for objects that have become still on the ground, but
|
||||
will fall if the floor is pulled out from under them.
|
||||
FIXME: is this true?
|
||||
=============
|
||||
*/
|
||||
|
||||
//FIXME: hacked in for E3 demo
|
||||
#define sv_stopspeed 100
|
||||
#define sv_friction 6
|
||||
#define sv_waterfriction 1
|
||||
|
||||
void SV_AddRotationalFriction (edict_t *ent)
|
||||
{
|
||||
int n;
|
||||
float adjustment;
|
||||
|
||||
VectorMA (ent->s.angles, FRAMETIME, ent->avelocity, ent->s.angles);
|
||||
adjustment = FRAMETIME * sv_stopspeed * sv_friction;
|
||||
for (n = 0; n < 3; n++)
|
||||
{
|
||||
if (ent->avelocity[n] > 0)
|
||||
{
|
||||
ent->avelocity[n] -= adjustment;
|
||||
if (ent->avelocity[n] < 0)
|
||||
ent->avelocity[n] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
ent->avelocity[n] += adjustment;
|
||||
if (ent->avelocity[n] > 0)
|
||||
ent->avelocity[n] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SV_Physics_Step (edict_t *ent)
|
||||
{
|
||||
qboolean wasonground;
|
||||
qboolean hitsound = false;
|
||||
float *vel;
|
||||
float speed, newspeed, control;
|
||||
float friction;
|
||||
edict_t *groundentity;
|
||||
int mask;
|
||||
|
||||
// airborn monsters should always check for ground
|
||||
if (!ent->groundentity)
|
||||
M_CheckGround (ent);
|
||||
|
||||
groundentity = ent->groundentity;
|
||||
|
||||
SV_CheckVelocity (ent);
|
||||
|
||||
if (groundentity)
|
||||
wasonground = true;
|
||||
else
|
||||
wasonground = false;
|
||||
|
||||
if (ent->avelocity[0] || ent->avelocity[1] || ent->avelocity[2])
|
||||
SV_AddRotationalFriction (ent);
|
||||
|
||||
// add gravity except:
|
||||
// flying monsters
|
||||
// swimming monsters who are in the water
|
||||
if (! wasonground)
|
||||
if (!(ent->flags & FL_FLY))
|
||||
if (!((ent->flags & FL_SWIM) && (ent->waterlevel > 2)))
|
||||
{
|
||||
if (ent->velocity[2] < sv_gravity->value*-0.1)
|
||||
hitsound = true;
|
||||
if (ent->waterlevel == 0)
|
||||
SV_AddGravity (ent);
|
||||
}
|
||||
|
||||
// friction for flying monsters that have been given vertical velocity
|
||||
if ((ent->flags & FL_FLY) && (ent->velocity[2] != 0))
|
||||
{
|
||||
speed = fabs(ent->velocity[2]);
|
||||
control = speed < sv_stopspeed ? sv_stopspeed : speed;
|
||||
friction = sv_friction/3;
|
||||
newspeed = speed - (FRAMETIME * control * friction);
|
||||
if (newspeed < 0)
|
||||
newspeed = 0;
|
||||
newspeed /= speed;
|
||||
ent->velocity[2] *= newspeed;
|
||||
}
|
||||
|
||||
// friction for flying monsters that have been given vertical velocity
|
||||
if ((ent->flags & FL_SWIM) && (ent->velocity[2] != 0))
|
||||
{
|
||||
speed = fabs(ent->velocity[2]);
|
||||
control = speed < sv_stopspeed ? sv_stopspeed : speed;
|
||||
newspeed = speed - (FRAMETIME * control * sv_waterfriction * ent->waterlevel);
|
||||
if (newspeed < 0)
|
||||
newspeed = 0;
|
||||
newspeed /= speed;
|
||||
ent->velocity[2] *= newspeed;
|
||||
}
|
||||
|
||||
if (ent->velocity[2] || ent->velocity[1] || ent->velocity[0])
|
||||
{
|
||||
// apply friction
|
||||
// let dead monsters who aren't completely onground slide
|
||||
if ((wasonground) || (ent->flags & (FL_SWIM|FL_FLY)))
|
||||
if (!(ent->health <= 0.0 && !M_CheckBottom(ent)))
|
||||
{
|
||||
vel = ent->velocity;
|
||||
speed = sqrt(vel[0]*vel[0] +vel[1]*vel[1]);
|
||||
if (speed)
|
||||
{
|
||||
friction = sv_friction;
|
||||
|
||||
control = speed < sv_stopspeed ? sv_stopspeed : speed;
|
||||
newspeed = speed - FRAMETIME*control*friction;
|
||||
|
||||
if (newspeed < 0)
|
||||
newspeed = 0;
|
||||
newspeed /= speed;
|
||||
|
||||
vel[0] *= newspeed;
|
||||
vel[1] *= newspeed;
|
||||
}
|
||||
}
|
||||
|
||||
if (ent->svflags & SVF_MONSTER)
|
||||
mask = MASK_MONSTERSOLID;
|
||||
else
|
||||
mask = MASK_SOLID;
|
||||
SV_FlyMove (ent, FRAMETIME, mask);
|
||||
|
||||
gi.linkentity (ent);
|
||||
G_TouchTriggers (ent);
|
||||
if (!ent->inuse)
|
||||
return;
|
||||
|
||||
if (ent->groundentity)
|
||||
if (!wasonground)
|
||||
if (hitsound)
|
||||
gi.sound (ent, 0, gi.soundindex("world/land.wav"), 1, 1, 0);
|
||||
}
|
||||
|
||||
// regular thinking
|
||||
SV_RunThink (ent);
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
/*
|
||||
================
|
||||
G_RunEntity
|
||||
|
||||
================
|
||||
*/
|
||||
void G_RunEntity (edict_t *ent)
|
||||
{
|
||||
if (ent->prethink)
|
||||
ent->prethink (ent);
|
||||
|
||||
switch ( (int)ent->movetype)
|
||||
{
|
||||
case MOVETYPE_PUSH:
|
||||
case MOVETYPE_STOP:
|
||||
SV_Physics_Pusher (ent);
|
||||
break;
|
||||
case MOVETYPE_NONE:
|
||||
SV_Physics_None (ent);
|
||||
break;
|
||||
case MOVETYPE_NOCLIP:
|
||||
SV_Physics_Noclip (ent);
|
||||
break;
|
||||
case MOVETYPE_STEP:
|
||||
SV_Physics_Step (ent);
|
||||
break;
|
||||
case MOVETYPE_TOSS:
|
||||
case MOVETYPE_BOUNCE:
|
||||
case MOVETYPE_FLY:
|
||||
case MOVETYPE_FLYMISSILE:
|
||||
SV_Physics_Toss (ent);
|
||||
break;
|
||||
default:
|
||||
gi.error ("SV_Physics: bad movetype %i", (int)ent->movetype);
|
||||
}
|
||||
}
|
||||
770
original/baseq2/g_save.c
Normal file
770
original/baseq2/g_save.c
Normal file
@@ -0,0 +1,770 @@
|
||||
/*
|
||||
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);
|
||||
needpass = gi.cvar ("needpass", "0", CVAR_SERVERINFO);
|
||||
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
original/baseq2/g_spawn.c
Normal file
984
original/baseq2/g_spawn.c
Normal 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
original/baseq2/g_svcmds.c
Normal file
300
original/baseq2/g_svcmds.c
Normal 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
original/baseq2/g_target.c
Normal file
809
original/baseq2/g_target.c
Normal 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
original/baseq2/g_trigger.c
Normal file
598
original/baseq2/g_trigger.c
Normal 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
original/baseq2/g_turret.c
Normal file
432
original/baseq2/g_turret.c
Normal 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
original/baseq2/g_utils.c
Normal file
568
original/baseq2/g_utils.c
Normal 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
|
||||
}
|
||||
918
original/baseq2/g_weapon.c
Normal file
918
original/baseq2/g_weapon.c
Normal file
@@ -0,0 +1,918 @@
|
||||
/*
|
||||
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
|
||||
{
|
||||
//ZOID--added so rail goes through SOLID_BBOX entities (gibs, etc)
|
||||
if ((tr.ent->svflags & SVF_MONSTER) || (tr.ent->client) ||
|
||||
(tr.ent->solid == SOLID_BBOX))
|
||||
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);
|
||||
}
|
||||
235
original/baseq2/game.h
Normal file
235
original/baseq2/game.h
Normal file
@@ -0,0 +1,235 @@
|
||||
/*
|
||||
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);
|
||||
609
original/baseq2/m_actor.c
Normal file
609
original/baseq2/m_actor.c
Normal 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
original/baseq2/m_actor.h
Normal file
506
original/baseq2/m_actor.h
Normal 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
original/baseq2/m_berserk.c
Normal file
457
original/baseq2/m_berserk.c
Normal 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
original/baseq2/m_berserk.h
Normal file
269
original/baseq2/m_berserk.h
Normal 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
original/baseq2/m_boss2.c
Normal file
679
original/baseq2/m_boss2.c
Normal 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
original/baseq2/m_boss2.h
Normal file
206
original/baseq2/m_boss2.h
Normal 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
original/baseq2/m_boss3.c
Normal file
76
original/baseq2/m_boss3.c
Normal 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
original/baseq2/m_boss31.c
Normal file
749
original/baseq2/m_boss31.c
Normal 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
original/baseq2/m_boss31.h
Normal file
213
original/baseq2/m_boss31.h
Normal 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
original/baseq2/m_boss32.c
Normal file
913
original/baseq2/m_boss32.c
Normal 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
original/baseq2/m_boss32.h
Normal file
516
original/baseq2/m_boss32.h
Normal 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
original/baseq2/m_brain.c
Normal file
676
original/baseq2/m_brain.c
Normal 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
original/baseq2/m_brain.h
Normal file
247
original/baseq2/m_brain.h
Normal 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
original/baseq2/m_chick.c
Normal file
677
original/baseq2/m_chick.c
Normal 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
original/baseq2/m_chick.h
Normal file
313
original/baseq2/m_chick.h
Normal 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
original/baseq2/m_flash.c
Normal file
488
original/baseq2/m_flash.c
Normal 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
original/baseq2/m_flipper.c
Normal file
403
original/baseq2/m_flipper.c
Normal 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
original/baseq2/m_flipper.h
Normal file
185
original/baseq2/m_flipper.h
Normal 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
original/baseq2/m_float.c
Normal file
663
original/baseq2/m_float.c
Normal 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
original/baseq2/m_float.h
Normal file
273
original/baseq2/m_float.h
Normal 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
original/baseq2/m_flyer.c
Normal file
626
original/baseq2/m_flyer.c
Normal 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
original/baseq2/m_flyer.h
Normal file
182
original/baseq2/m_flyer.h
Normal 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
original/baseq2/m_gladiator.c
Normal file
387
original/baseq2/m_gladiator.c
Normal 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
original/baseq2/m_gladiator.h
Normal file
115
original/baseq2/m_gladiator.h
Normal 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
original/baseq2/m_gunner.c
Normal file
628
original/baseq2/m_gunner.c
Normal 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
original/baseq2/m_gunner.h
Normal file
234
original/baseq2/m_gunner.h
Normal 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
original/baseq2/m_hover.c
Normal file
620
original/baseq2/m_hover.c
Normal 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
original/baseq2/m_hover.h
Normal file
230
original/baseq2/m_hover.h
Normal 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
original/baseq2/m_infantry.c
Normal file
607
original/baseq2/m_infantry.c
Normal 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
original/baseq2/m_infantry.h
Normal file
232
original/baseq2/m_infantry.h
Normal 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
original/baseq2/m_insane.c
Normal file
693
original/baseq2/m_insane.c
Normal 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
original/baseq2/m_insane.h
Normal file
307
original/baseq2/m_insane.h
Normal 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
original/baseq2/m_medic.c
Normal file
769
original/baseq2/m_medic.c
Normal 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
original/baseq2/m_medic.h
Normal file
262
original/baseq2/m_medic.h
Normal 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
original/baseq2/m_move.c
Normal file
556
original/baseq2/m_move.c
Normal 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
original/baseq2/m_mutant.c
Normal file
663
original/baseq2/m_mutant.c
Normal 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
original/baseq2/m_mutant.h
Normal file
174
original/baseq2/m_mutant.h
Normal 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
original/baseq2/m_parasite.c
Normal file
552
original/baseq2/m_parasite.c
Normal 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 = ¶site_move_end_fidget;
|
||||
}
|
||||
|
||||
void parasite_do_fidget (edict_t *self)
|
||||
{
|
||||
self->monsterinfo.currentmove = ¶site_move_fidget;
|
||||
}
|
||||
|
||||
void parasite_refidget (edict_t *self)
|
||||
{
|
||||
if (random() <= 0.8)
|
||||
self->monsterinfo.currentmove = ¶site_move_fidget;
|
||||
else
|
||||
self->monsterinfo.currentmove = ¶site_move_end_fidget;
|
||||
}
|
||||
|
||||
void parasite_idle (edict_t *self)
|
||||
{
|
||||
self->monsterinfo.currentmove = ¶site_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 = ¶site_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 = ¶site_move_stand;
|
||||
else
|
||||
self->monsterinfo.currentmove = ¶site_move_start_run;
|
||||
}
|
||||
|
||||
void parasite_run (edict_t *self)
|
||||
{
|
||||
if (self->monsterinfo.aiflags & AI_STAND_GROUND)
|
||||
self->monsterinfo.currentmove = ¶site_move_stand;
|
||||
else
|
||||
self->monsterinfo.currentmove = ¶site_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 = ¶site_move_start_walk;
|
||||
}
|
||||
|
||||
void parasite_walk (edict_t *self)
|
||||
{
|
||||
self->monsterinfo.currentmove = ¶site_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 = ¶site_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 = ¶site_move_break;
|
||||
// else
|
||||
self->monsterinfo.currentmove = ¶site_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 = ¶site_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 = ¶site_move_stand;
|
||||
self->monsterinfo.scale = MODEL_SCALE;
|
||||
|
||||
walkmonster_start (self);
|
||||
}
|
||||
143
original/baseq2/m_parasite.h
Normal file
143
original/baseq2/m_parasite.h
Normal 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
original/baseq2/m_player.h
Normal file
224
original/baseq2/m_player.h
Normal 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
original/baseq2/m_rider.h
Normal file
66
original/baseq2/m_rider.h
Normal 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
original/baseq2/m_soldier.c
Normal file
1299
original/baseq2/m_soldier.c
Normal file
File diff suppressed because it is too large
Load Diff
500
original/baseq2/m_soldier.h
Normal file
500
original/baseq2/m_soldier.h
Normal 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
original/baseq2/m_supertank.c
Normal file
717
original/baseq2/m_supertank.c
Normal 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
original/baseq2/m_supertank.h
Normal file
279
original/baseq2/m_supertank.h
Normal 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
original/baseq2/m_tank.c
Normal file
856
original/baseq2/m_tank.c
Normal 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
original/baseq2/m_tank.h
Normal file
319
original/baseq2/m_tank.h
Normal 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
|
||||
1815
original/baseq2/p_client.c
Normal file
1815
original/baseq2/p_client.c
Normal file
File diff suppressed because it is too large
Load Diff
571
original/baseq2/p_hud.c
Normal file
571
original/baseq2/p_hud.c
Normal 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
original/baseq2/p_trail.c
Normal file
146
original/baseq2/p_trail.c
Normal 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
original/baseq2/p_view.c
Normal file
1087
original/baseq2/p_view.c
Normal file
File diff suppressed because it is too large
Load Diff
1434
original/baseq2/p_weapon.c
Normal file
1434
original/baseq2/p_weapon.c
Normal file
File diff suppressed because it is too large
Load Diff
1418
original/baseq2/q_shared.c
Normal file
1418
original/baseq2/q_shared.c
Normal file
File diff suppressed because it is too large
Load Diff
1200
original/baseq2/q_shared.h
Normal file
1200
original/baseq2/q_shared.h
Normal file
File diff suppressed because it is too large
Load Diff
1117
original/ctf/g_ai.c
Normal file
1117
original/ctf/g_ai.c
Normal file
File diff suppressed because it is too large
Load Diff
157
original/ctf/g_chase.c
Normal file
157
original/ctf/g_chase.c
Normal file
@@ -0,0 +1,157 @@
|
||||
/*
|
||||
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 UpdateChaseCam(edict_t *ent)
|
||||
{
|
||||
vec3_t o, ownerv, goal;
|
||||
edict_t *targ;
|
||||
vec3_t forward, right;
|
||||
trace_t trace;
|
||||
int i;
|
||||
vec3_t oldgoal;
|
||||
vec3_t angles;
|
||||
|
||||
// is our chase target gone?
|
||||
if (!ent->client->chase_target->inuse) {
|
||||
ent->client->chase_target = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
targ = ent->client->chase_target;
|
||||
|
||||
VectorCopy(targ->s.origin, ownerv);
|
||||
VectorCopy(ent->s.origin, oldgoal);
|
||||
|
||||
ownerv[2] += targ->viewheight;
|
||||
|
||||
VectorCopy(targ->client->v_angle, angles);
|
||||
if (angles[PITCH] > 56)
|
||||
angles[PITCH] = 56;
|
||||
AngleVectors (angles, forward, right, NULL);
|
||||
VectorNormalize(forward);
|
||||
VectorMA(ownerv, -30, forward, o);
|
||||
|
||||
if (o[2] < targ->s.origin[2] + 20)
|
||||
o[2] = targ->s.origin[2] + 20;
|
||||
|
||||
// jump animation lifts
|
||||
if (!targ->groundentity)
|
||||
o[2] += 16;
|
||||
|
||||
trace = gi.trace(ownerv, vec3_origin, vec3_origin, o, targ, MASK_SOLID);
|
||||
|
||||
VectorCopy(trace.endpos, goal);
|
||||
|
||||
VectorMA(goal, 2, forward, goal);
|
||||
|
||||
// pad for floors and ceilings
|
||||
VectorCopy(goal, o);
|
||||
o[2] += 6;
|
||||
trace = gi.trace(goal, vec3_origin, vec3_origin, o, targ, MASK_SOLID);
|
||||
if (trace.fraction < 1) {
|
||||
VectorCopy(trace.endpos, goal);
|
||||
goal[2] -= 6;
|
||||
}
|
||||
|
||||
VectorCopy(goal, o);
|
||||
o[2] -= 6;
|
||||
trace = gi.trace(goal, vec3_origin, vec3_origin, o, targ, MASK_SOLID);
|
||||
if (trace.fraction < 1) {
|
||||
VectorCopy(trace.endpos, goal);
|
||||
goal[2] += 6;
|
||||
}
|
||||
|
||||
ent->client->ps.pmove.pm_type = PM_FREEZE;
|
||||
|
||||
VectorCopy(goal, ent->s.origin);
|
||||
for (i=0 ; i<3 ; i++)
|
||||
ent->client->ps.pmove.delta_angles[i] = ANGLE2SHORT(targ->client->v_angle[i] - ent->client->resp.cmd_angles[i]);
|
||||
|
||||
VectorCopy(targ->client->v_angle, ent->client->ps.viewangles);
|
||||
VectorCopy(targ->client->v_angle, ent->client->v_angle);
|
||||
|
||||
ent->viewheight = 0;
|
||||
ent->client->ps.pmove.pm_flags |= PMF_NO_PREDICTION;
|
||||
gi.linkentity(ent);
|
||||
|
||||
if ((!ent->client->showscores && !ent->client->menu &&
|
||||
!ent->client->showinventory && !ent->client->showhelp &&
|
||||
!(level.framenum & 31)) || ent->client->update_chase) {
|
||||
char s[1024];
|
||||
|
||||
ent->client->update_chase = false;
|
||||
sprintf(s, "xv 0 yb -68 string2 \"Chasing %s\"",
|
||||
targ->client->pers.netname);
|
||||
gi.WriteByte (svc_layout);
|
||||
gi.WriteString (s);
|
||||
gi.unicast(ent, false);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void ChaseNext(edict_t *ent)
|
||||
{
|
||||
int i;
|
||||
edict_t *e;
|
||||
|
||||
if (!ent->client->chase_target)
|
||||
return;
|
||||
|
||||
i = ent->client->chase_target - g_edicts;
|
||||
do {
|
||||
i++;
|
||||
if (i > maxclients->value)
|
||||
i = 1;
|
||||
e = g_edicts + i;
|
||||
if (!e->inuse)
|
||||
continue;
|
||||
if (e->solid != SOLID_NOT)
|
||||
break;
|
||||
} while (e != ent->client->chase_target);
|
||||
|
||||
ent->client->chase_target = e;
|
||||
ent->client->update_chase = true;
|
||||
}
|
||||
|
||||
void ChasePrev(edict_t *ent)
|
||||
{
|
||||
int i;
|
||||
edict_t *e;
|
||||
|
||||
if (!ent->client->chase_target)
|
||||
return;
|
||||
|
||||
i = ent->client->chase_target - g_edicts;
|
||||
do {
|
||||
i--;
|
||||
if (i < 1)
|
||||
i = maxclients->value;
|
||||
e = g_edicts + i;
|
||||
if (!e->inuse)
|
||||
continue;
|
||||
if (e->solid != SOLID_NOT)
|
||||
break;
|
||||
} while (e != ent->client->chase_target);
|
||||
|
||||
ent->client->chase_target = e;
|
||||
ent->client->update_chase = true;
|
||||
}
|
||||
1066
original/ctf/g_cmds.c
Normal file
1066
original/ctf/g_cmds.c
Normal file
File diff suppressed because it is too large
Load Diff
596
original/ctf/g_combat.c
Normal file
596
original/ctf/g_combat.c
Normal file
@@ -0,0 +1,596 @@
|
||||
/*
|
||||
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_combat.c
|
||||
|
||||
#include "g_local.h"
|
||||
|
||||
/*
|
||||
============
|
||||
CanDamage
|
||||
|
||||
Returns true if the inflictor can directly damage the target. Used for
|
||||
explosions and melee attacks.
|
||||
============
|
||||
*/
|
||||
qboolean CanDamage (edict_t *targ, edict_t *inflictor)
|
||||
{
|
||||
vec3_t dest;
|
||||
trace_t trace;
|
||||
|
||||
// bmodels need special checking because their origin is 0,0,0
|
||||
if (targ->movetype == MOVETYPE_PUSH)
|
||||
{
|
||||
VectorAdd (targ->absmin, targ->absmax, dest);
|
||||
VectorScale (dest, 0.5, dest);
|
||||
trace = gi.trace (inflictor->s.origin, vec3_origin, vec3_origin, dest, inflictor, MASK_SOLID);
|
||||
if (trace.fraction == 1.0)
|
||||
return true;
|
||||
if (trace.ent == targ)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
trace = gi.trace (inflictor->s.origin, vec3_origin, vec3_origin, targ->s.origin, inflictor, MASK_SOLID);
|
||||
if (trace.fraction == 1.0)
|
||||
return true;
|
||||
|
||||
VectorCopy (targ->s.origin, dest);
|
||||
dest[0] += 15.0;
|
||||
dest[1] += 15.0;
|
||||
trace = gi.trace (inflictor->s.origin, vec3_origin, vec3_origin, dest, inflictor, MASK_SOLID);
|
||||
if (trace.fraction == 1.0)
|
||||
return true;
|
||||
|
||||
VectorCopy (targ->s.origin, dest);
|
||||
dest[0] += 15.0;
|
||||
dest[1] -= 15.0;
|
||||
trace = gi.trace (inflictor->s.origin, vec3_origin, vec3_origin, dest, inflictor, MASK_SOLID);
|
||||
if (trace.fraction == 1.0)
|
||||
return true;
|
||||
|
||||
VectorCopy (targ->s.origin, dest);
|
||||
dest[0] -= 15.0;
|
||||
dest[1] += 15.0;
|
||||
trace = gi.trace (inflictor->s.origin, vec3_origin, vec3_origin, dest, inflictor, MASK_SOLID);
|
||||
if (trace.fraction == 1.0)
|
||||
return true;
|
||||
|
||||
VectorCopy (targ->s.origin, dest);
|
||||
dest[0] -= 15.0;
|
||||
dest[1] -= 15.0;
|
||||
trace = gi.trace (inflictor->s.origin, vec3_origin, vec3_origin, dest, inflictor, MASK_SOLID);
|
||||
if (trace.fraction == 1.0)
|
||||
return true;
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
============
|
||||
Killed
|
||||
============
|
||||
*/
|
||||
void Killed (edict_t *targ, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
|
||||
{
|
||||
if (targ->health < -999)
|
||||
targ->health = -999;
|
||||
|
||||
targ->enemy = attacker;
|
||||
|
||||
if ((targ->svflags & SVF_MONSTER) && (targ->deadflag != DEAD_DEAD))
|
||||
{
|
||||
// targ->svflags |= SVF_DEADMONSTER; // now treat as a different content type
|
||||
if (!(targ->monsterinfo.aiflags & AI_GOOD_GUY))
|
||||
{
|
||||
level.killed_monsters++;
|
||||
if (coop->value && attacker->client)
|
||||
attacker->client->resp.score++;
|
||||
// medics won't heal monsters that they kill themselves
|
||||
if (strcmp(attacker->classname, "monster_medic") == 0)
|
||||
targ->owner = attacker;
|
||||
}
|
||||
}
|
||||
|
||||
if (targ->movetype == MOVETYPE_PUSH || targ->movetype == MOVETYPE_STOP || targ->movetype == MOVETYPE_NONE)
|
||||
{ // doors, triggers, etc
|
||||
targ->die (targ, inflictor, attacker, damage, point);
|
||||
return;
|
||||
}
|
||||
|
||||
if ((targ->svflags & SVF_MONSTER) && (targ->deadflag != DEAD_DEAD))
|
||||
{
|
||||
targ->touch = NULL;
|
||||
monster_death_use (targ);
|
||||
}
|
||||
|
||||
targ->die (targ, inflictor, attacker, damage, point);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
SpawnDamage
|
||||
================
|
||||
*/
|
||||
void SpawnDamage (int type, vec3_t origin, vec3_t normal, int damage)
|
||||
{
|
||||
if (damage > 255)
|
||||
damage = 255;
|
||||
gi.WriteByte (svc_temp_entity);
|
||||
gi.WriteByte (type);
|
||||
// gi.WriteByte (damage);
|
||||
gi.WritePosition (origin);
|
||||
gi.WriteDir (normal);
|
||||
gi.multicast (origin, MULTICAST_PVS);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
============
|
||||
T_Damage
|
||||
|
||||
targ entity that is being damaged
|
||||
inflictor entity that is causing the damage
|
||||
attacker entity that caused the inflictor to damage targ
|
||||
example: targ=monster, inflictor=rocket, attacker=player
|
||||
|
||||
dir direction of the attack
|
||||
point point at which the damage is being inflicted
|
||||
normal normal vector from that point
|
||||
damage amount of damage being inflicted
|
||||
knockback force to be applied against targ as a result of the damage
|
||||
|
||||
dflags these flags are used to control how T_Damage works
|
||||
DAMAGE_RADIUS damage was indirect (from a nearby explosion)
|
||||
DAMAGE_NO_ARMOR armor does not protect from this damage
|
||||
DAMAGE_ENERGY damage is from an energy based weapon
|
||||
DAMAGE_NO_KNOCKBACK do not affect velocity, just view angles
|
||||
DAMAGE_BULLET damage is from a bullet (used for ricochets)
|
||||
DAMAGE_NO_PROTECTION kills godmode, armor, everything
|
||||
============
|
||||
*/
|
||||
static int CheckPowerArmor (edict_t *ent, vec3_t point, vec3_t normal, int damage, int dflags)
|
||||
{
|
||||
gclient_t *client;
|
||||
int save;
|
||||
int power_armor_type;
|
||||
int index;
|
||||
int damagePerCell;
|
||||
int pa_te_type;
|
||||
int power;
|
||||
int power_used;
|
||||
|
||||
if (!damage)
|
||||
return 0;
|
||||
|
||||
client = ent->client;
|
||||
|
||||
if (dflags & DAMAGE_NO_ARMOR)
|
||||
return 0;
|
||||
|
||||
if (client)
|
||||
{
|
||||
power_armor_type = PowerArmorType (ent);
|
||||
if (power_armor_type != POWER_ARMOR_NONE)
|
||||
{
|
||||
index = ITEM_INDEX(FindItem("Cells"));
|
||||
power = client->pers.inventory[index];
|
||||
}
|
||||
}
|
||||
else if (ent->svflags & SVF_MONSTER)
|
||||
{
|
||||
power_armor_type = ent->monsterinfo.power_armor_type;
|
||||
power = ent->monsterinfo.power_armor_power;
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
|
||||
if (power_armor_type == POWER_ARMOR_NONE)
|
||||
return 0;
|
||||
if (!power)
|
||||
return 0;
|
||||
|
||||
if (power_armor_type == POWER_ARMOR_SCREEN)
|
||||
{
|
||||
vec3_t vec;
|
||||
float dot;
|
||||
vec3_t forward;
|
||||
|
||||
// only works if damage point is in front
|
||||
AngleVectors (ent->s.angles, forward, NULL, NULL);
|
||||
VectorSubtract (point, ent->s.origin, vec);
|
||||
VectorNormalize (vec);
|
||||
dot = DotProduct (vec, forward);
|
||||
if (dot <= 0.3)
|
||||
return 0;
|
||||
|
||||
damagePerCell = 1;
|
||||
pa_te_type = TE_SCREEN_SPARKS;
|
||||
damage = damage / 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
damagePerCell = 1; // power armor is weaker in CTF
|
||||
pa_te_type = TE_SHIELD_SPARKS;
|
||||
damage = (2 * damage) / 3;
|
||||
}
|
||||
|
||||
save = power * damagePerCell;
|
||||
if (!save)
|
||||
return 0;
|
||||
if (save > damage)
|
||||
save = damage;
|
||||
|
||||
SpawnDamage (pa_te_type, point, normal, save);
|
||||
ent->powerarmor_time = level.time + 0.2;
|
||||
|
||||
power_used = save / damagePerCell;
|
||||
|
||||
if (client)
|
||||
client->pers.inventory[index] -= power_used;
|
||||
else
|
||||
ent->monsterinfo.power_armor_power -= power_used;
|
||||
return save;
|
||||
}
|
||||
|
||||
static int CheckArmor (edict_t *ent, vec3_t point, vec3_t normal, int damage, int te_sparks, int dflags)
|
||||
{
|
||||
gclient_t *client;
|
||||
int save;
|
||||
int index;
|
||||
gitem_t *armor;
|
||||
|
||||
if (!damage)
|
||||
return 0;
|
||||
|
||||
client = ent->client;
|
||||
|
||||
if (!client)
|
||||
return 0;
|
||||
|
||||
if (dflags & DAMAGE_NO_ARMOR)
|
||||
return 0;
|
||||
|
||||
index = ArmorIndex (ent);
|
||||
if (!index)
|
||||
return 0;
|
||||
|
||||
armor = GetItemByIndex (index);
|
||||
|
||||
if (dflags & DAMAGE_ENERGY)
|
||||
save = ceil(((gitem_armor_t *)armor->info)->energy_protection*damage);
|
||||
else
|
||||
save = ceil(((gitem_armor_t *)armor->info)->normal_protection*damage);
|
||||
if (save >= client->pers.inventory[index])
|
||||
save = client->pers.inventory[index];
|
||||
|
||||
if (!save)
|
||||
return 0;
|
||||
|
||||
client->pers.inventory[index] -= save;
|
||||
SpawnDamage (te_sparks, point, normal, save);
|
||||
|
||||
return save;
|
||||
}
|
||||
|
||||
void M_ReactToDamage (edict_t *targ, edict_t *attacker)
|
||||
{
|
||||
if (!(attacker->client) && !(attacker->svflags & SVF_MONSTER))
|
||||
return;
|
||||
|
||||
if (attacker == targ || attacker == targ->enemy)
|
||||
return;
|
||||
|
||||
// if we are a good guy monster and our attacker is a player
|
||||
// or another good guy, do not get mad at them
|
||||
if (targ->monsterinfo.aiflags & AI_GOOD_GUY)
|
||||
{
|
||||
if (attacker->client || (attacker->monsterinfo.aiflags & AI_GOOD_GUY))
|
||||
return;
|
||||
}
|
||||
|
||||
// we now know that we are not both good guys
|
||||
|
||||
// if attacker is a client, get mad at them because he's good and we're not
|
||||
if (attacker->client)
|
||||
{
|
||||
// this can only happen in coop (both new and old enemies are clients)
|
||||
// only switch if can't see the current enemy
|
||||
if (targ->enemy && targ->enemy->client)
|
||||
{
|
||||
if (visible(targ, targ->enemy))
|
||||
{
|
||||
targ->oldenemy = attacker;
|
||||
return;
|
||||
}
|
||||
targ->oldenemy = targ->enemy;
|
||||
}
|
||||
targ->enemy = attacker;
|
||||
if (!(targ->monsterinfo.aiflags & AI_DUCKED))
|
||||
FoundTarget (targ);
|
||||
return;
|
||||
}
|
||||
|
||||
// it's the same base (walk/swim/fly) type and a different classname and it's not a tank
|
||||
// (they spray too much), get mad at them
|
||||
if (((targ->flags & (FL_FLY|FL_SWIM)) == (attacker->flags & (FL_FLY|FL_SWIM))) &&
|
||||
(strcmp (targ->classname, attacker->classname) != 0) &&
|
||||
(strcmp(attacker->classname, "monster_tank") != 0) &&
|
||||
(strcmp(attacker->classname, "monster_supertank") != 0) &&
|
||||
(strcmp(attacker->classname, "monster_makron") != 0) &&
|
||||
(strcmp(attacker->classname, "monster_jorg") != 0) )
|
||||
{
|
||||
if (targ->enemy)
|
||||
if (targ->enemy->client)
|
||||
targ->oldenemy = targ->enemy;
|
||||
targ->enemy = attacker;
|
||||
if (!(targ->monsterinfo.aiflags & AI_DUCKED))
|
||||
FoundTarget (targ);
|
||||
}
|
||||
else
|
||||
// otherwise get mad at whoever they are mad at (help our buddy)
|
||||
{
|
||||
if (targ->enemy)
|
||||
if (targ->enemy->client)
|
||||
targ->oldenemy = targ->enemy;
|
||||
targ->enemy = attacker->enemy;
|
||||
FoundTarget (targ);
|
||||
}
|
||||
}
|
||||
|
||||
qboolean CheckTeamDamage (edict_t *targ, edict_t *attacker)
|
||||
{
|
||||
//ZOID
|
||||
if (ctf->value && targ->client && attacker->client)
|
||||
if (targ->client->resp.ctf_team == attacker->client->resp.ctf_team &&
|
||||
targ != attacker)
|
||||
return true;
|
||||
//ZOID
|
||||
|
||||
//FIXME make the next line real and uncomment this block
|
||||
// if ((ability to damage a teammate == OFF) && (targ's team == attacker's team))
|
||||
return false;
|
||||
}
|
||||
|
||||
void T_Damage (edict_t *targ, edict_t *inflictor, edict_t *attacker, vec3_t dir, vec3_t point, vec3_t normal, int damage, int knockback, int dflags, int mod)
|
||||
{
|
||||
gclient_t *client;
|
||||
int take;
|
||||
int save;
|
||||
int asave;
|
||||
int psave;
|
||||
int te_sparks;
|
||||
|
||||
if (!targ->takedamage)
|
||||
return;
|
||||
|
||||
// friendly fire avoidance
|
||||
// if enabled you can't hurt teammates (but you can hurt yourself)
|
||||
// knockback still occurs
|
||||
if ((targ != attacker) && ((deathmatch->value && ((int)(dmflags->value) & (DF_MODELTEAMS | DF_SKINTEAMS))) || coop->value))
|
||||
{
|
||||
if (OnSameTeam (targ, attacker))
|
||||
{
|
||||
if ((int)(dmflags->value) & DF_NO_FRIENDLY_FIRE)
|
||||
damage = 0;
|
||||
else
|
||||
mod |= MOD_FRIENDLY_FIRE;
|
||||
}
|
||||
}
|
||||
meansOfDeath = mod;
|
||||
|
||||
// easy mode takes half damage
|
||||
if (skill->value == 0 && deathmatch->value == 0 && targ->client)
|
||||
{
|
||||
damage *= 0.5;
|
||||
if (!damage)
|
||||
damage = 1;
|
||||
}
|
||||
|
||||
client = targ->client;
|
||||
|
||||
if (dflags & DAMAGE_BULLET)
|
||||
te_sparks = TE_BULLET_SPARKS;
|
||||
else
|
||||
te_sparks = TE_SPARKS;
|
||||
|
||||
VectorNormalize(dir);
|
||||
|
||||
// bonus damage for suprising a monster
|
||||
if (!(dflags & DAMAGE_RADIUS) && (targ->svflags & SVF_MONSTER) && (attacker->client) && (!targ->enemy) && (targ->health > 0))
|
||||
damage *= 2;
|
||||
|
||||
//ZOID
|
||||
//strength tech
|
||||
damage = CTFApplyStrength(attacker, damage);
|
||||
//ZOID
|
||||
|
||||
if (targ->flags & FL_NO_KNOCKBACK)
|
||||
knockback = 0;
|
||||
|
||||
// figure momentum add
|
||||
if (!(dflags & DAMAGE_NO_KNOCKBACK))
|
||||
{
|
||||
if ((knockback) && (targ->movetype != MOVETYPE_NONE) && (targ->movetype != MOVETYPE_BOUNCE) && (targ->movetype != MOVETYPE_PUSH) && (targ->movetype != MOVETYPE_STOP))
|
||||
{
|
||||
vec3_t kvel;
|
||||
float mass;
|
||||
|
||||
if (targ->mass < 50)
|
||||
mass = 50;
|
||||
else
|
||||
mass = targ->mass;
|
||||
|
||||
if (targ->client && attacker == targ)
|
||||
VectorScale (dir, 1600.0 * (float)knockback / mass, kvel); // the rocket jump hack...
|
||||
else
|
||||
VectorScale (dir, 500.0 * (float)knockback / mass, kvel);
|
||||
|
||||
VectorAdd (targ->velocity, kvel, targ->velocity);
|
||||
}
|
||||
}
|
||||
|
||||
take = damage;
|
||||
save = 0;
|
||||
|
||||
// check for godmode
|
||||
if ( (targ->flags & FL_GODMODE) && !(dflags & DAMAGE_NO_PROTECTION) )
|
||||
{
|
||||
take = 0;
|
||||
save = damage;
|
||||
SpawnDamage (te_sparks, point, normal, save);
|
||||
}
|
||||
|
||||
// check for invincibility
|
||||
if ((client && client->invincible_framenum > level.framenum ) && !(dflags & DAMAGE_NO_PROTECTION))
|
||||
{
|
||||
if (targ->pain_debounce_time < level.time)
|
||||
{
|
||||
gi.sound(targ, CHAN_ITEM, gi.soundindex("items/protect4.wav"), 1, ATTN_NORM, 0);
|
||||
targ->pain_debounce_time = level.time + 2;
|
||||
}
|
||||
take = 0;
|
||||
save = damage;
|
||||
}
|
||||
|
||||
//ZOID
|
||||
//team armor protect
|
||||
if (ctf->value && targ->client && attacker->client &&
|
||||
targ->client->resp.ctf_team == attacker->client->resp.ctf_team &&
|
||||
targ != attacker && ((int)dmflags->value & DF_ARMOR_PROTECT)) {
|
||||
psave = asave = 0;
|
||||
} else {
|
||||
//ZOID
|
||||
psave = CheckPowerArmor (targ, point, normal, take, dflags);
|
||||
take -= psave;
|
||||
|
||||
asave = CheckArmor (targ, point, normal, take, te_sparks, dflags);
|
||||
take -= asave;
|
||||
}
|
||||
|
||||
//treat cheat/powerup savings the same as armor
|
||||
asave += save;
|
||||
|
||||
//ZOID
|
||||
//resistance tech
|
||||
take = CTFApplyResistance(targ, take);
|
||||
//ZOID
|
||||
|
||||
// team damage avoidance
|
||||
if (!(dflags & DAMAGE_NO_PROTECTION) && CheckTeamDamage (targ, attacker))
|
||||
return;
|
||||
|
||||
//ZOID
|
||||
CTFCheckHurtCarrier(targ, attacker);
|
||||
//ZOID
|
||||
|
||||
// do the damage
|
||||
if (take)
|
||||
{
|
||||
if ((targ->svflags & SVF_MONSTER) || (client))
|
||||
SpawnDamage (TE_BLOOD, point, normal, take);
|
||||
else
|
||||
SpawnDamage (te_sparks, point, normal, take);
|
||||
|
||||
if (!CTFMatchSetup())
|
||||
targ->health = targ->health - take;
|
||||
|
||||
if (targ->health <= 0)
|
||||
{
|
||||
if ((targ->svflags & SVF_MONSTER) || (client))
|
||||
targ->flags |= FL_NO_KNOCKBACK;
|
||||
Killed (targ, inflictor, attacker, take, point);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (targ->svflags & SVF_MONSTER)
|
||||
{
|
||||
M_ReactToDamage (targ, attacker);
|
||||
if (!(targ->monsterinfo.aiflags & AI_DUCKED) && (take))
|
||||
{
|
||||
targ->pain (targ, attacker, knockback, take);
|
||||
// nightmare mode monsters don't go into pain frames often
|
||||
if (skill->value == 3)
|
||||
targ->pain_debounce_time = level.time + 5;
|
||||
}
|
||||
}
|
||||
else if (client)
|
||||
{
|
||||
if (!(targ->flags & FL_GODMODE) && (take) && !CTFMatchSetup())
|
||||
targ->pain (targ, attacker, knockback, take);
|
||||
}
|
||||
else if (take)
|
||||
{
|
||||
if (targ->pain)
|
||||
targ->pain (targ, attacker, knockback, take);
|
||||
}
|
||||
|
||||
// add to the damage inflicted on a player this frame
|
||||
// the total will be turned into screen blends and view angle kicks
|
||||
// at the end of the frame
|
||||
if (client)
|
||||
{
|
||||
client->damage_parmor += psave;
|
||||
client->damage_armor += asave;
|
||||
client->damage_blood += take;
|
||||
client->damage_knockback += knockback;
|
||||
VectorCopy (point, client->damage_from);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
============
|
||||
T_RadiusDamage
|
||||
============
|
||||
*/
|
||||
void T_RadiusDamage (edict_t *inflictor, edict_t *attacker, float damage, edict_t *ignore, float radius, int mod)
|
||||
{
|
||||
float points;
|
||||
edict_t *ent = NULL;
|
||||
vec3_t v;
|
||||
vec3_t dir;
|
||||
|
||||
while ((ent = findradius(ent, inflictor->s.origin, radius)) != NULL)
|
||||
{
|
||||
if (ent == ignore)
|
||||
continue;
|
||||
if (!ent->takedamage)
|
||||
continue;
|
||||
|
||||
VectorAdd (ent->mins, ent->maxs, v);
|
||||
VectorMA (ent->s.origin, 0.5, v, v);
|
||||
VectorSubtract (inflictor->s.origin, v, v);
|
||||
points = damage - 0.5 * VectorLength (v);
|
||||
if (ent == attacker)
|
||||
points = points * 0.5;
|
||||
if (points > 0)
|
||||
{
|
||||
if (CanDamage (ent, inflictor))
|
||||
{
|
||||
VectorSubtract (ent->s.origin, inflictor->s.origin, dir);
|
||||
T_Damage (ent, inflictor, attacker, dir, inflictor->s.origin, vec3_origin, (int)points, (int)points, DAMAGE_RADIUS, mod);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
4197
original/ctf/g_ctf.c
Normal file
4197
original/ctf/g_ctf.c
Normal file
File diff suppressed because it is too large
Load Diff
192
original/ctf/g_ctf.h
Normal file
192
original/ctf/g_ctf.h
Normal file
@@ -0,0 +1,192 @@
|
||||
/*
|
||||
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.
|
||||
|
||||
*/
|
||||
|
||||
#define CTF_VERSION 1.52
|
||||
#define CTF_VSTRING2(x) #x
|
||||
#define CTF_VSTRING(x) CTF_VSTRING2(x)
|
||||
#define CTF_STRING_VERSION CTF_VSTRING(CTF_VERSION)
|
||||
|
||||
#define STAT_CTF_TEAM1_PIC 17
|
||||
#define STAT_CTF_TEAM1_CAPS 18
|
||||
#define STAT_CTF_TEAM2_PIC 19
|
||||
#define STAT_CTF_TEAM2_CAPS 20
|
||||
#define STAT_CTF_FLAG_PIC 21
|
||||
#define STAT_CTF_JOINED_TEAM1_PIC 22
|
||||
#define STAT_CTF_JOINED_TEAM2_PIC 23
|
||||
#define STAT_CTF_TEAM1_HEADER 24
|
||||
#define STAT_CTF_TEAM2_HEADER 25
|
||||
#define STAT_CTF_TECH 26
|
||||
#define STAT_CTF_ID_VIEW 27
|
||||
#define STAT_CTF_MATCH 28
|
||||
#define STAT_CTF_ID_VIEW_COLOR 29
|
||||
#define STAT_CTF_TEAMINFO 30
|
||||
|
||||
#define CONFIG_CTF_MATCH (CS_AIRACCEL-1)
|
||||
#define CONFIG_CTF_TEAMINFO (CS_AIRACCEL-2)
|
||||
|
||||
typedef enum {
|
||||
CTF_NOTEAM,
|
||||
CTF_TEAM1,
|
||||
CTF_TEAM2
|
||||
} ctfteam_t;
|
||||
|
||||
typedef enum {
|
||||
CTF_GRAPPLE_STATE_FLY,
|
||||
CTF_GRAPPLE_STATE_PULL,
|
||||
CTF_GRAPPLE_STATE_HANG
|
||||
} ctfgrapplestate_t;
|
||||
|
||||
typedef struct ghost_s {
|
||||
char netname[16];
|
||||
int number;
|
||||
|
||||
// stats
|
||||
int deaths;
|
||||
int kills;
|
||||
int caps;
|
||||
int basedef;
|
||||
int carrierdef;
|
||||
|
||||
int code; // ghost code
|
||||
int team; // team
|
||||
int score; // frags at time of disconnect
|
||||
edict_t *ent;
|
||||
} ghost_t;
|
||||
|
||||
extern cvar_t *ctf;
|
||||
|
||||
#define CTF_TEAM1_SKIN "ctf_r"
|
||||
#define CTF_TEAM2_SKIN "ctf_b"
|
||||
|
||||
#define DF_CTF_FORCEJOIN 131072
|
||||
#define DF_ARMOR_PROTECT 262144
|
||||
#define DF_CTF_NO_TECH 524288
|
||||
|
||||
#define CTF_CAPTURE_BONUS 15 // what you get for capture
|
||||
#define CTF_TEAM_BONUS 10 // what your team gets for capture
|
||||
#define CTF_RECOVERY_BONUS 1 // what you get for recovery
|
||||
#define CTF_FLAG_BONUS 0 // what you get for picking up enemy flag
|
||||
#define CTF_FRAG_CARRIER_BONUS 2 // what you get for fragging enemy flag carrier
|
||||
#define CTF_FLAG_RETURN_TIME 40 // seconds until auto return
|
||||
|
||||
#define CTF_CARRIER_DANGER_PROTECT_BONUS 2 // bonus for fraggin someone who has recently hurt your flag carrier
|
||||
#define CTF_CARRIER_PROTECT_BONUS 1 // bonus for fraggin someone while either you or your target are near your flag carrier
|
||||
#define CTF_FLAG_DEFENSE_BONUS 1 // bonus for fraggin someone while either you or your target are near your flag
|
||||
#define CTF_RETURN_FLAG_ASSIST_BONUS 1 // awarded for returning a flag that causes a capture to happen almost immediately
|
||||
#define CTF_FRAG_CARRIER_ASSIST_BONUS 2 // award for fragging a flag carrier if a capture happens almost immediately
|
||||
|
||||
#define CTF_TARGET_PROTECT_RADIUS 400 // the radius around an object being defended where a target will be worth extra frags
|
||||
#define CTF_ATTACKER_PROTECT_RADIUS 400 // the radius around an object being defended where an attacker will get extra frags when making kills
|
||||
|
||||
#define CTF_CARRIER_DANGER_PROTECT_TIMEOUT 8
|
||||
#define CTF_FRAG_CARRIER_ASSIST_TIMEOUT 10
|
||||
#define CTF_RETURN_FLAG_ASSIST_TIMEOUT 10
|
||||
|
||||
#define CTF_AUTO_FLAG_RETURN_TIMEOUT 30 // number of seconds before dropped flag auto-returns
|
||||
|
||||
#define CTF_TECH_TIMEOUT 60 // seconds before techs spawn again
|
||||
|
||||
#define CTF_GRAPPLE_SPEED 650 // speed of grapple in flight
|
||||
#define CTF_GRAPPLE_PULL_SPEED 650 // speed player is pulled at
|
||||
|
||||
void CTFInit(void);
|
||||
void CTFSpawn(void);
|
||||
void CTFPrecache(void);
|
||||
|
||||
void SP_info_player_team1(edict_t *self);
|
||||
void SP_info_player_team2(edict_t *self);
|
||||
|
||||
char *CTFTeamName(int team);
|
||||
char *CTFOtherTeamName(int team);
|
||||
void CTFAssignSkin(edict_t *ent, char *s);
|
||||
void CTFAssignTeam(gclient_t *who);
|
||||
edict_t *SelectCTFSpawnPoint (edict_t *ent);
|
||||
qboolean CTFPickup_Flag(edict_t *ent, edict_t *other);
|
||||
qboolean CTFDrop_Flag(edict_t *ent, gitem_t *item);
|
||||
void CTFEffects(edict_t *player);
|
||||
void CTFCalcScores(void);
|
||||
void SetCTFStats(edict_t *ent);
|
||||
void CTFDeadDropFlag(edict_t *self);
|
||||
void CTFScoreboardMessage (edict_t *ent, edict_t *killer);
|
||||
void CTFTeam_f (edict_t *ent);
|
||||
void CTFID_f (edict_t *ent);
|
||||
void CTFSay_Team(edict_t *who, char *msg);
|
||||
void CTFFlagSetup (edict_t *ent);
|
||||
void CTFResetFlag(int ctf_team);
|
||||
void CTFFragBonuses(edict_t *targ, edict_t *inflictor, edict_t *attacker);
|
||||
void CTFCheckHurtCarrier(edict_t *targ, edict_t *attacker);
|
||||
|
||||
// GRAPPLE
|
||||
void CTFWeapon_Grapple (edict_t *ent);
|
||||
void CTFPlayerResetGrapple(edict_t *ent);
|
||||
void CTFGrapplePull(edict_t *self);
|
||||
void CTFResetGrapple(edict_t *self);
|
||||
|
||||
//TECH
|
||||
gitem_t *CTFWhat_Tech(edict_t *ent);
|
||||
qboolean CTFPickup_Tech (edict_t *ent, edict_t *other);
|
||||
void CTFDrop_Tech(edict_t *ent, gitem_t *item);
|
||||
void CTFDeadDropTech(edict_t *ent);
|
||||
void CTFSetupTechSpawn(void);
|
||||
int CTFApplyResistance(edict_t *ent, int dmg);
|
||||
int CTFApplyStrength(edict_t *ent, int dmg);
|
||||
qboolean CTFApplyStrengthSound(edict_t *ent);
|
||||
qboolean CTFApplyHaste(edict_t *ent);
|
||||
void CTFApplyHasteSound(edict_t *ent);
|
||||
void CTFApplyRegeneration(edict_t *ent);
|
||||
qboolean CTFHasRegeneration(edict_t *ent);
|
||||
void CTFRespawnTech(edict_t *ent);
|
||||
void CTFResetTech(void);
|
||||
|
||||
void CTFOpenJoinMenu(edict_t *ent);
|
||||
qboolean CTFStartClient(edict_t *ent);
|
||||
void CTFVoteYes(edict_t *ent);
|
||||
void CTFVoteNo(edict_t *ent);
|
||||
void CTFReady(edict_t *ent);
|
||||
void CTFNotReady(edict_t *ent);
|
||||
qboolean CTFNextMap(void);
|
||||
qboolean CTFMatchSetup(void);
|
||||
qboolean CTFMatchOn(void);
|
||||
void CTFGhost(edict_t *ent);
|
||||
void CTFAdmin(edict_t *ent);
|
||||
qboolean CTFInMatch(void);
|
||||
void CTFStats(edict_t *ent);
|
||||
void CTFWarp(edict_t *ent);
|
||||
void CTFBoot(edict_t *ent);
|
||||
void CTFPlayerList(edict_t *ent);
|
||||
|
||||
qboolean CTFCheckRules(void);
|
||||
|
||||
void SP_misc_ctf_banner (edict_t *ent);
|
||||
void SP_misc_ctf_small_banner (edict_t *ent);
|
||||
|
||||
extern char *ctf_statusbar;
|
||||
|
||||
void UpdateChaseCam(edict_t *ent);
|
||||
void ChaseNext(edict_t *ent);
|
||||
void ChasePrev(edict_t *ent);
|
||||
|
||||
void CTFObserver(edict_t *ent);
|
||||
|
||||
void SP_trigger_teleport (edict_t *ent);
|
||||
void SP_info_teleport_destination (edict_t *ent);
|
||||
|
||||
void CTFSetPowerUpEffect(edict_t *ent, int def);
|
||||
|
||||
2047
original/ctf/g_func.c
Normal file
2047
original/ctf/g_func.c
Normal file
File diff suppressed because it is too large
Load Diff
2446
original/ctf/g_items.c
Normal file
2446
original/ctf/g_items.c
Normal file
File diff suppressed because it is too large
Load Diff
1153
original/ctf/g_local.h
Normal file
1153
original/ctf/g_local.h
Normal file
File diff suppressed because it is too large
Load Diff
429
original/ctf/g_main.c
Normal file
429
original/ctf/g_main.c
Normal file
@@ -0,0 +1,429 @@
|
||||
/*
|
||||
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"
|
||||
|
||||
game_locals_t game;
|
||||
level_locals_t level;
|
||||
game_import_t gi;
|
||||
game_export_t globals;
|
||||
spawn_temp_t st;
|
||||
|
||||
int sm_meat_index;
|
||||
int snd_fry;
|
||||
int meansOfDeath;
|
||||
|
||||
edict_t *g_edicts;
|
||||
|
||||
cvar_t *deathmatch;
|
||||
cvar_t *coop;
|
||||
cvar_t *dmflags;
|
||||
cvar_t *skill;
|
||||
cvar_t *fraglimit;
|
||||
cvar_t *timelimit;
|
||||
//ZOID
|
||||
cvar_t *capturelimit;
|
||||
cvar_t *instantweap;
|
||||
//ZOID
|
||||
cvar_t *password;
|
||||
cvar_t *maxclients;
|
||||
cvar_t *maxentities;
|
||||
cvar_t *g_select_empty;
|
||||
cvar_t *dedicated;
|
||||
|
||||
cvar_t *filterban;
|
||||
|
||||
cvar_t *sv_maxvelocity;
|
||||
cvar_t *sv_gravity;
|
||||
|
||||
cvar_t *sv_rollspeed;
|
||||
cvar_t *sv_rollangle;
|
||||
cvar_t *gun_x;
|
||||
cvar_t *gun_y;
|
||||
cvar_t *gun_z;
|
||||
|
||||
cvar_t *run_pitch;
|
||||
cvar_t *run_roll;
|
||||
cvar_t *bob_up;
|
||||
cvar_t *bob_pitch;
|
||||
cvar_t *bob_roll;
|
||||
|
||||
cvar_t *sv_cheats;
|
||||
|
||||
cvar_t *flood_msgs;
|
||||
cvar_t *flood_persecond;
|
||||
cvar_t *flood_waitdelay;
|
||||
|
||||
cvar_t *sv_maplist;
|
||||
|
||||
void SpawnEntities (char *mapname, char *entities, char *spawnpoint);
|
||||
void ClientThink (edict_t *ent, usercmd_t *cmd);
|
||||
qboolean ClientConnect (edict_t *ent, char *userinfo);
|
||||
void ClientUserinfoChanged (edict_t *ent, char *userinfo);
|
||||
void ClientDisconnect (edict_t *ent);
|
||||
void ClientBegin (edict_t *ent);
|
||||
void ClientCommand (edict_t *ent);
|
||||
void RunEntity (edict_t *ent);
|
||||
void WriteGame (char *filename, qboolean autosave);
|
||||
void ReadGame (char *filename);
|
||||
void WriteLevel (char *filename);
|
||||
void ReadLevel (char *filename);
|
||||
void InitGame (void);
|
||||
void G_RunFrame (void);
|
||||
|
||||
|
||||
//===================================================================
|
||||
|
||||
|
||||
void ShutdownGame (void)
|
||||
{
|
||||
gi.dprintf ("==== ShutdownGame ====\n");
|
||||
|
||||
gi.FreeTags (TAG_LEVEL);
|
||||
gi.FreeTags (TAG_GAME);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=================
|
||||
GetGameAPI
|
||||
|
||||
Returns a pointer to the structure with all entry points
|
||||
and global variables
|
||||
=================
|
||||
*/
|
||||
game_export_t *GetGameAPI (game_import_t *import)
|
||||
{
|
||||
gi = *import;
|
||||
|
||||
globals.apiversion = GAME_API_VERSION;
|
||||
globals.Init = InitGame;
|
||||
globals.Shutdown = ShutdownGame;
|
||||
globals.SpawnEntities = SpawnEntities;
|
||||
|
||||
globals.WriteGame = WriteGame;
|
||||
globals.ReadGame = ReadGame;
|
||||
globals.WriteLevel = WriteLevel;
|
||||
globals.ReadLevel = ReadLevel;
|
||||
|
||||
globals.ClientThink = ClientThink;
|
||||
globals.ClientConnect = ClientConnect;
|
||||
globals.ClientUserinfoChanged = ClientUserinfoChanged;
|
||||
globals.ClientDisconnect = ClientDisconnect;
|
||||
globals.ClientBegin = ClientBegin;
|
||||
globals.ClientCommand = ClientCommand;
|
||||
|
||||
globals.RunFrame = G_RunFrame;
|
||||
|
||||
globals.ServerCommand = ServerCommand;
|
||||
|
||||
globals.edict_size = sizeof(edict_t);
|
||||
|
||||
return &globals;
|
||||
}
|
||||
|
||||
#ifndef GAME_HARD_LINKED
|
||||
// this is only here so the functions in q_shared.c and q_shwin.c can link
|
||||
void Sys_Error (char *error, ...)
|
||||
{
|
||||
va_list argptr;
|
||||
char text[1024];
|
||||
|
||||
va_start (argptr, error);
|
||||
vsprintf (text, error, argptr);
|
||||
va_end (argptr);
|
||||
|
||||
gi.error (ERR_FATAL, "%s", text);
|
||||
}
|
||||
|
||||
void Com_Printf (char *msg, ...)
|
||||
{
|
||||
va_list argptr;
|
||||
char text[1024];
|
||||
|
||||
va_start (argptr, msg);
|
||||
vsprintf (text, msg, argptr);
|
||||
va_end (argptr);
|
||||
|
||||
gi.dprintf ("%s", text);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
//======================================================================
|
||||
|
||||
|
||||
/*
|
||||
=================
|
||||
ClientEndServerFrames
|
||||
=================
|
||||
*/
|
||||
void ClientEndServerFrames (void)
|
||||
{
|
||||
int i;
|
||||
edict_t *ent;
|
||||
|
||||
// calc the player views now that all pushing
|
||||
// and damage has been added
|
||||
for (i=0 ; i<maxclients->value ; i++)
|
||||
{
|
||||
ent = g_edicts + 1 + i;
|
||||
if (!ent->inuse || !ent->client)
|
||||
continue;
|
||||
ClientEndServerFrame (ent);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
CreateTargetChangeLevel
|
||||
|
||||
Returns the created target changelevel
|
||||
=================
|
||||
*/
|
||||
edict_t *CreateTargetChangeLevel(char *map)
|
||||
{
|
||||
edict_t *ent;
|
||||
|
||||
ent = G_Spawn ();
|
||||
ent->classname = "target_changelevel";
|
||||
Com_sprintf(level.nextmap, sizeof(level.nextmap), "%s", map);
|
||||
ent->map = level.nextmap;
|
||||
return ent;
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
EndDMLevel
|
||||
|
||||
The timelimit or fraglimit has been exceeded
|
||||
=================
|
||||
*/
|
||||
void EndDMLevel (void)
|
||||
{
|
||||
edict_t *ent;
|
||||
char *s, *t, *f;
|
||||
static const char *seps = " ,\n\r";
|
||||
|
||||
// stay on same level flag
|
||||
if ((int)dmflags->value & DF_SAME_LEVEL)
|
||||
{
|
||||
BeginIntermission (CreateTargetChangeLevel (level.mapname) );
|
||||
return;
|
||||
}
|
||||
|
||||
if (*level.forcemap) {
|
||||
BeginIntermission (CreateTargetChangeLevel (level.forcemap) );
|
||||
return;
|
||||
}
|
||||
|
||||
// see if it's in the map list
|
||||
if (*sv_maplist->string) {
|
||||
s = strdup(sv_maplist->string);
|
||||
f = NULL;
|
||||
t = strtok(s, seps);
|
||||
while (t != NULL) {
|
||||
if (Q_stricmp(t, level.mapname) == 0) {
|
||||
// it's in the list, go to the next one
|
||||
t = strtok(NULL, seps);
|
||||
if (t == NULL) { // end of list, go to first one
|
||||
if (f == NULL) // there isn't a first one, same level
|
||||
BeginIntermission (CreateTargetChangeLevel (level.mapname) );
|
||||
else
|
||||
BeginIntermission (CreateTargetChangeLevel (f) );
|
||||
} else
|
||||
BeginIntermission (CreateTargetChangeLevel (t) );
|
||||
free(s);
|
||||
return;
|
||||
}
|
||||
if (!f)
|
||||
f = t;
|
||||
t = strtok(NULL, seps);
|
||||
}
|
||||
free(s);
|
||||
}
|
||||
|
||||
if (level.nextmap[0]) // go to a specific map
|
||||
BeginIntermission (CreateTargetChangeLevel (level.nextmap) );
|
||||
else { // search for a changelevel
|
||||
ent = G_Find (NULL, FOFS(classname), "target_changelevel");
|
||||
if (!ent)
|
||||
{ // the map designer didn't include a changelevel,
|
||||
// so create a fake ent that goes back to the same level
|
||||
BeginIntermission (CreateTargetChangeLevel (level.mapname) );
|
||||
return;
|
||||
}
|
||||
BeginIntermission (ent);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
CheckDMRules
|
||||
=================
|
||||
*/
|
||||
void CheckDMRules (void)
|
||||
{
|
||||
int i;
|
||||
gclient_t *cl;
|
||||
|
||||
if (level.intermissiontime)
|
||||
return;
|
||||
|
||||
if (!deathmatch->value)
|
||||
return;
|
||||
|
||||
//ZOID
|
||||
if (ctf->value && CTFCheckRules()) {
|
||||
EndDMLevel ();
|
||||
return;
|
||||
}
|
||||
if (CTFInMatch())
|
||||
return; // no checking in match mode
|
||||
//ZOID
|
||||
|
||||
if (timelimit->value)
|
||||
{
|
||||
if (level.time >= timelimit->value*60)
|
||||
{
|
||||
gi.bprintf (PRINT_HIGH, "Timelimit hit.\n");
|
||||
EndDMLevel ();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (fraglimit->value)
|
||||
for (i=0 ; i<maxclients->value ; i++)
|
||||
{
|
||||
cl = game.clients + i;
|
||||
if (!g_edicts[i+1].inuse)
|
||||
continue;
|
||||
|
||||
if (cl->resp.score >= fraglimit->value)
|
||||
{
|
||||
gi.bprintf (PRINT_HIGH, "Fraglimit hit.\n");
|
||||
EndDMLevel ();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=============
|
||||
ExitLevel
|
||||
=============
|
||||
*/
|
||||
void ExitLevel (void)
|
||||
{
|
||||
int i;
|
||||
edict_t *ent;
|
||||
char command [256];
|
||||
|
||||
level.exitintermission = 0;
|
||||
level.intermissiontime = 0;
|
||||
|
||||
if (CTFNextMap())
|
||||
return;
|
||||
|
||||
Com_sprintf (command, sizeof(command), "gamemap \"%s\"\n", level.changemap);
|
||||
gi.AddCommandString (command);
|
||||
ClientEndServerFrames ();
|
||||
|
||||
level.changemap = NULL;
|
||||
|
||||
// clear some things before going to next level
|
||||
for (i=0 ; i<maxclients->value ; i++)
|
||||
{
|
||||
ent = g_edicts + 1 + i;
|
||||
if (!ent->inuse)
|
||||
continue;
|
||||
if (ent->health > ent->client->pers.max_health)
|
||||
ent->health = ent->client->pers.max_health;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
G_RunFrame
|
||||
|
||||
Advances the world by 0.1 seconds
|
||||
================
|
||||
*/
|
||||
void G_RunFrame (void)
|
||||
{
|
||||
int i;
|
||||
edict_t *ent;
|
||||
|
||||
level.framenum++;
|
||||
level.time = level.framenum*FRAMETIME;
|
||||
|
||||
// choose a client for monsters to target this frame
|
||||
AI_SetSightClient ();
|
||||
|
||||
// exit intermissions
|
||||
|
||||
if (level.exitintermission)
|
||||
{
|
||||
ExitLevel ();
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
// treat each object in turn
|
||||
// even the world gets a chance to think
|
||||
//
|
||||
ent = &g_edicts[0];
|
||||
for (i=0 ; i<globals.num_edicts ; i++, ent++)
|
||||
{
|
||||
if (!ent->inuse)
|
||||
continue;
|
||||
|
||||
level.current_entity = ent;
|
||||
|
||||
VectorCopy (ent->s.origin, ent->s.old_origin);
|
||||
|
||||
// if the ground entity moved, make sure we are still on it
|
||||
if ((ent->groundentity) && (ent->groundentity->linkcount != ent->groundentity_linkcount))
|
||||
{
|
||||
ent->groundentity = NULL;
|
||||
if ( !(ent->flags & (FL_SWIM|FL_FLY)) && (ent->svflags & SVF_MONSTER) )
|
||||
{
|
||||
M_CheckGround (ent);
|
||||
}
|
||||
}
|
||||
|
||||
if (i > 0 && i <= maxclients->value)
|
||||
{
|
||||
ClientBeginServerFrame (ent);
|
||||
continue;
|
||||
}
|
||||
|
||||
G_RunEntity (ent);
|
||||
}
|
||||
|
||||
// see if it is time to end a deathmatch
|
||||
CheckDMRules ();
|
||||
|
||||
// build the playerstate_t structures for all players
|
||||
ClientEndServerFrames ();
|
||||
}
|
||||
|
||||
1909
original/ctf/g_misc.c
Normal file
1909
original/ctf/g_misc.c
Normal file
File diff suppressed because it is too large
Load Diff
740
original/ctf/g_monster.c
Normal file
740
original/ctf/g_monster.c
Normal file
@@ -0,0 +1,740 @@
|
||||
/*
|
||||
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"
|
||||
|
||||
|
||||
//
|
||||
// monster weapons
|
||||
//
|
||||
|
||||
//FIXME mosnters should call these with a totally accurate direction
|
||||
// and we can mess it up based on skill. Spread should be for normal
|
||||
// and we can tighten or loosen based on skill. We could muck with
|
||||
// the damages too, but I'm not sure that's such a good idea.
|
||||
void monster_fire_bullet (edict_t *self, vec3_t start, vec3_t dir, int damage, int kick, int hspread, int vspread, int flashtype)
|
||||
{
|
||||
fire_bullet (self, start, dir, damage, kick, hspread, vspread, MOD_UNKNOWN);
|
||||
|
||||
gi.WriteByte (svc_muzzleflash2);
|
||||
gi.WriteShort (self - g_edicts);
|
||||
gi.WriteByte (flashtype);
|
||||
gi.multicast (start, MULTICAST_PVS);
|
||||
}
|
||||
|
||||
void monster_fire_shotgun (edict_t *self, vec3_t start, vec3_t aimdir, int damage, int kick, int hspread, int vspread, int count, int flashtype)
|
||||
{
|
||||
fire_shotgun (self, start, aimdir, damage, kick, hspread, vspread, count, MOD_UNKNOWN);
|
||||
|
||||
gi.WriteByte (svc_muzzleflash2);
|
||||
gi.WriteShort (self - g_edicts);
|
||||
gi.WriteByte (flashtype);
|
||||
gi.multicast (start, MULTICAST_PVS);
|
||||
}
|
||||
|
||||
void monster_fire_blaster (edict_t *self, vec3_t start, vec3_t dir, int damage, int speed, int flashtype, int effect)
|
||||
{
|
||||
fire_blaster (self, start, dir, damage, speed, effect, false);
|
||||
|
||||
gi.WriteByte (svc_muzzleflash2);
|
||||
gi.WriteShort (self - g_edicts);
|
||||
gi.WriteByte (flashtype);
|
||||
gi.multicast (start, MULTICAST_PVS);
|
||||
}
|
||||
|
||||
void monster_fire_grenade (edict_t *self, vec3_t start, vec3_t aimdir, int damage, int speed, int flashtype)
|
||||
{
|
||||
fire_grenade (self, start, aimdir, damage, speed, 2.5, damage+40);
|
||||
|
||||
gi.WriteByte (svc_muzzleflash2);
|
||||
gi.WriteShort (self - g_edicts);
|
||||
gi.WriteByte (flashtype);
|
||||
gi.multicast (start, MULTICAST_PVS);
|
||||
}
|
||||
|
||||
void monster_fire_rocket (edict_t *self, vec3_t start, vec3_t dir, int damage, int speed, int flashtype)
|
||||
{
|
||||
fire_rocket (self, start, dir, damage, speed, damage+20, damage);
|
||||
|
||||
gi.WriteByte (svc_muzzleflash2);
|
||||
gi.WriteShort (self - g_edicts);
|
||||
gi.WriteByte (flashtype);
|
||||
gi.multicast (start, MULTICAST_PVS);
|
||||
}
|
||||
|
||||
void monster_fire_railgun (edict_t *self, vec3_t start, vec3_t aimdir, int damage, int kick, int flashtype)
|
||||
{
|
||||
fire_rail (self, start, aimdir, damage, kick);
|
||||
|
||||
gi.WriteByte (svc_muzzleflash2);
|
||||
gi.WriteShort (self - g_edicts);
|
||||
gi.WriteByte (flashtype);
|
||||
gi.multicast (start, MULTICAST_PVS);
|
||||
}
|
||||
|
||||
void monster_fire_bfg (edict_t *self, vec3_t start, vec3_t aimdir, int damage, int speed, int kick, float damage_radius, int flashtype)
|
||||
{
|
||||
fire_bfg (self, start, aimdir, damage, speed, damage_radius);
|
||||
|
||||
gi.WriteByte (svc_muzzleflash2);
|
||||
gi.WriteShort (self - g_edicts);
|
||||
gi.WriteByte (flashtype);
|
||||
gi.multicast (start, MULTICAST_PVS);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//
|
||||
// Monster utility functions
|
||||
//
|
||||
|
||||
static void M_FliesOff (edict_t *self)
|
||||
{
|
||||
self->s.effects &= ~EF_FLIES;
|
||||
self->s.sound = 0;
|
||||
}
|
||||
|
||||
static void M_FliesOn (edict_t *self)
|
||||
{
|
||||
if (self->waterlevel)
|
||||
return;
|
||||
self->s.effects |= EF_FLIES;
|
||||
self->s.sound = gi.soundindex ("infantry/inflies1.wav");
|
||||
self->think = M_FliesOff;
|
||||
self->nextthink = level.time + 60;
|
||||
}
|
||||
|
||||
void M_FlyCheck (edict_t *self)
|
||||
{
|
||||
if (self->waterlevel)
|
||||
return;
|
||||
|
||||
if (random() > 0.5)
|
||||
return;
|
||||
|
||||
self->think = M_FliesOn;
|
||||
self->nextthink = level.time + 5 + 10 * random();
|
||||
}
|
||||
|
||||
void AttackFinished (edict_t *self, float time)
|
||||
{
|
||||
self->monsterinfo.attack_finished = level.time + time;
|
||||
}
|
||||
|
||||
|
||||
void M_CheckGround (edict_t *ent)
|
||||
{
|
||||
vec3_t point;
|
||||
trace_t trace;
|
||||
|
||||
if (ent->flags & (FL_SWIM|FL_FLY))
|
||||
return;
|
||||
|
||||
if (ent->velocity[2] > 100)
|
||||
{
|
||||
ent->groundentity = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
// if the hull point one-quarter unit down is solid the entity is on ground
|
||||
point[0] = ent->s.origin[0];
|
||||
point[1] = ent->s.origin[1];
|
||||
point[2] = ent->s.origin[2] - 0.25;
|
||||
|
||||
trace = gi.trace (ent->s.origin, ent->mins, ent->maxs, point, ent, MASK_MONSTERSOLID);
|
||||
|
||||
// check steepness
|
||||
if ( trace.plane.normal[2] < 0.7 && !trace.startsolid)
|
||||
{
|
||||
ent->groundentity = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
// ent->groundentity = trace.ent;
|
||||
// ent->groundentity_linkcount = trace.ent->linkcount;
|
||||
// if (!trace.startsolid && !trace.allsolid)
|
||||
// VectorCopy (trace.endpos, ent->s.origin);
|
||||
if (!trace.startsolid && !trace.allsolid)
|
||||
{
|
||||
VectorCopy (trace.endpos, ent->s.origin);
|
||||
ent->groundentity = trace.ent;
|
||||
ent->groundentity_linkcount = trace.ent->linkcount;
|
||||
ent->velocity[2] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void M_CatagorizePosition (edict_t *ent)
|
||||
{
|
||||
vec3_t point;
|
||||
int cont;
|
||||
|
||||
//
|
||||
// get waterlevel
|
||||
//
|
||||
point[0] = ent->s.origin[0];
|
||||
point[1] = ent->s.origin[1];
|
||||
point[2] = ent->s.origin[2] + ent->mins[2] + 1;
|
||||
cont = gi.pointcontents (point);
|
||||
|
||||
if (!(cont & MASK_WATER))
|
||||
{
|
||||
ent->waterlevel = 0;
|
||||
ent->watertype = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
ent->watertype = cont;
|
||||
ent->waterlevel = 1;
|
||||
point[2] += 26;
|
||||
cont = gi.pointcontents (point);
|
||||
if (!(cont & MASK_WATER))
|
||||
return;
|
||||
|
||||
ent->waterlevel = 2;
|
||||
point[2] += 22;
|
||||
cont = gi.pointcontents (point);
|
||||
if (cont & MASK_WATER)
|
||||
ent->waterlevel = 3;
|
||||
}
|
||||
|
||||
|
||||
void M_WorldEffects (edict_t *ent)
|
||||
{
|
||||
int dmg;
|
||||
|
||||
if (ent->health > 0)
|
||||
{
|
||||
if (!(ent->flags & FL_SWIM))
|
||||
{
|
||||
if (ent->waterlevel < 3)
|
||||
{
|
||||
ent->air_finished = level.time + 12;
|
||||
}
|
||||
else if (ent->air_finished < level.time)
|
||||
{ // drown!
|
||||
if (ent->pain_debounce_time < level.time)
|
||||
{
|
||||
dmg = 2 + 2 * floor(level.time - ent->air_finished);
|
||||
if (dmg > 15)
|
||||
dmg = 15;
|
||||
T_Damage (ent, world, world, vec3_origin, ent->s.origin, vec3_origin, dmg, 0, DAMAGE_NO_ARMOR, MOD_WATER);
|
||||
ent->pain_debounce_time = level.time + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ent->waterlevel > 0)
|
||||
{
|
||||
ent->air_finished = level.time + 9;
|
||||
}
|
||||
else if (ent->air_finished < level.time)
|
||||
{ // suffocate!
|
||||
if (ent->pain_debounce_time < level.time)
|
||||
{
|
||||
dmg = 2 + 2 * floor(level.time - ent->air_finished);
|
||||
if (dmg > 15)
|
||||
dmg = 15;
|
||||
T_Damage (ent, world, world, vec3_origin, ent->s.origin, vec3_origin, dmg, 0, DAMAGE_NO_ARMOR, MOD_WATER);
|
||||
ent->pain_debounce_time = level.time + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ent->waterlevel == 0)
|
||||
{
|
||||
if (ent->flags & FL_INWATER)
|
||||
{
|
||||
gi.sound (ent, CHAN_BODY, gi.soundindex("player/watr_out.wav"), 1, ATTN_NORM, 0);
|
||||
ent->flags &= ~FL_INWATER;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if ((ent->watertype & CONTENTS_LAVA) && !(ent->flags & FL_IMMUNE_LAVA))
|
||||
{
|
||||
if (ent->damage_debounce_time < level.time)
|
||||
{
|
||||
ent->damage_debounce_time = level.time + 0.2;
|
||||
T_Damage (ent, world, world, vec3_origin, ent->s.origin, vec3_origin, 10*ent->waterlevel, 0, 0, MOD_LAVA);
|
||||
}
|
||||
}
|
||||
if ((ent->watertype & CONTENTS_SLIME) && !(ent->flags & FL_IMMUNE_SLIME))
|
||||
{
|
||||
if (ent->damage_debounce_time < level.time)
|
||||
{
|
||||
ent->damage_debounce_time = level.time + 1;
|
||||
T_Damage (ent, world, world, vec3_origin, ent->s.origin, vec3_origin, 4*ent->waterlevel, 0, 0, MOD_SLIME);
|
||||
}
|
||||
}
|
||||
|
||||
if ( !(ent->flags & FL_INWATER) )
|
||||
{
|
||||
if (!(ent->svflags & SVF_DEADMONSTER))
|
||||
{
|
||||
if (ent->watertype & CONTENTS_LAVA)
|
||||
if (random() <= 0.5)
|
||||
gi.sound (ent, CHAN_BODY, gi.soundindex("player/lava1.wav"), 1, ATTN_NORM, 0);
|
||||
else
|
||||
gi.sound (ent, CHAN_BODY, gi.soundindex("player/lava2.wav"), 1, ATTN_NORM, 0);
|
||||
else if (ent->watertype & CONTENTS_SLIME)
|
||||
gi.sound (ent, CHAN_BODY, gi.soundindex("player/watr_in.wav"), 1, ATTN_NORM, 0);
|
||||
else if (ent->watertype & CONTENTS_WATER)
|
||||
gi.sound (ent, CHAN_BODY, gi.soundindex("player/watr_in.wav"), 1, ATTN_NORM, 0);
|
||||
}
|
||||
|
||||
ent->flags |= FL_INWATER;
|
||||
ent->damage_debounce_time = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void M_droptofloor (edict_t *ent)
|
||||
{
|
||||
vec3_t end;
|
||||
trace_t trace;
|
||||
|
||||
ent->s.origin[2] += 1;
|
||||
VectorCopy (ent->s.origin, end);
|
||||
end[2] -= 256;
|
||||
|
||||
trace = gi.trace (ent->s.origin, ent->mins, ent->maxs, end, ent, MASK_MONSTERSOLID);
|
||||
|
||||
if (trace.fraction == 1 || trace.allsolid)
|
||||
return;
|
||||
|
||||
VectorCopy (trace.endpos, ent->s.origin);
|
||||
|
||||
gi.linkentity (ent);
|
||||
M_CheckGround (ent);
|
||||
M_CatagorizePosition (ent);
|
||||
}
|
||||
|
||||
|
||||
void M_SetEffects (edict_t *ent)
|
||||
{
|
||||
ent->s.effects &= ~(EF_COLOR_SHELL|EF_POWERSCREEN);
|
||||
ent->s.renderfx &= ~(RF_SHELL_RED|RF_SHELL_GREEN|RF_SHELL_BLUE);
|
||||
|
||||
if (ent->monsterinfo.aiflags & AI_RESURRECTING)
|
||||
{
|
||||
ent->s.effects |= EF_COLOR_SHELL;
|
||||
ent->s.renderfx |= RF_SHELL_RED;
|
||||
}
|
||||
|
||||
if (ent->health <= 0)
|
||||
return;
|
||||
|
||||
if (ent->powerarmor_time > level.time)
|
||||
{
|
||||
if (ent->monsterinfo.power_armor_type == POWER_ARMOR_SCREEN)
|
||||
{
|
||||
ent->s.effects |= EF_POWERSCREEN;
|
||||
}
|
||||
else if (ent->monsterinfo.power_armor_type == POWER_ARMOR_SHIELD)
|
||||
{
|
||||
ent->s.effects |= EF_COLOR_SHELL;
|
||||
ent->s.renderfx |= RF_SHELL_GREEN;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void M_MoveFrame (edict_t *self)
|
||||
{
|
||||
mmove_t *move;
|
||||
int index;
|
||||
|
||||
move = self->monsterinfo.currentmove;
|
||||
self->nextthink = level.time + FRAMETIME;
|
||||
|
||||
if ((self->monsterinfo.nextframe) && (self->monsterinfo.nextframe >= move->firstframe) && (self->monsterinfo.nextframe <= move->lastframe))
|
||||
{
|
||||
self->s.frame = self->monsterinfo.nextframe;
|
||||
self->monsterinfo.nextframe = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (self->s.frame == move->lastframe)
|
||||
{
|
||||
if (move->endfunc)
|
||||
{
|
||||
move->endfunc (self);
|
||||
|
||||
// regrab move, endfunc is very likely to change it
|
||||
move = self->monsterinfo.currentmove;
|
||||
|
||||
// check for death
|
||||
if (self->svflags & SVF_DEADMONSTER)
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (self->s.frame < move->firstframe || self->s.frame > move->lastframe)
|
||||
{
|
||||
self->monsterinfo.aiflags &= ~AI_HOLD_FRAME;
|
||||
self->s.frame = move->firstframe;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!(self->monsterinfo.aiflags & AI_HOLD_FRAME))
|
||||
{
|
||||
self->s.frame++;
|
||||
if (self->s.frame > move->lastframe)
|
||||
self->s.frame = move->firstframe;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
index = self->s.frame - move->firstframe;
|
||||
if (move->frame[index].aifunc)
|
||||
if (!(self->monsterinfo.aiflags & AI_HOLD_FRAME))
|
||||
move->frame[index].aifunc (self, move->frame[index].dist * self->monsterinfo.scale);
|
||||
else
|
||||
move->frame[index].aifunc (self, 0);
|
||||
|
||||
if (move->frame[index].thinkfunc)
|
||||
move->frame[index].thinkfunc (self);
|
||||
}
|
||||
|
||||
|
||||
void monster_think (edict_t *self)
|
||||
{
|
||||
M_MoveFrame (self);
|
||||
if (self->linkcount != self->monsterinfo.linkcount)
|
||||
{
|
||||
self->monsterinfo.linkcount = self->linkcount;
|
||||
M_CheckGround (self);
|
||||
}
|
||||
M_CatagorizePosition (self);
|
||||
M_WorldEffects (self);
|
||||
M_SetEffects (self);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
monster_use
|
||||
|
||||
Using a monster makes it angry at the current activator
|
||||
================
|
||||
*/
|
||||
void monster_use (edict_t *self, edict_t *other, edict_t *activator)
|
||||
{
|
||||
if (self->enemy)
|
||||
return;
|
||||
if (self->health <= 0)
|
||||
return;
|
||||
if (activator->flags & FL_NOTARGET)
|
||||
return;
|
||||
if (!(activator->client) && !(activator->monsterinfo.aiflags & AI_GOOD_GUY))
|
||||
return;
|
||||
|
||||
// delay reaction so if the monster is teleported, its sound is still heard
|
||||
self->enemy = activator;
|
||||
FoundTarget (self);
|
||||
}
|
||||
|
||||
|
||||
void monster_start_go (edict_t *self);
|
||||
|
||||
|
||||
void monster_triggered_spawn (edict_t *self)
|
||||
{
|
||||
self->s.origin[2] += 1;
|
||||
KillBox (self);
|
||||
|
||||
self->solid = SOLID_BBOX;
|
||||
self->movetype = MOVETYPE_STEP;
|
||||
self->svflags &= ~SVF_NOCLIENT;
|
||||
self->air_finished = level.time + 12;
|
||||
gi.linkentity (self);
|
||||
|
||||
monster_start_go (self);
|
||||
|
||||
if (self->enemy && !(self->spawnflags & 1) && !(self->enemy->flags & FL_NOTARGET))
|
||||
{
|
||||
FoundTarget (self);
|
||||
}
|
||||
else
|
||||
{
|
||||
self->enemy = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void monster_triggered_spawn_use (edict_t *self, edict_t *other, edict_t *activator)
|
||||
{
|
||||
// we have a one frame delay here so we don't telefrag the guy who activated us
|
||||
self->think = monster_triggered_spawn;
|
||||
self->nextthink = level.time + FRAMETIME;
|
||||
if (activator->client)
|
||||
self->enemy = activator;
|
||||
self->use = monster_use;
|
||||
}
|
||||
|
||||
void monster_triggered_start (edict_t *self)
|
||||
{
|
||||
self->solid = SOLID_NOT;
|
||||
self->movetype = MOVETYPE_NONE;
|
||||
self->svflags |= SVF_NOCLIENT;
|
||||
self->nextthink = 0;
|
||||
self->use = monster_triggered_spawn_use;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
monster_death_use
|
||||
|
||||
When a monster dies, it fires all of its targets with the current
|
||||
enemy as activator.
|
||||
================
|
||||
*/
|
||||
void monster_death_use (edict_t *self)
|
||||
{
|
||||
self->flags &= ~(FL_FLY|FL_SWIM);
|
||||
self->monsterinfo.aiflags &= AI_GOOD_GUY;
|
||||
|
||||
if (self->item)
|
||||
{
|
||||
Drop_Item (self, self->item);
|
||||
self->item = NULL;
|
||||
}
|
||||
|
||||
if (self->deathtarget)
|
||||
self->target = self->deathtarget;
|
||||
|
||||
if (!self->target)
|
||||
return;
|
||||
|
||||
G_UseTargets (self, self->enemy);
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
|
||||
qboolean monster_start (edict_t *self)
|
||||
{
|
||||
if (deathmatch->value)
|
||||
{
|
||||
G_FreeEdict (self);
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((self->spawnflags & 4) && !(self->monsterinfo.aiflags & AI_GOOD_GUY))
|
||||
{
|
||||
self->spawnflags &= ~4;
|
||||
self->spawnflags |= 1;
|
||||
// gi.dprintf("fixed spawnflags on %s at %s\n", self->classname, vtos(self->s.origin));
|
||||
}
|
||||
|
||||
if (!(self->monsterinfo.aiflags & AI_GOOD_GUY))
|
||||
level.total_monsters++;
|
||||
|
||||
self->nextthink = level.time + FRAMETIME;
|
||||
self->svflags |= SVF_MONSTER;
|
||||
self->s.renderfx |= RF_FRAMELERP;
|
||||
self->takedamage = DAMAGE_AIM;
|
||||
self->air_finished = level.time + 12;
|
||||
self->use = monster_use;
|
||||
self->max_health = self->health;
|
||||
self->clipmask = MASK_MONSTERSOLID;
|
||||
|
||||
self->s.skinnum = 0;
|
||||
self->deadflag = DEAD_NO;
|
||||
self->svflags &= ~SVF_DEADMONSTER;
|
||||
|
||||
if (!self->monsterinfo.checkattack)
|
||||
self->monsterinfo.checkattack = M_CheckAttack;
|
||||
VectorCopy (self->s.origin, self->s.old_origin);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
// randomize what frame they start on
|
||||
if (self->monsterinfo.currentmove)
|
||||
self->s.frame = self->monsterinfo.currentmove->firstframe + (rand() % (self->monsterinfo.currentmove->lastframe - self->monsterinfo.currentmove->firstframe + 1));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void monster_start_go (edict_t *self)
|
||||
{
|
||||
vec3_t v;
|
||||
|
||||
if (self->health <= 0)
|
||||
return;
|
||||
|
||||
// check for target to combat_point and change to combattarget
|
||||
if (self->target)
|
||||
{
|
||||
qboolean notcombat;
|
||||
qboolean fixup;
|
||||
edict_t *target;
|
||||
|
||||
target = NULL;
|
||||
notcombat = false;
|
||||
fixup = false;
|
||||
while ((target = G_Find (target, FOFS(targetname), self->target)) != NULL)
|
||||
{
|
||||
if (strcmp(target->classname, "point_combat") == 0)
|
||||
{
|
||||
self->combattarget = self->target;
|
||||
fixup = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
notcombat = true;
|
||||
}
|
||||
}
|
||||
if (notcombat && self->combattarget)
|
||||
gi.dprintf("%s at %s has target with mixed types\n", self->classname, vtos(self->s.origin));
|
||||
if (fixup)
|
||||
self->target = NULL;
|
||||
}
|
||||
|
||||
// validate combattarget
|
||||
if (self->combattarget)
|
||||
{
|
||||
edict_t *target;
|
||||
|
||||
target = NULL;
|
||||
while ((target = G_Find (target, FOFS(targetname), self->combattarget)) != NULL)
|
||||
{
|
||||
if (strcmp(target->classname, "point_combat") != 0)
|
||||
{
|
||||
gi.dprintf("%s at (%i %i %i) has a bad combattarget %s : %s at (%i %i %i)\n",
|
||||
self->classname, (int)self->s.origin[0], (int)self->s.origin[1], (int)self->s.origin[2],
|
||||
self->combattarget, target->classname, (int)target->s.origin[0], (int)target->s.origin[1],
|
||||
(int)target->s.origin[2]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (self->target)
|
||||
{
|
||||
self->goalentity = self->movetarget = G_PickTarget(self->target);
|
||||
if (!self->movetarget)
|
||||
{
|
||||
gi.dprintf ("%s can't find target %s at %s\n", self->classname, self->target, vtos(self->s.origin));
|
||||
self->target = NULL;
|
||||
self->monsterinfo.pausetime = 100000000;
|
||||
self->monsterinfo.stand (self);
|
||||
}
|
||||
else if (strcmp (self->movetarget->classname, "path_corner") == 0)
|
||||
{
|
||||
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;
|
||||
}
|
||||
else
|
||||
{
|
||||
self->goalentity = self->movetarget = NULL;
|
||||
self->monsterinfo.pausetime = 100000000;
|
||||
self->monsterinfo.stand (self);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
self->monsterinfo.pausetime = 100000000;
|
||||
self->monsterinfo.stand (self);
|
||||
}
|
||||
|
||||
self->think = monster_think;
|
||||
self->nextthink = level.time + FRAMETIME;
|
||||
}
|
||||
|
||||
|
||||
void walkmonster_start_go (edict_t *self)
|
||||
{
|
||||
if (!(self->spawnflags & 2) && level.time < 1)
|
||||
{
|
||||
M_droptofloor (self);
|
||||
|
||||
if (self->groundentity)
|
||||
if (!M_walkmove (self, 0, 0))
|
||||
gi.dprintf ("%s in solid at %s\n", self->classname, vtos(self->s.origin));
|
||||
}
|
||||
|
||||
if (!self->yaw_speed)
|
||||
self->yaw_speed = 20;
|
||||
self->viewheight = 25;
|
||||
|
||||
monster_start_go (self);
|
||||
|
||||
if (self->spawnflags & 2)
|
||||
monster_triggered_start (self);
|
||||
}
|
||||
|
||||
void walkmonster_start (edict_t *self)
|
||||
{
|
||||
self->think = walkmonster_start_go;
|
||||
monster_start (self);
|
||||
}
|
||||
|
||||
|
||||
void flymonster_start_go (edict_t *self)
|
||||
{
|
||||
if (!M_walkmove (self, 0, 0))
|
||||
gi.dprintf ("%s in solid at %s\n", self->classname, vtos(self->s.origin));
|
||||
|
||||
if (!self->yaw_speed)
|
||||
self->yaw_speed = 10;
|
||||
self->viewheight = 25;
|
||||
|
||||
monster_start_go (self);
|
||||
|
||||
if (self->spawnflags & 2)
|
||||
monster_triggered_start (self);
|
||||
}
|
||||
|
||||
|
||||
void flymonster_start (edict_t *self)
|
||||
{
|
||||
self->flags |= FL_FLY;
|
||||
self->think = flymonster_start_go;
|
||||
monster_start (self);
|
||||
}
|
||||
|
||||
|
||||
void swimmonster_start_go (edict_t *self)
|
||||
{
|
||||
if (!self->yaw_speed)
|
||||
self->yaw_speed = 10;
|
||||
self->viewheight = 10;
|
||||
|
||||
monster_start_go (self);
|
||||
|
||||
if (self->spawnflags & 2)
|
||||
monster_triggered_start (self);
|
||||
}
|
||||
|
||||
void swimmonster_start (edict_t *self)
|
||||
{
|
||||
self->flags |= FL_SWIM;
|
||||
self->think = swimmonster_start_go;
|
||||
monster_start (self);
|
||||
}
|
||||
959
original/ctf/g_phys.c
Normal file
959
original/ctf/g_phys.c
Normal file
@@ -0,0 +1,959 @@
|
||||
/*
|
||||
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_phys.c
|
||||
|
||||
#include "g_local.h"
|
||||
|
||||
/*
|
||||
|
||||
|
||||
pushmove objects do not obey gravity, and do not interact with each other or trigger fields, but block normal movement and push normal objects when they move.
|
||||
|
||||
onground is set for toss objects when they come to a complete rest. it is set for steping or walking objects
|
||||
|
||||
doors, plats, etc are SOLID_BSP, and MOVETYPE_PUSH
|
||||
bonus items are SOLID_TRIGGER touch, and MOVETYPE_TOSS
|
||||
corpses are SOLID_NOT and MOVETYPE_TOSS
|
||||
crates are SOLID_BBOX and MOVETYPE_TOSS
|
||||
walking monsters are SOLID_SLIDEBOX and MOVETYPE_STEP
|
||||
flying/floating monsters are SOLID_SLIDEBOX and MOVETYPE_FLY
|
||||
|
||||
solid_edge items only clip against bsp models.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
============
|
||||
SV_TestEntityPosition
|
||||
|
||||
============
|
||||
*/
|
||||
edict_t *SV_TestEntityPosition (edict_t *ent)
|
||||
{
|
||||
trace_t trace;
|
||||
int mask;
|
||||
|
||||
|
||||
if (ent->clipmask)
|
||||
mask = ent->clipmask;
|
||||
else
|
||||
mask = MASK_SOLID;
|
||||
trace = gi.trace (ent->s.origin, ent->mins, ent->maxs, ent->s.origin, ent, mask);
|
||||
|
||||
if (trace.startsolid)
|
||||
return g_edicts;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
SV_CheckVelocity
|
||||
================
|
||||
*/
|
||||
void SV_CheckVelocity (edict_t *ent)
|
||||
{
|
||||
int i;
|
||||
|
||||
//
|
||||
// bound velocity
|
||||
//
|
||||
for (i=0 ; i<3 ; i++)
|
||||
{
|
||||
if (ent->velocity[i] > sv_maxvelocity->value)
|
||||
ent->velocity[i] = sv_maxvelocity->value;
|
||||
else if (ent->velocity[i] < -sv_maxvelocity->value)
|
||||
ent->velocity[i] = -sv_maxvelocity->value;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
SV_RunThink
|
||||
|
||||
Runs thinking code for this frame if necessary
|
||||
=============
|
||||
*/
|
||||
qboolean SV_RunThink (edict_t *ent)
|
||||
{
|
||||
float thinktime;
|
||||
|
||||
thinktime = ent->nextthink;
|
||||
if (thinktime <= 0)
|
||||
return true;
|
||||
if (thinktime > level.time+0.001)
|
||||
return true;
|
||||
|
||||
ent->nextthink = 0;
|
||||
if (!ent->think)
|
||||
gi.error ("NULL ent->think");
|
||||
ent->think (ent);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
SV_Impact
|
||||
|
||||
Two entities have touched, so run their touch functions
|
||||
==================
|
||||
*/
|
||||
void SV_Impact (edict_t *e1, trace_t *trace)
|
||||
{
|
||||
edict_t *e2;
|
||||
// cplane_t backplane;
|
||||
|
||||
e2 = trace->ent;
|
||||
|
||||
if (e1->touch && e1->solid != SOLID_NOT)
|
||||
e1->touch (e1, e2, &trace->plane, trace->surface);
|
||||
|
||||
if (e2->touch && e2->solid != SOLID_NOT)
|
||||
e2->touch (e2, e1, NULL, NULL);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
==================
|
||||
ClipVelocity
|
||||
|
||||
Slide off of the impacting object
|
||||
returns the blocked flags (1 = floor, 2 = step / wall)
|
||||
==================
|
||||
*/
|
||||
#define STOP_EPSILON 0.1
|
||||
|
||||
int ClipVelocity (vec3_t in, vec3_t normal, vec3_t out, float overbounce)
|
||||
{
|
||||
float backoff;
|
||||
float change;
|
||||
int i, blocked;
|
||||
|
||||
blocked = 0;
|
||||
if (normal[2] > 0)
|
||||
blocked |= 1; // floor
|
||||
if (!normal[2])
|
||||
blocked |= 2; // step
|
||||
|
||||
backoff = DotProduct (in, normal) * overbounce;
|
||||
|
||||
for (i=0 ; i<3 ; i++)
|
||||
{
|
||||
change = normal[i]*backoff;
|
||||
out[i] = in[i] - change;
|
||||
if (out[i] > -STOP_EPSILON && out[i] < STOP_EPSILON)
|
||||
out[i] = 0;
|
||||
}
|
||||
|
||||
return blocked;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
============
|
||||
SV_FlyMove
|
||||
|
||||
The basic solid body movement clip that slides along multiple planes
|
||||
Returns the clipflags if the velocity was modified (hit something solid)
|
||||
1 = floor
|
||||
2 = wall / step
|
||||
4 = dead stop
|
||||
============
|
||||
*/
|
||||
#define MAX_CLIP_PLANES 5
|
||||
int SV_FlyMove (edict_t *ent, float time, int mask)
|
||||
{
|
||||
edict_t *hit;
|
||||
int bumpcount, numbumps;
|
||||
vec3_t dir;
|
||||
float d;
|
||||
int numplanes;
|
||||
vec3_t planes[MAX_CLIP_PLANES];
|
||||
vec3_t primal_velocity, original_velocity, new_velocity;
|
||||
int i, j;
|
||||
trace_t trace;
|
||||
vec3_t end;
|
||||
float time_left;
|
||||
int blocked;
|
||||
|
||||
numbumps = 4;
|
||||
|
||||
blocked = 0;
|
||||
VectorCopy (ent->velocity, original_velocity);
|
||||
VectorCopy (ent->velocity, primal_velocity);
|
||||
numplanes = 0;
|
||||
|
||||
time_left = time;
|
||||
|
||||
ent->groundentity = NULL;
|
||||
for (bumpcount=0 ; bumpcount<numbumps ; bumpcount++)
|
||||
{
|
||||
for (i=0 ; i<3 ; i++)
|
||||
end[i] = ent->s.origin[i] + time_left * ent->velocity[i];
|
||||
|
||||
trace = gi.trace (ent->s.origin, ent->mins, ent->maxs, end, ent, mask);
|
||||
|
||||
if (trace.allsolid)
|
||||
{ // entity is trapped in another solid
|
||||
VectorCopy (vec3_origin, ent->velocity);
|
||||
return 3;
|
||||
}
|
||||
|
||||
if (trace.fraction > 0)
|
||||
{ // actually covered some distance
|
||||
VectorCopy (trace.endpos, ent->s.origin);
|
||||
VectorCopy (ent->velocity, original_velocity);
|
||||
numplanes = 0;
|
||||
}
|
||||
|
||||
if (trace.fraction == 1)
|
||||
break; // moved the entire distance
|
||||
|
||||
hit = trace.ent;
|
||||
|
||||
if (trace.plane.normal[2] > 0.7)
|
||||
{
|
||||
blocked |= 1; // floor
|
||||
if ( hit->solid == SOLID_BSP)
|
||||
{
|
||||
ent->groundentity = hit;
|
||||
ent->groundentity_linkcount = hit->linkcount;
|
||||
}
|
||||
}
|
||||
if (!trace.plane.normal[2])
|
||||
{
|
||||
blocked |= 2; // step
|
||||
}
|
||||
|
||||
//
|
||||
// run the impact function
|
||||
//
|
||||
SV_Impact (ent, &trace);
|
||||
if (!ent->inuse)
|
||||
break; // removed by the impact function
|
||||
|
||||
|
||||
time_left -= time_left * trace.fraction;
|
||||
|
||||
// cliped to another plane
|
||||
if (numplanes >= MAX_CLIP_PLANES)
|
||||
{ // this shouldn't really happen
|
||||
VectorCopy (vec3_origin, ent->velocity);
|
||||
return 3;
|
||||
}
|
||||
|
||||
VectorCopy (trace.plane.normal, planes[numplanes]);
|
||||
numplanes++;
|
||||
|
||||
//
|
||||
// modify original_velocity so it parallels all of the clip planes
|
||||
//
|
||||
for (i=0 ; i<numplanes ; i++)
|
||||
{
|
||||
ClipVelocity (original_velocity, planes[i], new_velocity, 1);
|
||||
for (j=0 ; j<numplanes ; j++)
|
||||
if (j != i)
|
||||
{
|
||||
if (DotProduct (new_velocity, planes[j]) < 0)
|
||||
break; // not ok
|
||||
}
|
||||
if (j == numplanes)
|
||||
break;
|
||||
}
|
||||
|
||||
if (i != numplanes)
|
||||
{ // go along this plane
|
||||
VectorCopy (new_velocity, ent->velocity);
|
||||
}
|
||||
else
|
||||
{ // go along the crease
|
||||
if (numplanes != 2)
|
||||
{
|
||||
// gi.dprintf ("clip velocity, numplanes == %i\n",numplanes);
|
||||
VectorCopy (vec3_origin, ent->velocity);
|
||||
return 7;
|
||||
}
|
||||
CrossProduct (planes[0], planes[1], dir);
|
||||
d = DotProduct (dir, ent->velocity);
|
||||
VectorScale (dir, d, ent->velocity);
|
||||
}
|
||||
|
||||
//
|
||||
// if original velocity is against the original velocity, stop dead
|
||||
// to avoid tiny occilations in sloping corners
|
||||
//
|
||||
if (DotProduct (ent->velocity, primal_velocity) <= 0)
|
||||
{
|
||||
VectorCopy (vec3_origin, ent->velocity);
|
||||
return blocked;
|
||||
}
|
||||
}
|
||||
|
||||
return blocked;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
============
|
||||
SV_AddGravity
|
||||
|
||||
============
|
||||
*/
|
||||
void SV_AddGravity (edict_t *ent)
|
||||
{
|
||||
ent->velocity[2] -= ent->gravity * sv_gravity->value * FRAMETIME;
|
||||
}
|
||||
|
||||
/*
|
||||
===============================================================================
|
||||
|
||||
PUSHMOVE
|
||||
|
||||
===============================================================================
|
||||
*/
|
||||
|
||||
/*
|
||||
============
|
||||
SV_PushEntity
|
||||
|
||||
Does not change the entities velocity at all
|
||||
============
|
||||
*/
|
||||
trace_t SV_PushEntity (edict_t *ent, vec3_t push)
|
||||
{
|
||||
trace_t trace;
|
||||
vec3_t start;
|
||||
vec3_t end;
|
||||
int mask;
|
||||
|
||||
VectorCopy (ent->s.origin, start);
|
||||
VectorAdd (start, push, end);
|
||||
|
||||
retry:
|
||||
if (ent->clipmask)
|
||||
mask = ent->clipmask;
|
||||
else
|
||||
mask = MASK_SOLID;
|
||||
|
||||
trace = gi.trace (start, ent->mins, ent->maxs, end, ent, mask);
|
||||
|
||||
VectorCopy (trace.endpos, ent->s.origin);
|
||||
gi.linkentity (ent);
|
||||
|
||||
if (trace.fraction != 1.0)
|
||||
{
|
||||
SV_Impact (ent, &trace);
|
||||
|
||||
// if the pushed entity went away and the pusher is still there
|
||||
if (!trace.ent->inuse && ent->inuse)
|
||||
{
|
||||
// move the pusher back and try again
|
||||
VectorCopy (start, ent->s.origin);
|
||||
gi.linkentity (ent);
|
||||
goto retry;
|
||||
}
|
||||
}
|
||||
|
||||
if (ent->inuse)
|
||||
G_TouchTriggers (ent);
|
||||
|
||||
return trace;
|
||||
}
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
edict_t *ent;
|
||||
vec3_t origin;
|
||||
vec3_t angles;
|
||||
float deltayaw;
|
||||
} pushed_t;
|
||||
pushed_t pushed[MAX_EDICTS], *pushed_p;
|
||||
|
||||
edict_t *obstacle;
|
||||
|
||||
/*
|
||||
============
|
||||
SV_Push
|
||||
|
||||
Objects need to be moved back on a failed push,
|
||||
otherwise riders would continue to slide.
|
||||
============
|
||||
*/
|
||||
qboolean SV_Push (edict_t *pusher, vec3_t move, vec3_t amove)
|
||||
{
|
||||
int i, e;
|
||||
edict_t *check, *block;
|
||||
vec3_t mins, maxs;
|
||||
pushed_t *p;
|
||||
vec3_t org, org2, move2, forward, right, up;
|
||||
|
||||
// clamp the move to 1/8 units, so the position will
|
||||
// be accurate for client side prediction
|
||||
for (i=0 ; i<3 ; i++)
|
||||
{
|
||||
float temp;
|
||||
temp = move[i]*8.0;
|
||||
if (temp > 0.0)
|
||||
temp += 0.5;
|
||||
else
|
||||
temp -= 0.5;
|
||||
move[i] = 0.125 * (int)temp;
|
||||
}
|
||||
|
||||
// find the bounding box
|
||||
for (i=0 ; i<3 ; i++)
|
||||
{
|
||||
mins[i] = pusher->absmin[i] + move[i];
|
||||
maxs[i] = pusher->absmax[i] + move[i];
|
||||
}
|
||||
|
||||
// we need this for pushing things later
|
||||
VectorSubtract (vec3_origin, amove, org);
|
||||
AngleVectors (org, forward, right, up);
|
||||
|
||||
// save the pusher's original position
|
||||
pushed_p->ent = pusher;
|
||||
VectorCopy (pusher->s.origin, pushed_p->origin);
|
||||
VectorCopy (pusher->s.angles, pushed_p->angles);
|
||||
if (pusher->client)
|
||||
pushed_p->deltayaw = pusher->client->ps.pmove.delta_angles[YAW];
|
||||
pushed_p++;
|
||||
|
||||
// move the pusher to it's final position
|
||||
VectorAdd (pusher->s.origin, move, pusher->s.origin);
|
||||
VectorAdd (pusher->s.angles, amove, pusher->s.angles);
|
||||
gi.linkentity (pusher);
|
||||
|
||||
// see if any solid entities are inside the final position
|
||||
check = g_edicts+1;
|
||||
for (e = 1; e < globals.num_edicts; e++, check++)
|
||||
{
|
||||
if (!check->inuse)
|
||||
continue;
|
||||
if (check->movetype == MOVETYPE_PUSH
|
||||
|| check->movetype == MOVETYPE_STOP
|
||||
|| check->movetype == MOVETYPE_NONE
|
||||
|| check->movetype == MOVETYPE_NOCLIP)
|
||||
continue;
|
||||
|
||||
if (!check->area.prev)
|
||||
continue; // not linked in anywhere
|
||||
|
||||
// if the entity is standing on the pusher, it will definitely be moved
|
||||
if (check->groundentity != pusher)
|
||||
{
|
||||
// see if the ent needs to be tested
|
||||
if ( check->absmin[0] >= maxs[0]
|
||||
|| check->absmin[1] >= maxs[1]
|
||||
|| check->absmin[2] >= maxs[2]
|
||||
|| check->absmax[0] <= mins[0]
|
||||
|| check->absmax[1] <= mins[1]
|
||||
|| check->absmax[2] <= mins[2] )
|
||||
continue;
|
||||
|
||||
// see if the ent's bbox is inside the pusher's final position
|
||||
if (!SV_TestEntityPosition (check))
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((pusher->movetype == MOVETYPE_PUSH) || (check->groundentity == pusher))
|
||||
{
|
||||
// move this entity
|
||||
pushed_p->ent = check;
|
||||
VectorCopy (check->s.origin, pushed_p->origin);
|
||||
VectorCopy (check->s.angles, pushed_p->angles);
|
||||
pushed_p++;
|
||||
|
||||
// try moving the contacted entity
|
||||
VectorAdd (check->s.origin, move, check->s.origin);
|
||||
if (check->client)
|
||||
{ // FIXME: doesn't rotate monsters?
|
||||
check->client->ps.pmove.delta_angles[YAW] += amove[YAW];
|
||||
}
|
||||
|
||||
// figure movement due to the pusher's amove
|
||||
VectorSubtract (check->s.origin, pusher->s.origin, org);
|
||||
org2[0] = DotProduct (org, forward);
|
||||
org2[1] = -DotProduct (org, right);
|
||||
org2[2] = DotProduct (org, up);
|
||||
VectorSubtract (org2, org, move2);
|
||||
VectorAdd (check->s.origin, move2, check->s.origin);
|
||||
|
||||
// may have pushed them off an edge
|
||||
if (check->groundentity != pusher)
|
||||
check->groundentity = NULL;
|
||||
|
||||
block = SV_TestEntityPosition (check);
|
||||
if (!block)
|
||||
{ // pushed ok
|
||||
gi.linkentity (check);
|
||||
// impact?
|
||||
continue;
|
||||
}
|
||||
|
||||
// if it is ok to leave in the old position, do it
|
||||
// this is only relevent for riding entities, not pushed
|
||||
// FIXME: this doesn't acount for rotation
|
||||
VectorSubtract (check->s.origin, move, check->s.origin);
|
||||
block = SV_TestEntityPosition (check);
|
||||
if (!block)
|
||||
{
|
||||
pushed_p--;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// save off the obstacle so we can call the block function
|
||||
obstacle = check;
|
||||
|
||||
// move back any entities we already moved
|
||||
// go backwards, so if the same entity was pushed
|
||||
// twice, it goes back to the original position
|
||||
for (p=pushed_p-1 ; p>=pushed ; p--)
|
||||
{
|
||||
VectorCopy (p->origin, p->ent->s.origin);
|
||||
VectorCopy (p->angles, p->ent->s.angles);
|
||||
if (p->ent->client)
|
||||
{
|
||||
p->ent->client->ps.pmove.delta_angles[YAW] = p->deltayaw;
|
||||
}
|
||||
gi.linkentity (p->ent);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//FIXME: is there a better way to handle this?
|
||||
// see if anything we moved has touched a trigger
|
||||
for (p=pushed_p-1 ; p>=pushed ; p--)
|
||||
G_TouchTriggers (p->ent);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
SV_Physics_Pusher
|
||||
|
||||
Bmodel objects don't interact with each other, but
|
||||
push all box objects
|
||||
================
|
||||
*/
|
||||
void SV_Physics_Pusher (edict_t *ent)
|
||||
{
|
||||
vec3_t move, amove;
|
||||
edict_t *part, *mv;
|
||||
|
||||
// if not a team captain, so movement will be handled elsewhere
|
||||
if ( ent->flags & FL_TEAMSLAVE)
|
||||
return;
|
||||
|
||||
// make sure all team slaves can move before commiting
|
||||
// any moves or calling any think functions
|
||||
// if the move is blocked, all moved objects will be backed out
|
||||
//retry:
|
||||
pushed_p = pushed;
|
||||
for (part = ent ; part ; part=part->teamchain)
|
||||
{
|
||||
if (part->velocity[0] || part->velocity[1] || part->velocity[2] ||
|
||||
part->avelocity[0] || part->avelocity[1] || part->avelocity[2]
|
||||
)
|
||||
{ // object is moving
|
||||
VectorScale (part->velocity, FRAMETIME, move);
|
||||
VectorScale (part->avelocity, FRAMETIME, amove);
|
||||
|
||||
if (!SV_Push (part, move, amove))
|
||||
break; // move was blocked
|
||||
}
|
||||
}
|
||||
if (pushed_p > &pushed[MAX_EDICTS])
|
||||
gi.error (ERR_FATAL, "pushed_p > &pushed[MAX_EDICTS], memory corrupted");
|
||||
|
||||
if (part)
|
||||
{
|
||||
// the move failed, bump all nextthink times and back out moves
|
||||
for (mv = ent ; mv ; mv=mv->teamchain)
|
||||
{
|
||||
if (mv->nextthink > 0)
|
||||
mv->nextthink += FRAMETIME;
|
||||
}
|
||||
|
||||
// if the pusher has a "blocked" function, call it
|
||||
// otherwise, just stay in place until the obstacle is gone
|
||||
if (part->blocked)
|
||||
part->blocked (part, obstacle);
|
||||
#if 0
|
||||
// if the pushed entity went away and the pusher is still there
|
||||
if (!obstacle->inuse && part->inuse)
|
||||
goto retry;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
// the move succeeded, so call all think functions
|
||||
for (part = ent ; part ; part=part->teamchain)
|
||||
{
|
||||
SV_RunThink (part);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//==================================================================
|
||||
|
||||
/*
|
||||
=============
|
||||
SV_Physics_None
|
||||
|
||||
Non moving objects can only think
|
||||
=============
|
||||
*/
|
||||
void SV_Physics_None (edict_t *ent)
|
||||
{
|
||||
// regular thinking
|
||||
SV_RunThink (ent);
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
SV_Physics_Noclip
|
||||
|
||||
A moving object that doesn't obey physics
|
||||
=============
|
||||
*/
|
||||
void SV_Physics_Noclip (edict_t *ent)
|
||||
{
|
||||
// regular thinking
|
||||
if (!SV_RunThink (ent))
|
||||
return;
|
||||
|
||||
VectorMA (ent->s.angles, FRAMETIME, ent->avelocity, ent->s.angles);
|
||||
VectorMA (ent->s.origin, FRAMETIME, ent->velocity, ent->s.origin);
|
||||
|
||||
gi.linkentity (ent);
|
||||
}
|
||||
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
TOSS / BOUNCE
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
/*
|
||||
=============
|
||||
SV_Physics_Toss
|
||||
|
||||
Toss, bounce, and fly movement. When onground, do nothing.
|
||||
=============
|
||||
*/
|
||||
void SV_Physics_Toss (edict_t *ent)
|
||||
{
|
||||
trace_t trace;
|
||||
vec3_t move;
|
||||
float backoff;
|
||||
edict_t *slave;
|
||||
qboolean wasinwater;
|
||||
qboolean isinwater;
|
||||
vec3_t old_origin;
|
||||
|
||||
// regular thinking
|
||||
SV_RunThink (ent);
|
||||
|
||||
// if not a team captain, so movement will be handled elsewhere
|
||||
if ( ent->flags & FL_TEAMSLAVE)
|
||||
return;
|
||||
|
||||
if (ent->velocity[2] > 0)
|
||||
ent->groundentity = NULL;
|
||||
|
||||
// check for the groundentity going away
|
||||
if (ent->groundentity)
|
||||
if (!ent->groundentity->inuse)
|
||||
ent->groundentity = NULL;
|
||||
|
||||
// if onground, return without moving
|
||||
if ( ent->groundentity )
|
||||
return;
|
||||
|
||||
VectorCopy (ent->s.origin, old_origin);
|
||||
|
||||
SV_CheckVelocity (ent);
|
||||
|
||||
// add gravity
|
||||
if (ent->movetype != MOVETYPE_FLY
|
||||
&& ent->movetype != MOVETYPE_FLYMISSILE)
|
||||
SV_AddGravity (ent);
|
||||
|
||||
// move angles
|
||||
VectorMA (ent->s.angles, FRAMETIME, ent->avelocity, ent->s.angles);
|
||||
|
||||
// move origin
|
||||
VectorScale (ent->velocity, FRAMETIME, move);
|
||||
trace = SV_PushEntity (ent, move);
|
||||
if (!ent->inuse)
|
||||
return;
|
||||
|
||||
if (trace.fraction < 1)
|
||||
{
|
||||
if (ent->movetype == MOVETYPE_BOUNCE)
|
||||
backoff = 1.5;
|
||||
else
|
||||
backoff = 1;
|
||||
|
||||
ClipVelocity (ent->velocity, trace.plane.normal, ent->velocity, backoff);
|
||||
|
||||
// stop if on ground
|
||||
if (trace.plane.normal[2] > 0.7)
|
||||
{
|
||||
if (ent->velocity[2] < 60 || ent->movetype != MOVETYPE_BOUNCE )
|
||||
{
|
||||
ent->groundentity = trace.ent;
|
||||
ent->groundentity_linkcount = trace.ent->linkcount;
|
||||
VectorCopy (vec3_origin, ent->velocity);
|
||||
VectorCopy (vec3_origin, ent->avelocity);
|
||||
}
|
||||
}
|
||||
|
||||
// if (ent->touch)
|
||||
// ent->touch (ent, trace.ent, &trace.plane, trace.surface);
|
||||
}
|
||||
|
||||
// check for water transition
|
||||
wasinwater = (ent->watertype & MASK_WATER);
|
||||
ent->watertype = gi.pointcontents (ent->s.origin);
|
||||
isinwater = ent->watertype & MASK_WATER;
|
||||
|
||||
if (isinwater)
|
||||
ent->waterlevel = 1;
|
||||
else
|
||||
ent->waterlevel = 0;
|
||||
|
||||
if (!wasinwater && isinwater)
|
||||
gi.positioned_sound (old_origin, g_edicts, CHAN_AUTO, gi.soundindex("misc/h2ohit1.wav"), 1, 1, 0);
|
||||
else if (wasinwater && !isinwater)
|
||||
gi.positioned_sound (ent->s.origin, g_edicts, CHAN_AUTO, gi.soundindex("misc/h2ohit1.wav"), 1, 1, 0);
|
||||
|
||||
// move teamslaves
|
||||
for (slave = ent->teamchain; slave; slave = slave->teamchain)
|
||||
{
|
||||
VectorCopy (ent->s.origin, slave->s.origin);
|
||||
gi.linkentity (slave);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
===============================================================================
|
||||
|
||||
STEPPING MOVEMENT
|
||||
|
||||
===============================================================================
|
||||
*/
|
||||
|
||||
/*
|
||||
=============
|
||||
SV_Physics_Step
|
||||
|
||||
Monsters freefall when they don't have a ground entity, otherwise
|
||||
all movement is done with discrete steps.
|
||||
|
||||
This is also used for objects that have become still on the ground, but
|
||||
will fall if the floor is pulled out from under them.
|
||||
FIXME: is this true?
|
||||
=============
|
||||
*/
|
||||
|
||||
//FIXME: hacked in for E3 demo
|
||||
#define sv_stopspeed 100
|
||||
#define sv_friction 6
|
||||
#define sv_waterfriction 1
|
||||
|
||||
void SV_AddRotationalFriction (edict_t *ent)
|
||||
{
|
||||
int n;
|
||||
float adjustment;
|
||||
|
||||
VectorMA (ent->s.angles, FRAMETIME, ent->avelocity, ent->s.angles);
|
||||
adjustment = FRAMETIME * sv_stopspeed * sv_friction;
|
||||
for (n = 0; n < 3; n++)
|
||||
{
|
||||
if (ent->avelocity[n] > 0)
|
||||
{
|
||||
ent->avelocity[n] -= adjustment;
|
||||
if (ent->avelocity[n] < 0)
|
||||
ent->avelocity[n] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
ent->avelocity[n] += adjustment;
|
||||
if (ent->avelocity[n] > 0)
|
||||
ent->avelocity[n] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SV_Physics_Step (edict_t *ent)
|
||||
{
|
||||
qboolean wasonground;
|
||||
qboolean hitsound = false;
|
||||
float *vel;
|
||||
float speed, newspeed, control;
|
||||
float friction;
|
||||
edict_t *groundentity;
|
||||
int mask;
|
||||
|
||||
// airborn monsters should always check for ground
|
||||
if (!ent->groundentity)
|
||||
M_CheckGround (ent);
|
||||
|
||||
groundentity = ent->groundentity;
|
||||
|
||||
SV_CheckVelocity (ent);
|
||||
|
||||
if (groundentity)
|
||||
wasonground = true;
|
||||
else
|
||||
wasonground = false;
|
||||
|
||||
if (ent->avelocity[0] || ent->avelocity[1] || ent->avelocity[2])
|
||||
SV_AddRotationalFriction (ent);
|
||||
|
||||
// add gravity except:
|
||||
// flying monsters
|
||||
// swimming monsters who are in the water
|
||||
if (! wasonground)
|
||||
if (!(ent->flags & FL_FLY))
|
||||
if (!((ent->flags & FL_SWIM) && (ent->waterlevel > 2)))
|
||||
{
|
||||
if (ent->velocity[2] < sv_gravity->value*-0.1)
|
||||
hitsound = true;
|
||||
if (ent->waterlevel == 0)
|
||||
SV_AddGravity (ent);
|
||||
}
|
||||
|
||||
// friction for flying monsters that have been given vertical velocity
|
||||
if ((ent->flags & FL_FLY) && (ent->velocity[2] != 0))
|
||||
{
|
||||
speed = fabs(ent->velocity[2]);
|
||||
control = speed < sv_stopspeed ? sv_stopspeed : speed;
|
||||
friction = sv_friction/3;
|
||||
newspeed = speed - (FRAMETIME * control * friction);
|
||||
if (newspeed < 0)
|
||||
newspeed = 0;
|
||||
newspeed /= speed;
|
||||
ent->velocity[2] *= newspeed;
|
||||
}
|
||||
|
||||
// friction for flying monsters that have been given vertical velocity
|
||||
if ((ent->flags & FL_SWIM) && (ent->velocity[2] != 0))
|
||||
{
|
||||
speed = fabs(ent->velocity[2]);
|
||||
control = speed < sv_stopspeed ? sv_stopspeed : speed;
|
||||
newspeed = speed - (FRAMETIME * control * sv_waterfriction * ent->waterlevel);
|
||||
if (newspeed < 0)
|
||||
newspeed = 0;
|
||||
newspeed /= speed;
|
||||
ent->velocity[2] *= newspeed;
|
||||
}
|
||||
|
||||
if (ent->velocity[2] || ent->velocity[1] || ent->velocity[0])
|
||||
{
|
||||
// apply friction
|
||||
// let dead monsters who aren't completely onground slide
|
||||
if ((wasonground) || (ent->flags & (FL_SWIM|FL_FLY)))
|
||||
if (!(ent->health <= 0.0 && !M_CheckBottom(ent)))
|
||||
{
|
||||
vel = ent->velocity;
|
||||
speed = sqrt(vel[0]*vel[0] +vel[1]*vel[1]);
|
||||
if (speed)
|
||||
{
|
||||
friction = sv_friction;
|
||||
|
||||
control = speed < sv_stopspeed ? sv_stopspeed : speed;
|
||||
newspeed = speed - FRAMETIME*control*friction;
|
||||
|
||||
if (newspeed < 0)
|
||||
newspeed = 0;
|
||||
newspeed /= speed;
|
||||
|
||||
vel[0] *= newspeed;
|
||||
vel[1] *= newspeed;
|
||||
}
|
||||
}
|
||||
|
||||
if (ent->svflags & SVF_MONSTER)
|
||||
mask = MASK_MONSTERSOLID;
|
||||
else
|
||||
mask = MASK_SOLID;
|
||||
SV_FlyMove (ent, FRAMETIME, mask);
|
||||
|
||||
gi.linkentity (ent);
|
||||
G_TouchTriggers (ent);
|
||||
|
||||
if (ent->groundentity)
|
||||
if (!wasonground)
|
||||
if (hitsound)
|
||||
gi.sound (ent, 0, gi.soundindex("world/land.wav"), 1, 1, 0);
|
||||
}
|
||||
|
||||
// regular thinking
|
||||
SV_RunThink (ent);
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
/*
|
||||
================
|
||||
G_RunEntity
|
||||
|
||||
================
|
||||
*/
|
||||
void G_RunEntity (edict_t *ent)
|
||||
{
|
||||
if (ent->prethink)
|
||||
ent->prethink (ent);
|
||||
|
||||
switch ( (int)ent->movetype)
|
||||
{
|
||||
case MOVETYPE_PUSH:
|
||||
case MOVETYPE_STOP:
|
||||
SV_Physics_Pusher (ent);
|
||||
break;
|
||||
case MOVETYPE_NONE:
|
||||
SV_Physics_None (ent);
|
||||
break;
|
||||
case MOVETYPE_NOCLIP:
|
||||
SV_Physics_Noclip (ent);
|
||||
break;
|
||||
case MOVETYPE_STEP:
|
||||
SV_Physics_Step (ent);
|
||||
break;
|
||||
case MOVETYPE_TOSS:
|
||||
case MOVETYPE_BOUNCE:
|
||||
case MOVETYPE_FLY:
|
||||
case MOVETYPE_FLYMISSILE:
|
||||
SV_Physics_Toss (ent);
|
||||
break;
|
||||
default:
|
||||
gi.error ("SV_Physics: bad movetype %i", (int)ent->movetype);
|
||||
}
|
||||
}
|
||||
744
original/ctf/g_save.c
Normal file
744
original/ctf/g_save.c
Normal file
@@ -0,0 +1,744 @@
|
||||
/*
|
||||
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"
|
||||
|
||||
field_t fields[] = {
|
||||
{"classname", FOFS(classname), F_LSTRING},
|
||||
{"origin", FOFS(s.origin), F_VECTOR},
|
||||
{"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},
|
||||
{"angles", FOFS(s.angles), F_VECTOR},
|
||||
{"angle", FOFS(s.angles), F_ANGLEHACK},
|
||||
{"mass", FOFS(mass), F_INT},
|
||||
{"volume", FOFS(volume), F_FLOAT},
|
||||
{"attenuation", FOFS(attenuation), F_FLOAT},
|
||||
{"map", FOFS(map), F_LSTRING},
|
||||
|
||||
// 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},
|
||||
{"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}
|
||||
};
|
||||
|
||||
// -------- just for savegames ----------
|
||||
// all pointer fields should be listed here, or savegames
|
||||
// won't work properly (they will crash and burn).
|
||||
// this wasn't just tacked on to the fields array, because
|
||||
// these don't need names, we wouldn't want map fields using
|
||||
// some of these, and if one were accidentally present twice
|
||||
// it would double swizzle (fuck) the pointer.
|
||||
|
||||
field_t savefields[] =
|
||||
{
|
||||
{"", FOFS(classname), F_LSTRING},
|
||||
{"", FOFS(target), F_LSTRING},
|
||||
{"", FOFS(targetname), F_LSTRING},
|
||||
{"", FOFS(killtarget), F_LSTRING},
|
||||
{"", FOFS(team), F_LSTRING},
|
||||
{"", FOFS(pathtarget), F_LSTRING},
|
||||
{"", FOFS(deathtarget), F_LSTRING},
|
||||
{"", FOFS(combattarget), F_LSTRING},
|
||||
{"", FOFS(model), F_LSTRING},
|
||||
{"", FOFS(map), F_LSTRING},
|
||||
{"", FOFS(message), F_LSTRING},
|
||||
|
||||
{"", FOFS(client), F_CLIENT},
|
||||
{"", FOFS(item), F_ITEM},
|
||||
|
||||
{"", FOFS(goalentity), F_EDICT},
|
||||
{"", FOFS(movetarget), F_EDICT},
|
||||
{"", FOFS(enemy), F_EDICT},
|
||||
{"", FOFS(oldenemy), F_EDICT},
|
||||
{"", FOFS(activator), F_EDICT},
|
||||
{"", FOFS(groundentity), F_EDICT},
|
||||
{"", FOFS(teamchain), F_EDICT},
|
||||
{"", FOFS(teammaster), F_EDICT},
|
||||
{"", FOFS(owner), F_EDICT},
|
||||
{"", FOFS(mynoise), F_EDICT},
|
||||
{"", FOFS(mynoise2), F_EDICT},
|
||||
{"", FOFS(target_ent), F_EDICT},
|
||||
{"", FOFS(chain), F_EDICT},
|
||||
|
||||
{NULL, 0, F_INT}
|
||||
};
|
||||
|
||||
field_t levelfields[] =
|
||||
{
|
||||
{"", LLOFS(changemap), F_LSTRING},
|
||||
|
||||
{"", LLOFS(sight_client), F_EDICT},
|
||||
{"", LLOFS(sight_entity), F_EDICT},
|
||||
{"", LLOFS(sound_entity), F_EDICT},
|
||||
{"", LLOFS(sound2_entity), F_EDICT},
|
||||
|
||||
{NULL, 0, F_INT}
|
||||
};
|
||||
|
||||
field_t clientfields[] =
|
||||
{
|
||||
{"", CLOFS(pers.weapon), F_ITEM},
|
||||
{"", CLOFS(pers.lastweapon), F_ITEM},
|
||||
{"", 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);
|
||||
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);
|
||||
|
||||
//ZOID
|
||||
//This game.dll only supports deathmatch
|
||||
if (!deathmatch->value) {
|
||||
gi.dprintf("Forcing deathmatch.");
|
||||
gi.cvar_set("deathmatch", "1");
|
||||
}
|
||||
//force coop off
|
||||
if (coop->value)
|
||||
gi.cvar_set("coop", "0");
|
||||
//ZOID
|
||||
|
||||
|
||||
// change anytime vars
|
||||
dmflags = gi.cvar ("dmflags", "0", CVAR_SERVERINFO);
|
||||
fraglimit = gi.cvar ("fraglimit", "0", CVAR_SERVERINFO);
|
||||
timelimit = gi.cvar ("timelimit", "0", CVAR_SERVERINFO);
|
||||
//ZOID
|
||||
capturelimit = gi.cvar ("capturelimit", "0", CVAR_SERVERINFO);
|
||||
instantweap = gi.cvar ("instantweap", "0", CVAR_SERVERINFO);
|
||||
//ZOID
|
||||
password = gi.cvar ("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;
|
||||
|
||||
//ZOID
|
||||
CTFInit();
|
||||
//ZOID
|
||||
}
|
||||
|
||||
//=========================================================
|
||||
|
||||
void WriteField1 (FILE *f, field_t *field, byte *base)
|
||||
{
|
||||
void *p;
|
||||
int len;
|
||||
int index;
|
||||
|
||||
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;
|
||||
|
||||
default:
|
||||
gi.error ("WriteEdict: unknown field type");
|
||||
}
|
||||
}
|
||||
|
||||
void WriteField2 (FILE *f, field_t *field, byte *base)
|
||||
{
|
||||
int len;
|
||||
void *p;
|
||||
|
||||
p = (void *)(base + field->ofs);
|
||||
switch (field->type)
|
||||
{
|
||||
case F_LSTRING:
|
||||
case F_GSTRING:
|
||||
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;
|
||||
|
||||
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_GSTRING:
|
||||
len = *(int *)p;
|
||||
if (!len)
|
||||
*(char **)p = NULL;
|
||||
else
|
||||
{
|
||||
*(char **)p = gi.TagMalloc (len, TAG_GAME);
|
||||
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;
|
||||
|
||||
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=savefields ; 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=savefields ; 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=savefields ; 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);
|
||||
if (base != (void *)InitGame)
|
||||
{
|
||||
fclose (f);
|
||||
gi.error ("ReadLevel: function pointers have moved");
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
|
||||
989
original/ctf/g_spawn.c
Normal file
989
original/ctf/g_spawn.c
Normal file
@@ -0,0 +1,989 @@
|
||||
/*
|
||||
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},
|
||||
//ZOID
|
||||
{"info_player_team1", SP_info_player_team1},
|
||||
{"info_player_team2", SP_info_player_team2},
|
||||
//ZOID
|
||||
|
||||
{"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},
|
||||
#if 0 // remove monster code
|
||||
{"target_actor", SP_target_actor},
|
||||
#endif
|
||||
{"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},
|
||||
//ZOID
|
||||
{"misc_ctf_banner", SP_misc_ctf_banner},
|
||||
{"misc_ctf_small_banner", SP_misc_ctf_small_banner},
|
||||
//ZOID
|
||||
{"misc_satellite_dish", SP_misc_satellite_dish},
|
||||
#if 0 // remove monster code
|
||||
{"misc_actor", SP_misc_actor},
|
||||
#endif
|
||||
{"misc_gib_arm", SP_misc_gib_arm},
|
||||
{"misc_gib_leg", SP_misc_gib_leg},
|
||||
{"misc_gib_head", SP_misc_gib_head},
|
||||
#if 0 // remove monster code
|
||||
{"misc_insane", SP_misc_insane},
|
||||
#endif
|
||||
{"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},
|
||||
//ZOID
|
||||
{"trigger_teleport", SP_trigger_teleport},
|
||||
{"info_teleport_destination", SP_info_teleport_destination},
|
||||
//ZOID
|
||||
{"misc_blackhole", SP_misc_blackhole},
|
||||
{"misc_eastertank", SP_misc_eastertank},
|
||||
{"misc_easterchick", SP_misc_easterchick},
|
||||
{"misc_easterchick2", SP_misc_easterchick2},
|
||||
|
||||
#if 0 // remove monster code
|
||||
{"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},
|
||||
#endif
|
||||
|
||||
{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 (!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 (!stricmp(level.mapname, "command") && !stricmp(ent->classname, "trigger_once") && !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);
|
||||
|
||||
G_FindTeams ();
|
||||
|
||||
PlayerTrail_Init ();
|
||||
|
||||
//ZOID
|
||||
CTFSpawn();
|
||||
//ZOID
|
||||
}
|
||||
|
||||
|
||||
//===================================================================
|
||||
|
||||
#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"
|
||||
;
|
||||
|
||||
|
||||
/*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)
|
||||
//ZOID
|
||||
if (ctf->value) {
|
||||
gi.configstring (CS_STATUSBAR, ctf_statusbar);
|
||||
CTFPrecache();
|
||||
} else
|
||||
//ZOID
|
||||
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.modelindex ("#w_grapple.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
original/ctf/g_svcmds.c
Normal file
300
original/ctf/g_svcmds.c
Normal 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
original/ctf/g_target.c
Normal file
809
original/ctf/g_target.c
Normal 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 allways 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 (!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; // allready 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((stricmp(level.mapname, "fact1") == 0) && (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
original/ctf/g_trigger.c
Normal file
598
original/ctf/g_trigger.c
Normal 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;
|
||||
}
|
||||
|
||||
570
original/ctf/g_utils.c
Normal file
570
original/ctf/g_utils.c
Normal file
@@ -0,0 +1,570 @@
|
||||
/*
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// gi.dprintf("TARGET: activating %s\n", ent->target);
|
||||
|
||||
//
|
||||
// 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
|
||||
}
|
||||
921
original/ctf/g_weapon.c
Normal file
921
original/ctf/g_weapon.c
Normal file
@@ -0,0 +1,921 @@
|
||||
/*
|
||||
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_PROJECTILE; // special net code is used for projectiles
|
||||
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
|
||||
{
|
||||
//ZOID--added so rail goes through SOLID_BBOX entities (gibs, etc)
|
||||
if ((tr.ent->svflags & SVF_MONSTER) || (tr.ent->client) ||
|
||||
(tr.ent->solid == SOLID_BBOX))
|
||||
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;
|
||||
|
||||
//ZOID
|
||||
//don't target players in CTF
|
||||
if (ctf->value && ent->client &&
|
||||
self->owner->client &&
|
||||
ent->client->resp.ctf_team == self->owner->client->resp.ctf_team)
|
||||
continue;
|
||||
//ZOID
|
||||
|
||||
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);
|
||||
}
|
||||
242
original/ctf/game.h
Normal file
242
original/ctf/game.h
Normal file
@@ -0,0 +1,242 @@
|
||||
/*
|
||||
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
|
||||
//ZOID
|
||||
#define SVF_PROJECTILE 0x00000008 // entity is simple projectile, used for network optimization
|
||||
// if an entity is projectile, the model index/x/y/z/pitch/yaw are sent, encoded into
|
||||
// seven (or eight) bytes. This is to speed up projectiles. Currently, only the
|
||||
// hyperblaster makes use of this. use for items that are moving with a constant
|
||||
// velocity that don't change direction or model
|
||||
//ZOID
|
||||
|
||||
// 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);
|
||||
556
original/ctf/m_move.c
Normal file
556
original/ctf/m_move.c
Normal 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);
|
||||
}
|
||||
225
original/ctf/m_player.h
Normal file
225
original/ctf/m_player.h
Normal file
@@ -0,0 +1,225 @@
|
||||
/*
|
||||
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
|
||||
|
||||
|
||||
1741
original/ctf/p_client.c
Normal file
1741
original/ctf/p_client.c
Normal file
File diff suppressed because it is too large
Load Diff
544
original/ctf/p_hud.c
Normal file
544
original/ctf/p_hud.c
Normal file
@@ -0,0 +1,544 @@
|
||||
/*
|
||||
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; // allready activated
|
||||
|
||||
//ZOID
|
||||
if (deathmatch->value && ctf->value)
|
||||
CTFCalcScores();
|
||||
//ZOID
|
||||
|
||||
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;
|
||||
|
||||
//ZOID
|
||||
if (ctf->value) {
|
||||
CTFScoreboardMessage (ent, killer);
|
||||
return;
|
||||
}
|
||||
//ZOID
|
||||
|
||||
// sort the clients by score
|
||||
total = 0;
|
||||
for (i=0 ; i<game.maxclients ; i++)
|
||||
{
|
||||
cl_ent = g_edicts + 1 + i;
|
||||
if (!cl_ent->inuse)
|
||||
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;
|
||||
//ZOID
|
||||
if (ent->client->menu)
|
||||
PMenu_Close(ent);
|
||||
//ZOID
|
||||
|
||||
if (!deathmatch->value && !coop->value)
|
||||
return;
|
||||
|
||||
if (ent->client->showscores)
|
||||
{
|
||||
ent->client->showscores = false;
|
||||
ent->client->update_chase = true;
|
||||
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->resp.game_helpchanged == game.helpchanged))
|
||||
{
|
||||
ent->client->showhelp = false;
|
||||
return;
|
||||
}
|
||||
|
||||
ent->client->showhelp = true;
|
||||
ent->client->resp.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->resp.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;
|
||||
|
||||
//ZOID
|
||||
SetCTFStats(ent);
|
||||
//ZOID
|
||||
}
|
||||
|
||||
256
original/ctf/p_menu.c
Normal file
256
original/ctf/p_menu.c
Normal file
@@ -0,0 +1,256 @@
|
||||
/*
|
||||
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"
|
||||
|
||||
// Note that the pmenu entries are duplicated
|
||||
// this is so that a static set of pmenu entries can be used
|
||||
// for multiple clients and changed without interference
|
||||
// note that arg will be freed when the menu is closed, it must be allocated memory
|
||||
pmenuhnd_t *PMenu_Open(edict_t *ent, pmenu_t *entries, int cur, int num, void *arg)
|
||||
{
|
||||
pmenuhnd_t *hnd;
|
||||
pmenu_t *p;
|
||||
int i;
|
||||
|
||||
if (!ent->client)
|
||||
return NULL;
|
||||
|
||||
if (ent->client->menu) {
|
||||
gi.dprintf("warning, ent already has a menu\n");
|
||||
PMenu_Close(ent);
|
||||
}
|
||||
|
||||
hnd = malloc(sizeof(*hnd));
|
||||
|
||||
hnd->arg = arg;
|
||||
hnd->entries = malloc(sizeof(pmenu_t) * num);
|
||||
memcpy(hnd->entries, entries, sizeof(pmenu_t) * num);
|
||||
// duplicate the strings since they may be from static memory
|
||||
for (i = 0; i < num; i++)
|
||||
if (entries[i].text)
|
||||
hnd->entries[i].text = strdup(entries[i].text);
|
||||
|
||||
hnd->num = num;
|
||||
|
||||
if (cur < 0 || !entries[cur].SelectFunc) {
|
||||
for (i = 0, p = entries; i < num; i++, p++)
|
||||
if (p->SelectFunc)
|
||||
break;
|
||||
} else
|
||||
i = cur;
|
||||
|
||||
if (i >= num)
|
||||
hnd->cur = -1;
|
||||
else
|
||||
hnd->cur = i;
|
||||
|
||||
ent->client->showscores = true;
|
||||
ent->client->inmenu = true;
|
||||
ent->client->menu = hnd;
|
||||
|
||||
PMenu_Do_Update(ent);
|
||||
gi.unicast (ent, true);
|
||||
|
||||
return hnd;
|
||||
}
|
||||
|
||||
void PMenu_Close(edict_t *ent)
|
||||
{
|
||||
int i;
|
||||
pmenuhnd_t *hnd;
|
||||
|
||||
if (!ent->client->menu)
|
||||
return;
|
||||
|
||||
hnd = ent->client->menu;
|
||||
for (i = 0; i < hnd->num; i++)
|
||||
if (hnd->entries[i].text)
|
||||
free(hnd->entries[i].text);
|
||||
free(hnd->entries);
|
||||
if (hnd->arg)
|
||||
free(hnd->arg);
|
||||
free(hnd);
|
||||
ent->client->menu = NULL;
|
||||
ent->client->showscores = false;
|
||||
}
|
||||
|
||||
// only use on pmenu's that have been called with PMenu_Open
|
||||
void PMenu_UpdateEntry(pmenu_t *entry, const char *text, int align, SelectFunc_t SelectFunc)
|
||||
{
|
||||
if (entry->text)
|
||||
free(entry->text);
|
||||
entry->text = strdup(text);
|
||||
entry->align = align;
|
||||
entry->SelectFunc = SelectFunc;
|
||||
}
|
||||
|
||||
void PMenu_Do_Update(edict_t *ent)
|
||||
{
|
||||
char string[1400];
|
||||
int i;
|
||||
pmenu_t *p;
|
||||
int x;
|
||||
pmenuhnd_t *hnd;
|
||||
char *t;
|
||||
qboolean alt = false;
|
||||
|
||||
if (!ent->client->menu) {
|
||||
gi.dprintf("warning: ent has no menu\n");
|
||||
return;
|
||||
}
|
||||
|
||||
hnd = ent->client->menu;
|
||||
|
||||
strcpy(string, "xv 32 yv 8 picn inventory ");
|
||||
|
||||
for (i = 0, p = hnd->entries; i < hnd->num; i++, p++) {
|
||||
if (!p->text || !*(p->text))
|
||||
continue; // blank line
|
||||
t = p->text;
|
||||
if (*t == '*') {
|
||||
alt = true;
|
||||
t++;
|
||||
}
|
||||
sprintf(string + strlen(string), "yv %d ", 32 + i * 8);
|
||||
if (p->align == PMENU_ALIGN_CENTER)
|
||||
x = 196/2 - strlen(t)*4 + 64;
|
||||
else if (p->align == PMENU_ALIGN_RIGHT)
|
||||
x = 64 + (196 - strlen(t)*8);
|
||||
else
|
||||
x = 64;
|
||||
|
||||
sprintf(string + strlen(string), "xv %d ",
|
||||
x - ((hnd->cur == i) ? 8 : 0));
|
||||
|
||||
if (hnd->cur == i)
|
||||
sprintf(string + strlen(string), "string2 \"\x0d%s\" ", t);
|
||||
else if (alt)
|
||||
sprintf(string + strlen(string), "string2 \"%s\" ", t);
|
||||
else
|
||||
sprintf(string + strlen(string), "string \"%s\" ", t);
|
||||
alt = false;
|
||||
}
|
||||
|
||||
gi.WriteByte (svc_layout);
|
||||
gi.WriteString (string);
|
||||
}
|
||||
|
||||
void PMenu_Update(edict_t *ent)
|
||||
{
|
||||
if (!ent->client->menu) {
|
||||
gi.dprintf("warning: ent has no menu\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (level.time - ent->client->menutime >= 1.0) {
|
||||
// been a second or more since last update, update now
|
||||
PMenu_Do_Update(ent);
|
||||
gi.unicast (ent, true);
|
||||
ent->client->menutime = level.time;
|
||||
ent->client->menudirty = false;
|
||||
}
|
||||
ent->client->menutime = level.time + 0.2;
|
||||
ent->client->menudirty = true;
|
||||
}
|
||||
|
||||
void PMenu_Next(edict_t *ent)
|
||||
{
|
||||
pmenuhnd_t *hnd;
|
||||
int i;
|
||||
pmenu_t *p;
|
||||
|
||||
if (!ent->client->menu) {
|
||||
gi.dprintf("warning: ent has no menu\n");
|
||||
return;
|
||||
}
|
||||
|
||||
hnd = ent->client->menu;
|
||||
|
||||
if (hnd->cur < 0)
|
||||
return; // no selectable entries
|
||||
|
||||
i = hnd->cur;
|
||||
p = hnd->entries + hnd->cur;
|
||||
do {
|
||||
i++, p++;
|
||||
if (i == hnd->num)
|
||||
i = 0, p = hnd->entries;
|
||||
if (p->SelectFunc)
|
||||
break;
|
||||
} while (i != hnd->cur);
|
||||
|
||||
hnd->cur = i;
|
||||
|
||||
PMenu_Update(ent);
|
||||
}
|
||||
|
||||
void PMenu_Prev(edict_t *ent)
|
||||
{
|
||||
pmenuhnd_t *hnd;
|
||||
int i;
|
||||
pmenu_t *p;
|
||||
|
||||
if (!ent->client->menu) {
|
||||
gi.dprintf("warning: ent has no menu\n");
|
||||
return;
|
||||
}
|
||||
|
||||
hnd = ent->client->menu;
|
||||
|
||||
if (hnd->cur < 0)
|
||||
return; // no selectable entries
|
||||
|
||||
i = hnd->cur;
|
||||
p = hnd->entries + hnd->cur;
|
||||
do {
|
||||
if (i == 0) {
|
||||
i = hnd->num - 1;
|
||||
p = hnd->entries + i;
|
||||
} else
|
||||
i--, p--;
|
||||
if (p->SelectFunc)
|
||||
break;
|
||||
} while (i != hnd->cur);
|
||||
|
||||
hnd->cur = i;
|
||||
|
||||
PMenu_Update(ent);
|
||||
}
|
||||
|
||||
void PMenu_Select(edict_t *ent)
|
||||
{
|
||||
pmenuhnd_t *hnd;
|
||||
pmenu_t *p;
|
||||
|
||||
if (!ent->client->menu) {
|
||||
gi.dprintf("warning: ent has no menu\n");
|
||||
return;
|
||||
}
|
||||
|
||||
hnd = ent->client->menu;
|
||||
|
||||
if (hnd->cur < 0)
|
||||
return; // no selectable entries
|
||||
|
||||
p = hnd->entries + hnd->cur;
|
||||
|
||||
if (p->SelectFunc)
|
||||
p->SelectFunc(ent, hnd);
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user