hexen2/H2MP/hcode/pentacles.hc
2000-11-10 00:00:00 +00:00

1041 lines
28 KiB
C++

/*
Wall Shambler
Pentacles [PEN-tuh-kleez]
World's First 3-D engine wall/ceiling/floor crawler/jumper!!!(?)
MG & JM
*/
/*
Tentacly thing (or not?) That can "crawl" along walls and ceilings
and floors to get to player as well as throw itself, roll up like
a ball, and bounce. Does acid damage when splatters. Some may
spit acid. Some may work together, shooting beams radially inward
to a central spot, which coalesces into a beam that hits enemy
(or large missile? tracking?)
STEP1:
Designer puts wallsham in map may point it at a surface. The
Wallsham will begin on that surface. If the wallsham is not
pointed at a surface, it will look for the closest surface.
This is expensive, so designers should always point the wallsham
at a surface.
STEP2:
Wallsham waits to find an enemy. If it doesn't have one, it will
stick around and wait unless it has a path, which it will attempt
to follow. It will also add this entity to a global list of
wallsham enemies until it goes away or dies. Wallshams NEVER have
another wallsham as an enemy. If a wallsham doesn't have an enemy
or it's enemy is dead, it consults the list of wallsham enemies and
tries to track/attack the closest if it's visible.
STEP3:
When wallsham finds an enemy, it decides if it can attack. If
not, it gets closer. It may be scripted to run away (to, for example,
lead the player into an ambush). If it can attack, it decides
if it wants to. If so, does attack (may be launching itself
at enemy like a bouncing ball and splattering on enemy).
STEP4:
Movement. Wallsham attempts to move towards player. If it bumps
into a blocking world brush, it redirects it's angles and attaches
to that bumped surface. If it successfully moves, it checks it's
"stickdir" for a face and attaches itself to it if it finds one
that's 16 units or closer. It also will change it's angles to
match the slope of this new face. If it does not find one,
it will move back to where it was (real quick like), and either
prepare to jump, see if it can attack, choose some other direction,
or (very rarely) wait around. When it's on the ground, it uses
MOVETYPE_WALK, when it's on the walls or cielings, it uses
MOVETYPE_FLY with the FL_FLY flag on, when it jumps, it uses
MOVETYPE_TOSS, and finally, when it throws itself, it uses
MOVETYPE_BOUNCE.
STEP5:
When it dies, if doesn't explode, it deflates and green ooze runs
out that can do damage if stepped in. This eventually seeps into
the ground. If it does explode, it explodes into a goopy blob of
guts, tentacles, and acidic slime, this does radius damage, but not
to other wallshams.
*/
$frame ball000 ball001 ball002 ball003 ball004
$frame ball005 ball006 ball007 ball008 ball009
$frame ball010
//
$frame lunge000 lunge001 lunge002 lunge003 lunge004
$frame lunge005 lunge006 lunge007 lunge008 lunge009
$frame lunge010
//
$frame ready000 ready001 ready002 ready003 ready004
$frame ready005 ready006 ready007 ready008 ready009
$frame ready010 ready011 ready012 ready013 ready014
$frame ready015
//
$frame spit000 spit001 spit002 spit003 spit004
$frame spit005 spit006 spit007 spit008 spit009
$frame spit010
//
$frame walk000 walk001 walk002 walk003 walk004
$frame walk005 walk006 walk007 walk008 walk009
$frame walk010 walk011 walk012 walk013 walk014
$frame walk015
void(float do_move)face_movechain;
void(entity attacker, float damage)pent_pain;
void SUB_Return()
{
return;
}
void setnewwalldir ()
{
float shortest, dirnum;
makevectors (self.angles);
dirnum=shortest=1;
self.th_pain=SUB_Return;
// dprint("Grabbing any wall\n");
while(dirnum<7)
{
if(dirnum==1)
traceline(self.origin,self.origin+v_forward*64,TRUE,self);
else if(dirnum==2)
traceline(self.origin,self.origin-v_forward*64,TRUE,self);
else if(dirnum==3)
traceline(self.origin,self.origin+v_right*64,TRUE,self);
else if(dirnum==4)
traceline(self.origin,self.origin-v_right*64,TRUE,self);
else if(dirnum==5)
traceline(self.origin,self.origin+v_up*64,TRUE,self);
else
traceline(self.origin,self.origin-v_up*64,TRUE,self);
if(trace_fraction<shortest)
{
shortest=trace_fraction;
self.walldir=normalize(trace_endpos - self.origin);
}
dirnum+=1;
}
if(self.walldir=='0 0 0')
self.walldir='0 0 -1';//defaults to the floor
self.th_pain=pent_pain;
self.th_run();
}
void() flymonster_start_go =
{
entity latch;
// spread think times so they don't all happen at same time
if(self.target!=string_null)
latch=find(world,targetname,self.target);
else
latch=world;
if(!latch)
setnewwalldir();//objerror("Pentacles: Target Me!!!\n");
else
{
self.walldir=normalize(latch.origin-self.origin);
if(self.walldir=='0 0 0')
self.walldir='0 0 -1';//defaults to the floor
latch.think=SUB_Remove;
thinktime latch : 3;//Or leave for others?
}
// if (!walkmove(0,0, FALSE))
// {
// dprint ("flymonster in wall at: ");
// dprint (vtos(self.origin));
// dprint ("\n");
// }
/* if (self.target)
{
self.goalentity = self.pathentity = find(world, targetname, self.target);
// if (!self.pathentity)
// {
// dprint ("Monster can't find target at ");
// dprint (vtos(self.origin));
// dprint ("\n");
// }
// this used to be an objerror
if (self.pathentity.classname == "path_corner")
self.th_walk ();
else
{
self.pausetime = 99999999;
self.th_stand ();
}
}
else
{
*/
self.pausetime = 99999999;
self.th_stand ();
// }
};
void pent_pain_anim () [++ $ready000 .. $ready015]//FIME: Pain frames or some other effect?
{
self.movechain.frame=self.frame;
if(cycle_wrapped)
if(self.walldir=='0 0 0')
flymonster_start_go();
else
self.th_run();
}
void pent_pain (entity attacker, float damage)
{
sound (self, CHAN_VOICE, "pent/pain.wav", 1, ATTN_NORM);
if (random()*70 > damage)
return; // didn't flinch
pent_pain_anim ();
}
void pent_unball () [-- $ball010 .. $ball000]
{
self.movechain.frame=self.frame;
if(self.frame==$ball000)
{
self.think=self.th_run;
self.nextthink=0.05;
}
}
void pent_explode ()
{
if(self.movechain!=world)
if(self.movechain.model=="models/pent.mdl")
remove(self.movechain);
sound(self,CHAN_BODY,"weapons/expsmall.wav",1,ATTN_NORM);
MultiExplode();
}
void pent_hit ()
{
vector hitdir;
//float grab;
if(other.takedamage&&other.classname!="monster_pentacles")
pent_explode();
else if(other.solid==SOLID_BSP&&self.safe_time<time)
{
/* if(self.movedir=='0 0 0')
{
if(self.velocity=='0 0 0')
objerror("Pentacles: no velocity on hit!!!\n");
}*/
hitdir=normalize(self.velocity);
self.velocity='0 0 0';
tracearea(self.origin,self.origin+hitdir*64,self.mins*0.5,self.maxs*0.5,TRUE,self);
if(trace_plane_normal=='0 0 0');
{
// dprint("trace_area failed, using traceline\n");
traceline(self.origin,self.origin+hitdir*64,TRUE,self);
}
/* if(trace_fraction==1)
dprint("ERROR: Hit wall, but it's not there!");
else if(trace_plane_normal=='0 0 0')
dprint("ERROR: Hit wall with no normal!");
else if('0 0 1' * trace_plane_normal > 0.3)
{
if(random()<0.2)//least chance- land on floor
grab = TRUE;
else
grab = FALSE;
}
else if('0 0 -1' * trace_plane_normal > 0.3)//best chance to land on ceiling
grab = TRUE;
else// if(random()<0.8)//50/50 chance to grab walls
grab = TRUE;
else
grab = FALSE;
if(grab)
{
*/
sound (self, CHAN_BODY, "pent/latch.wav", 1, ATTN_NORM);
self.frags=0;
// dprint("Grabbed new wall\n");
self.walldir='0 0 0' - trace_plane_normal;
if(self.walldir=='0 0 0')
setnewwalldir();
if(self.walldir=='0 0 0')
{
// dprint("WHAT THE FUCK!@!!!!!\n");
self.walldir='0 0 -1';
}
self.touch=SUB_Null;
self.movechain.avelocity='0 0 0';
self.movetype=MOVETYPE_STEP;
self.flags(+)FL_FLY;
self.pos1=self.pos2=self.origin;
face_movechain(FALSE);
self.think=pent_unball;
thinktime self : 0.05;
/* }
else
{
if(self.velocity=='0 0 0')
{
self.frags=0;
dprint("Grabbed new wall\n");
self.touch=SUB_Return;
self.movechain.avelocity='0 0 0';
self.movetype=MOVETYPE_STEP;
self.flags(+)FL_FLY;
self.think=setnewwalldir;
thinktime self : 0.05;
}
else
{
self.flags(-)FL_ONGROUND;
self.think=setnewwalldir;
thinktime self : 1.5;
}
}
*/
}
}
void pent_keep_vel ()
{
self.think=pent_keep_vel;
if(self.velocity!='0 0 0')
self.movedir=normalize(self.velocity);
else if(self.movedir)
self.velocity=self.movedir*500;
// else
// dprint("pent in air with no vel!\n");
thinktime self : 0.05;
}
void pent_ball () [++ $ball000 .. $ball010]
{
self.movechain.frame=self.frame;
if(self.velocity!='0 0 0')
self.movedir=normalize(self.velocity);
else if(self.movedir)
self.velocity=self.movedir*500;
// else//remdp
// dprint("pent in air with no vel!\n");
if(self.frame==$ball010)
{
self.think=pent_keep_vel;
thinktime self : 0;
// self.think=self.th_run;
// self.nextthink=-1;
}
}
void pent_throw () [++ $lunge000 .. $lunge010]
{//FIXME: Prepare- go into a ball
self.movechain.frame=self.frame;
if(self.movetype!=MOVETYPE_STEP)
return;
// dprint("Throwing self\n");
if(self.frame==$lunge010)
{
self.safe_time=time+0.05;
sound (self, CHAN_VOICE, "pent/jump.wav", 1, ATTN_NORM);
self.movetype=MOVETYPE_BOUNCE;
self.flags(-)FL_FLY;
if(self.frags>1)
{
self.velocity_z=800*(self.frags/200);
self.movechain.avelocity=randomv('-300 -300 -300','300 300 300');
self.think=pent_ball;
thinktime self : 0.05;
}
else if(self.frags==1&&!visible(self.enemy))
{
self.weaponframe_cnt=0;
self.velocity=('0 0 0' - self.walldir)*500+'0 0 150';
self.movechain.avelocity=randomv('-300 -300 -300','300 300 300');
self.think=pent_ball;
thinktime self : 0.05;
}
else
{
self.weaponframe_cnt=0;
self.velocity=normalize(self.enemy.origin+self.enemy.view_ofs-self.origin)*500+'0 0 150';
self.movechain.angles=vectoangles(self.velocity);
self.movechain.angles_y=0;
self.movechain.angles_z-=90;
self.movechain.avelocity_z=random()*600 - 300;
self.think=pent_keep_vel;
thinktime self : 0;
// self.think=self.th_run;
// self.nextthink=-1;
}
self.pain_finished = time + 7;
self.flags(-)FL_ONGROUND;
self.touch=pent_hit;
}
}
void pent_fly () [++ $lunge000 .. $lunge010]
{
self.movechain.frame=self.frame;
if(self.movetype!=MOVETYPE_STEP)
return;
if(self.frame==$lunge010)
{
self.weaponframe_cnt=0;
self.safe_time=time+0.05;
sound (self, CHAN_VOICE, "pent/jump.wav", 1, ATTN_NORM);
self.movetype=MOVETYPE_BOUNCEMISSILE;//FLY;
self.flags(-)FL_FLY;
if(self.hull!=HULL_HYDRA)
{
// dprint("Hull fucked\n");
self.hull=HULL_HYDRA;
}
/* dprint("flying\n");
dprintv("origin: %s\n",self.origin);
dprintv("pos_ofs: %s\n",self.pos_ofs);
*/
self.velocity=normalize(self.pos_ofs-self.origin)*800;
// dprintv("velocity: %s\n",self.velocity);
self.movechain.angles=vectoangles(self.velocity);
self.movechain.angles_y=0;
self.movechain.angles_z-=90;
self.movechain.avelocity_z=random()*600 - 300;
self.think=pent_keep_vel;
thinktime self : 0;
// self.think=self.th_run;
// self.nextthink=-1;
self.pain_finished = time + 7;
self.flags(-)FL_ONGROUND;
self.touch=pent_hit;
}
}
void pent_find_near_wall ()
{
float try_cnt,foundwall,enemy_dist;
vector dest_spot;
enemy_dist=vlen(self.enemy.origin-self.origin);
if(enemy_dist>512)
{
self.think=self.th_run;
thinktime self : 0;
return;
}
while(!foundwall&&try_cnt<10)
{
dest_spot=normalize(self.enemy.origin+self.enemy.view_ofs-self.origin);
dest_spot=vectoangles(dest_spot);
makevectors(dest_spot);
dest_spot=v_forward+v_right*(random() - 0.5)+v_up*(random() - 0.5);
dest_spot=self.origin+dest_spot*(enemy_dist*1.2);
tracearea(self.origin,dest_spot,self.mins,self.maxs,FALSE,self);
if(trace_ent.solid==SOLID_BSP&&trace_fraction<1)
foundwall=TRUE;
else
try_cnt+=1;
}
if(try_cnt>=10||trace_endpos==self.origin)
{
self.think=self.th_run;
thinktime self : 0;
return;
}
self.pos_ofs=trace_endpos;
pent_fly();
}
void() pent_spitball =
{
entity missile;
self.effects(+)EF_MUZZLEFLASH;
missile=spawn();
missile.classname="acid missile";
missile.owner=self;
missile.drawflags(+)SCALE_ORIGIN_CENTER|MLS_FIREFLICKER;
missile.scale=.7;
missile.abslight=1;
missile.frags=FALSE;
missile.movetype=MOVETYPE_FLYMISSILE;
missile.solid=SOLID_BBOX;
missile.touch=BloodMissileTouch;
missile.dmg=random(2,7)*skill+1;
missile.speed=800;
missile.velocity=normalize(self.enemy.origin+self.enemy.proj_ofs - self.origin)*missile.speed+aim_adjust(self.enemy);
missile.avelocity=randomv('0 0 -400','0 0 400');
missile.movedir=normalize(missile.velocity);
missile.angles=vectoangles(missile.velocity);
setmodel(missile,"models/sucwp1p.mdl");
// setmodel(missile,"models/sucwp2p.mdl");
setsize(missile,'0 0 0','0 0 0');
setorigin(missile,self.origin/*+v_forward*8*/);
sound(missile,CHAN_AUTO,"pent/fire.wav",1,ATTN_NORM);
missile.think=SUB_Remove;//AcidMissileFade;
thinktime missile : 2;
};
void pent_spit () [++ $spit000 .. $spit010]
{
self.movechain.frame=self.frame;
if(self.frame==$spit010)
{
pent_spitball();
self.th_run();
}
}
void pent_deflate () [++ $ball000 .. $ball010]//fixme: death frames?
{
if(self.frame==$ball010)
{
self.movetype=MOVETYPE_BOUNCE;//was _STEP
self.flags(-)FL_FLY;
MakeSolidCorpse();
}
}
void pent_die ()
{
if(self.health<-20||self.health>0)
pent_explode();
else
{
setmodel (self, "models/pent.mdl");
if(self.movechain!=world)
if(self.movechain.model=="models/pent.mdl")
{
self.frame=self.movechain.frame;
self.angles=self.movechain.angles;
}
self.scale=1.7;
self.effects(-)EF_NODRAW;
if(self.movechain!=world)
if(self.movechain.model=="models/pent.mdl")
remove(self.movechain);
sound (self, CHAN_VOICE, "pent/die.wav", 1, ATTN_NORM);
pent_deflate();
}
}
float MAX_PENTJUMP = 256;
float pent_check_attack()
{
vector spot1, spot2;
entity targ;
float chance,targ_range;
targ = self.enemy;
// see if any entities are in the way of the shot
spot1 = self.origin;
spot2 = (targ.absmin+targ.absmax)*0.5;
traceline (spot1, spot2, FALSE, self);
if(trace_ent.thingtype>=THINGTYPE_WEBS)
traceline (trace_endpos, spot2, FALSE, trace_ent);
if (trace_ent != targ)
if(trace_ent.health>25||!trace_ent.takedamage||(trace_ent.flags&FL_MONSTER&&trace_ent.classname!="player_sheep"))
return FALSE;//Don't have a clear shot, and don't want to shoot obstruction
//FIXME: check for translucent water?
// if (trace_inopen && trace_inwater)
// return FALSE; // sight line crossed contents
targ_range = vlen(self.enemy.origin+self.enemy.view_ofs - self.origin);
if(self.movetype==MOVETYPE_STEP)
{
chance=random()*MAX_PENTJUMP;
if(chance > targ_range&&random()>0.8)//checks 20 times a second, so may jump once every sec, max
{ // melee attack
self.th_melee ();
return TRUE;
}
}
//FIXME: check for darkness, maybe won't fire, maybe aim will be off
// missile attack
if (time < self.attack_finished)
return FALSE;
if (enemy_range == RANGE_MELEE)
{
chance = 0.9;
self.attack_finished = 0;
}
else if (enemy_range == RANGE_NEAR)
{
chance = 0.3;
}
else if (enemy_range == RANGE_MID)
chance = 0.15;
else
chance = 0.05;
if(skill>0)
chance*=skill;
if (random () < chance)
{
self.th_missile ();
SUB_AttackFinished (random(0,3 - skill));
return TRUE;
}
else if(targ_range<=random(384,512)&&random()<0.5+(skill/5))
{
pent_find_near_wall();
SUB_AttackFinished (random(0,2 - (skill/2)));
return TRUE;
}
return FALSE;
}
float MAX_PENTDIST = 32;
void pent_check_wall_change ()
{
self.pos2=self.origin;
if(self.pos2!=self.pos1)
{
// dprint("Checking pos change\n");
self.movedir=normalize(self.pos2-self.pos1)*32;
tracearea(self.origin,self.origin+self.movedir,self.mins*0.5,self.maxs*0.5,FALSE,self);
if(trace_fraction<1&&trace_plane_normal!='0 0 0'&&trace_ent.solid==SOLID_BSP)
{
// dprintv("New wall, normal : %s\n",trace_plane_normal);
self.walldir='0 0 0'-trace_plane_normal;
setorigin(self,trace_endpos-self.walldir*vlen(self.size)*0.5);
}
/* else if(trace_allsolid)
dprint("trace entirely in wall\n");
else if(trace_startsolid)
dprint("trace started in wall\n");
else if(trace_fraction>=1)
dprint("Trace is 1\n");
else if(trace_plane_normal=='0 0 0')
dprint("No normal for plane\n");
else
{
dprint(trace_ent.classname);
dprint(" not solid_bsp\n");
}
*/ }
// else
// dprint("Didn't move!\n");
self.pos1=self.origin;
}
void offset_movechain ()
{
vector offset;
float ofs_dist,dot;
if(self.movechain!=world)
if(self.movechain.model=="models/pent.mdl")
makevectors(self.movechain.angles);
dot=v_up*'0 0 -1';
ofs_dist=8+8*dot;
offset=v_up*ofs_dist;
if(self.movechain!=world)
if(self.movechain.model=="models/pent.mdl")
setorigin(self.movechain,self.origin+offset);
}
void face_movechain (float do_move)
{
if(self.movetype!=MOVETYPE_STEP)
return;
if(self.movechain==world)
remove(self);
if(self.movechain.model!="models/pent.mdl")
remove(self);
float dist;
//vector new_angles,new_angles2,forward1;
// traceline(self.origin,self.origin+self.walldir*64,TRUE,self);
if(self.walldir=='0 0 0')
{
setnewwalldir();
// dprint("ERROR: Pent wall dir is zero!!!\n");
//self.nextthink = -1;
//self.think=SUB_Return;
//self.effects(+)EF_DIMLIGHT;
}
else if(pointcontents(self.origin)==CONTENT_SOLID)
{
// dprint("ERROR: Pent in wall!!!\n");
setorigin(self,self.oldorigin);
// self.nextthink = -1;
// self.think=SUB_Return;
// self.effects(+)EF_DIMLIGHT;
}
else
{
if(do_move)
tracearea(self.origin,self.origin+self.walldir*MAX_PENTDIST,self.mins,self.maxs,FALSE,self);
else
traceline(self.origin,self.origin+self.walldir*MAX_PENTDIST,TRUE,self);
//FIXME - look back a little... oldorigin?
// if(trace_fraction==1)
// self.movedir = normalize(self.oldorigin - self.origin) + self.walldir;
// tracearea(self.origin,self.origin+self.movedir*64,self.mins,self.maxs,FALSE,self);
dist=trace_fraction*MAX_PENTDIST;
if(trace_allsolid||trace_startsolid)//||trace_plane_normal=='0 0 0')
dist=0;
if(trace_plane_normal=='0 0 0')
dist=MAX_PENTDIST;
if(trace_ent.solid==SOLID_BSP&&dist>self.speed&&dist<MAX_PENTDIST)
{//Fixme: do a movestep here instead...
// dprint("Moving along wall\n");
if(do_move)
{
setorigin(self,trace_endpos);//self.origin+self.walldir*dist);
pent_check_wall_change();
}
self.movechain.angles='0 0 0';
matchAngleToSlope(trace_plane_normal,self.movechain);
//offset_movechain();
// new_angles = vectoangles(trace_plane_normal);
// makevectors(self.movechain.angles);//was new_angles
// forward1 = self.movedir - v_forward;
// new_angles2 = vectoangles(forward1);
// new_angles2 *=-1;
// self.movechain.angles += new_angles2;
// self.movechain.angles=new_angles;
// self.movechain.angles=vectoangles(self.movedir);
}
else if(dist>=MAX_PENTDIST)
{
// dprint("Ran out of wall!\n");
self.pos1=self.pos2='0 0 0';
self.frags=TRUE;//Grab next wall
self.th_melee();
}
else if(dist<=self.speed)
{
if(do_move)
pent_check_wall_change();
self.movechain.angles='0 0 0';
matchAngleToSlope(trace_plane_normal,self.movechain);
//offset_movechain();
// new_angles = vectoangles(trace_plane_normal);
// makevectors(self.movechain.angles);//was new_angles
// forward1 = self.movedir - v_forward;
// new_angles2 = vectoangles(forward1);
// new_angles2_y *=-1;
// self.movechain.angles += new_angles2;
// self.movechain.angles=new_angles;
// self.movechain.angles=vectoangles(self.movedir);
}
if(self.level==666)
{
self.movechain.avelocity='0 100 0';
self.think=SUB_Return;
thinktime self: -1;
}
}
}
void pent_up_down (float movespeed)
{
float goalheight,dot,goaldist;
makevectors(self.angles);
dot='0 0 1'*self.walldir;
if(dot<-0.7&&random()<0.3&&self.weaponframe_cnt+3<time)//on a almost flat surface, try to jump to cieling every three seconds
{//Make them do this if can't see enemy?
traceline(self.origin,self.origin+'0 0 512',FALSE,self);
if(trace_fraction<1&&trace_ent.solid==SOLID_BSP)//Roof within 132 above
{//Jump to ceiling
self.weaponframe_cnt=time;
self.frags=trace_fraction*512;
self.th_melee();
}
}
else if(dot<0.5&&dot>-0.5)//If on a 45 degree slope or more
if(visible(self.enemy))//if(visible(self.goalentity))
{
goalheight=self.enemy.origin_z+self.enemy.view_ofs_z;
if(goalheight!=self.origin_z)
{
goaldist=goalheight-self.origin_z;
if(fabs(goaldist)>movespeed)
if(goaldist>0)
goaldist=movespeed;
else
goaldist=0 - movespeed;
movestep(0,0,goaldist, FALSE);
}
}
else if(self.t_width>time)//Last dir change
{//This is getting canceled out in C- C FL_FLY monsters do a Z move towards goal!
// dprintf("Moving %s\n",self.level);
self.flags(-)FL_NOZ;
if(!movestep(0,0,self.level, FALSE))
self.t_width=0;
else
self.flags(+)FL_NOZ;
}
else
{
self.flags(-)FL_NOZ;
if(random()<0.5)
{
if(random()<0.8)
{
if(!movestep(0,0,movespeed, FALSE))
{
if(movestep(0,0,0 - movespeed, FALSE)&&random()<0.5)
{
self.level=0 - movespeed;
self.t_width=time+7;
self.flags(+)FL_NOZ;
}
}
else
{
self.level=movespeed;
self.t_width=time+7;
self.flags(+)FL_NOZ;
}
}
else if(!movestep(0,0,0 - movespeed, FALSE))
{
if(movestep(0,0,movespeed, FALSE))
{
self.level=movespeed;
self.t_width=time+7;
self.flags(+)FL_NOZ;
}
}
else
{
self.level=0 - movespeed;
self.t_width=time+7;
self.flags(+)FL_NOZ;
}
}
else if(visible(self.goalentity))//if(visible(self.goalentity))
{
goalheight=self.goalentity.origin_z+self.goalentity.view_ofs_z;
if(goalheight!=self.origin_z)
{
goaldist=goalheight-self.origin_z;
if(fabs(goaldist)>movespeed)
if(goaldist>0)
goaldist=movespeed;
else
goaldist=0 - movespeed;
movestep(0,0,goaldist, FALSE);
}
}
}
}
void pent_run () [++ $walk000 .. $walk015]
{
if(self.movetype==MOVETYPE_STEP)
{
self.movechain.frame=self.frame;
self.velocity='0 0 0';
// self.flags(-)FL_ONGROUND;
if(self.frame>$walk008 &&self.frame<=$walk015)
{
// self.pos1=self.origin;
ai_run(self.speed);
if(self.flags&FL_ONGROUND&&'0 0 -1'*self.walldir>0.75)
{
traceline(self.origin,self.origin - '0 0 64',TRUE,self);
if(trace_plane_normal!='0 0 0')
self.walldir = '0 0 0' - trace_plane_normal;
// dprintv("On ground, New walldir = %s\n",self.walldir);
}
if(random()<0.5)
pent_up_down(self.speed);
face_movechain(TRUE);
}
}
else if(self.movetype==MOVETYPE_BOUNCE&&(self.velocity=='0 0 0'||self.pain_finished<time))
{
// dprint("Fixing bounce\n");
self.touch=SUB_Return;
self.velocity='0 0 0';
self.movechain.avelocity='0 0 0';
self.flags(-)FL_ONGROUND;
self.movetype=MOVETYPE_STEP;
self.flags(+)FL_FLY;
setnewwalldir();
}
}
void pent_walk () [++ $walk000 .. $walk015]
{
if(self.movetype==MOVETYPE_STEP)
{
self.movechain.frame=self.frame;
self.velocity='0 0 0';
// self.flags(-)FL_ONGROUND;
if(self.frame>$walk008 &&self.frame<=$walk015)
{
// self.pos1=self.origin;
ai_walk(self.speed/2);
if(self.flags&FL_ONGROUND&&'0 0 -1'*self.walldir>0.75)
{
traceline(self.origin,self.origin - '0 0 64',TRUE,self);
if(trace_plane_normal!='0 0 0')
self.walldir = '0 0 0' - trace_plane_normal;
// dprintv("On ground, New walldir = %s\n",self.walldir);
}
if(random()<0.5)
pent_up_down(self.speed/2);
face_movechain(TRUE);
}
}
}
void pent_stand () [++ $ready000 .. $ready015]
{
if(self.movetype==MOVETYPE_STEP)
{
self.movechain.frame=self.frame;
self.velocity='0 0 0';
self.flags(-)FL_ONGROUND;
// self.pos1=self.origin;
ai_stand();
face_movechain(TRUE);
}
}
/*QUAKED monster_pentacles (1 0 0) (-8 -8 -8) (8 8 8) STATIONARY ONESURF NOFLOOR NOJUMP NOSPIT
All sides must be at least 8 away from the walls
'speed' (default = 8)
'experience_value' default = 100
skin
0 (default) = Brown Rocky
1 = White Snowy
The following are not implemented- if you want them implemented, let me know, otherwise, they will not be.
STATIONARY - Will not move from it's spot
ONESURF - Will not move from it's current wall or surface to a new one
NOFLOOR - Will not move around on the floor
NOJUMP - Will not jump off the walls
NOSPIT - Will not shoot
*/
void() monster_pentacles =
{
if (deathmatch)
{
remove(self);
return;
}
if(!self.th_init)
{
self.th_init=monster_pentacles;
self.init_org=self.origin;
}
if (!self.flags2 & FL_SUMMONED&&!self.flags2&FL2_RESPAWN)
{
precache_model4 ("models/pent.mdl");
precache_model4 ("models/sucwp1p.mdl");
// precache_model4 ("models/sucwp2p.mdl");
precache_model4 ("models/tempmetr.mdl");//temp- meteor projectile
precache_sound4 ("succubus/blobexpl.wav");
precache_sound4 ("succubus/dropfizz.wav");
precache_sound4 ("succubus/brnwall.wav");
precache_sound4 ("succubus/brnhit.wav");
precache_sound4 ("succubus/brnfire.wav");
precache_sound4 ("pent/fire.wav");
precache_sound4 ("pent/jump.wav");
precache_sound4 ("pent/die.wav");
precache_sound4 ("pent/pain.wav");
precache_sound4 ("pent/latch.wav");
}
self.solid = SOLID_PHASE;
self.movetype = MOVETYPE_STEP;
if(self.skin==1)
self.thingtype = THINGTYPE_ICE;
else
self.thingtype = THINGTYPE_BROWNSTONE;
if(!self.experience_value)
self.experience_value = 100;
setmodel (self, "models/null.spr");
self.effects=EF_NODRAW;
self.movechain=spawn();
setmodel (self.movechain, "models/pent.mdl");
self.movechain.solid=SOLID_NOT;
self.movechain.movetype=MOVETYPE_NOCLIP;
setsize(self.movechain,'0 0 0','0 0 0');
self.movechain.hull=HULL_POINT;
setorigin(self.movechain,self.origin);
self.movechain.angles=self.angles;
self.movechain.owner=self;
self.movechain.scale=1.7;
self.movechain.skin=self.skin;
setsize (self, '-8 -8 -8', '8 8 8');
self.hull=HULL_HYDRA;
if(!self.health)
self.health = 40 + skill * 10;
if(!self.max_health)
self.max_health=self.health;
self.mass = 25;
self.dmg = 50 + skill*20;
if(coop)
self.dmg+=20;//chunks don't do damage
self.th_stand = pent_stand;
self.th_walk = pent_walk;
self.th_run = pent_run;
self.th_missile = pent_spit;
self.th_melee = pent_throw;
self.th_pain = pent_pain;
self.th_die = pent_die;
self.takedamage=DAMAGE_YES;
self.flags2(+)FL_ALIVE;
total_monsters = total_monsters + 1;
self.ideal_yaw = self.angles * '0 1 0';
self.yaw_speed = 10;
if(!self.speed)
self.speed = 8;
self.use = monster_use;
self.pos1=self.pos2=self.origin;
self.init_exp_val = self.experience_value;
self.flags(+)FL_FLY;
self.flags(+)FL_MONSTER;
self.flags(+)FL_HUNTFACE|FL_SET_TRACE;
self.nextthink+=random(0.5);
self.think = flymonster_start_go;
};