mirror of
https://github.com/blendogames/thirtyflightsofloving.git
synced 2024-11-15 00:41:21 +00:00
d16b46e3cf
Overhauled child entity movement in default Lazarus DLL. Added bbox versions of various triggers to default Lazarus DLL. Added level.maptype field to default Lazarus DLL. Added entity class IDs to default Lazarus DLL. Incremented savegame version for default Lazarus DLL.
794 lines
18 KiB
C
794 lines
18 KiB
C
/*
|
|
===========================================================================
|
|
Copyright (C) 1997-2001 Id Software, Inc.
|
|
Copyright (C) 2000-2002 Mr. Hyde and Mad Dog
|
|
|
|
This file is part of Lazarus Quake 2 Mod source code.
|
|
|
|
Lazarus Quake 2 Mod source code 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.
|
|
|
|
Lazarus Quake 2 Mod source code 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 Lazarus Quake 2 Mod source code; if not, write to the Free Software
|
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 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 (!(self->fogclip & 2)) //custom bloodtype flag check
|
|
self->blood_type = 3; //sparks and blood
|
|
}
|
|
|
|
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;
|
|
int rocketSpeed;
|
|
|
|
if ((self->spawnflags & SF_MONSTER_SPECIAL))
|
|
rocketSpeed = 400; // DWH: Homing rockets are tougher if slow
|
|
else
|
|
rocketSpeed = 500 + (100 * skill->value);
|
|
|
|
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;
|
|
|
|
// Lazarus fog reduction of accuracy
|
|
if (self->monsterinfo.visibility < FOG_CANSEEGOOD)
|
|
{
|
|
vec[0] += crandom() * 640 * (FOG_CANSEEGOOD - self->monsterinfo.visibility);
|
|
vec[1] += crandom() * 640 * (FOG_CANSEEGOOD - self->monsterinfo.visibility);
|
|
vec[2] += crandom() * 320 * (FOG_CANSEEGOOD - self->monsterinfo.visibility);
|
|
}
|
|
|
|
VectorSubtract (vec, start, dir);
|
|
VectorNormalize (dir);
|
|
monster_fire_rocket (self, start, dir, 50, rocketSpeed, flash_number,
|
|
(self->spawnflags & SF_MONSTER_SPECIAL ? self->enemy : NULL) );
|
|
}
|
|
|
|
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;
|
|
|
|
// Lazarus fog reduction of accuracy
|
|
if (self->monsterinfo.visibility < FOG_CANSEEGOOD)
|
|
{
|
|
vec[0] += crandom() * 640 * (FOG_CANSEEGOOD - self->monsterinfo.visibility);
|
|
vec[1] += crandom() * 640 * (FOG_CANSEEGOOD - self->monsterinfo.visibility);
|
|
vec[2] += crandom() * 320 * (FOG_CANSEEGOOD - self->monsterinfo.visibility);
|
|
}
|
|
|
|
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);
|
|
|
|
if (level.num_reflectors)
|
|
ReflectExplosion (TE_EXPLOSION1, self->s.origin);
|
|
|
|
self->nextthink = level.time + 0.1;
|
|
}
|
|
|
|
|
|
void supertank_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
|
|
{
|
|
self->s.skinnum |= 1;
|
|
if (!(self->fogclip & 2)) //custom bloodtype flag check
|
|
self->blood_type = 3; //sparks and blood
|
|
|
|
self->monsterinfo.power_armor_type = POWER_ARMOR_NONE;
|
|
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;
|
|
}
|
|
|
|
// Lazarus: special purpose skins
|
|
if ( (self->spawnflags & SF_MONSTER_SPECIAL) && self->style )
|
|
{
|
|
PatchMonsterModel("models/monsters/boss1/tris.md2");
|
|
self->s.skinnum = self->style * 2;
|
|
}
|
|
|
|
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;
|
|
|
|
// Lazarus: special purpose skins
|
|
if ( self->style )
|
|
{
|
|
PatchMonsterModel("models/monsters/boss1/tris.md2");
|
|
self->s.skinnum = self->style * 2;
|
|
}
|
|
|
|
self->s.modelindex = gi.modelindex ("models/monsters/boss1/tris.md2");
|
|
VectorSet (self->mins, -64, -64, 0);
|
|
VectorSet (self->maxs, 64, 64, 112);
|
|
|
|
// Lazarus: mapper-configurable health
|
|
if (!self->health)
|
|
self->health = 1500;
|
|
if (!self->gib_health)
|
|
self->gib_health = -500;
|
|
if (!self->mass)
|
|
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;
|
|
|
|
// Knightmare- added sparks and blood type
|
|
if (!self->blood_type)
|
|
self->blood_type = 2; //sparks
|
|
else
|
|
self->fogclip |= 2; //custom bloodtype flag
|
|
|
|
// Lazarus
|
|
if (self->powerarmor) {
|
|
self->monsterinfo.power_armor_type = POWER_ARMOR_SHIELD;
|
|
self->monsterinfo.power_armor_power = self->powerarmor;
|
|
}
|
|
|
|
gi.linkentity (self);
|
|
self->monsterinfo.currentmove = &supertank_move_stand;
|
|
if (self->health < 0)
|
|
{
|
|
mmove_t *deathmoves[] = {&supertank_move_death,
|
|
NULL};
|
|
M_SetDeath(self,(mmove_t **)&deathmoves);
|
|
}
|
|
self->common_name = "Supertank";
|
|
self->class_id = ENTITY_MONSTER_SUPERTANK;
|
|
|
|
self->monsterinfo.scale = MODEL_SCALE;
|
|
walkmonster_start(self);
|
|
}
|