950 lines
25 KiB
C++
950 lines
25 KiB
C++
/*
|
|
* $Header: /H3/game/hcode/medusa.hc 39 9/25/97 2:19p Mgummelt $
|
|
*/
|
|
|
|
/*
|
|
==============================================================================
|
|
|
|
Q:\art\models\monsters\medusa\medusa.hc
|
|
MG
|
|
==============================================================================
|
|
*/
|
|
|
|
// For building the model
|
|
$cd Q:\art\models\monsters\medusa
|
|
$origin 0 0 0
|
|
$base BASE-F skin
|
|
$skin skin
|
|
$skin SKIN2
|
|
$flags 0
|
|
|
|
//MEDUSA.MDL
|
|
//
|
|
$frame looklf1 looklf2 looklf3 looklf4 looklf5
|
|
$frame looklf6 looklf7 looklf8 looklf9 looklf10
|
|
$frame looklf11 looklf12 looklf13 looklf14 looklf15
|
|
$frame looklf16 looklf17 looklf18 looklf19 looklf20
|
|
$frame looklf21 looklf22 looklf23 looklf24 looklf25
|
|
$frame looklf26 looklf27 looklf28 looklf29
|
|
|
|
//
|
|
$frame lookrt1 lookrt2 lookrt3 lookrt4 lookrt5
|
|
$frame lookrt6 lookrt7 lookrt8 lookrt9 lookrt10
|
|
$frame lookrt11 lookrt12 lookrt13 lookrt14 lookrt15
|
|
$frame lookrt16 lookrt17 lookrt18 lookrt19 lookrt20
|
|
$frame lookrt21 lookrt22 lookrt23 lookrt24 lookrt25
|
|
$frame lookrt26 lookrt27 lookrt28 lookrt29
|
|
|
|
//
|
|
$frame medusa1 medusa2 medusa3 medusa4 medusa5
|
|
$frame medusa6 medusa7 medusa8 medusa9 medusa10
|
|
$frame medusa11 medusa12 medusa13 medusa14 medusa15
|
|
$frame medusa16 medusa17 medusa18 medusa19 medusa20
|
|
$frame medusa21 medusa22 medusa23 medusa24 medusa25
|
|
$frame medusa26 medusa27 medusa28 medusa29
|
|
|
|
//
|
|
$frame ratatt1 ratatt2 ratatt3 ratatt4 ratatt5
|
|
$frame ratatt6 ratatt7 ratatt8 ratatt9 ratatt10
|
|
$frame ratatt11 ratatt12 ratatt13 ratatt14 ratatt15
|
|
$frame ratatt16 ratatt17 ratatt18 ratatt19 ratatt20
|
|
$frame ratatt21 ratatt22 ratatt23 ratatt24 ratatt25
|
|
$frame ratatt26 ratatt27 ratatt28 ratatt29
|
|
|
|
//
|
|
$frame ratlft1 ratlft2 ratlft3 ratlft4 ratlft5
|
|
$frame ratlft6 ratlft7 ratlft8 ratlft9 ratlft10
|
|
$frame ratlft11 ratlft12 ratlft13 ratlft14 ratlft15
|
|
$frame ratlft16 ratlft17 ratlft18 ratlft19 ratlft20
|
|
$frame ratlft21 ratlft22 ratlft23 ratlft24 ratlft25
|
|
$frame ratlft26 ratlft27 ratlft28 ratlft29
|
|
|
|
//
|
|
$frame ratrit1 ratrit2 ratrit3 ratrit4 ratrit5
|
|
$frame ratrit6 ratrit7 ratrit8 ratrit9 ratrit10
|
|
$frame ratrit11 ratrit12 ratrit13 ratrit14 ratrit15
|
|
$frame ratrit16 ratrit17 ratrit18 ratrit19 ratrit20
|
|
$frame ratrit21 ratrit22 ratrit23 ratrit24 ratrit25
|
|
$frame ratrit26 ratrit27 ratrit28 ratrit29
|
|
|
|
//
|
|
$frame stand1 stand2 stand3 stand4 stand5
|
|
$frame stand6 stand7 stand8 stand9 stand10
|
|
$frame stand11 stand12 stand13 stand14 stand15
|
|
$frame stand16 stand17 stand18 stand19 stand20
|
|
$frame stand21 stand22 stand23 stand24 stand25
|
|
$frame stand26 stand27 stand28 stand29
|
|
|
|
//
|
|
$frame swipe1 swipe2 swipe3 swipe4 swipe5
|
|
$frame swipe6 swipe7 swipe8 swipe9 swipe10
|
|
$frame swipe11 swipe12 swipe13 swipe14 swipe15
|
|
$frame swipe16 swipe17 swipe18 swipe19 swipe20
|
|
$frame swipe21 swipe22 swipe23 swipe24 swipe25
|
|
$frame swipe26 swipe27 swipe28 swipe29
|
|
|
|
|
|
//MEDUSA2.MDL
|
|
$framevalue 0
|
|
//
|
|
$frame adecap1 adecap2 adecap3 adecap4 adecap5
|
|
$frame adecap6 adecap7 adecap8 adecap9 adecap10
|
|
$frame adecap11 adecap12 adecap13 adecap14 adecap15
|
|
$frame adecap16 adecap17 adecap18 adecap19 adecap20
|
|
$frame adecap21 adecap22 adecap23 adecap24 adecap25
|
|
$frame adecap26 adecap27 adecap28 adecap29 adecap30
|
|
$frame adecap31 adecap32 adecap33 adecap34 adecap35
|
|
$frame adecap36 adecap37 adecap38 adecap39 adecap40
|
|
$frame adecap41 adecap42 adecap43 adecap44 adecap45
|
|
$frame adecap46 adecap47 adecap48 adecap49 adecap50
|
|
$frame adecap51 adecap52 adecap53 adecap54 adecap55
|
|
$frame adecap56 adecap57 adecap58 adecap59 adecap60
|
|
$frame adecap61 adecap62 adecap63 adecap64 adecap65
|
|
$frame adecap66 adecap67 adecap68 adecap69 adecap70
|
|
$frame adecap71 adecap72 adecap73 adecap74 adecap75
|
|
$frame adecap76 adecap77 adecap78 adecap79 adecap80
|
|
$frame adecap81 adecap82 adecap83 adecap84 adecap85
|
|
$frame adecap86 adecap87 adecap88
|
|
|
|
//
|
|
$frame bdecap1 bdecap2 bdecap3 bdecap4 bdecap5
|
|
$frame bdecap6 bdecap7 bdecap8 bdecap9 bdecap10
|
|
$frame bdecap11 bdecap12 bdecap13 bdecap14 bdecap15
|
|
$frame bdecap16 bdecap17 bdecap18 bdecap19 bdecap20
|
|
$frame bdecap21 bdecap22 bdecap23 bdecap24 bdecap25
|
|
|
|
//
|
|
$frame death01 death02 death03 death04 death05
|
|
$frame death06 death07 death08 death09 death10
|
|
$frame death11 death12 death13 death14 death15
|
|
$frame death16 death17 death18 death19 death20
|
|
|
|
//
|
|
$frame pain1 pain2 pain3 pain4 pain5
|
|
$frame pain6 pain7 pain8 pain9 pain10
|
|
$frame pain11
|
|
|
|
//
|
|
$frame rnatlf1 rnatlf2 rnatlf3 rnatlf4 rnatlf5
|
|
$frame rnatlf6 rnatlf7 rnatlf8 rnatlf9 rnatlf10
|
|
$frame rnatlf11 rnatlf12 rnatlf13 rnatlf14 rnatlf15
|
|
$frame rnatlf16 rnatlf17 rnatlf18 rnatlf19 rnatlf20
|
|
$frame rnatlf21
|
|
|
|
//
|
|
$frame rnatrt1 rnatrt2 rnatrt3 rnatrt4 rnatrt5
|
|
$frame rnatrt6 rnatrt7 rnatrt8 rnatrt9 rnatrt10
|
|
$frame rnatrt11 rnatrt12 rnatrt13 rnatrt14 rnatrt15
|
|
$frame rnatrt16 rnatrt17 rnatrt18 rnatrt19 rnatrt20
|
|
$frame rnatrt21
|
|
|
|
//
|
|
$frame runatt1 runatt2 runatt3 runatt4 runatt5
|
|
$frame runatt6 runatt7 runatt8 runatt9 runatt10
|
|
$frame runatt11 runatt12 runatt13 runatt14 runatt15
|
|
$frame runatt16 runatt17 runatt18 runatt19 runatt20
|
|
$frame runatt21 runatt22 runatt23 runatt24 runatt25
|
|
$frame runatt26 runatt27 runatt28 runatt29
|
|
|
|
//====================================================================
|
|
float MEDUSA_LOOK = 0;
|
|
float MEDUSA_RATTLE = 1;
|
|
float MEDUSA_HEADBUTT = 2;
|
|
float MEDUSA_SNAKES = 3;
|
|
|
|
void(entity attacker,float total_damage)medusa_pain;
|
|
void()medusa_attack_right;
|
|
void()medusa_attack_left;
|
|
void()medusa_attack;
|
|
void(float action)MedusaSelectDir;
|
|
|
|
void medusa_check_use_model (string modelstring)
|
|
{
|
|
if(self.model!=modelstring)
|
|
{
|
|
setmodel(self,modelstring);
|
|
setsize(self,'-16 -16 0','16 16 56');
|
|
}
|
|
}
|
|
|
|
void snake_remove ()
|
|
{
|
|
particleexplosion(self.origin,random(176,192),30,20);
|
|
remove(self);
|
|
}
|
|
|
|
void() SnakeHit =
|
|
{
|
|
if(other==self.owner||(other.owner==self.owner&&other.classname=="snakearrow"))
|
|
return;
|
|
starteffect(CE_MEDUSA_HIT,self.origin);
|
|
sound(other,CHAN_AUTO,"medusa/hitplayr.wav",1,ATTN_NORM);
|
|
if(other.takedamage)
|
|
{
|
|
other.bloodloss=other.bloodloss+1;
|
|
SpawnPuff(other.origin,'0 0 0',self.dmg,other);
|
|
//Snakehit sprite
|
|
T_Damage(other,self,self.owner,self.dmg);
|
|
}
|
|
snake_remove();
|
|
};
|
|
|
|
void snake_fly ()
|
|
{
|
|
particle4(self.origin,10,256+random(176,192),PARTICLETYPE_GRAV,3);
|
|
if(random()<0.1)
|
|
CreateGreenSmoke(self.origin,'0 0 0',HX_FRAME_TIME);
|
|
HomeThink();
|
|
self.think=snake_fly;
|
|
thinktime self : 0.05;
|
|
}
|
|
|
|
void FireSnakeArrow (vector offset)
|
|
{
|
|
//FIXME: add a greenish particle trail?
|
|
self.last_attack=time;
|
|
makevectors(self.angles);
|
|
//identity
|
|
newmis=spawn();
|
|
newmis.owner=self;
|
|
newmis.classname="snakearrow";
|
|
//Movement and solidity
|
|
newmis.movetype=MOVETYPE_FLYMISSILE;
|
|
newmis.solid=SOLID_BBOX;
|
|
//rendering
|
|
newmis.abslight=0.3;
|
|
newmis.drawflags(+)MLS_ABSLIGHT;
|
|
//velocity
|
|
newmis.speed=500;
|
|
newmis.o_angle=normalize((self.goalentity.origin+self.goalentity.view_ofs) - (self.origin+self.view_ofs+offset));
|
|
newmis.velocity=newmis.o_angle*newmis.speed;
|
|
newmis.angles=vectoangles(newmis.velocity);
|
|
//impact
|
|
newmis.touch=SnakeHit;
|
|
newmis.dmg=3;
|
|
//behaviour
|
|
newmis.lockentity=newmis.enemy=self.enemy;//lockentity means it will never track any other ent
|
|
newmis.veer=50; //slight veering, random course modifications
|
|
newmis.th_die=snake_remove;
|
|
newmis.think=snake_fly;
|
|
newmis.hoverz=TRUE; //slow down on turns
|
|
thinktime newmis : 0;
|
|
|
|
//appearance,size, and position, always in this order!!!
|
|
setmodel(newmis,"models/snakearr.mdl");
|
|
setsize(newmis,'0 0 0','0 0 0');
|
|
setorigin(newmis,self.origin+self.view_ofs+v_forward*8+offset);
|
|
}
|
|
|
|
void MedusaAttacks (void)
|
|
{
|
|
vector source, org;
|
|
float damg;
|
|
if(self.monster_stage==MEDUSA_SNAKES)
|
|
{
|
|
self.attack_finished=time+2;
|
|
sound (self,CHAN_WEAPON,"medusa/attack2.wav",1,ATTN_NORM);
|
|
FireSnakeArrow(v_up*12);
|
|
FireSnakeArrow(v_right*12);
|
|
FireSnakeArrow(v_right*-12);
|
|
}
|
|
else
|
|
{
|
|
self.attack_finished=time+1;
|
|
makevectors (self.angles+self.angle_ofs);
|
|
source = self.origin+self.view_ofs;
|
|
traceline (source, source + v_forward*48, FALSE, self);
|
|
if (trace_fraction == 1.0)
|
|
return;
|
|
org = trace_endpos + (v_forward * 4);
|
|
sound (self, CHAN_WEAPON, "weapons/gauntht1.wav", 1, ATTN_NORM);
|
|
if (trace_ent.takedamage)
|
|
{
|
|
damg = random(10,18);
|
|
SpawnPuff (org, '0 0 0', 20,trace_ent);
|
|
T_Damage (trace_ent, self, self, damg);
|
|
//punchangle
|
|
// if(other.classname=="player")
|
|
// other.punchangle=???
|
|
}
|
|
else
|
|
{ // hit wall
|
|
SpawnPuff (trace_endpos, '0 0 0', 20,self);
|
|
medusa_pain(self,0);
|
|
}
|
|
}
|
|
}
|
|
|
|
void()medusa_attack_left = [++ $rnatlf1 .. $rnatlf21]
|
|
{
|
|
medusa_check_use_model("models/medusa2.mdl");
|
|
if(self.frame==$rnatlf21)
|
|
self.think=self.th_run;
|
|
else if(self.frame==$rnatlf4)
|
|
MedusaAttacks();
|
|
};
|
|
|
|
void()medusa_attack_right = [++ $rnatrt1 .. $rnatrt21]
|
|
{
|
|
medusa_check_use_model("models/medusa2.mdl");
|
|
if(self.frame==$rnatrt21)
|
|
self.think=self.th_run;
|
|
else if(self.frame==$rnatrt4)
|
|
MedusaAttacks();
|
|
};
|
|
|
|
void()medusa_attack = [++ $runatt1 .. $runatt29]
|
|
{
|
|
medusa_check_use_model("models/medusa2.mdl");
|
|
if(self.frame==$runatt29)
|
|
self.think= self.th_run;
|
|
else if(self.frame==$runatt12)
|
|
MedusaAttacks();
|
|
};
|
|
|
|
void()MedusaGazeLoop;
|
|
void MedusaGaze (vector org, vector destiny, entity loser) [++ $medusa1 .. $medusa29]
|
|
{
|
|
//Anim?
|
|
//sound, temp ent
|
|
self.last_attack=time;
|
|
|
|
if(!self.aflag)
|
|
{
|
|
sound (self,CHAN_WEAPON,"medusa/attack1.wav",1,ATTN_NORM);
|
|
self.aflag=TRUE;
|
|
}
|
|
medusa_check_use_model("models/medusa.mdl");
|
|
|
|
ai_face();
|
|
WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
|
|
WriteByte (MSG_BROADCAST, TE_STREAM_GAZE);
|
|
WriteByte (MSG_BROADCAST, 1+STREAM_ATTACHED);
|
|
WriteByte (MSG_BROADCAST, 4);
|
|
WriteEntity (MSG_BROADCAST, self);
|
|
WriteCoord (MSG_BROADCAST, org_x);
|
|
WriteCoord (MSG_BROADCAST, org_y);
|
|
WriteCoord (MSG_BROADCAST, org_z);
|
|
WriteCoord (MSG_BROADCAST, destiny_x);
|
|
WriteCoord (MSG_BROADCAST, destiny_y);
|
|
WriteCoord (MSG_BROADCAST, destiny_z);
|
|
|
|
if(loser.health<=10&&!loser.artifact_active&ART_INVINCIBILITY)
|
|
{
|
|
sound(loser,CHAN_BODY,"medusa/stoned.wav",1,ATTN_NORM);
|
|
self.attack_finished=time+7;
|
|
loser.skin = GLOBAL_SKIN_STONE;
|
|
loser.think=loser.th_pain=loser.th_run=SUB_Null;
|
|
loser.attack_finished=loser.teleport_time=loser.pausetime = time+10000000000;
|
|
loser.nextthink=-1;
|
|
loser.th_die = chunk_death;
|
|
loser.thingtype = THINGTYPE_GREYSTONE;
|
|
loser.health = 10;
|
|
loser.touch = obj_push;
|
|
loser.flags(-)FL_FLY;
|
|
loser.flags(-)FL_SWIM;
|
|
if(loser.classname!="player")
|
|
loser.movetype = MOVETYPE_STEP;//step?
|
|
else
|
|
loser.o_angle=loser.v_angle;
|
|
loser.solid = SOLID_BBOX;
|
|
loser.artifact_active(+)ARTFLAG_STONED;
|
|
//Greying palette effect
|
|
}
|
|
else
|
|
{
|
|
T_Damage(loser,self,self,3);
|
|
if(loser.classname=="player"&&random()<0.2+skill/10+self.skin/5)
|
|
{
|
|
loser.o_angle=loser.v_angle;
|
|
loser.pausetime=time+random(0.05,0.3);
|
|
if(random()<0.5)
|
|
{
|
|
loser.attack_finished=time+random(0.05,0.3);
|
|
if(random()<0.5)
|
|
thinktime loser : 0.2;
|
|
}
|
|
}
|
|
}
|
|
|
|
if(lineofsight(self,loser)&&!loser.artifact_active&ARTFLAG_STONED)
|
|
{
|
|
self.goalentity=loser;
|
|
self.think=MedusaGazeLoop;
|
|
thinktime self : 0.1;
|
|
}
|
|
else
|
|
{
|
|
self.aflag=FALSE;
|
|
sound (self,CHAN_WEAPON,"misc/null.wav",1,ATTN_NORM);
|
|
self.attack_finished=time+2;
|
|
self.think=self.th_run;
|
|
thinktime self : 0;
|
|
}
|
|
}
|
|
|
|
void MedusaGazeLoop()
|
|
{
|
|
MedusaGaze(self.origin+self.view_ofs,self.goalentity.origin+self.goalentity.view_ofs,self.goalentity);
|
|
}
|
|
|
|
void MedusaSwipe () [++ $swipe1 .. $swipe29]
|
|
{
|
|
self.last_attack=time;
|
|
if(cycle_wrapped)
|
|
{
|
|
self.attack_finished=time+1;
|
|
self.think=self.th_run;
|
|
thinktime self : 0;
|
|
}
|
|
else if(self.frame==$swipe1)
|
|
{
|
|
sound(self,CHAN_VOICE,"medusa/sight.wav",1,ATTN_NORM);
|
|
sound(self,CHAN_BODY,"weapons/vorpswng.wav",1,ATTN_NORM);
|
|
}
|
|
else if(self.frame>=$swipe6 &&self.frame<=$swipe10)
|
|
{
|
|
makevectors(self.angles);
|
|
traceline(self.origin+'0 0 23',self.origin+'0 0 23'-v_forward*72+v_right*($swipe7 - self.frame)*10,FALSE,self);
|
|
if(trace_ent.takedamage)
|
|
{
|
|
T_Damage(trace_ent,self,self,7);
|
|
sound(trace_ent,CHAN_BODY,"weapons/met2flsh.wav",1,ATTN_NORM);
|
|
SpawnPuff(trace_endpos,'0 0 0',7,trace_ent);
|
|
trace_ent.velocity+=v_right*-200;
|
|
trace_ent.velocity_z+=100;
|
|
trace_ent.flags(-)FL_ONGROUND;
|
|
}
|
|
}
|
|
else if(self.frame>$swipe10)
|
|
ai_face();
|
|
}
|
|
|
|
float MedusaCheckAttack (void)
|
|
{
|
|
vector org,dir,destiny;
|
|
float r, loscheck1,loscheck2;
|
|
if(random()<0.5 - skill/10 - self.skin/5||self.enemy==world)
|
|
return FALSE;
|
|
|
|
org=self.origin+self.view_ofs;
|
|
|
|
if (time < self.attack_finished)
|
|
return FALSE;
|
|
|
|
if (!enemy_vis)
|
|
{
|
|
if(self.goalentity.classname=="waypoint")
|
|
{
|
|
if(visible2ent(self.enemy,self.goalentity))
|
|
{
|
|
MedusaSelectDir(MEDUSA_SNAKES);
|
|
return TRUE;
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
if(!enemy_infront)
|
|
{
|
|
if(enemy_range==RANGE_MELEE)
|
|
{
|
|
MedusaSwipe();
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
if (enemy_range == RANGE_FAR)
|
|
{
|
|
if (self.attack_state != AS_STRAIGHT)
|
|
self.attack_state = AS_STRAIGHT;
|
|
return FALSE;
|
|
}
|
|
|
|
// see if any entities are in the way of the shot
|
|
dir = self.enemy.origin + self.enemy.view_ofs;
|
|
|
|
traceline (org, dir, FALSE, self);
|
|
if (trace_ent != self.enemy)
|
|
{ // don't have a clear shot, so move to a side
|
|
if (self.attack_state != AS_SLIDING)
|
|
self.attack_state == AS_SLIDING;
|
|
return FALSE;
|
|
}
|
|
else
|
|
self.attack_state == AS_STRAIGHT;
|
|
|
|
destiny = self.enemy.origin+self.enemy.view_ofs;
|
|
//FIXME: account for z difference
|
|
loscheck1=lineofsight(self.enemy,self);
|
|
loscheck2=lineofsight(self,self.enemy);
|
|
r=random();
|
|
|
|
if(!self.enemy.artifact_active&ARTFLAG_STONED&&loscheck1&& (loscheck2|| (r<0.1&&infront_of_ent(self,self.enemy)) ) )
|
|
{
|
|
MedusaGaze(org,destiny,self.enemy);
|
|
return TRUE;
|
|
}
|
|
|
|
if (enemy_range == RANGE_MELEE)
|
|
{
|
|
MedusaSelectDir(MEDUSA_HEADBUTT);
|
|
return TRUE;
|
|
}
|
|
else if (enemy_range == RANGE_NEAR)
|
|
r = 0.2;
|
|
else if (enemy_range == RANGE_MID)
|
|
r = 0.3;
|
|
|
|
if (random () < r)
|
|
{
|
|
MedusaSelectDir(MEDUSA_SNAKES);
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
//====================================================================
|
|
void()medusa_look_right;
|
|
void MedusaHeadTouch ()
|
|
{
|
|
if(self.velocity!='0 0 0'&&!other.flags2&FL_ALIVE)
|
|
sound(self,CHAN_AUTO,"weapons/hithurt2.wav",1,ATTN_NORM);
|
|
}
|
|
|
|
void()MedusaHeadDying;
|
|
void MedusaHeadDead () [++ 0 .. 45]
|
|
{
|
|
thinktime self : 0.1;
|
|
ai_face();
|
|
if(self.frame==20)
|
|
sound(self,CHAN_VOICE,"medusa/sight.wav",0.5,ATTN_NORM);
|
|
else if(self.frame==45)
|
|
{
|
|
self.aflag=TRUE;
|
|
self.think=MedusaHeadDying;
|
|
}
|
|
}
|
|
|
|
void MedusaHeadDying () [++ 46 .. 105]
|
|
{
|
|
if(pointcontents(self.origin)==CONTENT_SOLID)
|
|
{
|
|
chunk_death();
|
|
return;
|
|
}
|
|
|
|
if(self.velocity=='0 0 0')
|
|
if(!self.aflag)
|
|
{
|
|
if(self.angles_x<-10||self.angles_x>10)
|
|
self.angles_x=0;
|
|
if(self.angles_z<-10||self.angles_z>10)
|
|
self.angles_z=0;
|
|
self.solid = SOLID_BBOX;
|
|
self.think=MedusaHeadDead;
|
|
thinktime self : 0;
|
|
}
|
|
else if(self.frame==105)
|
|
{
|
|
self.skin=1;
|
|
self.think=init_corpseblink;
|
|
thinktime self : 5;
|
|
}
|
|
}
|
|
|
|
void MedusaThrowHead ()
|
|
{
|
|
newmis = spawn();
|
|
newmis.owner=self;
|
|
newmis.enemy=newmis.goalentity=self.enemy;
|
|
newmis.yaw_speed=3;
|
|
setmodel (newmis, self.headmodel);
|
|
self.headmodel="";
|
|
setsize (newmis, '-3 -3 -3', '3 3 3');
|
|
setorigin(newmis,self.absmax - '0 0 15');
|
|
newmis.velocity = randomv('-200 -200 200','200 200 600');
|
|
newmis.movetype = MOVETYPE_BOUNCE;
|
|
if(pointcontents(newmis.origin)==CONTENT_SOLID)
|
|
newmis.solid = SOLID_NOT;
|
|
else
|
|
newmis.solid = SOLID_BBOX;
|
|
newmis.takedamage=DAMAGE_YES;
|
|
newmis.thingtype=self.thingtype;
|
|
newmis.th_die=chunk_death;
|
|
newmis.touch=MedusaHeadTouch;
|
|
newmis.health=25;
|
|
newmis.scale=2;
|
|
|
|
newmis.avelocity_x = random(600);
|
|
newmis.avelocity_y = random(600);
|
|
newmis.avelocity_z = random(600);
|
|
newmis.think=MedusaHeadDying;
|
|
thinktime newmis : 0;
|
|
}
|
|
|
|
void medusa_decap_drop ()[++ $bdecap1 .. $bdecap25]
|
|
{
|
|
if(self.frame==$bdecap9)
|
|
sound(self,CHAN_BODY,"player/land.wav",1,ATTN_NORM);
|
|
else if(self.frame==$bdecap25)
|
|
MakeSolidCorpse();
|
|
}
|
|
|
|
void medusa_decap_loop ()[++ $adecap1..$adecap88]
|
|
{
|
|
if(random()<0.5)
|
|
self.angles_y+=random(-3,3);
|
|
walkmove(self.angles_y,self.speed*random(),FALSE);
|
|
|
|
if(random()<0.2)
|
|
{
|
|
sound (self, CHAN_VOICE, "misc/decomp.wav", 0.3, ATTN_NORM);
|
|
SpawnPuff (self.origin+'0 0 56', '0 0 35',5,self);
|
|
}
|
|
|
|
if(self.frame==$adecap48)
|
|
sound(self,CHAN_BODY,"medusa/rattle.wav",1,ATTN_NORM);
|
|
if(cycle_wrapped)
|
|
{
|
|
self.think=medusa_decap_drop;
|
|
thinktime self : 0;
|
|
}
|
|
}
|
|
|
|
void medusa_decap_init ()
|
|
{
|
|
float throwdist;
|
|
throwdist=self.health;
|
|
ThrowGib("models/medsnake.mdl",throwdist);
|
|
ThrowGib("models/medsnake.mdl",throwdist);
|
|
ThrowGib("models/medsnake.mdl",throwdist);
|
|
sound(self,CHAN_VOICE,"player/gib2.wav",1,ATTN_NORM);
|
|
MedusaThrowHead();
|
|
SpawnPuff (self.origin+'0 0 56', '0 0 35',5,self);
|
|
medusa_decap_loop();
|
|
}
|
|
|
|
void medusa_die (void) [++ $death01..$death20]
|
|
{
|
|
medusa_check_use_model("models/medusa2.mdl");
|
|
if(self.decap)
|
|
medusa_decap_init();
|
|
else if(self.health<=-80)
|
|
{
|
|
MedusaThrowHead();
|
|
chunk_death();
|
|
}
|
|
else
|
|
{
|
|
if(self.frame==$death20)
|
|
MakeSolidCorpse();
|
|
else if(self.frame==$death01)
|
|
sound(self,CHAN_VOICE,"medusa/death.wav",1,ATTN_NORM);
|
|
}
|
|
}
|
|
|
|
void medusa_pain_anim () [++ $pain1 .. $pain11]
|
|
{
|
|
//sound
|
|
medusa_check_use_model("models/medusa2.mdl");
|
|
if (cycle_wrapped)
|
|
{
|
|
thinktime self : 0;
|
|
self.think=self.th_run;
|
|
}
|
|
else if(self.frame==$pain1)
|
|
sound(self,CHAN_VOICE,"medusa/pain.wav",1,ATTN_NORM);
|
|
}
|
|
|
|
void medusa_pain (entity attacker,float total_damage)
|
|
{
|
|
if(random()<0.6&&total_damage<50&&attacker!=self)
|
|
return;
|
|
|
|
medusa_pain_anim();
|
|
}
|
|
|
|
void()medusa_look_left = [++ $looklf1 .. $looklf29]
|
|
{
|
|
medusa_check_use_model("models/medusa.mdl");
|
|
if(self.oldthink==self.th_run)
|
|
ai_run(self.speed);
|
|
else
|
|
{
|
|
if(self.oldthink==self.th_stand)
|
|
ai_stand();
|
|
else if(self.oldthink==self.th_walk)
|
|
ai_walk(5);
|
|
}
|
|
if(cycle_wrapped)
|
|
{
|
|
self.think=self.oldthink;
|
|
if(self.think!=self.th_run)
|
|
if(random()<0.2)
|
|
self.think=medusa_look_right;
|
|
thinktime self : 0;
|
|
}
|
|
};
|
|
|
|
void()medusa_look_right = [++ $lookrt1 .. $lookrt29]
|
|
{
|
|
medusa_check_use_model("models/medusa.mdl");
|
|
if(self.oldthink==self.th_run)
|
|
ai_run(self.speed);
|
|
else
|
|
{
|
|
if(self.oldthink==self.th_stand)
|
|
ai_stand();
|
|
else if(self.oldthink==self.th_walk)
|
|
ai_walk(5);
|
|
}
|
|
if(cycle_wrapped)
|
|
{
|
|
self.think=self.oldthink;
|
|
if(self.think!=self.th_run)
|
|
if(random()<0.2)
|
|
self.think=medusa_look_left;
|
|
thinktime self : 0;
|
|
}
|
|
};
|
|
|
|
void()medusa_rattle_left = [++ $ratlft1 .. $ratlft29]
|
|
{
|
|
//sound
|
|
medusa_check_use_model("models/medusa.mdl");
|
|
if(cycle_wrapped)
|
|
{
|
|
thinktime self : 0;
|
|
self.think=self.th_run;
|
|
}
|
|
};
|
|
|
|
void()medusa_rattle_right = [++ $ratrit1 .. $ratrit29]
|
|
{
|
|
//sound
|
|
medusa_check_use_model("models/medusa.mdl");
|
|
if(cycle_wrapped)
|
|
{
|
|
thinktime self : 0;
|
|
self.think=self.th_run;
|
|
}
|
|
};
|
|
|
|
void()medusa_rattle = [++ $ratatt1 .. $ratatt29]
|
|
{
|
|
//sound
|
|
medusa_check_use_model("models/medusa.mdl");
|
|
if(cycle_wrapped)
|
|
{
|
|
thinktime self : 0;
|
|
self.think=self.th_run;
|
|
}
|
|
};
|
|
|
|
void MedusaSelectDir (float action)
|
|
{
|
|
vector enemy_dir;
|
|
float dot;
|
|
medusa_check_use_model("models/medusa.mdl");
|
|
self.monster_stage=action;
|
|
if(action>=MEDUSA_HEADBUTT)
|
|
{
|
|
self.last_attack=time;
|
|
sound (self,CHAN_VOICE,"medusa/hiss.wav",1,ATTN_NORM);
|
|
medusa_check_use_model("models/medusa2.mdl");
|
|
}
|
|
else if(action==MEDUSA_RATTLE)
|
|
sound(self,CHAN_BODY,"medusa/rattle.wav",1,ATTN_NORM);
|
|
makevectors(self.angles);
|
|
enemy_dir=normalize(self.enemy.origin-self.origin);
|
|
dot=v_right*enemy_dir;
|
|
if(dot>0.3)
|
|
{
|
|
self.angle_ofs_y=-90;
|
|
if(action>=MEDUSA_HEADBUTT)
|
|
self.think=medusa_attack_right;
|
|
else if(action==MEDUSA_RATTLE)
|
|
self.think=medusa_rattle_right;
|
|
else
|
|
self.think=medusa_look_right;
|
|
}
|
|
else if(dot<-0.3)
|
|
{
|
|
self.angle_ofs_y=-90;
|
|
if(action>=MEDUSA_HEADBUTT)
|
|
self.think=medusa_attack_left;
|
|
else if(action==MEDUSA_RATTLE)
|
|
self.think=medusa_rattle_left;
|
|
else
|
|
self.think=medusa_look_left;
|
|
}
|
|
else
|
|
{
|
|
self.angle_ofs_y=0;
|
|
if(action>=MEDUSA_HEADBUTT)
|
|
self.think=medusa_attack;
|
|
else if(action==MEDUSA_RATTLE)
|
|
self.think=medusa_rattle;
|
|
else
|
|
return;
|
|
}
|
|
thinktime self : 0;
|
|
}
|
|
|
|
void medusa_hunt () [++ $medusa1 .. $medusa29]
|
|
{
|
|
medusa_check_use_model("models/medusa.mdl");
|
|
|
|
if(random()<0.1)
|
|
ai_run(0);
|
|
else
|
|
ai_run(self.speed);
|
|
|
|
if(!enemy_vis)
|
|
if(random()<0.1&&random()<0.5)
|
|
if(random()<0.5)
|
|
MedusaSelectDir(MEDUSA_RATTLE);
|
|
else
|
|
{
|
|
self.oldthink=self.th_run;
|
|
MedusaSelectDir(MEDUSA_LOOK);
|
|
}
|
|
}
|
|
|
|
void medusa_walk () [++ $medusa1 .. $medusa29]
|
|
{
|
|
medusa_check_use_model("models/medusa.mdl");
|
|
self.monster_awake=FALSE;
|
|
if(random()<0.1)
|
|
ai_walk(0);
|
|
else
|
|
ai_walk(5);
|
|
if(cycle_wrapped)
|
|
{
|
|
if(random()<0.3)
|
|
{
|
|
self.oldthink=self.th_walk;
|
|
if(random()<0.5)
|
|
{
|
|
thinktime self : 0;
|
|
self.think=medusa_look_left;
|
|
}
|
|
else
|
|
{
|
|
thinktime self : 0;
|
|
self.think=medusa_look_right;
|
|
}
|
|
}
|
|
}
|
|
// MedusaCheckAttack();
|
|
if(random()<0.1&&random()<0.5)
|
|
sound(self,CHAN_VOICE,"medusa/hiss.wav",1,ATTN_NORM);
|
|
}
|
|
|
|
void medusa_stand () [++$stand1..$stand29]
|
|
{
|
|
medusa_check_use_model("models/medusa.mdl");
|
|
self.monster_awake=FALSE;
|
|
ai_stand();
|
|
if(random()<0.1)
|
|
{
|
|
self.oldthink=self.th_stand;
|
|
if(random()<0.5)
|
|
{
|
|
thinktime self : 0;
|
|
self.think=medusa_look_left;
|
|
}
|
|
else
|
|
{
|
|
thinktime self : 0;
|
|
self.think=medusa_look_right;
|
|
}
|
|
}
|
|
if(random()<0.1&&random()<0.3)
|
|
sound(self,CHAN_VOICE,"medusa/hiss.wav",1,ATTN_NORM);
|
|
}
|
|
|
|
|
|
/*QUAKED monster_medusa_green (1 0.3 0) (-16 -16 0) (16 16 56) AMBUSH STUCK JUMP PLAY_DEAD DORMANT
|
|
|
|
The medusa monster with its nasty sharp pointy teeth
|
|
-------------------------FIELDS-------------------------
|
|
--------------------------------------------------------
|
|
*/
|
|
void monster_medusa_green (void)
|
|
{
|
|
if (deathmatch)
|
|
{
|
|
remove(self);
|
|
return;
|
|
}
|
|
|
|
precache_model2("models/medusa.mdl");
|
|
precache_model2("models/medusa2.mdl");
|
|
precache_model2("models/snakearr.mdl");
|
|
precache_model2("models/medhit.spr");
|
|
precache_model2("models/medhead.mdl");
|
|
precache_model2("models/medsnake.mdl");
|
|
precache_sound2("medusa/rattle.wav");
|
|
precache_sound2("medusa/hiss.wav");
|
|
precache_sound2("medusa/sight.wav");
|
|
precache_sound2("medusa/attack1.wav");
|
|
precache_sound2("medusa/attack2.wav");
|
|
precache_sound2("medusa/pain.wav");
|
|
precache_sound2("medusa/death.wav");
|
|
precache_sound2("medusa/stoned.wav");
|
|
precache_sound2("medusa/hitplayr.wav");
|
|
|
|
// if(random()<0.5)
|
|
// self.skin=1;
|
|
|
|
self.headmodel="models/medhead.mdl";
|
|
self.solid = SOLID_SLIDEBOX;
|
|
self.movetype = MOVETYPE_STEP;
|
|
self.takedamage=DAMAGE_YES;
|
|
self.thingtype=THINGTYPE_FLESH;
|
|
self.monsterclass=CLASS_LEADER;
|
|
self.mintel = 20;//Very smart- excellent tracker
|
|
self.mass = 15;
|
|
self.view_ofs = '0 0 53';
|
|
self.speed=5;
|
|
self.yaw_speed = 5;
|
|
self.classname="monster_medusa";
|
|
self.health = 700;
|
|
self.experience_value = 500;
|
|
|
|
self.th_stand=medusa_stand;
|
|
self.th_run=medusa_hunt;
|
|
self.th_walk=medusa_walk;
|
|
self.th_die=medusa_die;
|
|
self.th_pain=medusa_pain;
|
|
self.th_missile=medusa_rattle;
|
|
self.th_melee=medusa_attack;
|
|
|
|
setmodel (self, "models/medusa.mdl");
|
|
|
|
setsize(self, '-28 -28 0', '28 28 56');
|
|
self.hull=HULL_PLAYER;
|
|
|
|
walkmonster_start();
|
|
}
|
|
|
|
void monster_medusa (void)
|
|
{
|
|
monster_medusa_green();
|
|
}
|
|
|
|
/*QUAKED monster_medusa_red (1 0.3 0) (-16 -16 0) (16 16 56) AMBUSH STUCK JUMP PLAY_DEAD DORMANT
|
|
|
|
The medusa monster with its nasty sharp pointy teeth
|
|
-------------------------FIELDS-------------------------
|
|
--------------------------------------------------------
|
|
*/
|
|
void monster_medusa_red (void)
|
|
{
|
|
// self.skin=1;
|
|
monster_medusa_green();
|
|
self.health = 250;
|
|
self.experience_value = 125;
|
|
}
|