thirtyflightsofloving/missionpack/g_misc_q1.c
Knightmare66 7b6f4281ad Added POSTTHINK_CHILD_MOVEMENT macro to new movewith host entities in g_spawn.c->SpawnEntities() in default Lazarus DLL.
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.
2020-10-29 13:03:20 -04:00

618 lines
17 KiB
C

// g_misc_q1.c
#include "g_local.h"
//======================================================================
// CRUCIFIED ZOMBIE
//======================================================================
void misc_zombie_crucified_think (edict_t *self)
{
float r1;
if (++self->s.frame < 198) // was FRAME_death4_22
self->nextthink = level.time + FRAMETIME;
else
{
self->s.frame = 192;
self->nextthink = level.time + FRAMETIME;
}
r1 = random();
if (r1 <= .017)
{
gi.sound (self, CHAN_VOICE, gi.soundindex ("q1zombie/idle_w2.wav"), 1, ATTN_IDLE, 0);
}
}
/*QUAKED misc_q1_zombie_crucified (1 .5 0) (-16 -16 -24) (16 16 32)
model="models/monsters/q1zombie/"
frame="192"
*/
void SP_misc_q1_zombie_crucified (edict_t *self)
{
// precache
gi.soundindex ("q1zombie/idle_w2.wav");
self->movetype = MOVETYPE_NONE;
self->solid = SOLID_NOT;
VectorSet (self->mins, -16, -16, -24);
VectorSet (self->maxs, 16, 16, 32);
self->s.modelindex = gi.modelindex ("models/monsters/q1zombie/tris.md2");
self->s.frame = 192;
self->common_name = "Crucified Zombie";
self->class_id = ENTITY_MISC_Q1_ZOMBIE_CRUCIFIED;
gi.linkentity (self);
self->think = misc_zombie_crucified_think;
self->nextthink = level.time + FRAMETIME;
}
//======================================================================
// AIR BUBBLES
//======================================================================
void bubble_bob (edict_t *bubble);
void bubble_touch (edict_t *ent, edict_t *other, cplane_t *plane, csurface_t *surf)
{
if (!strcmp (other->classname, ent->classname))
{
// gi.dprintf ("bump\n");
return;
}
G_FreeEdict (ent);
}
void bubble_split (edict_t *bubble)
{
edict_t *newbubble;
float r1 = random();
float r2 = random();
int i, j;
newbubble = G_Spawn();
newbubble->classname = "bubble";
newbubble->s.modelindex = gi.modelindex ("sprites/s_bubble.sp2");
VectorCopy (bubble->s.origin, newbubble->s.origin);
if (r1 > 0.5) i = 1;
else i = 0;
if (r2 > 0.5) j = 1;
else j = -1;
newbubble->s.origin[i] += (6 * j);
newbubble->movetype = MOVETYPE_FLYMISSILE;
newbubble->solid = SOLID_TRIGGER;
VectorCopy (bubble->velocity, newbubble->velocity);
newbubble->nextthink = level.time + 0.5;
newbubble->think = bubble_bob;
newbubble->touch = bubble_touch;
newbubble->s.frame = 1;
newbubble->count = 10;
VectorSet (newbubble->mins, -2, -2, -2);
VectorSet (newbubble->maxs, 2, 2, 2);
gi.linkentity (newbubble);
bubble->s.frame = 1;
bubble->count = 10;
if (bubble->waterlevel != 3)
G_FreeEdict (bubble);
}
void bubble_bob (edict_t *bubble)
{
float rnd1, rnd2, rnd3;
// vec3_t vtmp1, modi;
bubble->count++;
if (bubble->count == 4)
bubble_split (bubble);
if (bubble->count == 20)
G_FreeEdict (bubble);
rnd1 = bubble->velocity[0] + (-10 + (random() * 20));
rnd2 = bubble->velocity[1] + (-10 + (random() * 20));
rnd3 = bubble->velocity[2] + 10 + random() * 10;
if (rnd1 > 10)
rnd1 = 5;
if (rnd1 < -10)
rnd1 = -5;
if (rnd2 > 10)
rnd2 = 5;
if (rnd2 < -10)
rnd2 = -5;
if (rnd3 < 10)
rnd3 = 15;
if (rnd3 > 30)
rnd3 = 25;
bubble->velocity[0] = rnd1;
bubble->velocity[1] = rnd2;
bubble->velocity[2] = rnd3;
bubble->nextthink = level.time + 0.5;
bubble->think = bubble_bob;
}
void make_bubbles (edict_t *self)
{
edict_t *bubble;
bubble = G_Spawn();
bubble->classname = "bubble";
bubble->s.modelindex = gi.modelindex ("sprites/s_bubble.sp2");
VectorCopy (self->s.origin, bubble->s.origin);
bubble->movetype = MOVETYPE_FLYMISSILE;
bubble->solid = SOLID_TRIGGER;
VectorSet (bubble->mins, -2, -2, -2);
VectorSet (bubble->maxs, 2, 2, 2);
VectorSet (bubble->velocity, 0, 0, 15);
bubble->nextthink = level.time + 0.5;
bubble->think = bubble_bob;
bubble->touch = bubble_touch;
bubble->s.frame = 0;
bubble->count = 0;
bubble->common_name = "Bubble";
bubble->class_id = ENTITY_Q1_BUBBLE;
gi.linkentity (bubble);
self->nextthink = level.time + random() + 0.5;
self->think = make_bubbles;
}
/*QUAKED misc_q1_air_bubbles (1 0 0) (-8 -8 -8) (8 8 8)
This entity gives off sprite air bubbles, put it at the bottom of the water where the air should start bubbling up.
*/
void SP_misc_q1_air_bubbles (edict_t *self)
{
if (deathmatch->value)
{
G_FreeEdict (self);
return;
}
self->class_id = ENTITY_MISC_Q1_BUBBLE_SPAWNER;
gi.modelindex ("sprites/s_bubble.sp2");
self->nextthink = level.time + 1;
self->think = make_bubbles;
gi.linkentity (self);
}
//======================================================================
// GLOBE
//======================================================================
/*QUAKED misc_q1_globe (0 1 0) (-4 -4 -4) (4 4 4)
This is a sprite, is not solid
*/
void SP_misc_q1_globe(edict_t *self)
{
self->movetype = MOVETYPE_NONE;
self->solid = SOLID_NOT;
self->s.modelindex = gi.modelindex ("sprites/s_light.sp2");
self->s.frame = 0;
self->s.sound = 0;
self->common_name = "Globe Light";
self->class_id = ENTITY_MISC_Q1_GLOBE;
gi.linkentity (self);
}
//======================================================================
// SMALL FLAME
//======================================================================
void q1_small_flame_think (edict_t *self)
{
if(self->s.frame >= 5)
self->s.frame = 0;
else
self->s.frame++;
self->nextthink = level.time + FRAMETIME;
}
/*QUAKED misc_q1_small_flame (0 1 0) (-4 -4 -4) (4 4 4)
not solid
model="models/objects/q1flame/"
*/
void SP_misc_q1_small_flame (edict_t *ent)
{
ent->movetype = MOVETYPE_NONE;
ent->solid = SOLID_NOT;
ent->s.modelindex = gi.modelindex ("models/objects/q1flame/tris.md2");
ent->s.frame = 0;
ent->s.sound = gi.soundindex("q1world/fire1.wav");
ent->s.renderfx = RF_FULLBRIGHT | RF_NOSHADOW;
ent->nextthink = level.time + FRAMETIME;
ent->think = q1_small_flame_think;
ent->common_name = "Small Flame";
ent->class_id = ENTITY_MISC_Q1_FLAME_SMALL;
gi.linkentity (ent);
}
//======================================================================
// LARGE FLAME
//======================================================================
void q1_large_flame_think (edict_t *self)
{
if (self->s.frame >= 16)
self->s.frame = 6;
else
self->s.frame++;
self->nextthink = level.time + FRAMETIME;
}
/*QUAKED misc_q1_large_flame (0 1 0) (-4 -4 -4) (4 4 4)
not solid
model="models/objects/q1flame/"
frame="6"
*/
void SP_misc_q1_large_flame (edict_t *ent)
{
ent->movetype = MOVETYPE_NONE;
ent->solid = SOLID_NOT;
ent->s.modelindex = gi.modelindex ("models/objects/q1flame/tris.md2");
ent->s.frame = 6;
ent->s.sound = gi.soundindex("q1world/fire1.wav");
ent->nextthink = level.time + FRAMETIME;
ent->think = q1_large_flame_think;
ent->s.renderfx = RF_FULLBRIGHT | RF_NOSHADOW;
ent->common_name = "Large Flame";
ent->class_id = ENTITY_MISC_Q1_FLAME_LARGE;
gi.linkentity (ent);
}
//======================================================================
// TORCH
//======================================================================
void q1_torch_think (edict_t *self)
{
if(self->s.frame >= 5)
self->s.frame = 0;
else
self->s.frame++;
self->nextthink = level.time + FRAMETIME;
}
/*QUAKED misc_q1_torch (0 1 0) (-4 -4 -4) (4 4 4)
model="models/objects/q1torch/"
not solid
*/
void SP_misc_q1_torch (edict_t *ent)
{
ent->movetype = MOVETYPE_NONE;
ent->solid = SOLID_NOT;
ent->s.modelindex = gi.modelindex ("models/objects/q1torch/tris.md2");
ent->s.frame = 0;
ent->s.sound = gi.soundindex("q1world/fire1.wav");
ent->s.renderfx = RF_FULLBRIGHT | RF_NOSHADOW;
ent->nextthink = level.time + FRAMETIME;
ent->think = q1_torch_think;
ent->common_name = "Torch";
ent->class_id = ENTITY_MISC_Q1_TORCH;
gi.linkentity (ent);
}
/*
==============
target_q1_trap
spawnflag 1 = superspike
spawnflag 2 = laser
defualt speed 500, 600 for laser
damage 9 for spike, 15 for superspike, 15 for laser
==============
*/
void q1_use_target_trapshooter (edict_t *self, edict_t *other, edict_t *activator)
{
qboolean super = (self->spawnflags & 1);
gi.sound (self, CHAN_AUTO, self->noise_index, 1, ATTN_NORM, 0);
if (self->spawnflags & 2) {
q1_fire_laser (self, self->s.origin, self->movedir, self->dmg, self->speed);
}
else {
q1_fire_nail (self, self->s.origin, self->movedir, self->dmg, self->speed, super);
#ifndef KMQUAKE2_ENGINE_MOD
gi.sound (self, CHAN_AUTO, gi.soundindex("q1weapons/s_end.wav"), 1.0, ATTN_NORM, 0);
#endif
}
}
/*QUAKED target_q1_trap (1 0 0) (-8 -8 -8) (8 8 8) superspike laser
Fires a spike in the set direction when triggered.
default speed 500, 600 for laser
damage 9 for spike, 15 for superspike, 15 for laser
*/
void SP_target_q1_trap (edict_t *self)
{
self->class_id = ENTITY_TARGET_Q1_TRAPSHOOTER;
self->use = q1_use_target_trapshooter;
G_SetMovedir (self->s.angles, self->movedir);
if (self->spawnflags & 2)
{
self->noise_index = gi.soundindex ("q1enforcer/enfire.wav");
gi.soundindex("q1enforcer/enfstop.wav");
if (!self->speed)
self->speed = 600;
}
else {
#ifdef KMQUAKE2_ENGINE_MOD
self->noise_index = gi.soundindex ("q1weapons/spike2.wav");
#else
self->noise_index = gi.soundindex ("q1weapons/spike.wav");
gi.soundindex("q1weapons/s_end.wav");
#endif
if (!self->speed)
self->speed = 500;
}
if (self->spawnflags & 1 || self->spawnflags & 2) {
if (!self->dmg)
self->dmg = 15;
}
else {
if (!self->dmg)
self->dmg = 9;
}
self->svflags = SVF_NOCLIENT;
}
//======================================================================
// Q1 EXPLOBOX
//======================================================================
void q1_barrel_explode (edict_t *self)
{
self->nextthink = level.time + FRAMETIME;
self->s.frame++;
if (self->s.frame == 5)
G_FreeEdict(self);
}
/*static*/ void q1_explobox_delay (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
{
self->takedamage = DAMAGE_NO;
self->nextthink = level.time + 2 * FRAMETIME;
self->activator = attacker;
T_RadiusDamage (self, self->activator, self->dmg, NULL, self->dmg+30, MOD_BARREL);
if (!deathmatch->value)
{
vec3_t org;
float spd;
vec3_t save;
VectorCopy (self->s.origin, save);
VectorMA (self->absmin, 0.5, self->size, self->s.origin);
// a few big chunks
spd = 1.5 * (float)self->dmg / 200.0;
org[0] = self->s.origin[0] + crandom() * self->size[0];
org[1] = self->s.origin[1] + crandom() * self->size[1];
org[2] = self->s.origin[2] + crandom() * self->size[2];
ThrowDebris (self, "models/objects/debris1/tris.md2", spd, org, 0, 0);
org[0] = self->s.origin[0] + crandom() * self->size[0];
org[1] = self->s.origin[1] + crandom() * self->size[1];
org[2] = self->s.origin[2] + crandom() * self->size[2];
ThrowDebris (self, "models/objects/debris1/tris.md2", spd, org, 0, 0);
// bottom corners
spd = 1.75 * (float)self->dmg / 200.0;
VectorCopy (self->absmin, org);
ThrowDebris (self, "models/objects/debris3/tris.md2", spd, org, 0, 0);
VectorCopy (self->absmin, org);
org[0] += self->size[0];
ThrowDebris (self, "models/objects/debris3/tris.md2", spd, org, 0, 0);
VectorCopy (self->absmin, org);
org[1] += self->size[1];
ThrowDebris (self, "models/objects/debris3/tris.md2", spd, org, 0, 0);
VectorCopy (self->absmin, org);
org[0] += self->size[0];
org[1] += self->size[1];
ThrowDebris (self, "models/objects/debris3/tris.md2", spd, org, 0, 0);
// a bunch of little chunks
spd = 2 * self->dmg / 200;
org[0] = self->s.origin[0] + crandom() * self->size[0];
org[1] = self->s.origin[1] + crandom() * self->size[1];
org[2] = self->s.origin[2] + crandom() * self->size[2];
ThrowDebris (self, "models/objects/debris2/tris.md2", spd, org, 0, 0);
org[0] = self->s.origin[0] + crandom() * self->size[0];
org[1] = self->s.origin[1] + crandom() * self->size[1];
org[2] = self->s.origin[2] + crandom() * self->size[2];
ThrowDebris (self, "models/objects/debris2/tris.md2", spd, org, 0, 0);
org[0] = self->s.origin[0] + crandom() * self->size[0];
org[1] = self->s.origin[1] + crandom() * self->size[1];
org[2] = self->s.origin[2] + crandom() * self->size[2];
ThrowDebris (self, "models/objects/debris2/tris.md2", spd, org, 0, 0);
org[0] = self->s.origin[0] + crandom() * self->size[0];
org[1] = self->s.origin[1] + crandom() * self->size[1];
org[2] = self->s.origin[2] + crandom() * self->size[2];
ThrowDebris (self, "models/objects/debris2/tris.md2", spd, org, 0, 0);
org[0] = self->s.origin[0] + crandom() * self->size[0];
org[1] = self->s.origin[1] + crandom() * self->size[1];
org[2] = self->s.origin[2] + crandom() * self->size[2];
ThrowDebris (self, "models/objects/debris2/tris.md2", spd, org, 0, 0);
org[0] = self->s.origin[0] + crandom() * self->size[0];
org[1] = self->s.origin[1] + crandom() * self->size[1];
org[2] = self->s.origin[2] + crandom() * self->size[2];
ThrowDebris (self, "models/objects/debris2/tris.md2", spd, org, 0, 0);
org[0] = self->s.origin[0] + crandom() * self->size[0];
org[1] = self->s.origin[1] + crandom() * self->size[1];
org[2] = self->s.origin[2] + crandom() * self->size[2];
ThrowDebris (self, "models/objects/debris2/tris.md2", spd, org, 0, 0);
org[0] = self->s.origin[0] + crandom() * self->size[0];
org[1] = self->s.origin[1] + crandom() * self->size[1];
org[2] = self->s.origin[2] + crandom() * self->size[2];
ThrowDebris (self, "models/objects/debris2/tris.md2", spd, org, 0, 0);
VectorCopy (save, self->s.origin);
}
gi.sound (self, CHAN_AUTO, gi.soundindex ("q1weapons/r_exp3.wav"), 1.0, ATTN_NORM, 0);
gi.WriteByte (svc_temp_entity);
gi.WriteByte (TE_ROCKET_EXPLOSION);
gi.WritePosition (self->s.origin);
gi.multicast (self->s.origin, MULTICAST_PVS);
// explosion sprite
gi.unlinkentity (self);
self->solid = SOLID_NOT;
self->touch = NULL;
VectorClear (self->velocity);
self->s.modelindex = gi.modelindex ("sprites/s_explod.sp2");
self->s.frame = 0;
self->s.sound = 0;
self->s.effects &= ~EF_ANIM_ALLFAST;
self->think = q1_barrel_explode;
self->nextthink = level.time + FRAMETIME;
gi.linkentity (self);
}
/*QUAKED misc_q1_explobox (0 .5 .8) (-16 -16 -16) (16 16 48) small
If small is checked, it is only 40, not 64 units tall.
health defaults to 20
dmg defaults to 160
mass defaults to 400
model="models/objects/q1explo/big/"
*/
void SP_misc_q1_explobox (edict_t *self)
{
// precache
gi.modelindex ("sprites/s_explod.sp2");
gi.soundindex ("q1weapons/r_exp3.wav");
self->solid = SOLID_BBOX;
//self->solid = SOLID_NOT;
self->movetype = MOVETYPE_NONE;
self->svflags &= ~SVF_NOCLIENT;
if (self->spawnflags & 1)
{
self->model = "models/objects/q1explo/small/tris.md2";
VectorSet (self->mins, -16, -16, -16);
VectorSet (self->maxs, 16, 16, 24);
}
else
{
self->model = "models/objects/q1explo/big/tris.md2";
VectorSet (self->mins, -16, -16, -16);
VectorSet (self->maxs, 16, 16, 48);
}
self->s.modelindex = gi.modelindex (self->model);
if (!self->mass)
self->mass = 400;
if (!self->health)
self->health = 20;
if (!self->dmg)
self->dmg = 160;
self->die = q1_explobox_delay;
self->takedamage = DAMAGE_YES;
self->monsterinfo.aiflags = AI_NOSTEP;
self->touch = NULL;
self->think = M_droptofloor;
self->nextthink = level.time + 2 * FRAMETIME;
self->common_name = "Exploding Box";
self->class_id = ENTITY_MISC_Q1_EXPLOBOX;
gi.linkentity (self);
}
//======================================================================
// FIREBALL
//======================================================================
void q1_fireball_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
{
T_Damage (other, self, self->owner, self->velocity, self->s.origin, plane->normal, self->dmg, 0, 0, 0);
G_FreeEdict (self);
}
void q1_fireball_fly (edict_t *self)
{
edict_t *lavaball;
// gi.dprintf ("Launching Fireball\n");
lavaball = G_Spawn();
lavaball->speed = 200;
VectorCopy (self->s.origin, lavaball->s.origin);
VectorCopy (self->movedir, lavaball->movedir);
vectoangles (self->movedir, lavaball->s.angles);
VectorSet(lavaball->velocity,((random() * 100) - 50),
((random() * 100) - 50),
(self->speed + (random() * 150)));
// lavaball->movetype = MOVETYPE_FLYMISSILE;
lavaball->movetype = MOVETYPE_TOSS;
lavaball->clipmask = MASK_SHOT;
lavaball->solid = SOLID_BBOX;
lavaball->s.effects |= EF_ROCKET; // EF_FLAG1
lavaball->s.renderfx |= RF_GLOW;
VectorClear (lavaball->mins);
VectorClear (lavaball->maxs);
VectorSet (lavaball->mins, -8, -8, -8);
VectorSet (lavaball->maxs, 8, 8, 8);
lavaball->s.modelindex = gi.modelindex ("models/monsters/q1chthon/lavaball/tris.md2");
lavaball->owner = self;
lavaball->touch = q1_fireball_touch;
lavaball->nextthink = level.time + 7;
lavaball->think = G_FreeEdict;
lavaball->dmg = 20;
lavaball->classname = "lavaball";
lavaball->common_name = "Lavaball";
lavaball->class_id = ENTITY_Q1_FIREBALL;
gi.linkentity (lavaball);
self->nextthink = level.time + (4 + (random() * 3.0));
self->think = q1_fireball_fly;
}
/*QUAKED misc_q1_fireball (.5 .5 .5) (-8 -8 -8) (8 8 8)
model="models/monsters/q1chthon/lavaball/"
*/
void SP_misc_q1_fireball (edict_t *self)
{
// precache
gi.modelindex ("models/monsters/q1chthon/lavaball/tris.md2");
self->nextthink = level.time + (4 + (random() * 3.0));
self->think = q1_fireball_fly;
self->classname = "fireball";
self->common_name = "Lavaball Spawner";
self->class_id = ENTITY_MISC_Q1_FIREBALL_SPAWNER;
gi.linkentity(self);
}