Files
quakemapping/mod_xj18/my_progs/mon_ogre.qc
2020-01-07 11:54:38 +01:00

832 lines
32 KiB
Plaintext

/*==============================================================================
OGRE
==============================================================================*/
$cd id1/models/ogre_c
$origin 0 0 24
$base base
$skin base
$frame stand1 stand2 stand3 stand4 stand5 stand6 stand7 stand8 stand9
$frame walk1 walk2 walk3 walk4 walk5 walk6 walk7
$frame walk8 walk9 walk10 walk11 walk12 walk13 walk14 walk15 walk16
$frame run1 run2 run3 run4 run5 run6 run7 run8
$frame swing1 swing2 swing3 swing4 swing5 swing6 swing7
$frame swing8 swing9 swing10 swing11 swing12 swing13 swing14
$frame smash1 smash2 smash3 smash4 smash5 smash6 smash7
$frame smash8 smash9 smash10 smash11 smash12 smash13 smash14
$frame shoot1 shoot2 shoot3 shoot4 shoot5 shoot6
$frame pain1 pain2 pain3 pain4 pain5
$frame painb1 painb2 painb3
$frame painc1 painc2 painc3 painc4 painc5 painc6
$frame paind1 paind2 paind3 paind4 paind5 paind6 paind7 paind8 paind9 paind10
$frame paind11 paind12 paind13 paind14 paind15 paind16
$frame paine1 paine2 paine3 paine4 paine5 paine6 paine7 paine8 paine9 paine10
$frame paine11 paine12 paine13 paine14 paine15
$frame death1 death2 death3 death4 death5 death6
$frame death7 death8 death9 death10 death11 death12
$frame death13 death14
$frame bdeath1 bdeath2 bdeath3 bdeath4 bdeath5 bdeath6
$frame bdeath7 bdeath8 bdeath9 bdeath10
$frame pull1 pull2 pull3 pull4 pull5 pull6 pull7 pull8 pull9 pull10 pull11
//======================================================================
void() ogre_stand1 =[ $stand1, ogre_stand2 ] {ai_stand();};
void() ogre_stand2 =[ $stand2, ogre_stand3 ] {ai_stand();};
void() ogre_stand3 =[ $stand3, ogre_stand4 ] {ai_stand();};
void() ogre_stand4 =[ $stand4, ogre_stand5 ] {ai_stand();};
void() ogre_stand5 =[ $stand5, ogre_stand6 ] {monster_idle_sound(); ai_stand();};
void() ogre_stand6 =[ $stand6, ogre_stand7 ] {ai_stand();};
void() ogre_stand7 =[ $stand7, ogre_stand8 ] {ai_stand();};
void() ogre_stand8 =[ $stand8, ogre_stand9 ] {ai_stand();};
void() ogre_stand9 =[ $stand9, ogre_stand1 ] {ai_stand();};
//======================================================================
void() ogre_walk1 =[ $walk1, ogre_walk2 ] {monster_footstep(FALSE); ai_walk(3);};
void() ogre_walk2 =[ $walk2, ogre_walk3 ] {ai_walk(2);};
void() ogre_walk3 =[ $walk3, ogre_walk4 ] {monster_idle_sound(); ai_walk(2);};
void() ogre_walk4 =[ $walk4, ogre_walk5 ] {ai_walk(2);};
void() ogre_walk5 =[ $walk5, ogre_walk6 ] {ai_walk(2);};
void() ogre_walk6 =[ $walk6, ogre_walk7 ] {ai_walk(5);
if (random() < 0.1) sound (self, CHAN_VOICE, "ogre/ogdrag.wav", 1, ATTN_IDLE);};
void() ogre_walk7 =[ $walk7, ogre_walk8 ] {ai_walk(3);};
void() ogre_walk8 =[ $walk8, ogre_walk9 ] {ai_walk(2);};
void() ogre_walk9 =[ $walk9, ogre_walk10 ] {monster_footstep(FALSE); ai_walk(3);};
void() ogre_walk10 =[ $walk10, ogre_walk11 ] {ai_walk(1);};
void() ogre_walk11 =[ $walk11, ogre_walk12 ] {ai_walk(2);};
void() ogre_walk12 =[ $walk12, ogre_walk13 ] {ai_walk(3);};
void() ogre_walk13 =[ $walk13, ogre_walk14 ] {ai_walk(3);};
void() ogre_walk14 =[ $walk14, ogre_walk15 ] {ai_walk(3);};
void() ogre_walk15 =[ $walk15, ogre_walk16 ] {ai_walk(3);};
void() ogre_walk16 =[ $walk16, ogre_walk1 ] {ai_walk(4);};
//======================================================================
void() ogre_run1 =[ $run1, ogre_run2 ] {monster_idle_sound(); ai_run(9);};
void() ogre_run2 =[ $run2, ogre_run3 ] {monster_footstep(FALSE);ai_run(12);};
void() ogre_run3 =[ $run3, ogre_run4 ] {ai_run(8);};
void() ogre_run4 =[ $run4, ogre_run5 ] {ai_run(22);};
void() ogre_run5 =[ $run5, ogre_run6 ] {ai_run(16);};
void() ogre_run6 =[ $run6, ogre_run7 ] {monster_footstep(FALSE);ai_run(4);};
void() ogre_run7 =[ $run7, ogre_run8 ] {ai_run(13);};
void() ogre_run8 =[ $run8, ogre_run1 ] {ai_run(24);};
/*======================================================================
MELEE - Chainsaw
======================================================================*/
void(float side, float dmgmultipler) chainsaw =
{
local float ldmg;
if (!self.enemy) return;
if (self.health < 1) return;
ai_damagebreakable(20); // Damage any breakables
if (!ai_checkmelee(self.meleerange)) return; // Too far away
// Can the target bleed? - generate blood
if (!CanDamage (self.enemy, self)) return;
// Damage 1-12
ldmg = (random() + random() + random()) * (4*dmgmultipler);
if (ldmg < 1) ldmg = 1;
T_Damage (self.enemy, self, self, ldmg, DAMARMOR);
// Check for poisonous attribute (new poison version)
if (self.poisonous) PoisonDeBuff(self.enemy);
SpawnMeatSpray (self, self.enemy, side);
};
//----------------------------------------------------------------------
void() ogre_swing1 =[ $swing1, ogre_swing2 ] {ai_charge(11);};
void() ogre_swing2 =[ $swing2, ogre_swing3 ] {ai_charge(1);};
void() ogre_swing3 =[ $swing3, ogre_swing4 ] {ai_charge(4);};
void() ogre_swing4 =[ $swing4, ogre_swing5 ] {ai_charge(13);};
void() ogre_swing5 =[ $swing5, ogre_swing6 ] {monster_footstep(FALSE);
ai_charge(9); chainsaw(0,1);self.angles_y = self.angles_y + random()*25;};
void() ogre_swing6 =[ $swing6, ogre_swing7 ] {chainsaw(200,1);self.angles_y = self.angles_y + random()* 25;};
void() ogre_swing7 =[ $swing7, ogre_swing8 ] {chainsaw(0,1);self.angles_y = self.angles_y + random()* 25;};
void() ogre_swing8 =[ $swing8, ogre_swing9 ] {chainsaw(0,1);self.angles_y = self.angles_y + random()* 25;};
void() ogre_swing9 =[ $swing9, ogre_swing10 ] {chainsaw(0,1);self.angles_y = self.angles_y + random()* 25;};
void() ogre_swing10 =[ $swing10, ogre_swing11 ] {chainsaw(-200,1);self.angles_y = self.angles_y + random()* 25;};
void() ogre_swing11 =[ $swing11, ogre_swing12 ] {chainsaw(0,1);self.angles_y = self.angles_y + random()* 25;};
void() ogre_swing12 =[ $swing12, ogre_swing13 ] {ai_charge(3);};
void() ogre_swing13 =[ $swing13, ogre_swing14 ] {ai_charge(8);};
void() ogre_swing14 =[ $swing14, ogre_run1 ] {ai_charge(9);};
//----------------------------------------------------------------------
void() ogre_smash1 =[ $smash1, ogre_smash2 ] {ai_charge(6);};
void() ogre_smash2 =[ $smash2, ogre_smash3 ] {ai_charge(0);};
void() ogre_smash3 =[ $smash3, ogre_smash4 ] {ai_charge(0);};
void() ogre_smash4 =[ $smash4, ogre_smash5 ] {ai_charge(1);};
void() ogre_smash5 =[ $smash5, ogre_smash6 ] {ai_charge(4);};
void() ogre_smash6 =[ $smash6, ogre_smash7 ] {ai_charge(4); chainsaw(0,1);};
void() ogre_smash7 =[ $smash7, ogre_smash8 ] {ai_charge(4); chainsaw(0,1);};
void() ogre_smash8 =[ $smash8, ogre_smash9 ] {ai_charge(10); chainsaw(0,1);};
void() ogre_smash9 =[ $smash9, ogre_smash10 ] {monster_footstep(FALSE); ai_charge(13); chainsaw(0,1);};
void() ogre_smash10 =[ $smash10, ogre_smash11 ] {chainsaw(1,1);};
void() ogre_smash11 =[ $smash11, ogre_smash12 ] {ai_charge(2); chainsaw(0,1);
self.nextthink = self.nextthink + random()*0.2;}; // slight variation
void() ogre_smash12 =[ $smash12, ogre_smash13 ] {ai_charge(0);};
void() ogre_smash13 =[ $smash13, ogre_smash14 ] {ai_charge(4);};
void() ogre_smash14 =[ $smash14, ogre_run1 ] {ai_charge(12);};
//----------------------------------------------------------------------
void() ogre_melee =
{
sound (self, CHAN_WEAPON, "ogre/ogsawatk.wav", 1, ATTN_NORM);
if (random() > 0.5) ogre_smash1 ();
else ogre_swing1 ();
};
/*======================================================================
Range - Grenades (uses generic attack function in projectiles.qc)
Nail - Alternative firemode (based on nail ogre from Marcher Fortress)
======================================================================*/
void() OgreFireNails =
{
local vector org, dir, vec;
local float loopvar;
// Check for death?
if (self.health < 1) return;
loopvar = 0;
// Light up face, setup projectile speed and play fire sound
self.effects = self.effects | EF_MUZZLEFLASH;
self.attack_speed = SPEED_NAILOGREPROJ + (skill * SPEED_NAILOGRESKILL);
sound(self, CHAN_WEAPON, "ogre/nail_fire.wav", 1, ATTN_NORM);
// turn and face your enemy!
makevectors (self.angles);
org = self.origin + attack_vector(self.attack_offset);
// Loop through the nail burst (all at once)
while (loopvar < self.attack_count) {
// Random circle spread pattern
vec = (crandom()*20)*v_right + (crandom()*20)*v_up;
dir = normalize((self.enemy.origin + vec) - org);
// Generate a red hot nail projectile
launch_projectile(org, dir, CT_PROJ_MONNG, self.attack_speed);
loopvar = loopvar + 1;
}
};
//----------------------------------------------------------------------
void() ogre_shoot1 =[ $shoot1, ogre_shoot2 ] {
ai_face();
MonsterGrenadeSound();
self.attack_speed = MonsterGrenadeSpeed();
self.attack_elev = SUB_Elevation(ELEV_DEFAULT, self.origin, self.enemy.origin, self.attack_speed);
};
void() ogre_shoot2 =[ $shoot2, ogre_shoot3 ] {
ai_face();
self.attack_elev = SUB_Elevation(self.attack_elev, self.origin, self.enemy.origin, self.attack_speed);
};
void() ogre_shoot3 =[ $shoot2, ogre_shoot4 ] {
ai_face();
self.attack_elev = SUB_Elevation(self.attack_elev, self.origin, self.enemy.origin, self.attack_speed);
};
void() ogre_shoot4 =[ $shoot3, ogre_shoot5 ] {
ai_face();
MonsterFireGrenade(self.origin, self.enemy.origin);
};
void() ogre_shoot5 =[ $shoot4, ogre_shoot6 ] {};
void() ogre_shoot6 =[ $shoot5, ogre_shoot7 ] {};
void() ogre_shoot7 =[ $shoot6, ogre_run1 ] {ai_face();};
//----------------------------------------------------------------------
void() ogre_nail1 =[ $shoot1, ogre_nail2 ] {ai_face();};
void() ogre_nail2 =[ $shoot2, ogre_nail3 ] {ai_face();};
void() ogre_nail3 =[ $shoot2, ogre_nail4 ] {ai_face();};
void() ogre_nail4 =[ $shoot3, ogre_nail5 ] {ai_face();OgreFireNails();};
void() ogre_nail5 =[ $shoot4, ogre_nail6 ] {};
void() ogre_nail6 =[ $shoot5, ogre_nail7 ] {};
void() ogre_nail7 =[ $shoot6, ogre_run1 ] {ai_face();};
//======================================================================
// Lots of different pain animations (falling over is a classic
//======================================================================
void() ogre_pain1 =[ $pain1, ogre_pain2 ] {};
void() ogre_pain2 =[ $pain2, ogre_pain3 ] {};
void() ogre_pain3 =[ $pain3, ogre_pain4 ] {};
void() ogre_pain4 =[ $pain4, ogre_pain5 ] {};
void() ogre_pain5 =[ $pain5, ogre_run1 ] {};
//----------------------------------------------------------------------
void() ogre_painb1 =[ $painb1, ogre_painb2 ] {};
void() ogre_painb2 =[ $painb2, ogre_painb3 ] {};
void() ogre_painb3 =[ $painb3, ogre_run1 ] {};
//----------------------------------------------------------------------
void() ogre_painc1 =[ $painc1, ogre_painc2 ] {};
void() ogre_painc2 =[ $painc2, ogre_painc3 ] {};
void() ogre_painc3 =[ $painc3, ogre_painc4 ] {};
void() ogre_painc4 =[ $painc4, ogre_painc5 ] {};
void() ogre_painc5 =[ $painc5, ogre_painc6 ] {};
void() ogre_painc6 =[ $painc6, ogre_run1 ] {};
//----------------------------------------------------------------------
void() ogre_paind1 =[ $paind1, ogre_paind2 ] {};
void() ogre_paind2 =[ $paind2, ogre_paind3 ] {ai_pain(10);};
void() ogre_paind3 =[ $paind3, ogre_paind4 ] {ai_pain(9);};
void() ogre_paind4 =[ $paind4, ogre_paind5 ] {monster_footstep(FALSE);ai_pain(4);};
void() ogre_paind5 =[ $paind5, ogre_paind6 ] {};
void() ogre_paind6 =[ $paind6, ogre_paind7 ] {};
void() ogre_paind7 =[ $paind7, ogre_paind8 ] {};
void() ogre_paind8 =[ $paind8, ogre_paind9 ] {};
void() ogre_paind9 =[ $paind9, ogre_paind10 ] {};
void() ogre_paind10=[ $paind10, ogre_paind11 ] {monster_footstep(FALSE);};
void() ogre_paind11=[ $paind11, ogre_paind12 ] {};
void() ogre_paind12=[ $paind12, ogre_paind13 ] {monster_footstep(FALSE);};
void() ogre_paind13=[ $paind13, ogre_paind14 ] {};
void() ogre_paind14=[ $paind14, ogre_paind15 ] {};
void() ogre_paind15=[ $paind15, ogre_paind16 ] {};
void() ogre_paind16=[ $paind16, ogre_run1 ] {};
//----------------------------------------------------------------------
void() ogre_paine1 =[ $paine1, ogre_paine2 ] {};
void() ogre_paine2 =[ $paine2, ogre_paine3 ] {ai_pain(10);};
void() ogre_paine3 =[ $paine3, ogre_paine4 ] {monster_footstep(FALSE);ai_pain(9);};
void() ogre_paine4 =[ $paine4, ogre_paine5 ] {ai_pain(4);};
void() ogre_paine5 =[ $paine5, ogre_paine6 ] {};
void() ogre_paine6 =[ $paine6, ogre_paine7 ] {};
void() ogre_paine7 =[ $paine7, ogre_paine8 ] {};
void() ogre_paine8 =[ $paine8, ogre_paine9 ] {};
void() ogre_paine9 =[ $paine9, ogre_paine10 ] {};
void() ogre_paine10=[ $paine10, ogre_paine11 ] {};
void() ogre_paine11=[ $paine11, ogre_paine12 ] {};
void() ogre_paine12=[ $paine12, ogre_paine13 ] {};
void() ogre_paine13=[ $paine13, ogre_paine14 ] {};
void() ogre_paine14=[ $paine14, ogre_paine15 ] {};
void() ogre_paine15=[ $paine15, ogre_run1 ] {};
//----------------------------------------------------------------------
void(entity inflictor, entity attacker, float damage) ogre_pain =
{
// Check all pain conditions and set up what to do next
monster_pain_check(attacker, damage);
// Any pain animation/sound required?
if (self.pain_check > 0) {
sound (self, CHAN_VOICE, self.pain_sound, 1, ATTN_NORM);
if (self.pain_check == 1) {
// Randomly pick which pain animation to play
self.lip = random();
if (self.lip < 0.25) ogre_pain1 ();
else if (self.lip < 0.5) ogre_painb1 ();
else if (self.lip < 0.75) ogre_painc1 ();
else if (self.lip < 0.88) {
// Fall down to the ground
ogre_paind1 ();
self.pain_finished = time + 2;
}
else {
// Stagger backwards
ogre_paine1 ();
self.pain_finished = time + 2;
}
}
if (self.pain_check == 2) {
self.axhitme = 0;
if (random() < 0.5) {
self.pain_finished = time + 1.6;
ogre_paind1 (); // Fall to ground
}
else {
self.pain_finished = time + 1.5;
ogre_paine1 (); // Stagger backwards
}
}
}
};
//======================================================================
// DIE Ogre DIE!?!
//======================================================================
void() ogre_die1 =[ $death1, ogre_die2 ] {};
void() ogre_die2 =[ $death2, ogre_die3 ] {monster_check_gib();};
void() ogre_die3 =[ $death3, ogre_die4 ] {monster_check_gib();
self.solid = SOLID_NOT; if (!self.gibbed) DropBackpack();};
void() ogre_die4 =[ $death4, ogre_die5 ] {};
void() ogre_die5 =[ $death5, ogre_die6 ] {};
void() ogre_die6 =[ $death6, ogre_die7 ] {};
void() ogre_die7 =[ $death7, ogre_die8 ] {};
void() ogre_die8 =[ $death8, ogre_die9 ] {};
void() ogre_die9 =[ $death9, ogre_die10 ] {};
void() ogre_die10 =[ $death10, ogre_die11 ] {};
void() ogre_die11 =[ $death11, ogre_die12 ] {};
void() ogre_die12 =[ $death12, ogre_die13 ] {};
void() ogre_die13 =[ $death13, ogre_die14 ] {monster_death_postcheck();};
void() ogre_die14 =[ $death14, ogre_die14 ] {monster_deadbody_check();};
//----------------------------------------------------------------------
void() ogre_bdie1 =[ $bdeath1, ogre_bdie2 ] {};
void() ogre_bdie2 =[ $bdeath2, ogre_bdie3 ] {monster_check_gib();ai_forward(5);};
void() ogre_bdie3 =[ $bdeath3, ogre_bdie4 ] {monster_check_gib();
self.solid = SOLID_NOT; if (!self.gibbed) DropBackpack();};
void() ogre_bdie4 =[ $bdeath4, ogre_bdie5 ] {ai_forward(1);};
void() ogre_bdie5 =[ $bdeath5, ogre_bdie6 ] {ai_forward(3);};
void() ogre_bdie6 =[ $bdeath6, ogre_bdie7 ] {ai_forward(7);};
void() ogre_bdie7 =[ $bdeath7, ogre_bdie8 ] {ai_forward(25);};
void() ogre_bdie8 =[ $bdeath8, ogre_bdie9 ] {};
void() ogre_bdie9 =[ $bdeath9, ogre_bdie10 ] {monster_death_postcheck();};
void() ogre_bdie10 =[ $bdeath10, ogre_bdie10 ] {monster_deadbody_check();};
//----------------------------------------------------------------------
void() ogre_die =
{
// Pre-check routine to tidy up extra entities
monster_death_precheck();
if (!self.gibbed) {
sound (self, CHAN_VOICE, "ogre/ogdth.wav", 1, ATTN_NORM);
self.lip = random();
if (self.lip < 0.5) ogre_die1();
else ogre_bdie1();
}
};
//----------------------------------------------------------------------
// Special wakeup animation for attacking/breaking something infront
// The monster should be setup facing the right direction before call
// Starts in large overhead swing downwards (no damage checks)
//----------------------------------------------------------------------
void() ogre_wakeup1 =[ $smash7, ogre_wakeup2] {monster_sightsound();};
void() ogre_wakeup2 =[ $smash6, ogre_wakeup3] {};
void() ogre_wakeup3 =[ $smash8, ogre_wakeup4] {};
void() ogre_wakeup4 =[ $smash9, ogre_wakeup5 ] {};
void() ogre_wakeup5 =[ $smash10, ogre_wakeup6 ] {};
void() ogre_wakeup6 =[ $smash11, ogre_wakeup7 ] {};
void() ogre_wakeup7 =[ $smash12, ogre_wakeup8 ] {};
void() ogre_wakeup8 =[ $smash13, ogre_wakeup9 ] {};
void() ogre_wakeup9 =[ $smash14, ogre_run1 ] {};
//======================================================================
// From the crazy mind of Madfox, comes fishing ogre!?!
//======================================================================
float OGREFISH_FISHY = 0;
float OGREFISH_FISHING = 19;
float OGREFISH_CATCH = 79;
float ANIMATION_OGREFLAP = 18;
float ANIMATION_OGREFISH = 59;
float ANIMATION_OGRECATCH = 25;
//----------------------------------------------------------------------
// Special idle animation - Flappy the fish waggles tail
//----------------------------------------------------------------------
void() ogre_flappyfish =
{
// If dead, no more updates
if (self.health < 1) return;
self.nextthink = time + 0.1;
self.frame = OGREFISH_FISHY + self.walkframe;
// Check for special frame conditions
if (self.walkframe == 0)
sound (self, CHAN_VOICE, "ogre/ogrefish_flappy.wav", 1, ATTN_NORM);
// Move frame forward, check for conditions
self.walkframe = self.walkframe + 1;
if (self.walkframe > ANIMATION_OGREFLAP) {
self.walkframe = 0;
self.think = self.th_altstand;
}
else self.think = ogre_flappyfish;
};
//----------------------------------------------------------------------
// Special idle animation - Ogre finally catches something!
//----------------------------------------------------------------------
void() ogre_catchfish =
{
// If dead, no more updates
if (self.health < 1) return;
self.nextthink = time + 0.1;
self.frame = OGREFISH_CATCH + self.walkframe;
// Check for special frame conditions
if (self.walkframe == 6)
sound (self, CHAN_VOICE, "ogre/ogrefish_out.wav", 1, ATTN_NORM);
if (self.walkframe == 24)
sound (self, CHAN_VOICE, "ogre/ogrefish_in.wav", 1, ATTN_NORM);
// Move frame forward, check for conditions
self.walkframe = self.walkframe + 1;
if (self.walkframe > ANIMATION_OGRECATCH) {
self.walkframe = 0;
self.think = self.th_altstand;
}
else self.think = ogre_catchfish;
};
//----------------------------------------------------------------------
void() ogre_fishing =
{
// If dead, no more updates
if (self.health < 1) return;
self.idlebusy = FALSE;
self.nextthink = time + 0.1;
self.frame = OGREFISH_FISHING + self.walkframe;
// Check for fishing idle animations
if (self.walkframe == 0) {
self.lip = random();
// Finally caught a fish?
if (self.lip < 0.1) {
self.think = ogre_catchfish;
self.idlebusy = TRUE;
}
// Flappy the fish gasping for air
else if (self.lip < 0.2) {
self.think = ogre_flappyfish;
self.idlebusy = TRUE;
}
// Classic ogre idle + water
else if (self.lip < 0.3)
sound (self, CHAN_VOICE, "ogre/ogrefish_idle.wav", 1, ATTN_NORM);
}
// Ghost version updates alpha and spawns particles
if (self.spawnflags & MON_GHOST_ONLY) {
// Is ogre setup invisible?
if (self.alpha < 1) {
// Wait for the ogre to get into position
if (self.respawn_time < time) {
// exponential fade in model alpha
self.alpha = self.alpha + self.lefty;
self.lefty = self.lefty + self.lefty;
if (self.alpha >= 1) self.alpha = 1;
}
}
else {
// Model is all screwed up, with loads of extra surfaces
// cannot do alpha sparkle because of back surface problem
//self.alpha = 0.5 + (0.1*random());
self.pos1 = '0 0 0';
self.pos1_x = crandom()*16;
self.pos1_y = crandom()*16;
self.pos1_z = crandom()*24;
if (random() < 0.5)
particle_explode(self.origin+self.pos1, 2, 1, PARTICLE_BURST_WHITE, PARTICLE_BURST_LOSTUP);
}
}
if (self.idlebusy == FALSE) {
// Move frame forward, check for conditions
self.walkframe = self.walkframe + 1;
if (self.walkframe > ANIMATION_OGREFISH) self.walkframe = 0;
self.think = ogre_fishing;
}
};
//----------------------------------------------------------------------
// Re-using fall down pain animation
//----------------------------------------------------------------------
void() ogre_fishd6 =[ $paind6, ogre_fishd7 ] {};
void() ogre_fishd7 =[ $paind7, ogre_fishd8 ] {};
void() ogre_fishd8 =[ $paind8, ogre_fishd9 ] {};
void() ogre_fishd9 =[ $paind9, ogre_fishd10 ] {};
void() ogre_fishd10=[ $paind10, ogre_fishd11 ] {monster_footstep(FALSE);};
void() ogre_fishd11=[ $paind11, ogre_fishd12 ] {};
void() ogre_fishd12=[ $paind12, ogre_fishd13 ] {monster_footstep(FALSE);};
void() ogre_fishd13=[ $paind13, ogre_fishd14 ] {};
void() ogre_fishd14=[ $paind14, ogre_fishd15 ] {};
void() ogre_fishd15=[ $paind15, ogre_fishd16 ] {};
void() ogre_fishd16=[ $paind16, ogre_run1 ] {
// Restore pain/damage functionality
self.flags = self.flags | FL_MONSTER;
self.health = self.max_health;
// Fishing ogre is wearing a grenade bounce shirt!
self.takedamage = DAMAGE_YES;
self.noradiusdmg = FALSE;
self.use = monster_use;
// Does not feel much pain and attacks more often
self.pain_flinch = 200;
self.pain_timeout = 3;
// Restore animation/game logic
self.th_stand = ogre_stand1;
self.th_walk = ogre_walk1;
self.th_run = ogre_run1;
self.th_melee = ogre_melee;
self.th_missile = ogre_shoot1;
self.th_pain = ogre_pain;
self.th_die = ogre_die;
};
//----------------------------------------------------------------------
void() ogre_fishwakeup = {
self.use = SUB_Null; // Stop re-triggering
monster_sightsound(); // Classic wakeup sound
// Make sure no more pain or damage
self.takedamage = DAMAGE_NO;
self.pain_finished = time + 2;
// Check for model in original ogre position
// This is to save the space for the returning ogre
if (self.attachment) {
setmodel(self.attachment, "");
self.attachment.solid = SOLID_NOT;
self.attachment.movetype = MOVETYPE_NONE;
}
// Check for any wakeup triggers
if (self.target2 != "") {
trigger_strs(self.target2, self);
self.target2 = "";
}
// Shift ogre into pain (on floor) state
setmodel(self, self.mdl);
self.frame = $paind6; // Has to be set after model change
setorigin(self, self.pos1);
setsize (self, self.bbmins, self.bbmaxs);
ogre_fishd6();
};
//----------------------------------------------------------------------
void(entity inf, entity att, float dam) ogre_fishpain = {ogre_fishwakeup();};
void() ogre_fishdie = {};
//----------------------------------------------------------------------
void() ogre_fishsetup =
{
// Setup ghost version (no pain or death)
if (self.spawnflags & MON_GHOST_ONLY) {
self.respawn_time = time + 0.3; // Wait to get into position
self.lefty = 0.01; // Exponential increase
self.solid = SOLID_NOT; // No interaction with world
self.movetype = MOVETYPE_NONE; // Static item, no movement
self.takedamage = DAMAGE_NO;
self.noradiusdmg = TRUE;
self.gibhealth = MON_NEVERGIB;
self.health = LARGE_TIMER;
self.use = SUB_Null;
}
else {
// Take direct damage only and grenades bounce!
self.takedamage = DAMAGE_YES;
self.noradiusdmg = TRUE;
self.health = MEGADEATH;
self.use = ogre_fishwakeup;
// Create a temporary entity to fill up space behind ogre
// Prevent anthing getting in the way when ogre wakes up
if (!self.attachment) {
self.attachment = spawn();
setmodel(self.attachment, MODEL_EMPTY);
setorigin(self.attachment, self.origin);
setsize (self.attachment, self.bbmins, self.bbmaxs);
self.attachment.solid = SOLID_BBOX;
self.attachment.movetype = MOVETYPE_STEP;
}
}
setmodel(self, self.weaponglow); // Setup fishing model pose
self.pos1 = self.origin; // Save current origin for later
if (self.spawnflags & MON_GHOST_ONLY) self.skin = 2;
// Move ogre into fishing animation position
makevectors(self.angles);
self.pos2 = self.origin + attack_vector('36 0 -24');
setorigin(self, self.pos2);
// Got to reset bounding box after model change
setsize (self, self.bbmins, self.bbmaxs);
self.walkframe = 0;
ogre_fishing();
};
/*======================================================================
QUAKED monster_ogre (1 0 0) (-32 -32 -24) (32 32 64) Ambush
======================================================================*/
void() monster_ogre_precache =
{
self.mdl = "progs/mon_ogre.mdl"; // Rogue Ogre
self.headmdl = "progs/h_ogre.mdl";
self.gib1mdl = "progs/w_chainsaw.mdl"; // Chainsaw
self.gib2mdl = "progs/gib_ogfoot1.mdl"; // Left foot
self.gib3mdl = "progs/gib_ogfoot2.mdl"; // Right foot
self.gib4mdl = "progs/w_ogregl.mdl"; // Grenade Launcher
precache_model (self.mdl);
precache_model (MODEL_PROJ_GRENADE);
precache_model (self.headmdl);
precache_model (self.gib1mdl);
precache_model (self.gib2mdl);
precache_model (self.gib3mdl);
precache_model (self.gib4mdl);
// Randomly swap in GL instead of Chainsaw
self.gib1sound = GIB_IMPACT_WOOD;
if (random() < 0.5) self.gib1mdl = self.gib4mdl;
self.gib4mdl = "";
self.idle_sound = "ogre/ogidle.wav";
precache_sound (self.idle_sound);
self.idle_soundcom = "ogre/ogidle2.wav";
precache_sound (self.idle_soundcom);
precache_sound ("ogre/ogdth.wav");
self.pain_sound = "ogre/ogpain1.wav";
precache_sound (self.pain_sound);
precache_sound ("ogre/ogdrag.wav");
precache_sound ("ogre/ogsawatk.wav");
self.sight_sound = "ogre/ogwake.wav";
precache_sound (self.sight_sound);
// Load additional models/sounds for nail ogre
if (self.spawnflags & MON_OGRE_NAIL) {
// Default attack - red glowing nails
precache_model (MODEL_PROJ_NGRED);
precache_sound("ogre/nail_fire.wav");
// Default amount of nails to burst fire (5x9=45dmg)
if (self.attack_count < 1) self.attack_count = 5;
}
// Check for poisonous entity flag
if (self.poisonous) {
precache_poisongibs(); // precache gibs
self.gibtype = GIBTYPE_POISON; // Poisonous blood trails
precache_model (MODEL_PROJ_GRENADEGRN);
}
};
//----------------------------------------------------------------------
void() monster_ogre =
{
if (deathmatch) { remove(self); return; }
// Precache basic ogre models and sounds
monster_ogre_precache();
self.solid = SOLID_NOT; // No interaction with world
self.movetype = MOVETYPE_NONE; // Static item, no movement
self.idmins = VEC_HULL2_MIN; // -32 -32 -24, 32 32 64
self.idmaxs = VEC_HULL2_MAX;
if (self.bboxtype < 1) self.bboxtype = BBOX_WIDE;
self.gibhealth = -80;
self.gibbed = FALSE;
self.pain_flinch = 30; // Low pain flinch
self.pain_longanim = TRUE; // Can be chopped with shadow axe
self.steptype = FS_TYPESLOW; // Small sounding feet
self.meleerange = MONAI_MELEEOGRE; // Chainsaw range
self.no_zaware = TRUE; // Always NOT zware
self.attack_offset = '24 0 20'; // Run + Gun vector
if (!self.ammo_rockets) self.ammo_rockets = 2; // Default ammo drop
self.deathstring = " was destroyed by an Ogre\n";
// Standard ogre health 200 with green+ option
if (self.health < 1) self.health = 200;
if (self.spawnflags & MON_OGRE_GREEN) {
self.health = self.health + MON_OGRE_GRNUPG;
self.skin = 1;
}
// Always reset Ammo Resistance to be consistent
self.resist_shells = self.resist_nails = 0;
self.resist_rockets = self.resist_cells = 0;
self.th_checkattack = OgreCheckAttack;
self.th_stand = ogre_stand1;
self.th_walk = ogre_walk1;
self.th_run = ogre_run1;
self.th_melee = ogre_melee;
self.th_missile = ogre_shoot1;
self.th_pain = ogre_pain;
self.th_die = ogre_die;
self.th_wakeup = ogre_wakeup1;
// Switch attack types
if (self.spawnflags & MON_OGRE_NAIL) self.th_missile = ogre_nail1;
else self.th_missile = ogre_shoot1;
self.classtype = CT_MONOGRE; // Old style ogre
self.classgroup = CG_OGRE; // One big happy ogre family!
self.classmove = MON_MOVEWALK;
monster_start();
};
//----------------------------------------------------------------------
void() monster_ogre_marksman = { monster_ogre (); };
//----------------------------------------------------------------------
void() monster_ogre_fishing =
{
if (deathmatch) { remove(self); return; }
// Precache basic ogre models and sounds
monster_ogre_precache();
// Extra fishing ogre precache stuff
self.weaponglow = "progs/mon_ogrefish.mdl";
precache_model (self.weaponglow);
precache_sound ("ogre/ogrefish_out.wav");
precache_sound ("ogre/ogrefish_in.wav");
precache_sound ("ogre/ogrefish_idle.wav");
precache_sound ("ogre/ogrefish_flappy.wav");
self.solid = SOLID_NOT; // No interaction with world
self.movetype = MOVETYPE_NONE; // Static item, no movement
if (self.bboxtype < 1) self.bboxtype = BBOX_WIDE;
self.gibhealth = -80;
self.gibbed = FALSE;
self.pain_flinch = 1; // Pain is the wakeup trigger
self.pain_longanim = FALSE; // Cannot be chopped with shadow axe
self.steptype = FS_TYPESLOW; // Small sounding feet
self.no_zaware = FALSE; // Fishing ogre has perfect aim!
self.bouncegrenade = TRUE; // Grenades bounce off!
self.meleerange = MONAI_MELEEOGRE; // Chainsaw range
self.exactskin = 0; // Skin defined by spawnflag
self.noinfighting = TRUE; // No infighting
self.pain_ignore = TRUE; // Will not wake up from monsters
self.movespeed = 0; // This is not a turret
self.frame = OGREFISH_FISHING; // Start in fishing frame
self.deathstring = " was reeled in by a Fishing Ogre\n";
// Remove spawnflag options not needed for this monster
self.lip = 0;
// Ghost version has unique skin, cannot have green version as well
if (self.spawnflags & MON_GHOST_ONLY) self.lip = self.lip | MON_GHOST_ONLY;
else if (self.spawnflags & MON_OGRE_GREEN) self.lip = self.lip | MON_OGRE_GREEN;
// Classic check for fx/spawn options
if (self.spawnflags & MON_SPAWN_NOGFX) self.lip = self.lip | MON_SPAWN_NOGFX;
if (self.spawnflags & MON_SPAWN_DELAY) self.lip = self.lip | MON_SPAWN_DELAY;
self.spawnflags = self.lip;
// Special event monster has unique HP setup
if (self.spawnflags & MON_OGRE_GREEN) {
self.ammo_rockets = 6; // Tons of rockets!
self.health = 350; // Much stronger
self.skin = 1; // Green (Rogue) skin
}
else {
self.ammo_rockets = 4; // More rockets than fish!
self.health = 150; // Lower HP than regular
}
// Fishing ogre can never uses nails, grenades only
self.spawnflags = self.spawnflags - (self.spawnflags & MON_OGRE_NAIL);
// Always reset Ammo Resistance to be consistent
self.resist_shells = self.resist_nails = 0;
self.resist_rockets = 1; // Rocket resistance
self.resist_cells = 0;
self.th_checkattack = OgreCheckAttack;
self.th_stand = self.th_walk = self.th_run = ogre_fishsetup;
self.th_altstand = ogre_fishing;
// Setup ghost version (no pain or death)
if (self.spawnflags & MON_GHOST_ONLY) {
self.th_pain = SUB_Null_pain;
self.th_die = SUB_Null;
self.headmdl = "";
}
else {
self.th_pain = ogre_fishpain;
self.th_die = ogre_fishdie;
}
self.classtype = CT_MONOGREFISH;
self.classgroup = CG_OGRE; // One big happy ogre family!
self.classmove = MON_MOVEWALK;
monster_start();
}
//----------------------------------------------------------------------
void() monster_ogre_fishing_ghost =
{
// Special spawnflag (code only)
self.spawnflags = self.spawnflags | MON_GHOST_ONLY;
// Always no monster count
self.nomonstercount = TRUE;
// Start model invisible (to prevent snapping)
self.alpha = 0.01;
monster_ogre_fishing();
};