506 lines
17 KiB
C++
506 lines
17 KiB
C++
/*
|
|
==============================================================================
|
|
|
|
Dweller
|
|
coded by Michael Rogers a.k.a Xsniper
|
|
http://xsniper.virtualave.net/
|
|
some code done by iD software
|
|
|
|
==============================================================================
|
|
*/
|
|
|
|
$cd /models/enemies
|
|
$origin 0 0 32
|
|
$base base
|
|
$skin base
|
|
|
|
$frame idle101 idle102 idle103 idle104 idle105 idle106 idle107 idle108 idle109 idle110
|
|
$frame idle111 idle112 idle113 idle114 idle115 idle116
|
|
|
|
$frame idle201 idle202 idle203 idle204 idle205 idle206 idle207 idle208 idle209 idle210
|
|
$frame idle211 idle212 idle213 idle214 idle215 idle216
|
|
|
|
$frame run01 run02 run03 run04 run05 run06 run07 run08
|
|
|
|
$frame walk01 walk02 walk03 walk04 walk05 walk06 walk07 walk08 walk09 walk10
|
|
$frame walk11 walk12 walk13
|
|
|
|
$frame attack101 attack102 attack103 attack104 attack105 attack106 attack107 attack108 attack109 attack110
|
|
$frame attack111
|
|
|
|
$frame attack201 attack202 attack203 attack204 attack205 attack206 attack207 attack208
|
|
|
|
$frame pain101 pain102 pain103 pain104 pain105
|
|
|
|
$frame pain201 pain202 pain203 pain204 pain205 pain206 pain207
|
|
|
|
$frame pain301 pain302 pain303 pain304 pain305 pain306 pain307 pain308 pain309 pain310
|
|
$frame pain311
|
|
|
|
$frame death101 death102 death103 death104 death105 death106 death107 death108 death109
|
|
|
|
$frame death201 death202 death203 death204 death205 death206 death207 death208 death209 death210
|
|
$frame death211 death212 death213 death214 death215 death216 death217 death218 death219 death220
|
|
$frame death221 death222 death223 death224 death225 death226
|
|
|
|
$frame death301 death302 death303 death304 death305 death306 death307 death308 death309 death310
|
|
$frame death311 death312 death313 death314 death315 death316 death317 death318 death319 death320
|
|
$frame death321
|
|
|
|
float SPAWN_CRUCIFIED = 1;
|
|
.float inpain;
|
|
void() dweller_charge1;
|
|
void() dweller_die;
|
|
void() dweller_idlesound;
|
|
|
|
//=============================================================================
|
|
|
|
void() DwellerCheckForCharge =
|
|
{
|
|
// check for mad charge
|
|
if (!enemy_vis)
|
|
return;
|
|
if (time < self.attack_finished)
|
|
return;
|
|
if ( fabs(self.origin_z - self.enemy.origin_z) > 20)
|
|
return; // too much height change
|
|
if ( vlen (self.origin - self.enemy.origin) < 80)
|
|
return; // use regular attack
|
|
|
|
// play rage sound and charge in
|
|
sound (self, CHAN_VOICE, "enemy/dweller/rage.wav", 1, ATTN_NORM);
|
|
SUB_AttackFinished (2);
|
|
dweller_charge1 ();
|
|
|
|
};
|
|
|
|
//=============================================================================
|
|
|
|
void() dweller_stand1 =[ $idle101, dweller_stand2 ] {ai_stand();};
|
|
void() dweller_stand2 =[ $idle102, dweller_stand3 ] {ai_stand();};
|
|
void() dweller_stand3 =[ $idle103, dweller_stand4 ] {ai_stand();};
|
|
void() dweller_stand4 =[ $idle104, dweller_stand5 ] {ai_stand();};
|
|
void() dweller_stand5 =[ $idle105, dweller_stand6 ] {ai_stand();};
|
|
void() dweller_stand6 =[ $idle106, dweller_stand7 ] {ai_stand();};
|
|
void() dweller_stand7 =[ $idle107, dweller_stand8 ] {ai_stand();};
|
|
void() dweller_stand8 =[ $idle108, dweller_stand9 ] {ai_stand();};
|
|
void() dweller_stand9 =[ $idle109, dweller_stand10 ] {ai_stand();};
|
|
void() dweller_stand10 =[ $idle110, dweller_stand11 ] {ai_stand();};
|
|
void() dweller_stand11 =[ $idle111, dweller_stand12 ] {ai_stand();};
|
|
void() dweller_stand12 =[ $idle112, dweller_stand13 ] {ai_stand();};
|
|
void() dweller_stand13 =[ $idle113, dweller_stand14 ] {ai_stand();};
|
|
void() dweller_stand14 =[ $idle114, dweller_stand15 ] {ai_stand();};
|
|
void() dweller_stand15 =[ $idle115, dweller_stand16 ] {ai_stand();};
|
|
void() dweller_stand16 =[ $idle116, dweller_stand1 ] {ai_stand();};
|
|
|
|
//=============================================================================
|
|
|
|
void() dweller_walk1 =[ $walk01, dweller_walk2 ] {ai_walk(3);};
|
|
void() dweller_walk2 =[ $walk02, dweller_walk3 ] {ai_walk(2);};
|
|
void() dweller_walk3 =[ $walk03, dweller_walk4 ] {ai_walk(3);};
|
|
void() dweller_walk4 =[ $walk04, dweller_walk5 ] {ai_walk(2);};
|
|
void() dweller_walk5 =[ $walk05, dweller_walk6 ] {ai_walk(2);};
|
|
void() dweller_walk6 =[ $walk06, dweller_walk7 ] {ai_walk(3);};
|
|
void() dweller_walk7 =[ $walk07, dweller_walk8 ] {ai_walk(3);};
|
|
void() dweller_walk8 =[ $walk08, dweller_walk9 ] {ai_walk(2);};
|
|
void() dweller_walk9 =[ $walk09, dweller_walk10 ] {ai_walk(2);};
|
|
void() dweller_walk10 =[ $walk10, dweller_walk11 ] {ai_walk(1);};
|
|
void() dweller_walk11 =[ $walk11, dweller_walk12 ] {ai_walk(2);};
|
|
void() dweller_walk12 =[ $walk12, dweller_walk13 ] {ai_walk(3);};
|
|
void() dweller_walk13 =[ $walk13, dweller_walk1 ] {ai_walk(2);dweller_idlesound();};
|
|
|
|
//=============================================================================
|
|
|
|
void() dweller_run1 =[ $run01, dweller_run2 ]
|
|
{
|
|
ai_run(15);
|
|
self.inpain = 0;
|
|
DwellerCheckForCharge();
|
|
};
|
|
void() dweller_run2 =[ $run02, dweller_run3 ] {ai_run(10);};
|
|
void() dweller_run3 =[ $run03, dweller_run4 ] {ai_run(12);};
|
|
void() dweller_run4 =[ $run04, dweller_run5 ] {ai_run(14);};
|
|
void() dweller_run5 =[ $run05, dweller_run6 ] {ai_run(15);};
|
|
void() dweller_run6 =[ $run06, dweller_run7 ] {ai_run(14);};
|
|
void() dweller_run7 =[ $run07, dweller_run8 ] {ai_run(11);};
|
|
void() dweller_run8 =[ $run08, dweller_run1 ] {ai_run(16);dweller_idlesound();};
|
|
|
|
//=============================================================================
|
|
|
|
void() dweller_charge1 =[ $run01, dweller_charge2 ] {ai_charge(20);};
|
|
void() dweller_charge2 =[ $run02, dweller_charge3 ] {ai_charge(18);};
|
|
void() dweller_charge3 =[ $run03, dweller_charge4 ] {ai_charge(15);};
|
|
void() dweller_charge4 =[ $run04, dweller_charge5 ] {ai_charge(22);};
|
|
void() dweller_charge5 =[ $run05, dweller_charge6 ] {ai_charge(13);};
|
|
void() dweller_charge6 =[ $run06, dweller_charge7 ] {ai_charge(20);};
|
|
void() dweller_charge7 =[ $run07, dweller_charge8 ] {ai_charge(19);};
|
|
void() dweller_charge8 =[ $run08, dweller_run1 ] {ai_charge(21);};
|
|
|
|
//=============================================================================
|
|
|
|
void() dweller_atta1 =[ $attack101, dweller_atta2 ] {ai_charge(20);};
|
|
void() dweller_atta2 =[ $attack102, dweller_atta3 ] {ai_charge(22);};
|
|
void() dweller_atta3 =[ $attack103, dweller_atta4 ] {ai_charge(26);};
|
|
void() dweller_atta4 =[ $attack104, dweller_atta5 ] {ai_charge(20);ai_melee();};
|
|
void() dweller_atta5 =[ $attack105, dweller_atta6 ] {ai_charge(21);ai_melee();};
|
|
void() dweller_atta6 =[ $attack106, dweller_atta7 ] {ai_charge(24);ai_melee();};
|
|
void() dweller_atta7 =[ $attack107, dweller_atta8 ] {ai_charge(23);ai_melee();};
|
|
void() dweller_atta8 =[ $attack108, dweller_atta9 ] {ai_charge(22);ai_melee();};
|
|
void() dweller_atta9 =[ $attack109, dweller_atta10 ] {ai_face();};
|
|
void() dweller_atta10 =[ $attack110, dweller_atta11 ] {ai_face();};
|
|
void() dweller_atta11 =[ $attack111, dweller_run1 ] {ai_face();};
|
|
|
|
//=============================================================================
|
|
|
|
void() dweller_attb1 =[ $attack201, dweller_attb2 ] {ai_charge(29);};
|
|
void() dweller_attb2 =[ $attack202, dweller_attb3 ] {ai_charge(22);};
|
|
void() dweller_attb3 =[ $attack203, dweller_attb4 ] {ai_charge(21);ai_melee();};
|
|
void() dweller_attb4 =[ $attack204, dweller_attb5 ] {ai_charge(26);ai_melee();};
|
|
void() dweller_attb5 =[ $attack205, dweller_attb6 ] {ai_charge(24);ai_melee();};
|
|
void() dweller_attb6 =[ $attack206, dweller_attb7 ] {ai_charge(25);ai_melee();};
|
|
void() dweller_attb7 =[ $attack207, dweller_attb8 ] {ai_face();};
|
|
void() dweller_attb8 =[ $attack208, dweller_run1 ] {ai_face();};
|
|
|
|
//=============================================================================
|
|
|
|
/*
|
|
=============================================================================
|
|
|
|
PAIN
|
|
|
|
=============================================================================
|
|
*/
|
|
|
|
void() dweller_paina1 =[ $pain101, dweller_paina2 ] {};
|
|
void() dweller_paina2 =[ $pain102, dweller_paina3 ] {ai_painforward(3);};
|
|
void() dweller_paina3 =[ $pain103, dweller_paina4 ] {ai_painforward(1);};
|
|
void() dweller_paina4 =[ $pain104, dweller_paina5 ] {ai_pain(1);};
|
|
void() dweller_paina5 =[ $pain105, dweller_run1 ] {ai_pain(3);};
|
|
|
|
//=============================================================================
|
|
|
|
void() dweller_painb1 =[ $pain201, dweller_painb2 ] {};
|
|
void() dweller_painb2 =[ $pain202, dweller_painb3 ] {ai_pain(2);};
|
|
void() dweller_painb3 =[ $pain203, dweller_painb4 ] {ai_pain(8);};
|
|
void() dweller_painb4 =[ $pain204, dweller_painb5 ] {ai_pain(6);};
|
|
void() dweller_painb5 =[ $pain205, dweller_painb6 ] {ai_pain(2);};
|
|
void() dweller_painb6 =[ $pain206, dweller_painb7 ] {ai_pain(2);};
|
|
void() dweller_painb7 =[ $pain207, dweller_run1 ] {};
|
|
|
|
//=============================================================================
|
|
|
|
void() dweller_painc1 =[ $pain301, dweller_painc2 ] {};
|
|
void() dweller_painc2 =[ $pain302, dweller_painc3 ] {};
|
|
void() dweller_painc3 =[ $pain303, dweller_painc4 ] {ai_pain(3);};
|
|
void() dweller_painc4 =[ $pain304, dweller_painc5 ] {ai_pain(1);};
|
|
void() dweller_painc5 =[ $pain305, dweller_painc6 ] {};
|
|
void() dweller_painc6 =[ $pain306, dweller_painc7 ] {};
|
|
void() dweller_painc7 =[ $pain307, dweller_painc8 ] {};
|
|
void() dweller_painc8 =[ $pain308, dweller_painc9 ] {};
|
|
void() dweller_painc9 =[ $pain309, dweller_painc10 ] {};
|
|
void() dweller_painc10 =[ $pain310, dweller_painc11 ] {};
|
|
void() dweller_painc11 =[ $pain311, dweller_run1 ] {};
|
|
|
|
//=============================================================================
|
|
|
|
void() dweller_paine1 =[ $death101, dweller_paine2 ] {self.health = 60;};
|
|
void() dweller_paine2 =[ $death102, dweller_paine3 ] {ai_pain(8);};
|
|
void() dweller_paine3 =[ $death103, dweller_paine4 ] {ai_pain(5);};
|
|
void() dweller_paine4 =[ $death104, dweller_paine5 ] {ai_pain(3);};
|
|
void() dweller_paine5 =[ $death105, dweller_paine6 ] {ai_pain(1);};
|
|
void() dweller_paine6 =[ $death106, dweller_paine7 ] {ai_pain(2);};
|
|
void() dweller_paine7 =[ $death107, dweller_paine8 ] {ai_pain(1);};
|
|
void() dweller_paine8 =[ $death108, dweller_paine9 ] {ai_pain(1);};
|
|
void() dweller_paine9 =[ $death109, dweller_paine10 ] {self.solid = SOLID_NOT;};
|
|
void() dweller_paine10 =[ $death109, dweller_paine11 ]
|
|
{
|
|
self.nextthink = self.nextthink + 5;
|
|
self.health = 60;
|
|
};
|
|
void() dweller_paine11 =[ $death109, dweller_paine12 ]
|
|
{
|
|
// see if ok to stand up
|
|
self.health = 60;
|
|
self.solid = SOLID_SLIDEBOX;
|
|
if (!walkmove (0, 0))
|
|
{
|
|
self.health = -60;
|
|
return;
|
|
}
|
|
else if (random() <= 0.5)
|
|
{
|
|
//random chance of dieing anyway
|
|
//self.think = dweller_die;
|
|
//self.solid = SOLID_NOT;
|
|
self.health = -60;
|
|
return;
|
|
}
|
|
};
|
|
void() dweller_paine12 =[ $death108, dweller_paine13 ] {};
|
|
void() dweller_paine13 =[ $death107, dweller_paine14 ] {};
|
|
void() dweller_paine14 =[ $death106, dweller_paine15 ] {};
|
|
void() dweller_paine15 =[ $death105, dweller_paine16 ] {};
|
|
void() dweller_paine16 =[ $death104, dweller_paine17 ] {};
|
|
void() dweller_paine17 =[ $death103, dweller_paine18 ] {};
|
|
void() dweller_paine18 =[ $death102, dweller_paine19 ] {};
|
|
void() dweller_paine19 =[ $death101, dweller_run1 ] {};
|
|
|
|
/*
|
|
=================
|
|
dweller_pain
|
|
|
|
Dwellers can only be killed (gibbed) by doing 60 hit points of damage
|
|
in a single frame (rockets, grenades, quad shotgun, quad nailgun).
|
|
|
|
A hit of 25 points or more (super shotgun, quad nailgun) will allways put it
|
|
down to the ground.
|
|
|
|
A hit of from 10 to 40 points in one frame will cause it to go down if it
|
|
has been twice in two seconds, otherwise it goes into one of the four
|
|
fast pain frames.
|
|
|
|
A hit of less than 10 points of damage (winged by a shotgun) will be ignored.
|
|
|
|
FIXME: don't use pain_finished because of nightmare hack
|
|
=================
|
|
*/
|
|
void(entity attacker, float take) dweller_pain =
|
|
{
|
|
local float r;
|
|
|
|
self.health = set_health(60); // allways reset health
|
|
|
|
if (take < 9)
|
|
return; // totally ignore
|
|
|
|
if (self.inpain == 2)
|
|
return; // down on ground, so don't reset any counters
|
|
|
|
//pick a pain sound at random
|
|
r = random();
|
|
if (r <= 0.3)
|
|
sound (self, CHAN_VOICE, "enemy/dweller/pain1.wav", 1, ATTN_NORM);
|
|
else if(r <= 0.6)
|
|
sound (self, CHAN_VOICE, "enemy/dweller/pain2.wav", 1, ATTN_NORM);
|
|
else
|
|
sound (self, CHAN_VOICE, "enemy/dweller/pain3.wav", 1, ATTN_NORM);
|
|
|
|
// go down immediately if a big enough hit
|
|
if (take >= 25)
|
|
{
|
|
self.inpain = 2;
|
|
dweller_paine1 ();
|
|
return;
|
|
}
|
|
|
|
if (self.inpain)
|
|
{
|
|
// if hit again in next gre seconds while not in pain frames, definately drop
|
|
self.pain_finished = time + 3;
|
|
return; // currently going through an animation, don't change
|
|
}
|
|
|
|
if (self.pain_finished > time)
|
|
{
|
|
// hit again, so drop down
|
|
self.inpain = 2;
|
|
dweller_paine1 ();
|
|
return;
|
|
}
|
|
|
|
// go into one of the fast pain animations
|
|
self.inpain = 1;
|
|
|
|
r = random();
|
|
if (r < 0.35)
|
|
dweller_paina1 ();
|
|
else if (r < 0.65)
|
|
dweller_painb1 ();
|
|
else
|
|
dweller_painc1 ();
|
|
};
|
|
|
|
//=============================================================================
|
|
|
|
void() dweller_die =
|
|
{
|
|
//this seems important
|
|
self.solid = SOLID_NOT;
|
|
|
|
//lets do some damage here
|
|
T_RadiusDamage (self, self, 65, world);
|
|
|
|
self.origin = self.origin - 8*normalize(self.velocity);
|
|
|
|
WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
|
|
WriteByte (MSG_BROADCAST, TE_TAREXPLOSION);
|
|
WriteCoord (MSG_BROADCAST, self.origin_x);
|
|
WriteCoord (MSG_BROADCAST, self.origin_y);
|
|
WriteCoord (MSG_BROADCAST, self.origin_z);
|
|
|
|
BecomeExplosion ();
|
|
};
|
|
|
|
//=============================================================================
|
|
|
|
void() dweller_idlesound =
|
|
{
|
|
if (random() <= 0.2)
|
|
{
|
|
if (random() <= 0.5)
|
|
sound (self, CHAN_VOICE, "enemy/dweller/alert1.wav", 1, ATTN_NORM);
|
|
else
|
|
sound (self, CHAN_VOICE, "enemy/dweller/attack1.wav", 1, ATTN_NORM);
|
|
}
|
|
};
|
|
|
|
void() dweller_melee =
|
|
{
|
|
local float r;
|
|
|
|
r = random();
|
|
|
|
//play attack sound
|
|
sound (self, CHAN_VOICE, "enemy/dweller/miss.wav", 1, ATTN_NORM);
|
|
|
|
if (r > 0.5)
|
|
dweller_atta1 ();
|
|
else if (r < 0.5)
|
|
dweller_attb1 ();
|
|
};
|
|
|
|
//============================================================================
|
|
|
|
/*QUAKED monster_dweller (1 0 0) (-16 -16 -24) (16 16 32) Crucified ambush
|
|
|
|
If crucified, stick the bounding box 12 pixels back into a wall to look right.
|
|
*/
|
|
void() monster_dweller =
|
|
{
|
|
local float r;
|
|
|
|
if (deathmatch)
|
|
{
|
|
remove(self);
|
|
return;
|
|
}
|
|
|
|
if (self.spawnflags & SPAWN_CRUCIFIED)
|
|
{
|
|
remove(self);
|
|
return;
|
|
}
|
|
|
|
precache_model ("models/enemies/dweller.md2");
|
|
|
|
precache_sound ("enemy/dweller/alert1.wav");
|
|
precache_sound ("enemy/dweller/attack1.wav");
|
|
precache_sound ("enemy/dweller/miss.wav");
|
|
precache_sound ("enemy/dweller/pain1.wav");
|
|
precache_sound ("enemy/dweller/pain2.wav");
|
|
precache_sound ("enemy/dweller/pain3.wav");
|
|
precache_sound ("enemy/dweller/rage.wav");
|
|
|
|
self.solid = SOLID_SLIDEBOX;
|
|
self.movetype = MOVETYPE_STEP;
|
|
|
|
setmodel (self, "models/enemies/dweller.md2");
|
|
|
|
setsize (self, '-16 -16 -24', '16 16 32');
|
|
// setsize (self, VEC_HULL2_MIN, VEC_HULL2_MAX);
|
|
self.health = set_health(60);
|
|
self.speed = set_speed(600);
|
|
self.dtype = 4; //dodge type do nothing
|
|
|
|
self.th_stand = dweller_stand1;
|
|
self.th_walk = dweller_walk1;
|
|
self.th_run = dweller_run1;
|
|
self.th_pain = dweller_pain;
|
|
self.th_die = dweller_die;
|
|
self.th_melee = dweller_melee;
|
|
|
|
//pick a random skin
|
|
r = random();
|
|
if (r <= 0.25)
|
|
self.skin = 0;
|
|
else if (r <= 0.5)
|
|
self.skin = 1;
|
|
else if (r <= 0.75)
|
|
self.skin = 2;
|
|
else
|
|
self.skin = 3;
|
|
|
|
//my new classname is?
|
|
self.classname = "monster_dweller";
|
|
|
|
//set up our monflag
|
|
self.monflag = "TRUE";
|
|
|
|
walkmonster_start();
|
|
};
|
|
|
|
/*
|
|
=================
|
|
create_dwellerbot
|
|
|
|
Creates a Dweller at the specified 'spot'.
|
|
This is mostly used for the Necromancer's summoning ability.
|
|
=================
|
|
*/
|
|
void(vector spot) create_dwellerbot =
|
|
{
|
|
local entity bot;
|
|
local float r;
|
|
|
|
// start entity and place it in world
|
|
bot = spawn();
|
|
bot.angles = self.angles;
|
|
setorigin (bot, spot);
|
|
bot.fixangle = TRUE;
|
|
spawn_tfog (bot.origin);
|
|
spawn_tdeath (bot.origin, bot);
|
|
|
|
// set size and shape
|
|
bot.solid = SOLID_SLIDEBOX;
|
|
bot.movetype = MOVETYPE_STEP;
|
|
setmodel (bot, "models/enemies/dweller.md2");
|
|
setsize (bot, '-16 -16 -24', '16 16 32');
|
|
bot.flags = bot.flags | FL_MONSTER;
|
|
bot.takedamage = DAMAGE_AIM;
|
|
|
|
// define his animation
|
|
bot.th_stand = dweller_stand1;
|
|
bot.th_walk = dweller_walk1;
|
|
bot.th_run = dweller_run1;
|
|
bot.th_die = dweller_die;
|
|
bot.th_melee = dweller_melee;
|
|
bot.th_pain = dweller_pain;
|
|
bot.health = set_health(60);
|
|
bot.speed = set_speed(600);
|
|
bot.dtype = 4; //dodge type do nothing
|
|
|
|
// polish him up
|
|
bot.classname = "monster_dweller";
|
|
bot.ideal_yaw = bot.angles * '0 1 0';
|
|
bot.yaw_speed = 120;
|
|
bot.view_ofs = '0 0 22';
|
|
|
|
//set up our monflag
|
|
bot.monflag = "TRUE";
|
|
|
|
//pick a random skin
|
|
r = random();
|
|
if (r <= 0.25)
|
|
bot.skin = 0;
|
|
else if (r <= 0.5)
|
|
bot.skin = 1;
|
|
else if (r <= 0.75)
|
|
bot.skin = 2;
|
|
else
|
|
bot.skin = 3;
|
|
|
|
// begin his thinking
|
|
bot.nextthink = time + 0.1 + random();
|
|
bot.think = th_stuck;
|
|
};
|
|
|