587 lines
16 KiB
Text
587 lines
16 KiB
Text
// gesture effects
|
|
|
|
Class LoveHeartTrail : Actor
|
|
{
|
|
Default
|
|
{
|
|
RenderStyle "Add";
|
|
Radius .1;
|
|
Height 0.;
|
|
Alpha .1;
|
|
+NOGRAVITY;
|
|
+NOBLOCKMAP;
|
|
+NOINTERACTION;
|
|
+DONTSPLASH;
|
|
+NOTELEPORT;
|
|
+FORCEXYBILLBOARD;
|
|
}
|
|
override void Tick()
|
|
{
|
|
if ( isFrozen() ) return;
|
|
A_FadeOut(.01);
|
|
scale *= .95;
|
|
}
|
|
States
|
|
{
|
|
Spawn:
|
|
DOKI A -1 Bright;
|
|
Stop;
|
|
}
|
|
}
|
|
|
|
Class LoveHeartSparkle : Actor
|
|
{
|
|
Default
|
|
{
|
|
Radius .1;
|
|
Height 0.;
|
|
Scale .03;
|
|
+NOGRAVITY;
|
|
+NOBLOCKMAP;
|
|
+NOINTERACTION;
|
|
+DONTSPLASH;
|
|
+NOTELEPORT;
|
|
+FORCEXYBILLBOARD;
|
|
}
|
|
override void PostBeginPlay()
|
|
{
|
|
Scale *= FRandom[ExploS](.75,1.5);
|
|
specialf1 = FRandom[ExploS](.95,.98);
|
|
specialf2 = FRandom[ExploS](.01,.03);
|
|
vel = SWWMUtility.Vec3FromAngles(angle,pitch)*FRandom[ExploS](2,8);
|
|
}
|
|
override void Tick()
|
|
{
|
|
if ( isFrozen() ) return;
|
|
A_SetScale(scale.x*specialf1);
|
|
A_FadeOut(specialf2);
|
|
Vector3 dir = vel;
|
|
double magvel = dir.length();
|
|
magvel *= .99;
|
|
if ( magvel > 0. )
|
|
{
|
|
dir /= magvel;
|
|
dir += .2*SWWMUtility.Vec3FromAngles(FRandom[ExploS](0,360),FRandom[ExploS](-90,90));
|
|
vel = dir.unit()*magvel;
|
|
}
|
|
SetOrigin(level.Vec3Offset(pos,vel),true);
|
|
}
|
|
States
|
|
{
|
|
Spawn:
|
|
DOKI A -1 Bright;
|
|
Stop;
|
|
}
|
|
}
|
|
|
|
Class LoveHeartBurstLight : PaletteLight
|
|
{
|
|
Default
|
|
{
|
|
Tag "LovePal";
|
|
ReactionTime 15;
|
|
Args 0,0,0,150;
|
|
}
|
|
}
|
|
|
|
Class LoveHeart : Actor
|
|
{
|
|
Default
|
|
{
|
|
Obituary "$O_DOKIDOKI";
|
|
DamageType 'Love';
|
|
DamageFunction (clamp(special2,5,15));
|
|
Radius 4;
|
|
Height 4;
|
|
Speed 10;
|
|
Scale .2;
|
|
PROJECTILE;
|
|
+BLOODLESSIMPACT;
|
|
+FORCEXYBILLBOARD;
|
|
+SEEKERMISSILE;
|
|
+FOILINVUL;
|
|
+PAINLESS;
|
|
+NODAMAGETHRUST;
|
|
}
|
|
|
|
override int DoSpecialDamage( Actor target, int damage, Name damagetype )
|
|
{
|
|
bEXTREMEDEATH = false;
|
|
bNOEXTREMEDEATH = false;
|
|
SWWMStats s = null;
|
|
if ( Demolitionist(self.target) ) s = Demolitionist(self.target).mystats;
|
|
if ( s ) s.smooch++;
|
|
let raging = RagekitPower(self.target.FindInventory("RagekitPower"));
|
|
if ( (target is 'WolfensteinSS') || (target.Species == 'WolfensteinSS') ) target.bFRIENDLY = false;
|
|
if ( target.IsFriend(self.target) || SWWMUtility.IdentifyingDog(target) )
|
|
{
|
|
int healamt = clamp(special2,5,15);
|
|
if ( raging )
|
|
{
|
|
healamt *= 8;
|
|
raging.DoHitFX();
|
|
}
|
|
if ( target.GiveBody(healamt,target.GetSpawnHealth()) )
|
|
SWWMHandler.DoFlash(target,Color(32,224,128,255),10);
|
|
if ( SWWMUtility.IdentifyingDog(target) )
|
|
{
|
|
// befriend good doggo
|
|
if ( target.bCOUNTKILL )
|
|
{
|
|
target.bCOUNTKILL = false;
|
|
level.total_monsters--;
|
|
}
|
|
if ( !target.bFRIENDLY && s )
|
|
s.befriend++;
|
|
target.bFRIENDLY = true;
|
|
if ( deathmatch )
|
|
target.SetFriendPlayer(self.target.player);
|
|
}
|
|
return 0;
|
|
}
|
|
Vector3 dirto = level.Vec3Diff(pos,target.Vec3Offset(0,0,target.Height/2)).unit();
|
|
SWWMUtility.DoKnockback(target,dirto,1500.*damage);
|
|
let bread = target.FindState("Pain");
|
|
if ( bread ) target.SetState(bread);
|
|
if ( raging )
|
|
{
|
|
damage *= 8;
|
|
raging.DoHitFX();
|
|
}
|
|
if ( (target is 'WolfensteinSS') || (target.Species == 'WolfensteinSS') )
|
|
{
|
|
damage = int.max;
|
|
bEXTREMEDEATH = true;
|
|
}
|
|
else if ( target is 'SWWMHangingKeen' )
|
|
damage = max(target.Health,damage); // rescued by love :3
|
|
else if ( SWWMHDoomHandler.IsCuteGirl(target) )
|
|
{
|
|
// no cute demon girl can resist demo's charm
|
|
damage = max(target.Health,damage);
|
|
bNOEXTREMEDEATH = true;
|
|
}
|
|
return damage;
|
|
}
|
|
|
|
override int SpecialMissileHit( Actor victim )
|
|
{
|
|
if ( !victim.bSHOOTABLE && (victim != tracer) ) return 1;
|
|
if ( tracer && (victim != tracer) ) return 1;
|
|
return -1;
|
|
}
|
|
|
|
action void A_HeartTick()
|
|
{
|
|
special1++;
|
|
if ( !(special1%3) && (special2 > 0) ) special2--;
|
|
A_SetScale(.2+.02*sin(special1*.25*GameTicRate));
|
|
double magvel = vel.length();
|
|
if ( magvel > 0 )
|
|
{
|
|
Vector3 dir = vel/magvel;
|
|
vel = dir*min(30,magvel*1.1);
|
|
}
|
|
double steppy = vel.length()/4.;
|
|
for ( int i=2; i<6; i++ )
|
|
{
|
|
Vector3 dir2 = vel.unit();
|
|
let t = Spawn("LoveHeartTrail",level.Vec3Offset(pos,-dir2*steppy*i));
|
|
t.scale = scale;
|
|
}
|
|
int numpt = Random[ExploS](1,3);
|
|
for ( int i=0; i<numpt; i++ )
|
|
{
|
|
let s = Spawn("LoveHeartSparkle",pos);
|
|
s.angle = FRandom[ExploS](0,360);
|
|
s.pitch = FRandom[ExploS](-90,90);
|
|
}
|
|
if ( !tracer || (tracer.Health <= 0) ) return;
|
|
double mag = vel.length();
|
|
vel = mag*(level.Vec3Diff(pos,tracer.Vec3Offset(0,0,tracer.height/2)).unit()*mag*6./GameTicRate+vel).unit();
|
|
}
|
|
override void PostBeginPlay()
|
|
{
|
|
Super.PostBeginPlay();
|
|
A_StartSound("misc/heart",CHAN_WEAPON);
|
|
A_AttachLight('LOVELIGHT',DynamicLight.PointLight,Color(255,176,208),80,80,DYNAMICLIGHT.LF_ATTENUATE);
|
|
special2 = 25;
|
|
}
|
|
void CheckDefaceTexture()
|
|
{
|
|
TextureID HitTexture;
|
|
Line HitLine;
|
|
int LineSide, LinePart;
|
|
Sector HitSector;
|
|
F3DFloor Hit3DFloor;
|
|
bool HitCeiling;
|
|
if ( BlockingLine )
|
|
{
|
|
HitLine = BlockingLine;
|
|
// which side and part we hit?
|
|
LineSide = SWWMUtility.PointOnLineSide(pos.xy,BlockingLine);
|
|
double fl, cl;
|
|
if ( BlockingLine.sidedef[1] )
|
|
{
|
|
fl = max(BlockingLine.frontsector.floorplane.ZAtPoint(pos.xy),BlockingLine.backsector.floorplane.ZAtPoint(pos.xy));
|
|
cl = min(BlockingLine.frontsector.ceilingplane.ZAtPoint(pos.xy),BlockingLine.backsector.ceilingplane.ZAtPoint(pos.xy));
|
|
if ( max(floorz,pos.z) < fl ) LinePart = 2;
|
|
else if ( min(ceilingz,pos.z+height) > cl ) LinePart = 0;
|
|
else LinePart = 1;
|
|
}
|
|
else
|
|
{
|
|
LinePart = 1; // always middle
|
|
LineSide = 0;
|
|
}
|
|
if ( Blocking3DFloor )
|
|
{
|
|
Sector sec = LineSide?BlockingLine.frontsector:BlockingLine.backsector;
|
|
for ( int i=0; i<sec.Get3DFloorCount(); i++ )
|
|
{
|
|
F3DFloor ff = sec.Get3DFloor(i);
|
|
if ( ff.model != Blocking3DFloor ) continue;
|
|
Hit3DFloor = ff;
|
|
break;
|
|
}
|
|
if ( Hit3DFloor )
|
|
{
|
|
if ( Hit3DFloor.flags&F3DFloor.FF_UPPERTEXTURE ) HitTexture = HitLine.sidedef[LineSide].GetTexture(0);
|
|
else if ( Hit3DFloor.flags&F3DFloor.FF_LOWERTEXTURE ) HitTexture = HitLine.sidedef[LineSide].GetTexture(2);
|
|
}
|
|
}
|
|
else HitTexture = HitLine.sidedef[LineSide].GetTexture(LinePart);
|
|
}
|
|
else if ( BlockingCeiling )
|
|
{
|
|
if ( Blocking3DFloor )
|
|
{
|
|
for ( int i=0; i<BlockingCeiling.Get3DFloorCount(); i++ )
|
|
{
|
|
F3DFloor ff = BlockingCeiling.Get3DFloor(i);
|
|
if ( ff.model != Blocking3DFloor ) continue;
|
|
Hit3DFloor = ff;
|
|
break;
|
|
}
|
|
}
|
|
HitSector = BlockingCeiling;
|
|
HitCeiling = true;
|
|
HitTexture = ceilingpic;
|
|
}
|
|
else if ( BlockingFloor )
|
|
{
|
|
if ( Blocking3DFloor )
|
|
{
|
|
for ( int i=0; i<BlockingFloor.Get3DFloorCount(); i++ )
|
|
{
|
|
F3DFloor ff = BlockingFloor.Get3DFloor(i);
|
|
if ( ff.model != Blocking3DFloor ) continue;
|
|
Hit3DFloor = ff;
|
|
break;
|
|
}
|
|
}
|
|
HitSector = BlockingFloor;
|
|
HitCeiling = false;
|
|
HitTexture = floorpic;
|
|
}
|
|
bool remove;
|
|
TextureID replacewith;
|
|
[remove, replacewith] = SWWMUtility.DefaceTexture(HitTexture);
|
|
if ( !remove ) return;
|
|
A_StartSound("bestsound",CHAN_ITEMEXTRA,CHANF_OVERLAP);
|
|
if ( target && target.player )
|
|
{
|
|
int scr = (TexMan.GetName(HitTexture).Left(6)~=="ZZWOLF")?200:20;
|
|
if ( scr == 20 ) SWWMUtility.AchievementProgressInc("doodle",1,player);
|
|
SWWMCredits.Give(target.player,scr);
|
|
if ( target.player == players[consoleplayer] ) SWWMScoreObj.Spawn(scr,pos);
|
|
}
|
|
if ( HitLine )
|
|
{
|
|
if ( Hit3DFloor )
|
|
{
|
|
// TODO connected textures for upper/lower
|
|
if ( Hit3DFloor.flags&F3DFloor.FF_UPPERTEXTURE ) HitLine.sidedef[LineSide].SetTexture(0,replacewith);
|
|
else if ( Hit3DFloor.flags&F3DFloor.FF_LOWERTEXTURE ) HitLine.sidedef[LineSide].SetTexture(2,replacewith);
|
|
else Hit3DFloor.master.sidedef[0].SetTexture(1,replacewith);
|
|
}
|
|
else
|
|
{
|
|
// find connected sidedefs with the same texture
|
|
Array<Line> con;
|
|
con.Clear();
|
|
con.Push(HitLine);
|
|
Sector s = LineSide?HitLine.backsector:HitLine.frontsector;
|
|
int found = 0;
|
|
do
|
|
{
|
|
found = 0;
|
|
for ( int i=0; i<s.Lines.Size(); i++ )
|
|
{
|
|
let l = s.Lines[i];
|
|
if ( !l.sidedef[LineSide] || (l.sidedef[LineSide].GetTexture(LinePart) != HitTexture) )
|
|
continue;
|
|
if ( con.Find(l) < con.Size() ) continue;
|
|
bool notmatched = true;
|
|
for ( int j=0; j<con.Size(); j++ )
|
|
{
|
|
if ( (l.v1 != con[j].v1) && (l.v2 != con[j].v2) && (l.v1 != con[j].v2) && (l.v2 != con[j].v1) )
|
|
continue;
|
|
notmatched = false;
|
|
break;
|
|
}
|
|
if ( notmatched ) continue;
|
|
con.Push(l);
|
|
found++;
|
|
}
|
|
}
|
|
while ( found > 0 );
|
|
for ( int i=0; i<con.Size(); i++ )
|
|
con[i].sidedef[LineSide].SetTexture(LinePart,replacewith);
|
|
}
|
|
}
|
|
else if ( HitSector && HitCeiling )
|
|
{
|
|
if ( Hit3DFloor )
|
|
{
|
|
if ( Hit3DFloor.flags&F3DFloor.FF_INVERTSECTOR ) Hit3DFloor.model.SetTexture(1,replacewith);
|
|
else Hit3DFloor.model.SetTexture(0,replacewith);
|
|
}
|
|
else
|
|
{
|
|
// find connected sectors with the same ceiling texture (THIS IS VERY UGLY CODE)
|
|
Array<Sector> con;
|
|
con.Clear();
|
|
con.Push(HitSector);
|
|
int found;
|
|
do
|
|
{
|
|
found = 0;
|
|
for ( int i=0; i<con.Size(); i++ )
|
|
{
|
|
Sector s = con[i];
|
|
for ( int j=0; j<s.Lines.Size(); j++ )
|
|
{
|
|
Line l = s.Lines[j];
|
|
// only check two-sided
|
|
if ( !l.sidedef[1] ) continue;
|
|
// don't check if there's a height difference
|
|
if ( (l.frontsector.ceilingplane.ZAtPoint(l.v1.p) != l.backsector.ceilingplane.ZAtPoint(l.v1.p))
|
|
|| (l.frontsector.ceilingplane.ZAtPoint(l.v2.p) != l.backsector.ceilingplane.ZAtPoint(l.v2.p)) )
|
|
continue;
|
|
if ( (l.frontsector.GetTexture(1) == HitTexture) && (con.Find(l.frontsector) >= con.Size()) )
|
|
{
|
|
found++;
|
|
con.Push(l.frontsector);
|
|
}
|
|
if ( (l.backsector.GetTexture(1) == HitTexture) && (con.Find(l.backsector) >= con.Size()) )
|
|
{
|
|
found++;
|
|
con.Push(l.backsector);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
while ( found > 0 );
|
|
for ( int i=0; i<con.Size(); i++ )
|
|
con[i].SetTexture(1,replacewith);
|
|
}
|
|
}
|
|
else if ( HitSector && !HitCeiling )
|
|
{
|
|
if ( Hit3DFloor )
|
|
{
|
|
if ( Hit3DFloor.flags&F3DFloor.FF_INVERTSECTOR ) Hit3DFloor.model.SetTexture(0,replacewith);
|
|
else Hit3DFloor.model.SetTexture(1,replacewith);
|
|
}
|
|
else
|
|
{
|
|
// find connected sectors with the same floor texture (THIS IS VERY UGLY CODE)
|
|
Array<Sector> con;
|
|
con.Clear();
|
|
con.Push(HitSector);
|
|
int found;
|
|
do
|
|
{
|
|
found = 0;
|
|
for ( int i=0; i<con.Size(); i++ )
|
|
{
|
|
Sector s = con[i];
|
|
for ( int j=0; j<s.Lines.Size(); j++ )
|
|
{
|
|
Line l = s.Lines[j];
|
|
// only check two-sided
|
|
if ( !l.sidedef[1] ) continue;
|
|
// don't check if there's a height difference
|
|
if ( (l.frontsector.floorplane.ZAtPoint(l.v1.p) != l.backsector.floorplane.ZAtPoint(l.v1.p))
|
|
|| (l.frontsector.floorplane.ZAtPoint(l.v2.p) != l.backsector.floorplane.ZAtPoint(l.v2.p)) )
|
|
continue;
|
|
if ( (l.frontsector.GetTexture(0) == HitTexture) && (con.Find(l.frontsector) >= con.Size()) )
|
|
{
|
|
found++;
|
|
con.Push(l.frontsector);
|
|
}
|
|
if ( (l.backsector.GetTexture(0) == HitTexture) && (con.Find(l.backsector) >= con.Size()) )
|
|
{
|
|
found++;
|
|
con.Push(l.backsector);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
while ( found > 0 );
|
|
for ( int i=0; i<con.Size(); i++ )
|
|
con[i].SetTexture(0,replacewith);
|
|
}
|
|
}
|
|
}
|
|
action void A_HeartBurst()
|
|
{
|
|
invoker.CheckDefaceTexture();
|
|
// use line
|
|
if ( BlockingLine )
|
|
{
|
|
int s = SWWMUtility.PointOnLineSide(pos.xy,BlockingLine);
|
|
int locknum = SWWMUtility.GetLineLock(BlockingLine);
|
|
if ( !locknum || (target && target.CheckKeys(locknum,false,true)) )
|
|
BlockingLine.RemoteActivate(target,s,SPAC_Use,pos);
|
|
}
|
|
if ( swwm_omnibust )
|
|
{
|
|
int dmg = GetMissileDamage(0,0);
|
|
let raging = RagekitPower(self.target.FindInventory("RagekitPower"));
|
|
if ( raging ) dmg *= 8;
|
|
if ( BusterWall.ProjectileBust(self,dmg,SWWMUtility.Vec3FromAngles(angle,pitch)) )
|
|
raging.DoHitFX();
|
|
}
|
|
A_SetRenderStyle(1.,STYLE_Add);
|
|
// RemoveLight causes heavy performance issues, just overwrite with a "blank light"
|
|
A_AttachLight('LOVELIGHT',DynamicLight.PointLight,0,0,0);
|
|
//A_RemoveLight('LOVELIGHT');
|
|
CheckSplash(40);
|
|
A_QuakeEx(2,2,2,8,0,300,"",QF_RELATIVE|QF_SCALEDOWN|QF_3D);
|
|
A_SprayDecal("HeartyGlow",64);
|
|
A_StartSound("bestsound",CHAN_VOICE);
|
|
Spawn("LoveHeartBurstLight",pos);
|
|
int numpt = Random[ExploS](10,15);
|
|
for ( int i=0; i<numpt; i++ )
|
|
{
|
|
Vector3 pvel = SWWMUtility.Vec3FromAngles(FRandom[ExploS](0,360),FRandom[ExploS](-90,90))*FRandom[ExploS](.5,4);
|
|
let s = Spawn("SWWMSmoke",pos);
|
|
s.vel = pvel;
|
|
s.SetShade(Color(10,8,9)*Random[ExploS](20,25));
|
|
s.special1 = Random[ExploS](1,3);
|
|
s.scale *= 2.;
|
|
s.alpha *= .6;
|
|
}
|
|
numpt = Random[ExploS](40,50);
|
|
for ( int i=0; i<numpt; i++ )
|
|
{
|
|
let s = Spawn("LoveHeartSparkle",pos);
|
|
s.angle = FRandom[ExploS](0,360);
|
|
s.pitch = FRandom[ExploS](-90,90);
|
|
s.scale *= RandomPick[ExploS](1,3);
|
|
s.alpha *= 2;
|
|
}
|
|
}
|
|
action void A_HeartDie()
|
|
{
|
|
scale *= 1.2;
|
|
A_FadeOut();
|
|
}
|
|
|
|
States
|
|
{
|
|
Spawn:
|
|
DOKI A 1 Bright A_HeartTick();
|
|
Wait;
|
|
Death:
|
|
DOKI A 0 Bright A_HeartBurst();
|
|
DOKI A 1 Bright A_HeartDie();
|
|
Wait;
|
|
}
|
|
}
|
|
|
|
Class HeadpatTracker : Actor
|
|
{
|
|
State patstate; // state the target will jump to on headpat
|
|
// if null, will simply resume current state
|
|
State deathstate; // if the actor enters this state, we can't headpat no more
|
|
int oldtargettics; // previous tics left in target's pre-pat state
|
|
bool patting; // currently in pat
|
|
Actor patter; // who's patting
|
|
double hdoomheightfix; // certain hdoom monsters kneel down, so their heads are lower than expected
|
|
double hdoomangfix; // fix for imp in a chair
|
|
bool lethalpat; // ending headpat immediately drops enemy health to 0
|
|
bool dvacationarghack; // hackfix for some girls in doom vacation, disallows headpats if args[0] is 1
|
|
|
|
default
|
|
{
|
|
+NOGRAVITY;
|
|
+NOTELEPORT;
|
|
+DONTSPLASH;
|
|
}
|
|
override void Tick()
|
|
{
|
|
if ( !target || (target.Health <= 0) || (deathstate && target.InStateSequence(target.CurState,deathstate)) )
|
|
{
|
|
Destroy();
|
|
return;
|
|
}
|
|
if ( patting )
|
|
{
|
|
// keep bolted in here
|
|
target.vel *= 0;
|
|
patter.vel *= 0;
|
|
patter.player.vel *= 0;
|
|
target.SetOrigin(pos,true);
|
|
// keep aim
|
|
double delta = deltaangle(target.angle,target.AngleTo(patter));
|
|
if ( abs(delta) < 1. ) target.angle = target.AngleTo(patter);
|
|
else target.angle += .3*delta;
|
|
delta = deltaangle(patter.angle,patter.AngleTo(target)+hdoomangfix);
|
|
if ( abs(delta) < 1. ) patter.A_SetAngle(patter.AngleTo(target)+hdoomangfix,SPF_INTERPOLATE);
|
|
else patter.A_SetAngle(patter.angle+.3*delta,SPF_INTERPOLATE);
|
|
double hfact = 1.2-hdoomheightfix;
|
|
delta = deltaangle(patter.pitch,SWWMUtility.PitchTo(patter,target,hfact));
|
|
if ( abs(delta) < 1. ) patter.A_SetPitch(SWWMUtility.PitchTo(patter,target,hfact),SPF_INTERPOLATE);
|
|
else patter.A_SetPitch(patter.pitch+.3*delta,SPF_INTERPOLATE);
|
|
return;
|
|
}
|
|
if ( (radius != target.radius+8) || (height != target.height+8) )
|
|
A_SetSize(target.radius+8,target.height+8);
|
|
if ( pos != target.pos ) SetOrigin(target.pos,false);
|
|
}
|
|
override bool Used( Actor user )
|
|
{
|
|
if ( !target ) return false;
|
|
if ( patting ) return false; // already on it
|
|
if ( user.player.crouchdir == -1 ) return false; // need to be standing up
|
|
if ( !user.player.onground ) return false; // need to be on solid ground
|
|
if ( dvacationarghack && (target.args[0] == 1) ) return false; // can't pat at the moment
|
|
if ( !(user.player.WeaponState&WF_WEAPONSWITCHOK) || (user.player.WeaponState&WF_DISABLESWITCH) ) return false; // weapon needs to be ready for switching
|
|
// check use range
|
|
Vector3 diff = level.Vec3Diff(user.Vec2OffsetZ(0,0,user.player.viewz),Vec3Offset(0,0,target.Height));
|
|
if ( abs(diff.z) > PlayerPawn(user.player.mo).UseRange ) return false;
|
|
if ( user is 'Demolitionist' )
|
|
{
|
|
patter = user;
|
|
let g = SWWMGesture.SetGesture(Demolitionist(patter),GS_Headpat);
|
|
if ( !g ) return false; // can't headpat at the moment
|
|
patting = true;
|
|
g.pats = self;
|
|
oldtargettics = target.tics;
|
|
target.tics = -1;
|
|
patter.player.cheats |= CF_TOTALLYFROZEN;
|
|
Demolitionist(patter).scriptedinvul = true;
|
|
target.bDORMANT = true;
|
|
if ( SWWMUtility.IdentifyingDog(target) ) SWWMUtility.MarkAchievement("mbf",user.player);
|
|
else if ( SWWMUtility.IdentifyingCaco(target) ) SWWMHandler.AddOneliner("petcaco",2,20);
|
|
else if ( SWWMHDoomHandler.IsCuteGirl(target) || SWWMHDoomHandler.IsStaticSexyTime(target) ) SWWMHandler.AddOneliner("pethdoom",2,40);
|
|
else if ( SWWMHDoomHandler.IsSexyTime(target) ) SWWMHandler.AddOneliner("pethdoomfinish",2,80);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
|