// script by klasky and glide ks (he did most of the work as of v2), i looked at banskins.lua and l_admintools-v1.3.lua for reference + enes2gamer helped me out with this a bit -- Ty Romoney5 for the find player function (GLide KS) local function findPlayer(name,p) if name==nil then return p end if tonumber(name)~=nil and players[tonumber(name)] then return players[tonumber(name)] end for player in players.iterate do if player.name:lower()==name:lower() then return player end end local len = name:len() for player in players.iterate do --2nd pass, using string.sub for short names if player.name:lower():sub(1,len)==name:lower() then return player end end end local function SetSkin(sender, player, arg, islocal) -- Main function to get a false skin. -- Let's handle the messages a bit better for these situations. local who = (player == consoleplayer and "you") or player.name or "this player" local is = (player == consoleplayer and "are") or "is" local r = (player == consoleplayer and "r") or "'s" local final_arg = (arg == "random" and skins[P_RandomRange(0, #skins - 1)].name) or arg if not (player.mo and player.mo.valid) or gamestate != GS_LEVEL then CONS_Printf(sender, "Either the argument is invalid or "..who.." "..is.." not in a map.") return end if skins[final_arg] then -- Change the player to the given skin (arg) if final_arg == ((islocal and player.falseskinlocal or player.falseskin) or player.mo.skin) then CONS_Printf(sender, who.." "..is.." already using that skin's sprites.") return end if islocal then player.falseskinlocal = final_arg -- for local skin switching other players. takes priority over player.falseskin else player.falseskin = final_arg end CONS_Printf(sender, who..r.." sprites has been switched to '"..final_arg.."' skin sprites.") if islocal then CONS_Printf(sender, "\x82".."NOTE: Skin applied locally") end elseif (final_arg == "off" or final_arg == "none" or final_arg == "false") then -- Disable if not ((islocal and player.falseskinlocal) or player.falseskin) then CONS_Printf(sender, "Already disabled...") return end if islocal then player.falseskinlocal = player.falseskin or nil CONS_Printf(sender, "\x82".."NOTE: Skin disabled locally") else player.falseskin = nil end else CONS_Printf(sender, "Skin '"..final_arg.."' can't be found.") end end COM_AddCommand("switchskinsprites", function(player, arg, pname) -- The command itself if not arg then CONS_Printf(player, "Sets your skin's sprites to another's.") return end -- Modify a player's sprites, local only. if pname then if player != consoleplayer then return end if pname == "all" then -- For everyone? Sure. for otherplayer in players.iterate() do if otherplayer.mo and otherplayer.mo.valid then if otherplayer == consoleplayer then continue end SetSkin(player, otherplayer, arg, true) end end return end if not findPlayer(pname, player) then CONS_Printf(player, "Player '"..pname.."' cannot be found.") return elseif findPlayer(pname, player) == consoleplayer then CONS_Printf(player, "You can't apply this for yourself. Don't use the 2nd argument instead.") return end SetSkin(player, findPlayer(pname, player), arg, true) -- For the specific player return else SetSkin(player, player, arg) -- It's for yourself, should be shown to everyone. end end) -------The main "cape"------- freeslot("MT_FALSESKIN") -- We could just use MT_THOK but then we don't have a way to remove it when the player reborns (GLide KS) -- MT_OVERLAY neither because it will draw over shields. -- So a custom object is needed to remove the object when the player's mobj doesn't exists anymore. -- ...Unless do you want to remove it when the player dies? mobjinfo[MT_FALSESKIN] = { doomednum = -1, spawnstate = mobjinfo[MT_PLAYER].spawnstate, radius = mobjinfo[MT_PLAYER].radius, height = mobjinfo[MT_PLAYER].height, flags = MF_NOGRAVITY|MF_NOCLIP|MF_NOBLOCKMAP|MF_SCENERY|MF_NOCLIPTHING|MF_NOCLIPHEIGHT } -- False skin's thinker, use this to sync anything visual -- falsemo : the falseskin's mobj -- p : player_t local function FalseSkinThinker(falsemo, p) if not (p and p.mo and p.mo.valid) then return end local pmo = p.mo local falseskin_name = p.falseskinlocal or p.falseskin -- Hide the player. we could just use MF2_DONTDRAW -- But we're synching player flags2 as well for visual properties accuracy pmo.alpha = 0 -- We should also reset the state and frame to avoid errors dropping when changing skins if falsemo.skin and falsemo.skin != falseskin_name then falsemo.frame = 0 if not falsemo.fixapply then -- Umm.. trust falsemo.fixapply = true end end -- Sync up the main things of a skin. SPR_PLAY, Sprite2 and States falsemo.skin = falseskin_name local spinjump_check = (not (p.charflags & SF_NOJUMPSPIN) and pmo.state == S_PLAY_JUMP) local state = spinjump_check and S_PLAY_ROLL or pmo.state -- this is to fix an issue where non-spin character's jump behaves different if falsemo.state != state then P_SetMobjStateNF(falsemo, state) -- Very important to set state first before everything else. falsemo.sprite = pmo.sprite falsemo.sprite2 = pmo.sprite2 falsemo.frame = pmo.frame & ~FF_FRAMEMASK end -- And now eeeverything visual related. falsemo.tics = (falsemo.fixapply and 1) or pmo.tics if falsemo.fixapply then falsemo.fixapply = false end falsemo.scale = pmo.scale falsemo.spritexscale = pmo.spritexscale falsemo.dispoffset = pmo.dispoffset falsemo.spriteyscale = pmo.spriteyscale falsemo.spriteroll = pmo.spriteroll falsemo.dontdrawforviewmobj = pmo -- Don't draw on first person falsemo.translation = pmo.translation falsemo.colorized = pmo.colorized falsemo.color = pmo.color falsemo.shadowscale = FixedMul(FixedDiv(skins[falsemo.skin].radius, pmo.radius or 1), pmo.scale) falsemo.radius = pmo.radius falsemo.height = pmo.height falsemo.angle = p.drawangle falsemo.flags2 = pmo.flags2 P_MoveOrigin(falsemo, pmo.x, pmo.y, pmo.z) -- Adapt sprites for superform as well local is_using_supersprites = p.powers[pw_super] or (pmo.eflags & MFE_FORCESUPER) -- Super Sprites addon support. falsemo.eflags = pmo.eflags|(is_using_supersprites and MFE_FORCESUPER or 0) end local function Main(p) local mo = p.mo if not (mo and mo.valid and mo.skin) then return end local falseskin = p.falseskinlocal or p.falseskin if not falseskin then return end if falseskin != mo.skin and not (mo.falseskinmobj and mo.falseskinmobj.valid) then mo.falseskinmobj = P_SpawnMobjFromMobj(mo, 0, 0, 0, MT_FALSESKIN) mo.falseskinmobj.target = mo P_SetOrigin(mo.falseskinmobj, mo.x, mo.y, mo.z) FalseSkinThinker(mo.falseskinmobj, p) end end local function FalseSkin_Removal(mo) if not (mo and mo.valid) then return end -- If the player doesn't even exist anymore or reborns, remove. if not (mo.target and mo.target.valid and mo.target.player) then P_RemoveMobj(mo) return end local p = mo.target.player local falseskin = p.falseskinlocal or p.falseskin -- The player has the same skin or doesn't have a falseskin set. why keep it? if mo.target.skin == mo.skin or falseskin == nil then mo.target.alpha = FU P_RemoveMobj(mo) return end FalseSkinThinker(mo, p) end addHook("PlayerThink", Main) addHook("MobjThinker", FalseSkin_Removal, MT_FALSESKIN)