// The Demolitionist Enum EDemoFaceState { FS_DEFAULT, FS_EVIL, FS_GRIN, FS_WINK, FS_BLINK, FS_SAD, FS_PAIN, FS_OUCH, FS_DEAD // UNUSED }; Class Demolitionist : PlayerPawn { int last_jump_held, last_boost, last_kick; Vector3 dashdir; double dashfuel, dashboost; int dashcooldown, boostcooldown, fuelcooldown; int dashlockst; bool fullfuel; bool sendtoground; bool key_reentrant; bool bInDefaultInventory; bool oldsinglefirst; transient int lastdamage; transient int lastdamagetic, lastdamagetimer; bool lastground; int lastgroundtic, lastairtic; double lastvelz, prevvelz, landvelz; double ssup; SWWMStats mystats; int cairtime; bool hasteleported; bool hasrevived; int lastmpain; double guideangle, guidepitch, guideroll; // for weapon bobbing stuff double bumpvelz, bumpangle, bumppitch, bumproll; double oldangle, oldpitch, oldroll; double oldlagangle, oldlagpitch, oldlagroll, oldlagready; Vector3 oldlagvel; double lagangle, lagpitch, lagroll, lagready; Vector3 lagvel; enum EUnderType { UNDER_NONE, UNDER_WATER, UNDER_SLIME, UNDER_LAVA }; int lastunder; Color undercol; int deadtimer; transient int revivefail; transient int bumptic; transient double lastbump; DemolitionistSelfLight selflight; Actor oldencroached; Vector3 oldencroachedpos; int encroachtics; Vector3 pretelepos; SWWMItemSense itemsense; int healcooldown, healtimer, oldhealth; bool scriptedinvul; bool hitactivate; Actor froggy; transient int lastuse, failcounter, failcooldown, mirrorcooldown; transient SWWMItemTracer itrace; transient SWWMMirrorTracer mtrace; bool meleeuse; transient bool bWalking; int airscreamtime; enum EInvWipe { WIPE_EPISODE = 1, WIPE_CLUSTER = 2, WIPE_MAP = 4 } int invwipe; // inventory wipe flags for next level transient int lastbang, lastbust, lastkiss; transient bool ingivecheat; Property DashFuel : dashfuel; EDemoFaceState facestate; int paindir; int facetimer; int blinktime; transient int oldfaceidx; transient int rss; transient bool facedamage, facegrin, facesad, facewink, faceblink; int oldtagcolor; transient int magtime; SWWMMagItem magitem; int magitem_cnt; SWWMShadow myshadow; double bobtime, oldbobtime, oldbob; SWWMHandler hnd; Default { Tag "$T_DEMOLITIONIST"; Speed 1; Radius 16; // should be 9 in theory, but it'd be too thin Height 56; Mass 500; PainChance 255; MaxSlopeSteepness 0; // mountain goat mode, all slopes are walkable Player.DisplayName "$T_DEMOLITIONIST"; // StartItem array is defined but not used directly // just declared here for mod compat Player.StartItem "ExplodiumGun"; Player.StartItem "DeepImpact"; Player.StartItem "AlmasteelPlating"; Player.StartItem "SayaCollar"; Player.ViewHeight 52; Player.AirCapacity 0; Player.GruntSpeed 20; Player.ForwardMove 1., 1.; Player.SideMove 1., 1.; Player.SoundClass "demolitionist"; DamageFactor "Drowning", 0.; DamageFactor "Poison", 0.; DamageFactor "PoisonCloud", 0.; DamageFactor "Falling", 0.; Demolitionist.DashFuel 240.; +NOBLOOD; +DONTGIB; +NOICEDEATH; +NOSKIN; +DONTMORPH; +DONTDRAIN; +DONTCORPSE; -WINDTHRUST; // too heavy } override String GetObituary( Actor victim, Actor inflictor, Name mod, bool playerattack ) { if ( inflictor && inflictor.FindInventory("ParriedBuff") ) return StringTable.Localize("$O_PARRY"); if ( mod == 'Jump' ) return StringTable.Localize("$O_JUMP"); if ( mod == 'Dash' ) return StringTable.Localize("$O_DASH"); if ( mod == 'Buttslam' ) return StringTable.Localize("$O_BUTT"); if ( mod == 'GroundPound' ) return StringTable.Localize("$O_POUND"); return Super.GetObituary(victim,inflictor,mod,playerattack); } override double GetDeathHeight() { double basedeathheight = Super.GetDeathHeight(); // limit death height to crouch height, to avoid dying players from getting stuck on revive return max(Height*.3,basedeathheight); } override void PostBeginPlay() { Super.PostBeginPlay(); lastground = true; // prevent sudden landing sound on map start blinktime = 30; // swap ourselves for a voodoo doll if ( !player || (player.mo != self) ) { let v = Spawn("SWWMVoodooDoll",pos); v.angle = angle; v.player = player; // give it a face if it belongs to a player if ( player ) { v.bFRIENDLY = true; v.A_ChangeModel("",0,"","",1,"models","VoodooDollFace.png",CMDL_USESURFACESKIN,-1); } Destroy(); return; } oldsinglefirst = swwm_singlefirst; // super already sets up the slots, so save the cvar value now mystats = SWWMStats.Find(player); // sanity checks if ( !EventHandler.Find("SWWMHandler") || !StaticEventHandler.Find("SWWMStaticHandler") ) ThrowAbortException("Panic! SWWM event handlers not detected!"); } void BumpView( double str, Vector3 dir = (0,0,0) ) { double dirlen = dir.length(); if ( dirlen < double.epsilon ) { bumppitch += str; return; } dir /= dirlen; Vector3 x, y; Quat r = Quat.FromAngles(angle+viewangle,pitch+viewpitch,roll+viewroll); x = r*(1,0,0); y = r*(0,-1,0); double sx = dir dot x; double sy = dir dot y; if ( !sx && !sy ) bumppitch += str; else { bumppitch += str*sx; bumproll += str*sy; } } override void CheckFOV() { if ( !player ) return; float desired = player.desiredfov; // adjust fov from weapon (abs due to special use of negative // to prevent it from scaling look sensitivity) if ( (player.playerstate != PST_DEAD) && player.readyweapon && player.readyweapon.fovscale ) desired *= abs(player.readyweapon.fovscale); // additional fov bump from various effects // akin to the old A_ZoomFactor trick, but not limited to weapons and can stack if ( lastbump <= 0. ) lastbump = 1.; if ( lastbump != 1. ) { double str = CVar.GetCVar('swwm_bumpstrength',player).GetFloat(); player.fov *= lastbump*str+1.-str; lastbump = 1.; } // adjust fov from dashing double spd = vel.length(); if ( InStateSequence(CurState,FindState("Dash")) && (spd > 10.) ) { Vector3 facedir = SWWMUtility.Vec3FromAngles(angle,pitch); if ( spd > 0. ) { double rel = max(0,vel.unit() dot facedir); desired *= 1.+clamp(rel*(spd-10.),-80.,80.)*.002; } } if ( player.fov == desired ) return; // interpolate towards desired fov if ( abs(player.fov-desired) < .1 ) player.fov = desired; else { float zoom = max(.1,abs(player.fov-desired)*.35); if ( player.fov > desired ) player.fov -= zoom; else player.fov += zoom; } } override void CheckPoison() { // HAHA no player.poisoncount = 0; } private void CheckBreakCrusher() { double gaph = (ceilingz-floorz); if ( gaph > height*.8 ) return; // the smaller the gap, the more likely the crusher will snap if ( Random[Demolitionist](0,2) && (FRandom[Demolitionist](0,gaph/height) > .2) ) return; double diffh = 8.+(default.height-gaph); // how much the crusher will have to "snap" after breaking let ceil = ceilingsector; let flor = floorsector; let ceilse = ceil.ceilingdata; let florse = flor.floordata; if ( ceilse && florse ) { // snap both planes let q = Spawn("BustedQuake",(ceil.centerspot.x,ceil.centerspot.y,ceil.ceilingplane.ZAtPoint(ceil.centerspot))); q.special1 = 6; q = Spawn("BustedQuake",(flor.centerspot.x,flor.centerspot.y,flor.floorplane.ZAtPoint(flor.centerspot))); q.special1 = 6; SWWMCrusherBroken.Create(flor,ceil,diffh/2.); } else if ( ceilse ) { // snap ceiling let q = Spawn("BustedQuake",(ceil.centerspot.x,ceil.centerspot.y,ceil.ceilingplane.ZAtPoint(ceil.centerspot))); q.special1 = 10; SWWMCrusherBroken.Create(null,ceil,diffh); } else if ( florse ) { // snap floor let q = Spawn("BustedQuake",(flor.centerspot.x,flor.centerspot.y,flor.floorplane.ZAtPoint(flor.centerspot))); q.special1 = 10; SWWMCrusherBroken.Create(flor,null,diffh); } SWWMUtility.MarkAchievement("crush",player); } private void CheckBreakPolyobject( int dmg ) { // see if there are any crushing polyobjects currently "encroaching" the player Array touching; BlockLinesIterator bl = BlockLinesIterator.Create(self,radius+8); double tbox[4]; // top, bottom, left, right tbox[0] = pos.y+(radius+8); tbox[1] = pos.y-(radius+8); tbox[2] = pos.x-(radius+8); tbox[3] = pos.x+(radius+8); while ( bl.Next() ) { Line l = bl.CurLine; if ( !l ) continue; if ( tbox[2] > l.bbox[3] ) continue; if ( tbox[3] < l.bbox[2] ) continue; if ( tbox[0] < l.bbox[1] ) continue; if ( tbox[1] > l.bbox[0] ) continue; if ( SWWMUtility.BoxOnLineSide(tbox[0],tbox[1],tbox[2],tbox[3],l) != -1 ) continue; touching.Push(l); } let pi = swwm_PolyobjectIterator.Create(); swwm_PolyobjectHandle p; while ( p = pi.Next() ) { if ( (p.Type != swwm_PolyobjectHandle.POTYP_CRUSH) && (p.Type != swwm_PolyobjectHandle.POTYP_HURT) ) continue; foreach ( l:touching ) { if ( p.Lines.Find(l) >= p.Lines.Size() ) continue; Vector2 diragainst = pos.xy-p.GetPos(); double vsiz = diragainst.length(); if ( vsiz > 0 ) diragainst /= vsiz; if ( BusterWall.BustPolyobj(p,max(dmg,(100-health)*5),self,(diragainst.x,diragainst.y,0)) ) SWWMUtility.MarkAchievement("crush",player); if ( p.Mirror && BusterWall.BustPolyobj(p.Mirror,max(dmg,(100-health)*5),self,-(diragainst.x,diragainst.y,0)) ) SWWMUtility.MarkAchievement("crush",player); } } } override int DamageMobj( Actor inflictor, Actor source, int damage, Name mod, int flags, double angle ) { // we still have to ENSURE ENTIRELY that this gets nullified (TELEFRAG_DAMAGE overrides damage factors somehow) if ( (mod == 'Falling') | (mod == 'Drowning') || (mod == 'Poison') || (mod == 'PoisonCloud') ) damage = 0; if ( (swwm_strictuntouchable >= 2) && (damage > 0) && player ) { if ( !hnd ) hnd = SWWMHandler(EventHandler.Find("SWWMHandler")); if ( hnd ) hnd.tookdamage[PlayerNumber()] = true; } if ( (mod == 'Crush') && player && (player.mo == self) ) { // check if we can break any active crushers // (or polyobjects) if ( !inflictor && !source ) { CheckBreakCrusher(); CheckBreakPolyobject(damage); } // break a spike trap else if ( source is 'ThrustFloor' ) { let q = Spawn("BustedQuake",source.pos); q.special1 = 4; int numpt = Random[ExploS](30,40); for ( int i=0; i 0) && (PainChance == 0) && (level.maptime>lastmpain) ) { lastmpain = level.maptime; if ( player && (player.mo == self) ) A_DemoPain(); } PainChance = oldpchance; if ( (Health <= 0) && (source == self) && (flags&DMG_EXPLOSION) ) SWWMUtility.MarkAchievement("dime",player); facedamage = true; return realdmg; } private Vector2 BobWeaponAngle( double ticfrac ) { // bob with player view Vector2 prevbob = (-sin(oldbobtime*180.),.5*abs(sin(oldbobtime*180.)))*oldbob*.25; Vector2 bob = (-sin(bobtime*180.),.5*abs(sin(bobtime*180.)))*player.bob*.25; double bobstr = (player.WeaponState&WF_WEAPONBOBBING)?1.:player.GetWBobFire(); return SWWMUtility.LerpVector2(prevbob,bob,ticfrac)*bobstr*clamp(viewbob,0.,1.5); } // [4.11] proper 3D/2D weapon bob separation /*override Vector3, Vector3 BobWeapon3D( double ticfrac ) { if ( !player || !player.ReadyWeapon || player.ReadyWeapon.bDontBob ) return (0,0,0), (0,0,0); bool oldbob = !!(player.WeaponState&WF_WEAPONBOBBING); player.WeaponState |= WF_WEAPONBOBBING; // always bob Vector2 cur = BobWeaponAngle(ticfrac); if ( !oldbob ) player.WeaponState &= ~WF_WEAPONBOBBING; double fangle = SWWMUtility.Lerp(oldangle,angle,ticfrac); double fpitch = SWWMUtility.Lerp(oldpitch,pitch,ticfrac); double froll = SWWMUtility.Lerp(oldroll,roll,ticfrac); double flagangle = SWWMUtility.Lerp(oldlagangle,lagangle,ticfrac); double flagpitch = SWWMUtility.Lerp(oldlagpitch,lagpitch,ticfrac); double flagroll = SWWMUtility.Lerp(oldlagroll,lagroll,ticfrac); double diffang = fangle-flagangle; double diffpitch = fpitch-flagpitch; double diffroll = froll-flagroll; if ( abs(diffang) > 1. ) { int sgn = (diffang>0)?1:-1; diffang = abs(diffang)**.7*sgn; } if ( abs(diffpitch) > 1. ) { int sgn = (diffpitch>0)?1:-1; diffpitch = abs(diffpitch)**.7*sgn; } if ( abs(diffroll) > 1. ) { int sgn = (diffroll>0)?1:-1; diffroll = abs(diffroll)**.7*sgn; } Vector3 flagvel = SWWMUtility.LerpVector3(oldlagvel,lagvel,ticfrac); let [x, y, z] = SWWMUtility.GetAxes(flagangle,flagpitch,flagroll); let [x2, y2, z2] = SWWMUtility.GetAxes(flagangle,0,flagroll); double diffx = flagvel dot x; double diffy = flagvel dot y; double diffz = flagvel dot z; double diffy2 = flagvel dot y2; double diffz2 = flagvel dot z2; if ( abs(diffx) > 1. ) { int sgn = (diffx>0)?1:-1; diffx = abs(diffx)**.5*sgn; } if ( abs(diffy) > 1. ) { int sgn = (diffy>0)?1:-1; diffy = abs(diffy)**.5*sgn; } if ( abs(diffz) > 1. ) { int sgn = (diffz>0)?1:-1; diffz = abs(diffz)**.5*sgn; } if ( abs(diffy2) > 1. ) { int sgn = (diffy2>0)?1:-1; diffy2 = abs(diffy2)**.5*sgn; } if ( abs(diffz2) > 1. ) { int sgn = (diffz2>0)?1:-1; diffz2 = abs(diffz2)**.5*sgn; } Vector3 bobvec = (diffy,-diffz,diffx*.5)*20. + (cur.x,-cur.y,cur.y)*15.; Vector3 bobang = (dangles.x,dangles.y,dangles.z)*.15 - (cur.x,cur.y,-cur.x*2.)*.05 - (diffy2,diffz2,0)*.02; double fready = SWWMUtility.Lerp(oldlagready,lagready,ticfrac); double rfact = 1., vfact = 1.; if ( player.ReadyWeapon is 'SWWMWeapon' ) { let sw = SWWMWeapon(player.ReadyWeapon); rfact = sw.bobfactor_ang; vfact = sw.bobfactor_vec; } return bobvec*fready*vfact, bobang*fready*rfact; } // compatibility with 2D weapons override Vector2 BobWeapon( double ticfrac ) { if ( !player || !player.ReadyWeapon || player.ReadyWeapon.bDontBob ) return (0,0); bool oldbob = !!(player.WeaponState&WF_WEAPONBOBBING); player.WeaponState |= WF_WEAPONBOBBING; // always bob Vector2 cur = BobWeaponAngle(ticfrac); if ( !oldbob ) player.WeaponState &= ~WF_WEAPONBOBBING; double fangle = SWWMUtility.Lerp(oldangle,angle,ticfrac); double fpitch = SWWMUtility.Lerp(oldpitch,pitch,ticfrac); double flagangle = SWWMUtility.Lerp(oldlagangle,lagangle,ticfrac); double flagpitch = SWWMUtility.Lerp(oldlagpitch,lagpitch,ticfrac); double diffang = fangle-flagangle; double diffpitch = fpitch-flagpitch; if ( abs(diffang) > 1. ) { int sgn = (diffang>0)?1:-1; diffang = abs(diffang)**.7*sgn; } if ( abs(diffpitch) > 1. ) { int sgn = (diffpitch>0)?1:-1; diffpitch = abs(diffpitch)**.7*sgn; } cur.x += diffang*.4; cur.y -= diffpitch*.4; Vector3 flagvel = SWWMUtility.LerpVector3(oldlagvel,lagvel,ticfrac); double flagroll = SWWMUtility.Lerp(oldlagroll,lagroll,ticfrac); let [x, y, z] = SWWMUtility.GetAxes(flagangle,0,flagroll); double diffy = flagvel dot y; double diffz = flagvel dot z; if ( abs(diffy) > 1. ) { int sgn = (diffy>0)?1:-1; diffy = abs(diffy)**.5*sgn; } if ( abs(diffz) > 1. ) { int sgn = (diffz>0)?1:-1; diffz = abs(diffz)**.5*sgn; } cur.x -= diffy*.8; cur.y += diffz*.8; return cur*SWWMUtility.Lerp(oldlagready,lagready,ticfrac); }*/ override Vector2 BobWeapon( double ticfrac ) { if ( !player || !player.ReadyWeapon || player.ReadyWeapon.bDontBob ) return (0,0); bool oldbob = !!(player.WeaponState&WF_WEAPONBOBBING); player.WeaponState |= WF_WEAPONBOBBING; // always bob Vector2 cur = BobWeaponAngle(ticfrac); if ( !oldbob ) player.WeaponState &= ~WF_WEAPONBOBBING; double fangle = SWWMUtility.Lerp(oldangle,angle,ticfrac); double fpitch = SWWMUtility.Lerp(oldpitch,pitch,ticfrac); double flagangle = SWWMUtility.Lerp(oldlagangle,lagangle,ticfrac); double flagpitch = SWWMUtility.Lerp(oldlagpitch,lagpitch,ticfrac); double diffang = fangle-flagangle; double diffpitch = fpitch-flagpitch; if ( abs(diffang) > 1. ) { int sgn = (diffang>0)?1:-1; diffang = abs(diffang)**.7*sgn; } if ( abs(diffpitch) > 1. ) { int sgn = (diffpitch>0)?1:-1; diffpitch = abs(diffpitch)**.7*sgn; } cur.x += diffang*.4; cur.y -= diffpitch*.4; Vector3 flagvel = SWWMUtility.LerpVector3(oldlagvel,lagvel,ticfrac); double flagroll = SWWMUtility.Lerp(oldlagroll,lagroll,ticfrac); Vector3 x, y, z; [x, y, z] = SWWMUtility.GetAxes(flagangle,0,flagroll); double diffy = flagvel dot y; double diffz = flagvel dot z; if ( abs(diffy) > 1. ) { int sgn = (diffy>0)?1:-1; diffy = abs(diffy)**.5*sgn; } if ( abs(diffz) > 1. ) { int sgn = (diffz>0)?1:-1; diffz = abs(diffz)**.5*sgn; } cur.x -= diffy*.8; cur.y += diffz*.8; return cur*SWWMUtility.Lerp(oldlagready,lagready,ticfrac); } override bool OnGiveSecret( bool printmsg, bool playsound ) { if ( !player ) return false; int score = 100; // last secret (this is called before counting it up, so have to subtract) if ( !hnd ) hnd = SWWMHandler(EventHandler.Find("SWWMHandler")); if ( !deathmatch && !(gameinfo.gametype&GAME_Hexen) && (level.found_secrets == level.total_secrets-1) && (!hnd || !hnd.allsecrets) ) { if ( hnd ) hnd.allsecrets = true; score = 1000; if ( player == players[consoleplayer] ) { Console.Printf(StringTable.Localize("$SWWM_LASTSECRET"),score); SWWMHandler.AddOneliner("findsecret",2,40); facegrin = true; } else Console.Printf(StringTable.Localize("$SWWM_LASTSECRETREM"),player.GetUserName(),score); SWWMUtility.AchievementProgressInc("allsecrets",1,player); } else if ( player == players[consoleplayer] ) { Console.Printf(StringTable.Localize("$SWWM_FINDSECRET"),score); SWWMHandler.AddOneliner("findsecret",2,40); facegrin = true; } else Console.Printf(StringTable.Localize("$SWWM_FINDSECRETREM"),player.GetUserName(),score); SWWMCredits.Give(player,score); SWWMScoreObj.Spawn(score,Vec3Offset(0,0,Height/2)); // somehow ongivesecret can be called BEFORE PostBeginPlay (wat) if ( !mystats ) mystats = SWWMStats.Find(player); mystats.secrets++; return true; } override bool Used( Actor user ) { if ( !(user is 'Demolitionist') || !player || (player.mo != self) ) return false; if ( (user.player == players[consoleplayer]) && (health > 0) ) { SWWMHandler.AddOneliner("greet",2); return true; } return false; } override void PreTravelled() { // clean up attached actors if ( selflight ) selflight.Destroy(); if ( myshadow ) myshadow.Destroy(); // clean up our objects SWWMItemSense si = itemsense; while ( si ) { let next = si.next; si.Destroy(); si = next; } SWWMMagItem mi = magitem; while ( mi ) { let next = mi.next; mi.Destroy(); mi = next; } magitem_cnt = 0; // disable death exits if ( player && (player.playerstate == PST_DEAD) ) { player.cheats &= ~(CF_FROZEN|CF_TOTALLYFROZEN); player.Resurrect(); player.damagecount = 0; player.bonuscount = 0; player.poisoncount = 0; roll = 0; if ( special1 > 2 ) special1 = 0; } // inventory wipes if ( invwipe && (player.playerstate != PST_DEAD) ) { bool wiped = false; bool resetammo = false; bool resetitems = false; bool resethealth = false; if ( invwipe&WIPE_EPISODE ) { SWWMUtility.WipeInventory(self,swwm_resetscore); wiped = true; } if ( invwipe&WIPE_CLUSTER ) { if ( (swwm_ps_fullreset == 2) && !wiped ) { SWWMUtility.WipeInventory(self,swwm_resetscore); wiped = true; } if ( (swwm_ps_resetammo == 2) && !wiped ) { SWWMUtility.ResetAmmo(self); resetammo = true; } if ( (swwm_ps_resetitems == 2) && !wiped ) { SWWMUtility.ResetItems(self); resetitems = true; } if ( (swwm_ps_resethealth == 2) && !wiped ) { SWWMUtility.ResetHealth(self); resethealth = true; } } if ( invwipe&WIPE_MAP ) { if ( (swwm_ps_fullreset == 1) && !wiped ) { SWWMUtility.WipeInventory(self,swwm_resetscore); wiped = true; } if ( (swwm_ps_resetammo == 1) && !wiped && !resetammo ) SWWMUtility.ResetAmmo(self); if ( (swwm_ps_resetitems == 1) && !wiped && !resetitems ) SWWMUtility.ResetItems(self); if ( (swwm_ps_resethealth == 1) && !wiped && !resethealth ) SWWMUtility.ResetHealth(self); } } invwipe = 0; } override void Travelled() { // reinitialize dashfuel = default.dashfuel; last_boost = 0; last_kick = 0; hasrevived = false; blinktime = 30; // cancel dash/boost A_StopSound(CHAN_JETPACK); fuelcooldown = 0.; dashcooldown = 0.; dashboost = 0.; // prevent sudden stomping if we were previously falling lastvelz = vel.z; // early cancel gestures if ( player ) { if ( player.ReadyWeapon is 'SWWMItemGesture' ) player.ReadyWeapon = SWWMItemGesture(player.ReadyWeapon).gest; if ( player.ReadyWeapon is 'SWWMGesture' ) { player.PendingWeapon = SWWMGesture(player.ReadyWeapon).formerweapon; player.SetPSprite(PSP_WEAPON,player.ReadyWeapon.ResolveState("Deselect")); } } // re-add ourselves to the "suckable list" (otherwise the Ynykron Singularity won't hurt us) if ( !hnd ) hnd = SWWMHandler(EventHandler.Find("SWWMHandler")); if ( hnd && (hnd.SuckableActors.Find(self) >= hnd.SuckableActors.Size()) ) hnd.SuckableActors.Push(self); } override bool PreTeleport( Vector3 destpos, double destangle, int flags ) { // store old pos pretelepos = pos; return true; } override void PostTeleport( Vector3 destpos, double destangle, int flags ) { hasteleported = true; // notify tick that we teleported, so it ignores the travel distance mystats.teledist += level.Vec3Diff(pretelepos,pos).length(); // reset all smooth bob variables if angles/velocity aren't carried over if ( !(flags&TELF_KEEPORIENTATION) ) { oldlagangle = lagangle = oldangle = angle; oldlagpitch = lagpitch = oldpitch = pitch; oldlagroll = lagroll = oldroll = roll; } if ( !(flags&TELF_KEEPVELOCITY) ) { oldlagvel = lagvel = vel; lastvelz = vel.z; } // notify carried lamp that we just moved let l = SWWMLamp(FindInventory("SWWMLamp")); if ( l && l.thelamp ) CompanionLamp(l.thelamp).justteleport = true; } override void MarkPrecacheSounds() { Super.MarkPrecacheSounds(); MarkSound("demolitionist/walk1"); MarkSound("demolitionist/walk2"); MarkSound("demolitionist/walk3"); MarkSound("demolitionist/walk4"); MarkSound("demolitionist/runstart1"); MarkSound("demolitionist/runstart2"); MarkSound("demolitionist/runstart3"); MarkSound("demolitionist/runstart4"); MarkSound("demolitionist/run1"); MarkSound("demolitionist/run2"); MarkSound("demolitionist/run3"); MarkSound("demolitionist/run4"); MarkSound("demolitionist/runstop1"); MarkSound("demolitionist/runstop2"); MarkSound("demolitionist/runstop3"); MarkSound("demolitionist/runstop4"); MarkSound("demolitionist/jet"); MarkSound("demolitionist/jetstop"); MarkSound("demolitionist/death1"); MarkSound("demolitionist/death2"); MarkSound("demolitionist/death3"); MarkSound("demolitionist/xdeath1"); MarkSound("demolitionist/xdeath2"); MarkSound("demolitionist/xdeath3"); MarkSound("demolitionist/wdeath1"); MarkSound("demolitionist/wdeath2"); MarkSound("demolitionist/wdeath3"); MarkSound("demolitionist/pain1"); MarkSound("demolitionist/pain2"); MarkSound("demolitionist/pain3"); MarkSound("demolitionist/hipain1"); MarkSound("demolitionist/hipain2"); MarkSound("demolitionist/hipain3"); MarkSound("demolitionist/lopain1"); MarkSound("demolitionist/lopain2"); MarkSound("demolitionist/lopain3"); MarkSound("demolitionist/hardland1"); MarkSound("demolitionist/hardland2"); MarkSound("demolitionist/hardland3"); MarkSound("demolitionist/swing1"); MarkSound("demolitionist/swing2"); MarkSound("demolitionist/swing3"); MarkSound("demolitionist/wswing1"); MarkSound("demolitionist/wswing2"); MarkSound("demolitionist/punch1"); MarkSound("demolitionist/punch2"); MarkSound("demolitionist/punch3"); MarkSound("demolitionist/punchf1"); MarkSound("demolitionist/punchf2"); MarkSound("demolitionist/punchf3"); MarkSound("demolitionist/bump1"); MarkSound("demolitionist/bump2"); MarkSound("demolitionist/bump3"); MarkSound("demolitionist/kick1"); MarkSound("demolitionist/kick2"); MarkSound("demolitionist/kick3"); MarkSound("demolitionist/revive"); MarkSound("demolitionist/youdied"); MarkSound("demolitionist/parry"); MarkSound("demolitionist/handsup"); MarkSound("demolitionist/handsdown"); MarkSound("demolitionist/whits1"); MarkSound("demolitionist/whits2"); MarkSound("demolitionist/whits3"); MarkSound("demolitionist/whitm1"); MarkSound("demolitionist/whitm2"); MarkSound("demolitionist/whitm3"); MarkSound("demolitionist/whitl1"); MarkSound("demolitionist/whitl2"); MarkSound("demolitionist/buttslam1"); MarkSound("demolitionist/buttslam2"); MarkSound("demolitionist/buttslam3"); MarkSound("demolitionist/buttslamx"); MarkSound("demolitionist/petting"); MarkSound("demolitionist/knockout"); } }