297 lines
11 KiB
Plaintext
297 lines
11 KiB
Plaintext
/*==============================================================================
|
|
XMAS Snowman - From Twisted Christmas Mod by Twisted Matrix
|
|
==============================================================================*/
|
|
|
|
// (000) Standing Still
|
|
$frame stand1
|
|
|
|
// (001 - 005) Fast Claw attack
|
|
$frame claw1 claw2 claw3 claw4 claw5
|
|
|
|
// (006 - 008) Fast Nail Attack
|
|
$frame attack1 attack2 attack3
|
|
|
|
// (009 - 010) Misc modelling stuff
|
|
$frame base1 base2
|
|
|
|
//======================================================================
|
|
void() snowm_stand1 = [ $stand1, snowm_stand2 ] {monster_idle_sound();ai_stand();}
|
|
void() snowm_stand2 = [ $stand1, snowm_stand3 ] {ai_stand();};
|
|
void() snowm_stand3 = [ $stand1, snowm_stand4 ] {ai_stand();};
|
|
void() snowm_stand4 = [ $stand1, snowm_stand5 ] {ai_stand();};
|
|
void() snowm_stand5 = [ $stand1, snowm_stand6 ] {ai_stand();};
|
|
void() snowm_stand6 = [ $stand1, snowm_stand7 ] {ai_stand();};
|
|
void() snowm_stand7 = [ $stand1, snowm_stand8 ] {ai_stand();};
|
|
void() snowm_stand8 = [ $stand1, snowm_stand1 ] {ai_stand();};
|
|
|
|
//======================================================================
|
|
void() snowm_walk1 = [ $stand1, snowm_walk2 ] {monster_idle_sound();ai_walk(0);}
|
|
void() snowm_walk2 = [ $stand1, snowm_walk3 ] {ai_walk(0);};
|
|
void() snowm_walk3 = [ $stand1, snowm_walk4 ] {ai_walk(0);};
|
|
void() snowm_walk4 = [ $stand1, snowm_walk5 ] {ai_walk(0);};
|
|
void() snowm_walk5 = [ $stand1, snowm_walk6 ] {ai_walk(0);};
|
|
void() snowm_walk6 = [ $stand1, snowm_walk7 ] {ai_walk(0);};
|
|
void() snowm_walk7 = [ $stand1, snowm_walk8 ] {ai_walk(0);};
|
|
void() snowm_walk8 = [ $stand1, snowm_walk1 ] {ai_walk(0);};
|
|
|
|
//======================================================================
|
|
void() snowm_run1 = [ $stand1, snowm_run2 ] {monster_idle_sound();ai_run(0);}
|
|
void() snowm_run2 = [ $stand1, snowm_run3 ] {ai_run(0);};
|
|
void() snowm_run3 = [ $stand1, snowm_run4 ] {ai_run(0);};
|
|
void() snowm_run4 = [ $stand1, snowm_run5 ] {ai_run(0);};
|
|
void() snowm_run5 = [ $stand1, snowm_run6 ] {ai_run(0);};
|
|
void() snowm_run6 = [ $stand1, snowm_run7 ] {ai_run(0);};
|
|
void() snowm_run7 = [ $stand1, snowm_run8 ] {ai_run(0);};
|
|
void() snowm_run8 = [ $stand1, snowm_run1 ] {ai_run(0);};
|
|
|
|
//======================================================================
|
|
// MELEE : Crows Claw
|
|
//======================================================================
|
|
void() SnowmMelee =
|
|
{
|
|
local float ldmg;
|
|
|
|
if (!self.enemy) return;
|
|
if (self.health < 1) return;
|
|
|
|
ai_damagebreakable(10); // Damage any breakables
|
|
if (!ai_checkmelee(MONAI_MELEESNOWMAN)) return; // Too far away
|
|
|
|
// Can the target bleed?
|
|
if (!self.enemy.takedamage) return;
|
|
|
|
sound(self, CHAN_WEAPON, "xmas/snowman/claw.wav", TRUE, TRUE);
|
|
|
|
// Claw attack is good (1-15)
|
|
ldmg = (random() + random() + random()) * 5;
|
|
if (ldmg < 1) ldmg = 1;
|
|
T_Damage (self.enemy, self, self, ldmg, DAMARMOR);
|
|
|
|
// Spawn blood at claw
|
|
spawn_touchblood (self, self.enemy, ldmg*3);
|
|
};
|
|
|
|
//----------------------------------------------------------------------
|
|
void() snowm_claw1 = [ $claw1, snowm_claw2 ] {ai_face();};
|
|
void() snowm_claw2 = [ $claw2, snowm_claw3 ] {ai_face();};
|
|
void() snowm_claw3 = [ $claw3, snowm_claw4 ] {ai_face();SnowmMelee();};
|
|
void() snowm_claw4 = [ $claw4, snowm_claw5 ] {};
|
|
void() snowm_claw5 = [ $claw5, snowm_run1 ] {
|
|
// Check if snowman is within range to attack again
|
|
if (ai_checkmelee(MONAI_MELEESNOWMAN) && self.enemy.health > 0) {
|
|
if (self.health > 0) self.think = snowm_claw1;
|
|
}
|
|
};
|
|
|
|
//======================================================================
|
|
// RANGE : Burst of Nails
|
|
//======================================================================
|
|
void() SnowmFireNails =
|
|
{
|
|
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_NAILSNOWMPROJ + (skill * SPEED_NAILSNOWMSKILL);
|
|
sound(self, CHAN_WEAPON, "xmas/snowman/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() snowm_nail1 = [ $attack1, snowm_nail2 ] {ai_face();};
|
|
void() snowm_nail2 = [ $attack2, snowm_nail3 ] {ai_face();};
|
|
void() snowm_nail3 = [ $attack3, snowm_nail4 ] {ai_face();SnowmFireNails();};
|
|
void() snowm_nail4 = [ $attack2, snowm_nail5 ] {};
|
|
void() snowm_nail5 = [ $attack1, snowm_run1 ] {ai_face();};
|
|
|
|
//======================================================================
|
|
// PAIN : quick reflection
|
|
//======================================================================
|
|
void() snowm_pain1 = [ $claw4, snowm_pain2 ] {};
|
|
void() snowm_pain2 = [ $claw3, snowm_pain3 ] {};
|
|
void() snowm_pain3 = [ $claw2, snowm_pain4 ] {};
|
|
void() snowm_pain4 = [ $claw1, snowm_run1 ] {};
|
|
|
|
//----------------------------------------------------------------------
|
|
void(entity inflictor, entity attacker, float damage) snowm_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) {
|
|
if (random() < 0.5) sound (self, CHAN_VOICE, self.pain_sound, 1, ATTN_NORM);
|
|
else sound (self, CHAN_VOICE, self.pain_sound2, 1, ATTN_NORM);
|
|
if (self.pain_check == 1) snowm_pain1 ();
|
|
else if (self.pain_check == 2) {
|
|
// reset axe hit and setup short pain recovery
|
|
self.pain_finished = time + 0.6;
|
|
self.axhitme = 0;
|
|
snowm_pain1 ();
|
|
}
|
|
}
|
|
};
|
|
|
|
//======================================================================
|
|
// Exploding snowball!
|
|
//======================================================================
|
|
void() snowm_explode =
|
|
{
|
|
// no more raindeer!
|
|
entity_hide (self);
|
|
// Make sure gibs go flying up
|
|
self.max_health = MON_GIBFOUNTAIN;
|
|
self.health = -100;
|
|
|
|
// ID style explosion
|
|
WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
|
|
WriteByte (MSG_BROADCAST, TE_EXPLOSION);
|
|
WriteCoord (MSG_BROADCAST, self.origin_x);
|
|
WriteCoord (MSG_BROADCAST, self.origin_y);
|
|
WriteCoord (MSG_BROADCAST, self.origin_z);
|
|
if (self.death_dmg > 0)
|
|
T_RadiusDamage (self, self, self.death_dmg, world, DAMAGEALL);
|
|
|
|
// Sprite + Dust
|
|
SpawnExplosion(EXPLODE_BIG, self.origin, self.death_sound);
|
|
SpawnProjectileSmoke(self.origin, 200, 250, 100);
|
|
SpawnProjectileSmoke(self.origin, 200, 250, 100);
|
|
|
|
// No blood or guts!
|
|
ThrowGib(25, 1);
|
|
ThrowGib(11, 1);
|
|
ThrowGib(12, 1);
|
|
ThrowGib(13, 8 + rint(random()*8));
|
|
|
|
/*-------------------------------------------------------------------
|
|
// The snowball model has a melting animation (6 frames)
|
|
// Unfortunately it does look really old and dated,
|
|
// its better to let model just fade away.
|
|
//
|
|
// The final gib is a snowball which has a melting animation
|
|
// Setup animation start/finish parameters before throwing
|
|
self.gibAnimstart = 1;
|
|
self.gibAnimfinal = 5;
|
|
self.gibAnimTimer = 2; // timer + (random() * (timer*2))
|
|
ThrowGib(13, 8 + rint(random()*8)); */
|
|
};
|
|
|
|
//----------------------------------------------------------------------
|
|
void() snowm_die =
|
|
{
|
|
// Pre-check routine to tidy up extra entities
|
|
monster_death_precheck();
|
|
|
|
// There is no death animation
|
|
if (random() < 0.5)
|
|
sound (self, CHAN_BODY, self.death_sound, 1, ATTN_NORM);
|
|
else sound (self, CHAN_BODY, self.death_sound2, 1, ATTN_NORM);
|
|
snowm_explode();
|
|
};
|
|
|
|
/*======================================================================
|
|
QUAKED monster_snowman (1 0 0) (-16 -16 -24) (16 16 32) Ambush
|
|
======================================================================*/
|
|
void() monster_xmas_snowman =
|
|
{
|
|
if (deathmatch) { remove(self); return; }
|
|
|
|
self.mdl = "progs/xmas/mon_snowman.mdl"; // Top Hat Snow
|
|
self.headmdl = "progs/xmas/h_snowman.mdl"; // Top Hat
|
|
self.gib1mdl = "progs/xmas/gib_snowclaw.mdl"; // Claw
|
|
self.gib2mdl = "progs/xmas/gib_snowgun.mdl"; // Nail Gun
|
|
self.gib3mdl = "progs/xmas/gib_snowball.mdl"; // Snowballs
|
|
self.gib1sound = GIB_IMPACT_WOOD;
|
|
self.gib2sound = GIB_IMPACT_METALA;
|
|
|
|
precache_model (self.mdl);
|
|
precache_model (self.headmdl); // Top Hat
|
|
precache_model (self.gib1mdl); // Claw
|
|
precache_model (self.gib2mdl); // Gun
|
|
precache_model (self.gib3mdl); // Snow-BALLS!
|
|
precache_model (MODEL_PROJ_NGRED); // Red Nails (easier to see)
|
|
|
|
// Idle calm/angry
|
|
self.idle_sound = "xmas/snowman/idle.wav"; // Rustling sound
|
|
precache_sound (self.idle_sound);
|
|
|
|
// Many different sight sounds
|
|
self.sight_sound = "xmas/snowman/sight1.wav"; // Deep voice
|
|
self.sight_sound2 = "xmas/snowman/sight2.wav"; // Growling
|
|
precache_sound (self.sight_sound);
|
|
precache_sound (self.sight_sound2);
|
|
self.sight_count = 2;
|
|
|
|
// Melee/Range Attacks
|
|
// Original version used ice, switched to red nails
|
|
// Ice nails are really difficult to see
|
|
precache_sound ("xmas/snowman/claw.wav");
|
|
precache_sound ("xmas/snowman/nail_fire.wav");
|
|
|
|
// precache sight, pain and death (changes on type)
|
|
self.pain_sound = "xmas/snowman/pain1.wav";
|
|
self.pain_sound2 = "xmas/snowman/pain2.wav";
|
|
self.death_sound = "xmas/snowman/death1.wav";
|
|
self.death_sound2 = "xmas/snowman/death2.wav";
|
|
precache_sound (self.pain_sound);
|
|
precache_sound (self.pain_sound2);
|
|
precache_sound (self.death_sound);
|
|
precache_sound (self.death_sound2);
|
|
|
|
self.solid = SOLID_NOT; // No interaction with world
|
|
self.movetype = MOVETYPE_NONE; // Static item, no movement
|
|
if (self.bboxtype < 1) self.bboxtype = BBOX_SHORT;
|
|
if (self.health < 1) self.health = 125;
|
|
if (self.death_dmg < 1) self.death_dmg = DAMAGE_SNOWMAN;
|
|
self.gibhealth = MON_NEVERGIB; // Cannot be gibbed by weapons
|
|
self.blockudeath = TRUE; // No humanoid death sound
|
|
self.gibbed = FALSE; // Still in one peice
|
|
self.pain_flinch = 30; // Light pain threshold
|
|
self.pain_longanim = FALSE; // No long pain animation
|
|
self.steptype = FS_TYPESLOW; // Small sounding feet
|
|
self.poisonous = FALSE; // Not Supported
|
|
self.meleeoffset = '24 0 20'; // Claw attack offset
|
|
self.attack_offset = '24 0 20'; // Run + Gun vector
|
|
self.bleedcolour = MON_BCOLOR_SILVER;// Red is odd for snow
|
|
self.deathstring = " was smashed on a Snowman\n";
|
|
|
|
// Default amount of nails to burst fire (5x9=45dmg)
|
|
if (self.attack_count < 1) self.attack_count = 5;
|
|
|
|
// Always reset Ammo Resistance to be consistent
|
|
self.resist_shells = self.resist_nails = 0;
|
|
self.resist_rockets = self.resist_cells = 0;
|
|
|
|
self.th_checkattack = SnowmanCheckAttack;
|
|
self.th_stand = snowm_stand1;
|
|
self.th_walk = snowm_walk1;
|
|
self.th_run = snowm_run1;
|
|
self.th_melee = snowm_claw1;
|
|
self.th_missile = snowm_nail1;
|
|
self.th_pain = snowm_pain;
|
|
self.th_die = snowm_die;
|
|
|
|
self.classtype = CT_MONSNOWMAN;
|
|
self.classgroup = CG_XMAS;
|
|
self.classmove = MON_MOVEWALK;
|
|
|
|
monster_start();
|
|
}; |