Class UTranslocatorAmmo : Ammo { Default { Inventory.Icon "I_Tele"; Inventory.Amount 1; Inventory.MaxAmount 2; Ammo.BackpackAmount 0; Ammo.BackpackMaxAmount 2; +INVENTORY.IGNORESKILL; } override void Tick() { Super.Tick(); if ( sting_proto && sting_telegun ) return; if ( Owner ) Owner.RemoveInventory(self); Destroy(); } } Class UTranslocatorModule : Actor { Actor b; bool alreadyhit; double anglevel; Default { Radius 2; Height 2; Speed 16; PROJECTILE; -NOGRAVITY; +USEBOUNCESTATE; +SKYEXPLODE; +HITTRACER; +MOVEWITHSECTOR; +CANBOUNCEWATER; +BLOCKASPLAYER; -ALLOWBOUNCEONACTORS; +DONTBOUNCEONSHOOTABLES; +INTERPOLATEANGLES; BounceType "Hexen"; BounceFactor 0.3; WallBounceFactor 0.3; Gravity 0.35; } override void PostBeginPlay() { Super.PostBeginPlay(); if ( !target ) { Destroy(); return; } b = Spawn("ModuleHitbox",pos); b.A_SetSize(6,6); b.master = self; anglevel = FRandom[TeleHand](3,5)*RandomPick[TeleHand](-1,1); } override bool CanCollideWith( Actor other, bool passive ) { return (other != tracer); } override void Tick() { Super.Tick(); if ( bAMBUSH && !Random[Transloc](0,40) ) { A_PlaySound("transloc/spark"); int numpt = Random[Transloc](20,40); for ( int i=0; i= tracer.pos.z+tracer.height) && tracer.bACTLIKEBRIDGE) ) alreadyhit = true; } } Goto Spawn; Death: TMOD A -1 { if ( tracer && !tracer.bACTLIKEBRIDGE ) { SetOrigin(tracer.Vec2OffsetZ(0,0,pos.z),false); vel.xy *= 0; tracer = null; bHITTRACER = false; } } Stop; } } Class UTranslocator : UnrealWeapon { Actor module; override bool TryPickup( in out Actor toucher ) { if ( !sting_proto || !sting_telegun ) return false; // not allowed return Super.TryPickup(toucher); } override void Tick() { Super.Tick(); if ( sting_proto && sting_telegun ) return; if ( Owner ) Owner.RemoveInventory(self); Destroy(); } override void DoEffect() { Super.DoEffect(); if ( Ammo1 ) Ammo1.Amount = module?1:2; } action void A_ThrowModule() { Weapon weap = Weapon(invoker); if ( !weap ) return; A_PlaySound("telehand/throw",CHAN_WEAPON); invoker.FireEffect(); UTMainHandler.DoSwing(self,(FRandom[Translocator](0.2,-0.4),FRandom[Translocator](0.2,-0.7)),2,-0.3,3,SWING_Spring,2,3); Vector3 x, y, z; [x, y, z] = dt_CoordUtil.GetAxes(pitch,angle,roll); Vector3 origin = level.Vec3Offset(Vec2OffsetZ(0,0,player.viewz),10*x-8*y-12*z); let p = Spawn("UTranslocatorModule",origin); p.target = self; p.angle = angle; p.pitch = BulletSlope(); p.A_SetSize(radius); Vector3 dir = (cos(p.angle)*cos(p.pitch),sin(p.angle)*cos(p.pitch),-sin(p.pitch)); dir.z += 0.35*(1-abs(dir.z)); p.vel = dir*p.speed; invoker.module = p; } action void A_ReturnModule() { Weapon weap = Weapon(invoker); if ( !weap ) return; A_PlaySound("transloc/return",CHAN_WEAPON); invoker.FireEffect(); UTMainHandler.DoSwing(self,(FRandom[Translocator](-0.2,-0.4),FRandom[Translocator](-0.2,0.7)),3,-1,2,SWING_Spring,2,2); if ( invoker.module && invoker.module.bAMBUSH ) { UTMainHandler.DoFlash(self,Color(255,255,255,255),50); A_PlaySound("transloc/spark",CHAN_WEAPON); DamageMobj(invoker,self,int.max,'Telefrag',DMG_THRUSTLESS); } if ( invoker.module ) invoker.module.Destroy(); } action void A_Translocate() { Weapon weap = Weapon(invoker); if ( !weap ) return; if ( !invoker.module ) { invoker.FireEffect(); A_PlaySound("transloc/return",CHAN_WEAPON); return; } // check if there's enough space Vector3 oldpos = pos, newpos = invoker.module.pos; double modulefloorz = invoker.module.floorz, moduleceilingz = invoker.module.ceilingz; bool bBroken = invoker.module.bAMBUSH; invoker.module.Destroy(); invoker.FireEffect(); // squeeze down new z if ceiling is in the way if ( (newpos.z+height > moduleceilingz) ) newpos.z = max(modulefloorz,moduleceilingz-height); // temporarily disable telefragging for all allies bool oldnotele[MAXPLAYERS]; for ( int i=0; i