Files
quakemapping/mod_xj19/my_progs/mon_xmas_snowman.qc
2020-01-01 23:35:17 +01:00

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();
};