432 lines
17 KiB
Plaintext
432 lines
17 KiB
Plaintext
/*==============================================================================
|
|
XMAS Elf - From Twisted Christmas Mod by Twisted Matrix
|
|
==============================================================================*/
|
|
|
|
// (000 - 007) Rocking back and forth on feet
|
|
$frame stand1 stand2 stand3 stand4 stand5 stand6 stand7 stand8
|
|
|
|
// (008 - 017) Skipping! (Running)
|
|
$frame skip1 skip2 skip3 skip4 skip5 skip6 skip7 skip8
|
|
$frame skip9 skip10
|
|
|
|
// (018 - 029) Walking
|
|
$frame walk1 walk2 walk3 walk4 walk5 walk6 walk7 walk8
|
|
$frame walk9 walk10 walk11 walk12
|
|
|
|
// (030 - 036) Suprise, jump up into the air with legs wide apart
|
|
$frame surprise1 surprise2 surprise3 surprise4 surprise5 surprise6 surprise7
|
|
|
|
// (037 - 048) ATTACK - Swing cane around (long version)
|
|
$frame magic1 magic2 magic3 magic4 magic5 magic6 magic7 magic8
|
|
$frame magic9 magic10 magic11 magic12
|
|
|
|
// (049 - 056) ATTACK - Jump up and smash cane into ground
|
|
$frame jump1 jump2 jump3 jump4 jump5 jump6 jump7 jump8
|
|
|
|
// (057 - 061) ATTACK - Swing cane around (short version)
|
|
$frame attack1 attack2 attack3 attack4 attack5
|
|
|
|
// (062 - 066) PAIN - Recoil backward
|
|
$frame pain1 pain2 pain3 pain4 pain5
|
|
|
|
// (067 - 078) ATTACK - Fall downward with cane infront
|
|
$frame ambush1 ambush2 ambush3 ambush4 ambush5 ambush6 ambush7 ambush8
|
|
$frame ambush9 ambush10 ambush11 ambush12
|
|
|
|
// (079 - 093) DEATH - Backward
|
|
$frame bdeath1 bdeath2 bdeath3 bdeath4 bdeath5 bdeath6 bdeath7 bdeath8
|
|
$frame bdeath9 bdeath10 bdeath11 bdeath12 bdeath13 bdeath14 bdeath15
|
|
|
|
// (094 - 107) DEATH - Forward
|
|
$frame death1 death2 death3 death4 death5 death6 death7 death8
|
|
$frame death9 death10 death11 death12 death13 death14
|
|
|
|
// (108 - 109) Misc modelling stuff
|
|
$frame base1 base2
|
|
|
|
//======================================================================
|
|
void() elf_stand1 = [ $stand1, elf_stand2 ] {monster_idle_sound();ai_stand();};
|
|
void() elf_stand2 = [ $stand2, elf_stand3 ] {ai_stand();};
|
|
void() elf_stand3 = [ $stand3, elf_stand4 ] {ai_stand();};
|
|
void() elf_stand4 = [ $stand4, elf_stand5 ] {ai_stand();};
|
|
void() elf_stand5 = [ $stand5, elf_stand6 ] {ai_stand();};
|
|
void() elf_stand6 = [ $stand6, elf_stand7 ] {ai_stand();};
|
|
void() elf_stand7 = [ $stand7, elf_stand8 ] {ai_stand();};
|
|
void() elf_stand8 = [ $stand8, elf_stand1 ] {ai_stand();};
|
|
|
|
//======================================================================
|
|
void() elf_walk1 = [ $walk1, elf_walk2 ] {monster_idle_sound();ai_walk(10);};
|
|
void() elf_walk2 = [ $walk2, elf_walk3 ] {ai_walk(6);};
|
|
void() elf_walk3 = [ $walk3, elf_walk4 ] {monster_footstep(FALSE);ai_walk(4);};
|
|
void() elf_walk4 = [ $walk4, elf_walk5 ] {ai_walk(0);};
|
|
void() elf_walk5 = [ $walk5, elf_walk6 ] {ai_walk(2);};
|
|
void() elf_walk6 = [ $walk6, elf_walk7 ] {ai_walk(3);};
|
|
|
|
void() elf_walk7 = [ $walk7, elf_walk8 ] {ai_walk(10);};
|
|
void() elf_walk8 = [ $walk8, elf_walk9 ] {ai_walk(6);};
|
|
void() elf_walk9 = [ $walk9, elf_walk10 ] {monster_footstep(FALSE);ai_walk(4);};
|
|
void() elf_walk10 = [ $walk10, elf_walk11 ] {ai_walk(0);};
|
|
void() elf_walk11 = [ $walk11, elf_walk12 ] {ai_walk(2);};
|
|
void() elf_walk12 = [ $walk12, elf_walk1 ] {ai_walk(3);};
|
|
|
|
//======================================================================
|
|
void() elf_run1 = [ $skip1, elf_run2 ] {monster_idle_sound();ai_run(1);};
|
|
void() elf_run2 = [ $skip2, elf_run3 ] {ai_run(6);};
|
|
void() elf_run3 = [ $skip3, elf_run4 ] {ai_run(20);};
|
|
void() elf_run4 = [ $skip4, elf_run5 ] {monster_footstep(FALSE);ai_run(12);};
|
|
void() elf_run5 = [ $skip5, elf_run6 ] {ai_run(8);};
|
|
|
|
void() elf_run6 = [ $skip6, elf_run7 ] {ai_run(1);};
|
|
void() elf_run7 = [ $skip7, elf_run8 ] {ai_run(6);};
|
|
void() elf_run8 = [ $skip8, elf_run9 ] {ai_run(20);};
|
|
void() elf_run9 = [ $skip9, elf_run10 ] {monster_footstep(FALSE);ai_run(12);};
|
|
void() elf_run10 = [ $skip10, elf_run1 ] {ai_run(8);};
|
|
|
|
//======================================================================
|
|
void() elf_slide1 = [ $surprise1, elf_slide2 ] {ai_run_slide(2);monster_idle_sound();};
|
|
void() elf_slide2 = [ $surprise2, elf_slide3 ] {ai_run_slide(4);};
|
|
void() elf_slide3 = [ $surprise3, elf_slide4 ] {ai_run_slide(6);};
|
|
void() elf_slide4 = [ $surprise4, elf_slide5 ] {ai_run_slide(6);};
|
|
void() elf_slide5 = [ $surprise5, elf_slide6 ] {ai_run_slide(4);};
|
|
void() elf_slide6 = [ $surprise6, elf_slide7 ] {ai_run_slide(3);};
|
|
void() elf_slide7 = [ $surprise7, elf_run1 ] {ai_run(2);};
|
|
|
|
//======================================================================
|
|
// ELF 2 - SPRAY MAGIC (Range)
|
|
//======================================================================
|
|
void(float sideang) elf_shot =
|
|
{
|
|
local vector org, ang, dir, avel;
|
|
|
|
if (!self.enemy) return;
|
|
if (self.health < 1) return;
|
|
|
|
// Flash effect to show where projectile is coming from
|
|
self.effects = self.effects | EF_MUZZLEFLASH;
|
|
if (sideang < 0) sound (self, CHAN_WEAPON, "xmas/elf/attack1.wav", 1, ATTN_NORM);
|
|
|
|
makevectors (self.angles);
|
|
org = self.origin + attack_vector(self.attack_offset);
|
|
|
|
// Create elevation angle and use makevectors to create projectile direction
|
|
ang = vectoangles(self.enemy.origin - org);
|
|
ang_x = -self.attack_elev; // Negative = upwards angle
|
|
makevectors (ang);
|
|
// fire magic in arc pattern (sideang)
|
|
dir = (v_forward + v_right * sideang) * SPEED_ELF;
|
|
|
|
avel = vecrand(100,200,FALSE);
|
|
Launch_Grenade(org, dir, avel, CT_PROJ_ELF);
|
|
};
|
|
|
|
//----------------------------------------------------------------------
|
|
void() elf_magic1 = [ $magic12, elf_magic2 ] {
|
|
sound(self, CHAN_WEAPON, "xmas/elf/magic.wav", 1, ATTN_NORM);};
|
|
void() elf_magic2 = [ $magic11, elf_magic3 ] {ai_face();};
|
|
void() elf_magic3 = [ $magic10, elf_magic4 ] {ai_face();};
|
|
void() elf_magic4 = [ $magic9, elf_magic5 ] {ai_face();};
|
|
void() elf_magic5 = [ $magic8, elf_magic6 ] {ai_face();
|
|
self.attack_elev = SUB_Elevation(ELEV_DEFAULT, self.origin, self.enemy.origin, SPEED_ELF); };
|
|
void() elf_magic6 = [ $magic7, elf_magic7 ] {ai_face();
|
|
self.attack_elev = SUB_Elevation(self.attack_elev, self.origin, self.enemy.origin, SPEED_ELF); };
|
|
void() elf_magic7 = [ $magic6, elf_magic8 ] {ai_face();
|
|
self.attack_elev = SUB_Elevation(self.attack_elev, self.origin, self.enemy.origin, SPEED_ELF); };
|
|
void() elf_magic8 = [ $magic5, elf_magic9 ] {elf_shot(-0.1);};
|
|
void() elf_magic9 = [ $magic4, elf_magic10 ] {elf_shot(0);};
|
|
void() elf_magic10 = [ $magic3, elf_magic11 ] {elf_shot(0.1);};
|
|
void() elf_magic11 = [ $magic2, elf_magic12 ] {};
|
|
void() elf_magic12 = [ $magic1, elf_run1 ] {};
|
|
|
|
//======================================================================
|
|
// ELF 1 - SWING CANE - Both elf types can swing cane if within range
|
|
//======================================================================
|
|
void() elf_melee =
|
|
{
|
|
local float ldmg;
|
|
|
|
if (!self.enemy) return;
|
|
if (self.health < 1) return;
|
|
|
|
ai_charge(10);
|
|
ai_damagebreakable(10);
|
|
if (!ai_checkmelee(MONAI_MELEEELF)) return;
|
|
|
|
// Can the target bleed?
|
|
if (!self.enemy.takedamage) return;
|
|
|
|
if (random() < 0.5) sound(self, CHAN_VOICE, "xmas/elf/cane_hit1.wav", 1, ATTN_NORM);
|
|
else sound(self, CHAN_VOICE, "xmas/elf/cane_hit2.wav", 1, ATTN_NORM);
|
|
|
|
// Cane Impact (damage 1-9) is very weak
|
|
ldmg = (random() + random() + random()) * 3;
|
|
if (ldmg < 1) ldmg = 1;
|
|
T_Damage (self.enemy, self, self, ldmg, DAMARMOR);
|
|
|
|
// Spawn blood at cane of elf
|
|
spawn_touchblood (self, self.enemy, ldmg*3);
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
void() elf_cane1 = [ $attack1, elf_cane2 ] {ai_charge(5);
|
|
if (random() < 0.5) sound(self, CHAN_WEAPON, "xmas/elf/cane_swipe1.wav", 1, ATTN_NORM);
|
|
else sound(self, CHAN_WEAPON, "xmas/elf/cane_swipe2.wav", 1, ATTN_NORM);
|
|
};
|
|
void() elf_cane2 = [ $attack2, elf_cane3 ] {ai_charge(5);};
|
|
void() elf_cane3 = [ $attack3, elf_cane4 ] {elf_melee();};
|
|
void() elf_cane4 = [ $attack4, elf_cane5 ] {};
|
|
void() elf_cane5 = [ $attack5, elf_run1 ] {
|
|
if (ai_checkmelee(MONAI_MELEEELF) && self.enemy.health > 0) {
|
|
if (self.health > 0) self.think = elf_cane1;
|
|
}
|
|
};
|
|
|
|
//======================================================================
|
|
// ELF 1 - JUMP FUNCTION (range)
|
|
//======================================================================
|
|
void() Elf_JumpTouch =
|
|
{
|
|
local float ldmg;
|
|
|
|
if (self.health <= 0) return;
|
|
ai_jumpbreakable(20); // Damage any breakables
|
|
self.touch = SUB_Null; // No more touching
|
|
self.count = self.count + 1; // Total amount of touch jumps
|
|
self.think = self.th_jumpexit; // Exit frame
|
|
self.jumptouch = other; // Keep track of touch target
|
|
|
|
// Do not damage other elves with jump attacks
|
|
// Prevents packs from killing themselves
|
|
if (self.classtype != other.classtype && other.takedamage) {
|
|
if ( vlen(self.velocity) > 300 ) {
|
|
ldmg = 5 + 5*random();
|
|
T_Damage (other, self, self, ldmg, DAMARMOR);
|
|
// Spawn some touch blood (no explicit direction)
|
|
spawn_touchblood (self.enemy, self.enemy, ldmg*3);
|
|
}
|
|
}
|
|
|
|
// Is the elf floating in the air?
|
|
if (!checkbottom(self)) {
|
|
// Is the elf standing on something?
|
|
if (self.flags & FL_ONGROUND) {
|
|
// Do an extra jump if got the count
|
|
if (self.count < 2) self.think = self.th_jump;
|
|
}
|
|
}
|
|
|
|
// Next timer
|
|
self.nextthink = time + 0.1;
|
|
};
|
|
|
|
//----------------------------------------------------------------------------
|
|
void() elf_leap1 =[ $jump1, elf_leap2 ] {ai_face();
|
|
self.jump_flag = time + MONAI_JUMPTIMEOUT; // Stop jumping so much
|
|
if (random() < 0.5) sound(self, CHAN_WEAPON, "xmas/elf/jump1.wav", 1, ATTN_NORM);
|
|
else sound(self, CHAN_WEAPON, "xmas/elf/jump2.wav", 1, ATTN_NORM);
|
|
};
|
|
void() elf_leap2 =[ $jump2, elf_leap3 ] {ai_face();};
|
|
void() elf_leap3 =[ $jump3, elf_leap4 ] {
|
|
ai_face();
|
|
self.jump_flag = time + MONAI_JUMPTIMEOUT; // Stop jumping so much
|
|
self.touch = Elf_JumpTouch;
|
|
makevectors (self.angles);
|
|
self.velocity = v_forward * MONAI_JUMPELFDIST + '0 0 200';
|
|
self.origin_z = self.origin_z + 4;
|
|
self.flags = self.flags - (self.flags & FL_ONGROUND);
|
|
self.oldorigin = self.origin;
|
|
};
|
|
void() elf_leap4 =[ $jump4, elf_leap5 ] {};
|
|
void() elf_leap5 =[ $jump5, elf_leap6 ] {};
|
|
void() elf_leap6 =[ $jump6, elf_leap7 ] {
|
|
// Double check monster is still falling?
|
|
if (CheckZeroVector(self.velocity) || self.oldorigin == self.origin) {
|
|
self.ideal_yaw = random() * 360; //random jump angle
|
|
self.think = elf_leap3;
|
|
}
|
|
self.oldorigin = self.origin;
|
|
};
|
|
|
|
//----------------------------------------------------------------------
|
|
void() elf_leap7 =[ $jump7, elf_leap8] {monster_footstep(FALSE);};
|
|
void() elf_leap8 =[ $jump8, elf_run1] {ai_resetangles();};
|
|
|
|
//======================================================================
|
|
// Elven Pain!
|
|
//======================================================================
|
|
void() elf_pain1 = [ $pain1, elf_pain2 ] {};
|
|
void() elf_pain2 = [ $pain2, elf_pain3 ] {};
|
|
void() elf_pain3 = [ $pain3, elf_pain4 ] {};
|
|
void() elf_pain4 = [ $pain4, elf_pain5 ] {};
|
|
void() elf_pain5 = [ $pain5, elf_run1 ] {};
|
|
|
|
//----------------------------------------------------------------------
|
|
void(entity inflictor, entity attacker, float damage) elf_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) elf_pain1 ();
|
|
else if (self.pain_check == 2) {
|
|
// reset axe hit and setup short pain recovery
|
|
self.axhitme = 0;
|
|
self.pain_finished = time + 1;
|
|
elf_pain1 ();
|
|
}
|
|
}
|
|
};
|
|
|
|
//======================================================================
|
|
// Typical forward/backward death animation
|
|
//======================================================================
|
|
void() elf_die1 =[ $death1, elf_die2] {};
|
|
void() elf_die2 =[ $death2, elf_die3] {monster_check_gib();};
|
|
void() elf_die3 =[ $death3, elf_die4] {monster_check_gib();
|
|
self.solid = SOLID_NOT;};
|
|
void() elf_die4 =[ $death4, elf_die5] {};
|
|
void() elf_die5 =[ $death5, elf_die6] {};
|
|
void() elf_die6 =[ $death6, elf_die7] {
|
|
// Drop metal cane sound
|
|
sound (self, CHAN_WEAPON, GIB_SOUND_METALA, 1, ATTN_NORM);
|
|
};
|
|
void() elf_die7 =[ $death7, elf_die8] {};
|
|
void() elf_die8 =[ $death8, elf_die9] {monster_death_postcheck();};
|
|
void() elf_die9 =[ $death9, elf_die9] {monster_deadbody_check();};
|
|
|
|
//----------------------------------------------------------------------
|
|
void() elf_dieb1 =[ $bdeath1, elf_dieb2] {};
|
|
void() elf_dieb2 =[ $bdeath2, elf_dieb3] {monster_check_gib();};
|
|
void() elf_dieb3 =[ $bdeath3, elf_dieb4] {monster_check_gib();
|
|
self.solid = SOLID_NOT;};
|
|
void() elf_dieb4 =[ $bdeath4, elf_dieb5] {};
|
|
void() elf_dieb5 =[ $bdeath5, elf_dieb6] {};
|
|
void() elf_dieb6 =[ $bdeath6, elf_dieb7] {};
|
|
void() elf_dieb7 =[ $bdeath7, elf_dieb8] {};
|
|
void() elf_dieb8 =[ $bdeath8, elf_dieb9] {ai_back(4);monster_death_postcheck();};
|
|
void() elf_dieb9 =[ $bdeath9, elf_dieb9] {monster_deadbody_check();};
|
|
|
|
//----------------------------------------------------------------------
|
|
void() elf_die =
|
|
{
|
|
// Sync cane to elf skin
|
|
self.gib1skin = self.exactskin;
|
|
|
|
// Pre-check routine to tidy up extra entities
|
|
monster_death_precheck();
|
|
|
|
// regular death
|
|
if (!self.gibbed) {
|
|
// Pick a random death sound
|
|
if (random() > 0.5)
|
|
sound (self, CHAN_VOICE, self.death_sound, 1, ATTN_NORM);
|
|
else
|
|
sound (self, CHAN_VOICE, self.death_sound2, 1, ATTN_NORM);
|
|
|
|
// Pick a random fall direction
|
|
if (random() > 0.5) elf_die1 ();
|
|
else elf_dieb1 ();
|
|
}
|
|
};
|
|
|
|
/*======================================================================
|
|
QUAKED monster_xmas_elf (1 0 0) (-16 -16 -24) (16 16 16) Ambush
|
|
======================================================================*/
|
|
void() monster_xmas_elf =
|
|
{
|
|
if (deathmatch) { remove(self); return; }
|
|
|
|
self.mdl = "progs/xmas/mon_elf.mdl"; // Crazy Grinning Fool
|
|
self.headmdl = "progs/xmas/h_elf.mdl"; // Shrunken Head
|
|
self.gib1mdl = "progs/xmas/gib_elfcane.mdl";// Candy Cane
|
|
self.gib1sound = GIB_IMPACT_METALA;
|
|
|
|
precache_model (self.mdl);
|
|
precache_model (self.headmdl); // Grinning Pointy Hat
|
|
precache_model (self.gib1mdl); // Sugar Cane
|
|
precache_model (MODEL_PROJ_ELF); // Magic ice
|
|
|
|
// Idle calm/angry
|
|
self.idle_sound = "xmas/elf/idle.wav"; // Lots of giggling
|
|
precache_sound (self.idle_sound);
|
|
|
|
// Many different sight sounds (2 is very annoying)
|
|
self.sight_sound = "xmas/elf/sight1.wav"; // Snarling sound
|
|
self.sight_sound2 = "xmas/elf/sight2.wav"; // DIE HUMAN!?!
|
|
self.sight_sound3 = "xmas/elf/sight3.wav"; // Screams
|
|
self.sight_sound4 = "xmas/elf/sight4.wav"; // Screams
|
|
precache_sound (self.sight_sound);
|
|
precache_sound (self.sight_sound2);
|
|
precache_sound (self.sight_sound3);
|
|
precache_sound (self.sight_sound4);
|
|
self.sight_count = 4;
|
|
|
|
// Elf 1 - Melee/Jump attacks - cane impacts
|
|
precache_sound ("xmas/elf/cane_swipe1.wav");
|
|
precache_sound ("xmas/elf/cane_swipe2.wav");
|
|
precache_sound ("xmas/elf/cane_hit1.wav");
|
|
precache_sound ("xmas/elf/cane_hit2.wav");
|
|
precache_sound ("xmas/elf/jump1.wav");
|
|
precache_sound ("xmas/elf/jump2.wav");
|
|
|
|
// Elf 2 - Magic attacks
|
|
precache_sound ("xmas/elf/magic.wav");
|
|
precache_sound ("xmas/elf/attack1.wav");
|
|
precache_sound ("xmas/elf/miss.wav");
|
|
|
|
// precache sight, pain and death (changes on type)
|
|
self.pain_sound = "xmas/elf/pain.wav";
|
|
self.death_sound = "xmas/elf/death1.wav";
|
|
self.death_sound2 = "xmas/elf/death2.wav";
|
|
precache_sound (self.pain_sound);
|
|
precache_sound (self.death_sound);
|
|
precache_sound (self.death_sound2);
|
|
|
|
if (self.spawnflags & MON_ELF_MAGIC) {
|
|
if (self.health < 1) self.health = 75;
|
|
self.gibhealth = -25;
|
|
self.th_missile = elf_magic1;
|
|
self.exactskin = 2;
|
|
}
|
|
else {
|
|
if (self.health < 1) self.health = 30;
|
|
self.gibhealth = -20;
|
|
self.th_jump = elf_leap1;
|
|
self.th_jumpexit = elf_leap7;
|
|
// pick a random one instead
|
|
if (self.exactskin < 0 || self.exactskin > 1) self.exactskin = 0;
|
|
if (self.exactskin == 0 && random() < 0.5) self.exactskin = 1;
|
|
}
|
|
|
|
self.solid = SOLID_NOT; // No interaction with world
|
|
self.movetype = MOVETYPE_NONE; // Static item, no movement
|
|
if (self.bboxtype < 1) self.bboxtype = BBOX_TINY;
|
|
self.gibbed = FALSE; // Still in one peice
|
|
self.blockudeath = TRUE; // No humanoid death sound
|
|
self.pain_flinch = 10; // Light pain threshold
|
|
self.steptype = FS_TYPELIGHT; // Very light feet
|
|
self.meleeoffset = '20 0 20'; // Cane attack offset
|
|
self.attack_offset = '10 0 4'; // Magic attack offset
|
|
self.poisonous = FALSE; // Not Supported
|
|
self.deathstring = " was torn to pieces by a Elf\n";
|
|
|
|
// Always reset Ammo Resistance to be consistent
|
|
self.resist_shells = self.resist_nails = 0;
|
|
self.resist_rockets = self.resist_cells = 0;
|
|
|
|
self.th_checkattack = ElfCheckAttack;
|
|
self.th_stand = elf_stand1;
|
|
self.th_walk = elf_walk1;
|
|
self.th_run = elf_run1;
|
|
self.th_melee = elf_cane1;
|
|
self.th_slide = elf_slide1;
|
|
self.th_pain = elf_pain;
|
|
self.th_die = elf_die;
|
|
|
|
self.classtype = CT_MONELF;
|
|
self.classgroup = CG_XMAS;
|
|
self.classmove = MON_MOVEWALK;
|
|
|
|
monster_start();
|
|
}; |