// Other items Class Omnisight : Inventory { Mixin SWWMOverlapPickupSound; Mixin SWWMUseToPickup; Mixin SWWMRespawn; Mixin SWWMRotatingPickup; Mixin SWWMUnrealStyleDrop; override bool TryPickup( Actor &toucher ) { if ( !level.allmap ) { Actor rt = toucher; if ( toucher.player ) rt = toucher.player.mo; if ( rt.player == players[consoleplayer] ) rt.A_StartSound("powerup/omnisight",CHAN_ITEMEXTRA,CHANF_OVERLAP); if ( rt is 'Demolitionist' ) Demolitionist(rt).lastbump *= 1.1; level.allmap = true; // activate all interest markers let ti = ThinkerIterator.Create('SWWMInterestMarker',STAT_MAPMARKER); Actor a; while ( a = Actor(ti.Next()) ) a.bDORMANT = false; // "spread" to all players for ( int i=0; i=2)?default.Icon:(primetim>=6)?(bFailed?OnIcon[1]:OnIcon[2]):OnIcon[0]; if ( !bFailed && (primetim == 20) ) Owner.A_StartSound("hahaha/hahaha",CHAN_POWERUP,CHANF_OVERLAP); primetim++; if ( (primetim <= 20) || (!bFailed && (primetim <= 50)) ) return; primetim = 0; bPrimed = false; Icon = default.Icon; if ( bFailed ) return; Vector3 safepos; double safeangle; if ( deathmatch ) [safepos, safeangle] = level.PickDeathmatchStart(); else [safepos, safeangle] = level.PickPlayerStart(Owner.PlayerNumber()); if ( !level.useplayerstartz ) safepos.z = ONFLOORZ; Vector3 oldpos = Owner.pos; if ( !Owner.Teleport(safepos,safeangle,0) ) { if ( Owner is 'Demolitionist' ) Demolitionist(Owner).lastbump *= .95; Owner.A_StartSound("powerup/tethererror",CHAN_ITEMEXTRA,CHANF_OVERLAP); if ( Owner.player == players[consoleplayer] ) Console.Printf(StringTable.Localize("$D_TETHERFAIL")); return; } let s = Spawn('DemolitionistShockwave',oldpos); s.target = Owner; s.special1 = 120; s.A_AlertMonsters(0,AMF_EMITFROMTARGET); s = Spawn('DemolitionistShockwave',Owner.pos); s.target = Owner; s.special1 = 120; s.A_AlertMonsters(0,AMF_EMITFROMTARGET); if ( Owner.player == players[consoleplayer] ) { Owner.A_StartSound("demolitionist/hardland",CHAN_FOOTSTEP,CHANF_OVERLAP); Owner.A_StartSound("demolitionist/hardland",CHAN_FOOTSTEP,CHANF_OVERLAP,pitch:.7); Owner.A_StartSound("demolitionist/hardland",CHAN_FOOTSTEP,CHANF_OVERLAP,pitch:.4); } SWWMHandler.DoFlash(Owner,Color(255,255,255,255),10); SWWMHandler.DoFlash(Owner,Color(255,128,192,255),30); Owner.GiveBody(100,100); SWWMUtility.AchievementProgressInc("sneaky",1,Owner.player); Amount--; if ( Amount <= 0 ) DepleteOrDestroy(); } override bool Use( bool pickup ) { if ( pickup || bPrimed ) return false; if ( !OnIcon[0] ) OnIcon[0] = TexMan.CheckForTexture("graphics/HUD/Icons/I_SafetyOn.png"); if ( !OnIcon[1] ) OnIcon[1] = TexMan.CheckForTexture("graphics/HUD/Icons/I_SafetyNo.png"); if ( !OnIcon[2] ) OnIcon[2] = TexMan.CheckForTexture("graphics/HUD/Icons/I_SafetyYes.png"); bPrimed = true; primetim = 0; Vector3 safepos; if ( deathmatch ) safepos = level.PickDeathmatchStart(); else safepos = level.PickPlayerStart(Owner.PlayerNumber()); if ( !level.useplayerstartz ) { // find the floor for proper distance check let s = level.PointInSector(safepos.xy); safepos.z = s.floorplane.ZAtPoint(safepos.xy); } bFailed = (level.Vec3Diff(Owner.pos,safepos).length() < 400); Owner.A_StartSound(bFailed?"powerup/tetherfail":"powerup/tetheruse",CHAN_ITEMEXTRA,CHANF_OVERLAP); // don't consume on use, will happen later Amount++; return true; } Default { Tag "$T_SAFETY"; Stamina 240000; Inventory.Icon "graphics/HUD/Icons/I_Safety.png"; Inventory.PickupSound "misc/p_pkup"; Inventory.UseSound ""; Inventory.PickupMessage "$T_SAFETY"; Inventory.MaxAmount 5; Inventory.InterHubAmount 5; Inventory.PickupFlash 'SWWMCyanPickupFlash'; +INVENTORY.ALWAYSPICKUP; +INVENTORY.AUTOACTIVATE; +INVENTORY.INVBAR; +COUNTITEM; +INVENTORY.BIGPOWERUP; +FLOATBOB; +DONTGIB; FloatBobStrength 0.25; } States { Spawn: XZW1 A 33; XZW1 B 2; Loop; } } // TBD 1.4 Ballsy Bomb Class BallImpact : SWWMNonInteractiveActor { override void PostBeginPlay() { Super.PostBeginPlay(); A_QuakeEx(3.,3.,3.,12,0,200,"",QF_RELATIVE|QF_SCALEDOWN|QF_3D,falloff:100,rollIntensity:.3); A_StartSound("leadball/hit",CHAN_VOICE); A_SprayDecal("WallCrack",-20); int numpt = Random[Spreadgun](5,10); Vector3 x = SWWMUtility.Vec3FromAngles(angle,pitch); for ( int i=0; i 0) && victim ) { victim.A_StartSound("leadball/hitf",CHAN_DAMAGE,CHANF_OVERLAP,(vel.length()/30.)**.5); victim.TraceBleed(newdmg,self); victim.SpawnBlood(pos,atan2(dir.y,dir.x),dmg); } } else { A_StartSound("leadball/hit",CHAN_VOICE,CHANF_OVERLAP,(vel.length()/30.)**.5); if ( victim ) victim.A_StartSound("leadball/hit",CHAN_DAMAGE,CHANF_OVERLAP,(vel.length()/30.)**.5); if ( vel.length() > 15. ) { let s = Spawn('BallImpact',pos); s.angle = atan2(dir.y,dir.x); s.pitch = asin(-dir.z); } } // make it so the crit does not propagate to friendlies unless we bonked a friend (you monster!) if ( crit ) SWWMUtility.DoExplosion(self,dmg/2,25000,150,80,((victim.isFriend(target))?0:DE_NOHURTFRIEND)|DE_NONEXPLOSIVE,crit?'CriticalConcussion':'Concussion',target,DMG_FOILINVUL); if ( crit && victim && (victim.Health <= 0) && (victim.bBOSS || victim.FindInventory('BossMarker')) && target ) SWWMUtility.MarkAchievement("clonk",target.player); // only rip shootables if ( (slamforce > girth) && is_schutt ) { vel *= .7; return MHIT_PASS; } // force bounce BlockingMobj = victim; A_HandleBounce(); lasthit = victim; // pretend to pass through return MHIT_PASS; } override void PostBeginPlay() { Super.PostBeginPlay(); A_StartSound("leadball/fly",CHAN_WEAPON,CHANF_LOOP,.6,3.,2.); heat = 1.; } override void Tick() { oldvel = vel; Super.Tick(); if ( isFrozen() || (freezetics > 0) ) return; if ( InStateSequence(CurState,ResolveState('Death')) ) { deadtimer++; if ( deadtimer > 300 ) { let numpt = Random[Spreadgun](3,6); for ( int i=0; i 15 ) { let s = Spawn('BallImpact',pos); s.angle = atan2(HitNormal.y,HitNormal.x); s.pitch = asin(-HitNormal.z); } } gravity = .35; if ( (vel.length() < 5) && (pos.z <= floorz) ) { ClearBounce(); ExplodeMissile(); } } States { Spawn: XZW1 A -1; Stop; Bounce: XZW1 A 0 A_HandleBounce(); Goto Spawn; Death: XZW1 A -1 { bMOVEWITHSECTOR = true; A_StopSound(CHAN_WEAPON); } Stop; } } // TBD 1.4 Battle-Boi Sentry Class SaltTracer : LineTracer { Array ShootThroughList; Array WaterHitList; override ETraceStatus TraceCallback() { // liquid splashes if ( Results.CrossedWater ) { let hl = new('WaterHit'); hl.hitpos = Results.CrossedWaterPos; WaterHitList.Push(hl); } else if ( Results.Crossed3DWater ) { let hl = new('WaterHit'); hl.hitpos = Results.Crossed3DWaterPos; WaterHitList.Push(hl); } if ( Results.HitType == TRACE_HitActor ) { if ( Results.HitActor.bSHOOTABLE ) return TRACE_Stop; return TRACE_Skip; } else if ( (Results.HitType == TRACE_HitWall) && (Results.Tier == TIER_Middle) ) { if ( !Results.HitLine.sidedef[1] || (Results.HitLine.Flags&Line.ML_BlockHitscan) ) return TRACE_Stop; ShootThroughList.Push(Results.HitLine); return TRACE_Skip; } return TRACE_Stop; } } Class SaltLight : PaletteLight { Default { Tag "SaltExpl,1"; ReactionTime 30; Args 0,0,0,240; } } Class SaltLight2 : PaletteLight { Default { Tag "SaltExpl"; ReactionTime 30; Args 0,0,0,70; } } Class SaltImpact : SWWMNonInteractiveActor { Default { Obituary "$O_SALTSHOT"; DamageType 'Salt'; RenderStyle 'Add'; Scale 1.8; +NODAMAGETHRUST; +FORCERADIUSDMG; +FORCEXYBILLBOARD; +FOILINVUL; } override void PostBeginPlay() { Super.PostBeginPlay(); A_AlertMonsters(swwm_uncapalert?0:6000,AMF_EMITFROMTARGET); SWWMUtility.DoExplosion(self,30+special2*4,15000,100,40); A_QuakeEx(3.,3.,3.,10,0,250,"",QF_RELATIVE|QF_SCALEDOWN|QF_3D,falloff:150,rollintensity:0.2); A_StartSound("saltshot/hit",CHAN_VOICE,attenuation:.35); A_SprayDecal("ShockMarkSmall",-172); A_SprayDecal("SaltMark",-172); Scale *= FRandom[ExploS](0.8,1.1); int numpt = Random[ExploS](5,9)-special1; for ( int i=0; i 20) && !Random[Spreadgun](0,800/args[0]) ) { let i = Spawn('SaltImpact',level.Vec3Offset(pos,x*speed)); i.angle = atan2(x.y,x.x); i.pitch = asin(-x.z); i.target = target; i.special1 = (Stamina-9)/4; i.special2 = Accuracy; i.args[0] = args[1]; return; } // next beam if ( !(special2%4) && !Random[Spreadgun](0,Stamina) ) Spawn('SaltLight',level.Vec3Offset(pos,x*speed/2)); let next = Spawn('SaltBeam',level.Vec3Offset(pos,x*speed)); double a = FRandom[Spreadgun](0,360), s = FRandom[Spreadgun](0,.06); Vector3 dir = SWWMUtility.ConeSpread(x,y,z,a,s); next.angle = atan2(dir.y,dir.x); next.pitch = asin(-dir.z); next.target = target; next.special2 = (special2+1)%10; next.args[0] = args[0]+1; next.args[1] = args[1]; next.SetStateLabel('TrailSpawn'); } override void PostBeginPlay() { Super.PostBeginPlay(); if ( !Random[Spreadgun](0,3) ) A_StartSound("saltshot/trail",CHAN_VOICE,CHANF_DEFAULT,.3,4.); } override void Tick() { if ( freezetics > 0 ) { freezetics--; return; } if ( isFrozen() ) return; A_FadeOut(.04); if ( Random[Spreadgun](-2,args[2]/10) == 0 ) SWWMUtility.DoExplosion(self,5+Accuracy,5000,speed,flags:DE_HOWL|DE_NONEXPLOSIVE,ignoreme:target); if ( ((special2%4) || args[2]) && !special1 ) SpreadOut(); args[2]++; if ( !CheckNoDelay() || (tics == -1) ) return; if ( tics > 0 ) tics--; while ( !tics ) { if ( !SetState(CurState.NextState) ) return; } } States { Spawn: XZW1 A -1 Bright NoDelay { return FindState('StarterDev')+Random[Spreadgun](0,11)*2; } Stop; TrailSpawn: XZW2 A -1 Bright { return FindState('TrailerDev')+Random[Spreadgun](0,11)*2; } Stop; StarterDev: #### # 25 Bright; XZW1 B -1 Bright; Stop; #### # 25 Bright; XZW1 C -1 Bright; Stop; #### # 25 Bright; XZW1 D -1 Bright; Stop; #### # 25 Bright; XZW1 E -1 Bright; Stop; #### # 25 Bright; XZW1 F -1 Bright; Stop; #### # 25 Bright; XZW1 G -1 Bright; Stop; #### # 25 Bright; XZW1 H -1 Bright; Stop; #### # 25 Bright; XZW1 I -1 Bright; Stop; #### # 25 Bright; XZW1 J -1 Bright; Stop; #### # 25 Bright; XZW1 K -1 Bright; Stop; #### # 25 Bright; XZW1 L -1 Bright; Stop; #### # 25 Bright; XZW1 M -1 Bright; Stop; TrailerDev: #### # 25 Bright; XZW2 B -1 Bright; Stop; #### # 25 Bright; XZW2 C -1 Bright; Stop; #### # 25 Bright; XZW2 D -1 Bright; Stop; #### # 25 Bright; XZW2 E -1 Bright; Stop; #### # 25 Bright; XZW2 F -1 Bright; Stop; #### # 25 Bright; XZW2 G -1 Bright; Stop; #### # 25 Bright; XZW2 H -1 Bright; Stop; #### # 25 Bright; XZW2 I -1 Bright; Stop; #### # 25 Bright; XZW2 J -1 Bright; Stop; #### # 25 Bright; XZW2 K -1 Bright; Stop; #### # 25 Bright; XZW2 L -1 Bright; Stop; #### # 25 Bright; XZW2 M -1 Bright; Stop; } }