mirror of
https://github.com/blendogames/thirtyflightsofloving.git
synced 2024-11-15 00:41:21 +00:00
7b6f4281ad
Added Zaero flare gun to no-autoswitch in p_weapon.c->Pickup_Weapon() in missionpack DLL. Added LM plasma rifle to p_weapon.c->NoAmmoWeaponChange() in missionpack DLL. Added output of modelindex5&6, alpha, and attenuation to properties command in missionpack DLL. Added nogib and environment spawnflags to trigger_hurt and trigger_hurt_boox in missionpack DLL. Added MONSTER_KNOWS_MIRRORS flag to berserker, barracuda shark, and mutant in missionpack DLL. Added entity class IDs to misc_actor and target_actor in missionpack DLL. Added syntax whitespacing to some files in missionpack DLL. Added backpack drop to certain monsters in missionpack DLL. Changed some sound paths for new monsters and weapons in missionpack DLL.
552 lines
14 KiB
C
552 lines
14 KiB
C
#include "g_local.h"
|
|
|
|
//void plat_CalcMove (edict_t *ent, vec3_t dest, void(*func)(edict_t*));
|
|
|
|
void fd_secret_move1(edict_t *self);
|
|
void fd_secret_move2(edict_t *self);
|
|
void fd_secret_move3(edict_t *self);
|
|
void fd_secret_move4(edict_t *self);
|
|
void fd_secret_move5(edict_t *self);
|
|
void fd_secret_move6(edict_t *self);
|
|
void fd_secret_done(edict_t *self);
|
|
|
|
/*
|
|
=============================================================================
|
|
|
|
SECRET DOORS
|
|
|
|
=============================================================================
|
|
*/
|
|
|
|
#define SEC_OPEN_ONCE 1 // stays open
|
|
#define SEC_1ST_LEFT 2 // 1st move is left of arrow
|
|
#define SEC_1ST_DOWN 4 // 1st move is down from arrow
|
|
#define SEC_NO_SHOOT 8 // only opened by trigger
|
|
#define SEC_YES_SHOOT 16 // shootable even if targeted
|
|
#define SEC_MOVE_RIGHT 32
|
|
#define SEC_MOVE_FORWARD 64
|
|
|
|
#define STATE_TOP 0
|
|
#define STATE_BOTTOM 1
|
|
#define STATE_UP 2
|
|
#define STATE_DOWN 3
|
|
#define STATE_LOWEST 4
|
|
|
|
void fd_secret_use (edict_t *self, edict_t *other, edict_t *activator)
|
|
{
|
|
edict_t *ent;
|
|
|
|
// gi.dprintf("fd_secret_use\n");
|
|
if (self->flags & FL_TEAMSLAVE)
|
|
return;
|
|
|
|
// added sound
|
|
if (self->moveinfo.sound_start)
|
|
gi.sound (self, CHAN_NO_PHS_ADD+CHAN_VOICE, self->moveinfo.sound_start, 1, self->attenuation, 0); // was ATTN_STATIC
|
|
if (self->moveinfo.sound_middle) {
|
|
self->s.sound = self->moveinfo.sound_middle;
|
|
#ifdef LOOP_SOUND_ATTENUATION
|
|
self->s.attenuation = self->attenuation;
|
|
#endif
|
|
}
|
|
|
|
// trigger all paired doors
|
|
for (ent = self; ent; ent = ent->teamchain)
|
|
{
|
|
if (self->moveinfo.state == STATE_LOWEST)
|
|
{
|
|
ent->moveinfo.state = STATE_DOWN;
|
|
Move_Calc (ent, ent->pos1, fd_secret_move1);
|
|
door_use_areaportals (self, true);
|
|
}
|
|
else if (self->moveinfo.state == STATE_TOP) // Knightmare added
|
|
{
|
|
ent->moveinfo.state = STATE_UP;
|
|
Move_Calc (ent, ent->pos1, fd_secret_move5);
|
|
}
|
|
}
|
|
}
|
|
|
|
void fd_secret_killed (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
|
|
{
|
|
// gi.dprintf("fd_secret_killed\n");
|
|
self->health = self->max_health;
|
|
self->takedamage = DAMAGE_NO;
|
|
|
|
if (self->flags & FL_TEAMSLAVE && self->teammaster && self->teammaster->takedamage != DAMAGE_NO)
|
|
fd_secret_killed (self->teammaster, inflictor, attacker, damage, point);
|
|
else
|
|
fd_secret_use (self, inflictor, attacker);
|
|
}
|
|
|
|
// Wait after first movement...
|
|
void fd_secret_move1 (edict_t *self)
|
|
{
|
|
// gi.dprintf("fd_secret_move1\n");
|
|
self->nextthink = level.time + 1.0;
|
|
self->think = fd_secret_move2;
|
|
self->moveinfo.state = STATE_BOTTOM;
|
|
|
|
// added sound
|
|
self->s.sound = 0;
|
|
if (self->moveinfo.sound_end)
|
|
gi.sound (self, CHAN_NO_PHS_ADD+CHAN_VOICE, self->moveinfo.sound_end, 1, self->attenuation, 0); // was ATTN_STATIC
|
|
}
|
|
|
|
// Start moving sideways w/sound...
|
|
void fd_secret_move2 (edict_t *self)
|
|
{
|
|
// gi.dprintf("fd_secret_move2\n");
|
|
// added sound
|
|
if (self->moveinfo.sound_start)
|
|
gi.sound (self, CHAN_NO_PHS_ADD+CHAN_VOICE, self->moveinfo.sound_start, 1, self->attenuation, 0); // was ATTN_STATIC
|
|
if (self->moveinfo.sound_middle) {
|
|
self->s.sound = self->moveinfo.sound_middle;
|
|
#ifdef LOOP_SOUND_ATTENUATION
|
|
self->s.attenuation = self->attenuation;
|
|
#endif
|
|
}
|
|
|
|
self->moveinfo.state = STATE_UP;
|
|
Move_Calc (self, self->pos2, fd_secret_move3);
|
|
}
|
|
|
|
// Wait here until time to go back...
|
|
void fd_secret_move3 (edict_t *self)
|
|
{
|
|
// gi.dprintf("fd_secret_move3\n");
|
|
if (!(self->spawnflags & SEC_OPEN_ONCE))
|
|
{
|
|
self->nextthink = level.time + self->wait;
|
|
self->think = fd_secret_move4;
|
|
}
|
|
self->moveinfo.state = STATE_TOP;
|
|
|
|
// added sound
|
|
self->s.sound = 0;
|
|
if (self->moveinfo.sound_end)
|
|
gi.sound (self, CHAN_NO_PHS_ADD+CHAN_VOICE, self->moveinfo.sound_end, 1, self->attenuation, 0); // was ATTN_STATIC
|
|
}
|
|
|
|
// Move backward...
|
|
void fd_secret_move4 (edict_t *self)
|
|
{
|
|
// gi.dprintf("fd_secret_move4\n");
|
|
// added sound
|
|
if (self->moveinfo.sound_start)
|
|
gi.sound (self, CHAN_NO_PHS_ADD+CHAN_VOICE, self->moveinfo.sound_start, 1, self->attenuation, 0); // was ATTN_STATIC
|
|
if (self->moveinfo.sound_middle) {
|
|
self->s.sound = self->moveinfo.sound_middle;
|
|
#ifdef LOOP_SOUND_ATTENUATION
|
|
self->s.attenuation = self->attenuation;
|
|
#endif
|
|
}
|
|
|
|
self->moveinfo.state = STATE_UP;
|
|
Move_Calc (self, self->pos1, fd_secret_move5);
|
|
}
|
|
|
|
// Wait 1 second...
|
|
void fd_secret_move5 (edict_t *self)
|
|
{
|
|
// gi.dprintf("fd_secret_move5\n");
|
|
self->nextthink = level.time + 1.0;
|
|
self->think = fd_secret_move6;
|
|
self->moveinfo.state = STATE_BOTTOM;
|
|
|
|
// added sound
|
|
self->s.sound = 0;
|
|
if (self->moveinfo.sound_end)
|
|
gi.sound (self, CHAN_NO_PHS_ADD+CHAN_VOICE, self->moveinfo.sound_end, 1, self->attenuation, 0); // was ATTN_STATIC
|
|
}
|
|
|
|
void fd_secret_move6 (edict_t *self)
|
|
{
|
|
// gi.dprintf("fd_secret_move6\n");
|
|
// added sound
|
|
if (self->moveinfo.sound_start)
|
|
gi.sound (self, CHAN_NO_PHS_ADD+CHAN_VOICE, self->moveinfo.sound_start, 1, self->attenuation, 0); // was ATTN_STATIC
|
|
if (self->moveinfo.sound_middle)
|
|
self->s.sound = self->moveinfo.sound_middle;
|
|
#ifdef LOOP_SOUND_ATTENUATION
|
|
self->s.attenuation = self->attenuation;
|
|
#endif
|
|
|
|
self->moveinfo.state = STATE_DOWN;
|
|
Move_Calc (self, self->pos0, fd_secret_done);
|
|
}
|
|
|
|
void fd_secret_done (edict_t *self)
|
|
{
|
|
// gi.dprintf("fd_secret_done\n");
|
|
if (!self->targetname || self->spawnflags & SEC_YES_SHOOT)
|
|
{
|
|
// self->health = 1;
|
|
self->health = self->max_health; // Knightmare- restore max health
|
|
self->takedamage = DAMAGE_YES;
|
|
self->die = fd_secret_killed;
|
|
}
|
|
self->moveinfo.state = STATE_LOWEST;
|
|
|
|
// added sound
|
|
self->s.sound = 0;
|
|
if (self->moveinfo.sound_end)
|
|
gi.sound (self, CHAN_NO_PHS_ADD+CHAN_VOICE, self->moveinfo.sound_end, 1, self->attenuation, 0); // was ATTN_STATIC
|
|
|
|
door_use_areaportals (self, false);
|
|
}
|
|
|
|
void secret_blocked (edict_t *self, edict_t *other)
|
|
{
|
|
// Remove dead Q1 monsters, as they can't be gibbed
|
|
if ( (other->svflags & SVF_DEADMONSTER) && (other->flags & FL_Q1_MONSTER) )
|
|
{
|
|
G_FreeEdict(other);
|
|
return;
|
|
}
|
|
|
|
if (!(self->flags & FL_TEAMSLAVE))
|
|
T_Damage (other, self, self, vec3_origin, other->s.origin, vec3_origin, self->dmg, 0, 0, MOD_CRUSH);
|
|
|
|
// if (time < self->attack_finished)
|
|
// return;
|
|
// self->attack_finished = time + 0.5;
|
|
// T_Damage (other, self, self, self->dmg);
|
|
}
|
|
|
|
/*
|
|
================
|
|
secret_touch
|
|
|
|
Prints messages
|
|
================
|
|
*/
|
|
void secret_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
|
|
{
|
|
if (other->health <= 0)
|
|
return;
|
|
|
|
// if (!(other->client))
|
|
// Lazarus: Allows robot usage
|
|
if (!other->client && !(other->flags & FL_ROBOT))
|
|
return;
|
|
|
|
if (self->monsterinfo.attack_finished > level.time)
|
|
return;
|
|
self->monsterinfo.attack_finished = level.time + 2;
|
|
|
|
if (self->message)
|
|
{
|
|
gi.centerprintf (other, self->message);
|
|
gi.sound (other, CHAN_AUTO, gi.soundindex ("misc/talk1.wav"), 1, ATTN_NORM, 0);
|
|
// fixme - put this sound back??
|
|
// gi.sound (other, CHAN_BODY, "misc/talk.wav", 1, ATTN_NORM);
|
|
}
|
|
}
|
|
|
|
|
|
/*QUAKED func_door_secret2 (0 .5 .8) ? OPEN_ONCE 1st_LEFT 1st_DOWN NO_SHOOT ALWAYS_SHOOT SLIDE_RIGHT SLIDE_FORWARD
|
|
Basic secret door. Slides back, then to the left. Angle determines direction.
|
|
|
|
FLAGS:
|
|
OPEN_ONCE = Stay open, never close
|
|
1st_LEFT = 1st move is left/right of arrow
|
|
1st_DOWN = 1st move is forwards/backwards
|
|
NO_SHOOT = not implemented yet
|
|
ALWAYS_SHOOT = even if targeted, keep shootable
|
|
SLIDE_RIGHT = the sideways move will be to right of arrow
|
|
SLIDE_FORWARD = the to/fro move will be forward
|
|
|
|
VALUES:
|
|
wait = # of seconds before coming back (5 default)
|
|
dmg = damage to inflict when blocked (2 default)
|
|
width- override how far the door pops out
|
|
length- override how far the door slides
|
|
*/
|
|
|
|
void SP_func_door_secret2 (edict_t *ent)
|
|
{
|
|
vec3_t forward, right, up;
|
|
// float lrSize, fbSize;
|
|
|
|
ent->class_id = ENTITY_FUNC_DOOR_SECRET2;
|
|
|
|
if ( (level.maptype == MAPTYPE_CUSTOM) && (ent->sounds > 4) && (ent->sounds < 100) ) // custom sounds
|
|
{
|
|
ent->moveinfo.sound_start = gi.soundindex (va("doors/dr%02i_strt.wav", ent->sounds));
|
|
ent->moveinfo.sound_middle = gi.soundindex (va("doors/dr%02i_mid.wav", ent->sounds));
|
|
ent->moveinfo.sound_end = gi.soundindex (va("doors/dr%02i_end.wav", ent->sounds));
|
|
}
|
|
else if (ent->sounds != 1)
|
|
{
|
|
ent->moveinfo.sound_start = gi.soundindex ("doors/dr1_strt.wav");
|
|
ent->moveinfo.sound_middle = gi.soundindex ("doors/dr1_mid.wav");
|
|
ent->moveinfo.sound_end = gi.soundindex ("doors/dr1_end.wav");
|
|
}
|
|
else
|
|
{
|
|
ent->moveinfo.sound_start = 0;
|
|
ent->moveinfo.sound_middle = 0;
|
|
ent->moveinfo.sound_end = 0;
|
|
}
|
|
|
|
if (ent->attenuation <= 0)
|
|
ent->attenuation = ATTN_STATIC;
|
|
|
|
if (!ent->dmg)
|
|
ent->dmg = 2;
|
|
|
|
AngleVectors (ent->s.angles, forward, right, up);
|
|
VectorCopy (ent->s.origin, ent->pos0);
|
|
VectorCopy (ent->s.angles, ent->move_angles);
|
|
G_SetMovedir (ent->s.angles, ent->movedir);
|
|
|
|
ent->movetype = MOVETYPE_PUSH;
|
|
ent->solid = SOLID_BSP;
|
|
gi.setmodel (ent, ent->model);
|
|
|
|
if (ent->move_angles[1] == 0 || ent->move_angles[1] == 180)
|
|
{
|
|
if (!ent->width)
|
|
ent->width = ent->size[1] - 2; // was lrSize
|
|
if (!ent->length)
|
|
ent->length = ent->size[0] - 2; // was fbSize
|
|
}
|
|
else if (ent->move_angles[1] == 90 || ent->move_angles[1] == 270)
|
|
{
|
|
if (!ent->width)
|
|
ent->width = ent->size[0] - 2; // was lrSize
|
|
if (!ent->length)
|
|
ent->length = ent->size[1] - 2; // was fbSize
|
|
}
|
|
else {
|
|
gi.dprintf("func_door_secret2 angles not set at 0, 90, 180, 270!\n");
|
|
}
|
|
|
|
if (ent->spawnflags & SEC_MOVE_FORWARD)
|
|
VectorScale (forward, ent->length, forward);
|
|
else
|
|
VectorScale (forward, ent->length * -1 , forward);
|
|
|
|
if (ent->spawnflags & SEC_MOVE_RIGHT)
|
|
VectorScale (right, ent->width, right);
|
|
else
|
|
VectorScale (right, ent->width * -1, right);
|
|
|
|
if (ent->spawnflags & SEC_1ST_DOWN)
|
|
{
|
|
VectorAdd (ent->s.origin, forward, ent->pos1); // was ent->moveinfo.start_origin
|
|
VectorAdd (ent->pos1, right, ent->pos2); // was ent->moveinfo.end_origin
|
|
}
|
|
else
|
|
{
|
|
VectorAdd (ent->s.origin, right, ent->pos1); // was ent->moveinfo.start_origin
|
|
VectorAdd (ent->pos1, forward, ent->pos2); // was ent->moveinfo.end_origin
|
|
}
|
|
|
|
ent->touch = secret_touch;
|
|
ent->blocked = secret_blocked;
|
|
ent->use = fd_secret_use;
|
|
|
|
ent->moveinfo.speed = 50;
|
|
ent->moveinfo.accel = 50;
|
|
ent->moveinfo.decel = 50;
|
|
ent->moveinfo.state = STATE_LOWEST;
|
|
|
|
if (!ent->targetname || ent->spawnflags & SEC_YES_SHOOT)
|
|
{
|
|
if (!ent->health) {
|
|
ent->health = 1;
|
|
}
|
|
ent->max_health = ent->health; // Knightmare- store health value
|
|
ent->takedamage = DAMAGE_YES;
|
|
ent->die = fd_secret_killed;
|
|
}
|
|
if (!ent->wait)
|
|
ent->wait = 5; // 5 seconds before closing
|
|
ent->postthink = train_move_children; // Knightmare- now supports movewith
|
|
|
|
gi.linkentity(ent);
|
|
}
|
|
|
|
// ==================================================
|
|
|
|
#define FWALL_START_ON 1
|
|
|
|
void force_wall_think(edict_t *self)
|
|
{
|
|
if (self->solid == SOLID_BSP)
|
|
{
|
|
gi.WriteByte (svc_temp_entity);
|
|
gi.WriteByte (TE_FORCEWALL);
|
|
gi.WritePosition (self->pos1);
|
|
gi.WritePosition (self->pos2);
|
|
gi.WriteByte (self->style);
|
|
gi.multicast (self->offset, MULTICAST_PVS);
|
|
}
|
|
|
|
self->think = force_wall_think;
|
|
self->nextthink = level.time + FRAMETIME;
|
|
}
|
|
|
|
void force_wall_use (edict_t *self, edict_t *other, edict_t *activator)
|
|
{
|
|
if (self->solid == SOLID_NOT)
|
|
{
|
|
self->wait = 0;
|
|
self->think = force_wall_think;
|
|
self->nextthink = level.time + FRAMETIME;
|
|
self->solid = SOLID_BSP;
|
|
KillBox(self); // Is this appropriate?
|
|
gi.linkentity (self);
|
|
}
|
|
else
|
|
{
|
|
self->wait = 1;
|
|
self->think = NULL;
|
|
self->nextthink = 0;
|
|
self->solid = SOLID_NOT;
|
|
gi.linkentity( self );
|
|
}
|
|
}
|
|
|
|
void force_wall_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
|
|
{
|
|
if (!self->dmg)
|
|
return;
|
|
|
|
if (!other->takedamage)
|
|
return;
|
|
|
|
if (self->timestamp > level.time)
|
|
return;
|
|
|
|
self->timestamp = level.time + 1;
|
|
|
|
if (!(self->spawnflags & 4))
|
|
{
|
|
if ((level.framenum % 10) == 0)
|
|
gi.sound (other, CHAN_AUTO, self->noise_index, 1, ATTN_NORM, 0);
|
|
}
|
|
|
|
T_Damage (other, self, self, vec3_origin, other->s.origin, vec3_origin, self->dmg, self->dmg, 0, MOD_TRIGGER_HURT);
|
|
}
|
|
|
|
/*QUAKED func_force_wall (1 0 1) ? START_ON
|
|
A vertical particle force wall. Turns on and solid when triggered.
|
|
If someone is in the force wall when it turns on, they're telefragged.
|
|
|
|
START_ON - forcewall begins activated. triggering will turn it off.
|
|
style - color of particles to use.
|
|
0: black
|
|
208: green
|
|
215: white
|
|
220: yellow
|
|
240: red
|
|
241: blue
|
|
224: orange
|
|
*/
|
|
void SP_func_force_wall(edict_t *ent)
|
|
{
|
|
ent->class_id = ENTITY_FUNC_FORCE_WALL;
|
|
|
|
gi.setmodel (ent, ent->model);
|
|
|
|
ent->offset[0] = (ent->absmax[0] + ent->absmin[0]) / 2;
|
|
ent->offset[1] = (ent->absmax[1] + ent->absmin[1]) / 2;
|
|
ent->offset[2] = (ent->absmax[2] + ent->absmin[2]) / 2;
|
|
|
|
ent->pos1[2] = ent->absmax[2];
|
|
ent->pos2[2] = ent->absmax[2];
|
|
if (ent->size[0] > ent->size[1])
|
|
{
|
|
ent->pos1[0] = ent->absmin[0];
|
|
ent->pos2[0] = ent->absmax[0];
|
|
ent->pos1[1] = ent->offset[1];
|
|
ent->pos2[1] = ent->offset[1];
|
|
}
|
|
else
|
|
{
|
|
ent->pos1[0] = ent->offset[0];
|
|
ent->pos2[0] = ent->offset[0];
|
|
ent->pos1[1] = ent->absmin[1];
|
|
ent->pos2[1] = ent->absmax[1];
|
|
}
|
|
|
|
if (!ent->style)
|
|
ent->style = 208;
|
|
|
|
ent->movetype = MOVETYPE_NONE;
|
|
ent->wait = 1;
|
|
|
|
if (ent->spawnflags & FWALL_START_ON)
|
|
{
|
|
ent->solid = SOLID_BSP;
|
|
ent->think = force_wall_think;
|
|
ent->nextthink = level.time + FRAMETIME;
|
|
}
|
|
else
|
|
ent->solid = SOLID_NOT;
|
|
|
|
ent->use = force_wall_use;
|
|
ent->touch = force_wall_touch;
|
|
|
|
ent->svflags = SVF_NOCLIENT;
|
|
|
|
gi.linkentity(ent);
|
|
}
|
|
|
|
/*======================================================================================*/
|
|
|
|
/*QUAKED func_dm_wall (1 0 1) ?
|
|
When the number of clients that connect to the server is less than
|
|
the value in maxclient, the wall will appear and cut off areas of
|
|
the map. This only applies when the level is first loaded, so if
|
|
2 players start, the map will be sized to 2 player. If another 16
|
|
connect then it'll be a bit frantic (haha)
|
|
|
|
count - number of clients before disappearing
|
|
*/
|
|
|
|
/*
|
|
FIXME : Make a spawnflag to check if the designer wants to use an effect.
|
|
actually make this a point entity so ANY entity can be set up like this.
|
|
i.e. one could target func_walls, weapons, ammo and health and have a different
|
|
setup depending on the number of clients conncted.
|
|
*/
|
|
|
|
void SP_func_dm_wall (edict_t *self)
|
|
{
|
|
qboolean spawn = false;
|
|
|
|
self->class_id = ENTITY_FUNC_DM_WALL;
|
|
|
|
// if it was lower than this something went very wrong.
|
|
if (self->count > 2)
|
|
{
|
|
if (self->count > game.maxclients)
|
|
{
|
|
spawn = true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
gi.dprintf("func_dm_wall with a count less than 2 at %s");
|
|
|
|
G_FreeEdict(self);
|
|
return;
|
|
}
|
|
|
|
if (spawn)
|
|
{
|
|
self->movetype = MOVETYPE_PUSH;
|
|
gi.setmodel (self, self->model);
|
|
self->solid = SOLID_BSP;
|
|
gi.linkentity (self);
|
|
}
|
|
else
|
|
{
|
|
G_FreeEdict(self);
|
|
return;
|
|
}
|
|
}
|