PWADX3//Hit text needs to be colored //Hearts destroy team monitors //PINK RING SPEED local function L_SpeedReduce(mo,minspeed,reduce) if not (mo and mo.valid) then return end if minspeed == nil then minspeed = mo.scale*16 //Speed to reduce to end if reduce == nil then reduce = mo.scale*2 //Deceleration amount end if abs(mo.momx)+abs(mo.momy)+abs(mo.momz) > minspeed then //Get speeds local momxy = FixedHypot(mo.momx,mo.momy) local momxyz = FixedHypot(mo.momz,momxy) if momxyz > minspeed then //Get axes speed ratios local momxyratio = FixedDiv(momxy,momxyz) local momzratio = FixedDiv(mo.momz,momxyz) //Setup momentum reduction local newmomxyz = max(minspeed,momxyz-reduce) // New full speed local newmomxy = FixedMul(momxyratio,newmomxyz) local newmomz = FixedMul(momzratio,newmomxyz) //Implement speed decrease P_InstaThrust(mo,mo.angle,newmomxy) mo.momz = newmomz end end end local function L_PinkRing(mo) if not (mo and mo.valid) then return false end //Get ring "pink" status if mo.pinkring == nil then //New ring //Get owner ability if mo.target != nil and mo.target.type == MT_PLAYER and mo.target.player.charability2 == CA2_MELEE then //Change color -- if gametype != GT_CTF and gametype != GT_TEAMMATCH then mo.color = SKINCOLOR_PINK -- end //Set "pink" status mo.pinkring = true if mo.flags2&MF2_BOUNCERING then L_SpeedReduce(mo,mo.scale*16,mo.scale*16) end else mo.pinkring = false end elseif mo.pinkring == true //Do traveling pinkring heart spawns if not(leveltime&3) then local angle = ANG1*P_RandomRange(0,359) local dist = mo.scale*16 local hx = P_ReturnThrustX(nil,angle,dist) local hy = P_ReturnThrustY(nil,angle,dist) local hz = P_RandomRange(-8,8)*mo.scale local heart = P_SpawnAlteredDirectionMissile(mo,MT_LHRT,mo.x+hx,mo.y+hy,mo.z+mo.height/2,0) if heart and heart.valid then if P_MobjFlip(mo) == -1 then mo.target.eflags = $|MFE_VERTICALFLIP end if mo.flags&MF_GRENADEBOUNCE then heart.angle = angle else heart.angle = mo.angle end P_InstaThrust(heart,heart.angle,heart.scale*3) P_SetObjectMomZ(heart,heart.scale*2) heart.scale = $/4 heart.fuse = 16 heart.thrust = true end end //Do incremental pinkring speed reduction if not (mo.flags2&MF2_RAILRING or mo.flags2&MF2_BOUNCERING) then L_SpeedReduce(mo,mo.scale*16,mo.scale*2) end //Do death heart if not(mo.flags&MF_MISSILE) then -- print("Pinkring death, creating heart spawns") local steps = 2 repeat local area = 0 repeat local size = 1 if mo.flags2&MF2_EXPLOSION then size = 2 end local heart = P_SpawnMobj(mo.x,mo.y,mo.z+mo.height/2,MT_LHRT) if heart and heart.valid then -- print("Heart is valid.") heart.target = mo.target heart.thrust = true local div = 1 if steps == 1 then div = 4 end P_SetObjectMomZ(heart,heart.scale*4/div) P_InstaThrust(heart,area*ANG1,heart.scale*2*size) heart.scale = $/2 heart.fuse = 35 end area = $+45/size -- print(area) until area >= 360 steps = $-1 until steps <= 0 mo.pinkring = false end end return true end addHook("MobjThinker", function(mo) L_PinkRing(mo) end, MT_REDRING) addHook("MobjThinker", function(mo) L_PinkRing(mo) end, MT_THROWNAUTOMATIC) addHook("MobjThinker", function(mo) L_PinkRing(mo) end, MT_THROWNSCATTER) addHook("MobjThinker", function(mo) L_PinkRing(mo) end, MT_THROWNBOUNCE) addHook("MobjThinker", function(mo) L_PinkRing(mo) end, MT_THROWNEXPLOSION) addHook("MobjThinker", function(mo) L_PinkRing(mo) end, MT_THROWNGRENADE) addHook("MobjThinker", function(mo) L_PinkRing(mo) end, MT_THROWNINFINITY) //THRUST HEART SPEED addHook("MobjThinker", function(mo) if mo and mo.valid then if mo.thrust then mo.extravalue2 = FRACUNIT else mo.thrust = false end end end, MT_LHRT) //MONITOR/PLAYER, THRUST HEART INTERACTION addHook("ShouldDamage", function(mo,heart,owner,dmg) if not(mo and mo.valid) then return nil end //Relegate this hook to interactions with heart projectiles if not(heart and heart.valid and heart.type == MT_LHRT) then return nil end //Monitors if (mo.flags&MF_MONITOR) then //Get hearth "thrust" status -- print("Thrust heart<>monitor collision. Checking thrust status") if heart.thrust then -- print("Thrust heart specifications met. Monitor will not be destroyed.") return false elseif heart.thrust == nil then -- print("Thrust is nil. Setting to false, monitor will not be destroyed.") heart.thrust = false return false end -- print("Thrust is false. Monitor will be destroyed.") //Resume normal touch behavior return //Players elseif mo.type == MT_PLAYER then -- print("Heart<>player collision check") if heart.target and heart.target.type == MT_PLAYER if not(P_PlayerInPain(mo.player)) and not(mo.player.powers[pw_flashing]) and (((gametype == GT_TEAMMATCH or gametype == GT_CTF) and heart.target.player.ctfteam != mo.player.ctfteam) or (G_TagGametype() and heart.target.player.pflags&PF_TAGIT != mo.player.pflags&PF_TAGIT and not(mo.player.pflags&PF_TAGIT)) or gametype == GT_MATCH) then local naked = not(mo.player.rings or mo.player.powers[pw_shield]) //Do message if netgame and G_RingSlingerGametype() then local col0,col1,col2 //Get player name colors if not(G_GametypeHasTeams()) then col0 = "\x80" col1 = "\x80" col2 = "\x80" else col0 = "\x80" //White if heart.target.player.ctfteam == 2 then col1 = "\x84" //Blue else col1 = "\x85" //Red end if mo.player.ctfteam == 2 then col2 = "\x84" else col2 = "\x85" end end local hurttext = " hit " if G_TagGametype() and not(mo.player.pflags&PF_TAGIT) then hurttext = " tagged " elseif naked then if heart.thrust then hurttext = " smothered " else hurttext = " crushed " end end local weptext = "hammer" if heart.thrust then weptext = "love hearts" end print(col1..heart.target.player.name..col0.."'s "..weptext..hurttext..col2..mo.player.name..col0) end if G_TagGametype() then //Do our own function mo.player.pflags = $|PF_TAGIT if naked then P_DoPlayerPain(mo.player,heart,heart.target) P_PlayDeathSound(mo,mo.player) P_AddPlayerScore(heart.target.player,100) for player in players.iterate() if not(player.pflags&PF_TAGIT) then return true end end print("All players have been tagged!") G_ExitLevel() end return true end return true end -- print("skipped damage") if //Shield and reward points not(mo.player.powers[pw_shield]) and not(mo.player.charability2 == CA2_MELEE) and ((G_GametypeHasTeams() and mo.player.ctfteam == heart.target.player.ctfteam) or gametype == GT_COOP) then -- print("rewarding points") P_AddPlayerScore(heart.target.player,25) return end end end return nil end, MT_NULL)freeslot("mt_targetdummy") addHook("ThinkFrame",function() for player in players.iterate local pmo = player.mo if pmo and pmo.valid and G_RingSlingerGametype() then //Create targetdummy object, which can be used to allow popgun to lock onto players if player.targetdummy == nil or not(player.targetdummy.valid) then player.targetdummy = P_SpawnMissile (pmo,pmo,MT_TARGETDUMMY) player.targetdummy.target = pmo -- print("spawned targetdummy") end end end end) addHook("MobjThinker",function(mo) //Check if target is valid and a player object local target = mo.target if G_RingSlingerGametype() and target and target.valid and target.player then //Check if target is vulnerable if not(P_PlayerInPain(target.player)) and not(target.player.powers[pw_flashing]) and target.health then P_TeleportMove(mo,target.x,target.y,target.z) //Center position onto player object mo.flags2 = $|MF2_INVERTAIMABLE //Allow lock-on else //Target is not vulnerable. Disallow lock-on. mo.flags2 = $&~MF2_INVERTAIMABLE end else //Target was assigned but is now invalid. Remove object. -- print("targetdummy removed") P_RemoveMobj(mo) end end, MT_TARGETDUMMY)addHook("ThinkFrame",function() for player in players.iterate if not(player.mo and player.mo.valid) or player.charability2 != CA2_GUNSLINGER then continue end //Create history if player.firedlast == nil then player.firedlast = player.weapondelay end if player.weaponlast == nil then player.weaponlast = player.currentweapon end //Check if player.weapondelay and not(player.firedlast) and not(player.panim == PA_ABILITY2) then //Increase weapon penalties local cost = 1 if player.rings == 0 then cost = 2 end if player.weaponlast or not(player.powers[pw_infinityring]) then player.rings = max(0,$-1) end -- print("Fired") local side = 0 local pj local doubleup = 0 local spread = 0 local pjtype = MT_REDRING local pjflag = 0 if player.weaponlast == WEP_AUTO then player.weapondelay = $+$ pjtype = MT_THROWNAUTOMATIC pjflag = MF2_AUTOMATIC player.powers[pw_automaticring] = max(0,$-cost) elseif player.weaponlast == WEP_BOUNCE then player.weapondelay = $+$/3 pjtype = MT_THROWNBOUNCE pjflag = MF2_BOUNCERING player.powers[pw_bouncering] = max(0,$-cost) elseif player.weaponlast == WEP_SCATTER then player.weapondelay = $+$/3 pjtype = MT_THROWNSCATTER pjflag = MF2_SCATTER spread = ANGLE_45 doubleup = 1 player.powers[pw_scatterring] = max(0,$-cost) elseif player.weaponlast == WEP_GRENADE then player.weapondelay = $+$*4/3 pjtype = MT_THROWNGRENADE pjflag = MF2_EXPLOSION spread = ANGLE_135 player.powers[pw_grenadering] = max(0,$-cost) elseif player.weaponlast == WEP_EXPLODE then player.weapondelay = $+$/3 pjtype = MT_THROWNEXPLOSION pjflag = MF2_EXPLOSION spread = ANGLE_315 player.powers[pw_explosionring] = max(0,$-cost) elseif player.weaponlast == WEP_RAIL then player.weapondelay = $+$/2 pjtype = MT_REDRING pjflag = MF2_RAILRING|MF2_DONTDRAW player.powers[pw_railring] = max(0,$-cost) elseif player.powers[pw_infinityring] then player.weapondelay = $+$/4 pjtype = MT_THROWNINFINITY player.powers[pw_infinityring] = max(0,$-cost) else player.weapondelay = $+$/4 end repeat -- print(pjflag) pj = P_SpawnPlayerMissile(player.mo,pjtype,pjflag) if pj and pj.valid then //Reposition local thrustfactor = 32 local angle = player.mo.angle + ANGLE_90 + ANGLE_180*side if spread == 0 then local movedist = player.mo.scale*thrustfactor local movex = P_ReturnThrustX(nil,angle,movedist) local movey = P_ReturnThrustY(nil,angle,movedist) local movez = doubleup*movedist*3/2 P_TeleportMove(pj,pj.x+movex,pj.y+movey,pj.z+movez) else local momxy = FixedHypot(pj.momx,pj.momy) local momxyz = FixedHypot(momxy,pj.momz) P_Thrust(pj,pj.angle+spread,momxy*4/thrustfactor) if doubleup != 0 then pj.momz = $+FixedDiv(momxy,momxyz)*doubleup end end //Timers if pjtype == MT_THROWNBOUNCE then pj.fuse = 35*4-P_RandomRange(10,35) elseif pjtype == MT_THROWNGRENADE then pj.fuse = 35*6-P_RandomRange(10,35) end if (pj.flags & MF_MISSILE and pj.flags2 & MF2_RAILRING) local nblockmap = !(pj.flags & MF_NOBLOCKMAP) for i = 0,256 if (i&1) P_SpawnMobj(pj.x, pj.y, pj.z, MT_SPARK) end if not P_TryMove(pj,pj.x+pj.momx,pj.y+pj.momy,1) break end pj.z = $+pj.momz if pj.floorz > min(pj.z,pj.z+pj.height) or pj.ceilingz < max(pj.z,pj.z+pj.height) break end end // Other rail sound plays at contact point. S_StartSound(pj, sfx_rail2) P_KillMobj(pj,nil,nil) end //Aesthetic if pj.type == MT_REDRING and player.ctfteam == 2 then pj.color = SKINCOLOR_BLUE end end side = $+1 spread = $*-1 if doubleup == 1 and side == 2 then doubleup = -1 side = 0 elseif doubleup == -1 and side == 2 then doubleup = 0 end until (side >= 2 and doubleup == 0) end //Update history player.firedlast = player.weapondelay player.weaponlast = player.currentweapon end end)# TargetDummy - for Fang's firing reticle Thing MT_TARGETDUMMY SPEED = 0 SPAWNSTATE = 1 SPAWNHEALTH = 1 DEATHSTATE = S_NULL RADIUS = 24*FRACUNIT HEIGHT = 60*FRACUNIT FLAGS = MF_NOBLOCKMAP|MF2_DONTDRAW|MF_SCENERY ÛLUA_AMYçÊLUA_PGUN±!ËLUA_FANG|2ÜOBJCTCFG