This commit is contained in:
lifestorm
2024-08-05 18:40:29 +03:00
parent 9f505a0646
commit c6d9b6f580
8044 changed files with 1853472 additions and 21 deletions

View File

@@ -0,0 +1,42 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
function PLUGIN:HUDPaint()
local client = LocalPlayer()
local ghostNest = client.ghostNest
if (client.isBuildingNest) then
draw.SimpleTextOutlined("Press LMB to place nest", "DermaLarge", ScrW() / 2, ScrH()-230, Color(250,250,250), TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER, 1, Color(25, 25, 25, 250))
draw.SimpleTextOutlined("Press RMB to cancel", "DermaLarge", ScrW() / 2, ScrH()-200, Color(250,250,250), TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER, 1, Color(25, 25, 25, 250))
if (ghostNest) then
ghostNest:SetPos(client:GetPos() + Angle(0, client:EyeAngles().y, 0):Forward() * 20 + Angle(0, client:EyeAngles().y, 0):Up() * -0.1)
ghostNest:SetAngles(Angle(0, client:EyeAngles().y + 180, 0))
else
client.ghostNest = ents.CreateClientProp()
client.ghostNest:SetModel("models/fless/exodus/gnezdo.mdl")
client.ghostNest:SetMaterial("models/wireframe")
client.ghostNest:Spawn()
client.ghostNest:Activate()
client.ghostNest:SetParent(client)
client.ghostNest:SetRenderMode(RENDERMODE_TRANSALPHA)
end
elseif (ghostNest) then
timer.Simple(0, function()
if (ghostNest and IsValid(ghostNest)) then
ghostNest:Remove()
client.ghostNest = nil
end
end)
elseif (client:GetNetVar("ixBirdMounting")) then
draw.SimpleTextOutlined("Press SPACE to get off", "DermaLarge", ScrW() / 2, ScrH()-230, Color(250,250,250), TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER, 1, Color(25, 25, 25, 250))
end
end

View File

@@ -0,0 +1,57 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
net.Receive("toggleBuildingNest", function()
LocalPlayer().isBuildingNest = net.ReadBool()
end)
local blocked = {}
net.Receive("BirdMountRequest", function()
local client = net.ReadEntity()
if (blocked[client]) then
net.Start("BirdMountDecline")
net.SendToServer()
return
end
local name = hook.Run("GetCharacterName", client, "ic") or client:GetName()
local panel = Derma_Query(name .. " is trying to land on you. Will you let it do that?", "Bird Mount Request",
"Allow", function()
net.Start("BirdMountAllow")
net.SendToServer()
end,
"Decline", function()
net.Start("BirdMountDecline")
net.SendToServer()
end,
"Block", function()
net.Start("BirdMountDecline")
net.SendToServer()
blocked[client] = true
end)
timer.Simple(30, function()
if (IsValid(panel)) then
panel:Remove()
net.Start("BirdMountTimeout")
net.SendToServer()
end
end)
end)
net.Receive("birdEggHatch", function()
vgui.Create("ixbirdEggHatch")
end)

View File

@@ -0,0 +1,130 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
local PANEL = {}
function PANEL:Init()
self:SetSize(ScrW(), ScrH())
self:SetAlpha(0)
self:AlphaTo(255, 0.5, 0)
self.Paint = function(self, width, height)
surface.SetDrawColor(Color(63, 58, 115, 220))
surface.DrawRect(0, 0, width, height)
Derma_DrawBackgroundBlur(self, 1)
end
self.innerContent = self:Add("Panel")
self.innerContent:SetSize(SScaleMin(180), SScaleMin(300))
self.innerContent:Center()
self.innerContent:MakePopup()
self.innerContent.Paint = function(self, w, h)
surface.SetDrawColor(0, 0, 0, 130)
surface.DrawRect(0, 0, w, h)
end
local topbar = self.innerContent:Add("Panel")
topbar:SetHeight(SScaleMin(50 / 3))
topbar:Dock(TOP)
topbar.Paint = function(self, width, height)
surface.SetDrawColor(0, 0, 0, 130)
surface.DrawRect(0, 0, width, height)
end
local titleText = topbar:Add("DLabel")
titleText:SetFont("CharCreationBoldTitleNoClamp")
titleText:Dock(LEFT)
titleText:SetText("Egg Hatch Menu")
titleText:DockMargin(SScaleMin(10 / 3), 0, 0, 0)
titleText:SetContentAlignment(4)
titleText:SizeToContents()
local exit = topbar:Add("DImageButton")
exit:SetImage("willardnetworks/tabmenu/navicons/exit.png")
exit:SetSize(SScaleMin(20 / 3), SScaleMin(20 / 3))
exit:DockMargin(0, SScaleMin(15 / 3), SScaleMin(10 / 3), SScaleMin(15 / 3))
exit:Dock(RIGHT)
exit.DoClick = function()
if (self.ExitCallback) then
self.ExitCallback()
end
self:Remove()
surface.PlaySound("helix/ui/press.wav")
end
local divider = topbar:Add("Panel")
divider:SetSize(1, topbar:GetTall())
divider:Dock(RIGHT)
divider:DockMargin(0, SScaleMin(10 / 3), SScaleMin(10 / 3), SScaleMin(10 / 3))
divider.Paint = function(self, w, h)
surface.SetDrawColor(Color(111, 111, 136, (255 / 100 * 30)))
surface.DrawLine(0, 0, 0, h)
end
local titleText = self.innerContent:Add("DLabel")
titleText:SetFont("TitlesFontNoClamp")
titleText:Dock(TOP)
titleText:SetText("Select a player to receive a temporary bird whitelist:")
titleText:DockMargin(0, SScaleMin(10 / 3), 0, SScaleMin(10 / 3))
titleText:SetContentAlignment(5)
titleText:SizeToContents()
local scrollPanel = self.innerContent:Add("DScrollPanel")
scrollPanel:Dock(FILL)
scrollPanel:DockMargin(0, 0, 0, 20)
for _, v in pairs(player.GetAll()) do
if (v == LocalPlayer()) then continue end
local playerPanel = scrollPanel:Add("DPanel")
playerPanel:Dock(TOP)
playerPanel:DockMargin(20, 0, 20, SScaleMin(10 / 3))
playerPanel:SetTall(SScaleMin(50 / 3))
playerPanel.Paint = function(self, w, h)
surface.SetDrawColor(0, 0, 0, 130)
surface.DrawRect(0, 0, w, h)
end
local avatar = playerPanel:Add("AvatarImage")
avatar:SetSize(SScaleMin(50 / 3), SScaleMin(50 / 3))
avatar:Dock(LEFT)
avatar:SetPlayer(v, 64)
local name = playerPanel:Add("DLabel")
name:SetFont("TitlesFontNoClamp")
name:Dock(FILL)
name:DockMargin(10, 0, 0, 0)
name:SetText(v:SteamName())
name:SetContentAlignment(4)
name:SizeToContents()
local button = playerPanel:Add("DButton")
button:SetText("")
button:Dock(RIGHT)
button:SetSize(SScaleMin(50 / 3), SScaleMin(50 / 3))
button.Paint = function(self, w, h)
surface.SetDrawColor(color_white)
surface.SetMaterial(ix.util.GetMaterial("willardnetworks/mainmenu/charcreation/tick.png"))
surface.DrawTexturedRectRotated(w / 2, h / 2, 30, 72, 0)
end
button.DoClick = function()
net.Start("birdEggHatch")
net.WriteEntity(v)
net.SendToServer()
self:Remove()
surface.PlaySound("helix/ui/press.wav")
end
end
end
vgui.Register("ixbirdEggHatch", PANEL, "EditablePanel")

View File

@@ -0,0 +1,31 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
include("shared.lua")
ENT.PopulateEntityInfo = true
function ENT:OnPopulateEntityInfo(container)
local name = container:AddRow("name")
name:SetImportant()
name:SetText("Bird Nest")
name:SizeToContents()
local description = container:AddRow("description")
description:SetText("A small bird nest, made of wooden sticks, leaves, etc.")
description:SizeToContents()
local progress = container:AddRow("progress")
progress:SetText("Sticks: " .. self:GetNetVar("progress", 0) .. "/30")
progress:SetBackgroundColor(derma.GetColor("Info", container))
progress:SizeToContents()
end

View File

@@ -0,0 +1,97 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
AddCSLuaFile("cl_init.lua")
AddCSLuaFile("shared.lua")
include("shared.lua")
function ENT:Initialize()
self:SetModel("models/fless/exodus/gnezdo.mdl")
self:SetUseType(SIMPLE_USE)
self:PhysicsInit(SOLID_VPHYSICS)
self:SetMoveType(MOVETYPE_VPHYSICS)
self:SetSolid(SOLID_VPHYSICS)
self:SetRenderMode(RENDERMODE_TRANSCOLOR)
self:SetNetVar("progress", 0)
local physObj = self:GetPhysicsObject()
if (IsValid(physObj)) then
physObj:EnableMotion(false)
physObj:Sleep()
end
ix.saveEnts:SaveEntity(self)
end
function ENT:SetProgress(progress)
self:SetNetVar("progress", progress)
if (progress < 30) then
self:SetColor(Color(255, 255, 255, 155 * (progress / 30) + 100))
else
local model = self:GetModel()
local data = ix.container.stored[model]
local container = ents.Create("ix_container")
container:SetPos(self:GetPos())
container:SetAngles(self:GetAngles())
container:SetModel(model)
container:Spawn()
ix.inventory.New(0, "container:" .. model, function(inventory)
inventory.vars.isBag = true
inventory.vars.isContainer = true
if (IsValid(container)) then
container:SetInventory(inventory)
if (ix.plugin.list.containers) then
ix.plugin.list.containers:SaveContainer()
end
end
end)
local physObj = container:GetPhysicsObject()
if (IsValid(physObj)) then
physObj:EnableMotion(false)
physObj:Sleep()
end
self:Remove()
end
end
function ENT:StartTouch(entity)
local progress = self:GetNetVar("progress", 0)
if (progress <= 30 and entity:GetClass() == "ix_item") then
local item = ix.item.instances[entity.ixItemID]
if (item.uniqueID == "woodstick") then
self:SetProgress(progress + item:GetStackSize())
entity:EmitSound("physics/cardboard/cardboard_box_break" .. math.random(1, 3) .. ".wav")
local position = entity:LocalToWorld(entity:OBBCenter())
local effect = EffectData()
effect:SetStart(position)
effect:SetOrigin(position)
effect:SetScale(1)
util.Effect("GlassImpact", effect)
entity:Remove()
end
end
end

View File

@@ -0,0 +1,17 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
ENT.Type = "anim"
ENT.Base = "base_gmodentity"
ENT.PrintName = "Bird Nest"
ENT.Author = "Aspect™"
ENT.Category = "HL2 RP"
ENT.Spawnable = false

View File

@@ -0,0 +1,86 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
FACTION.name = "Bird"
FACTION.description = "A regular bird surviving on scrap and food."
FACTION.color = Color(128, 128, 128, 255)
FACTION.isDefault = false
FACTION.bAllowDatafile = false
FACTION.noAppearances = true
FACTION.noBackground = true
FACTION.noBeard = true
FACTION.noGender = true
FACTION.noGenetics = true
FACTION.ReadOptionDisabled = true
FACTION.noAttributes = true
FACTION.noTBC = true
FACTION.bDrinkUnfilteredWater = true
FACTION.canEatRaw = true
FACTION.factionImage = "materials/willardnetworks/faction_imgs/bird.png"
FACTION.selectImage = "materials/willardnetworks/faction_imgs/bird.png"
FACTION.inventoryImage = "materials/willardnetworks/tabmenu/inventory/backgrounds/sky.png"
FACTION.models = {
"models/crow.mdl",
"models/pigeon.mdl",
"models/seagull.mdl"
}
FACTION.npcRelations = {
["npc_combine_camera"] = D_LI,
["npc_turret_ceiling"] = D_LI,
["npc_cscanner"] = D_LI,
["npc_manhack"] = D_LI,
["npc_rollermine"] = D_LI,
["npc_clawscanner"] = D_LI,
["npc_turret_floor"] = D_LI,
["npc_combinedropship"] = D_LI,
["CombineElite"] = D_LI,
["npc_combinegunship"] = D_LI,
["npc_combine_s"] = D_LI,
["npc_hunter"] = D_LI,
["npc_helicopter"] = D_LI,
["CombinePrison"] = D_LI,
["PrisonShotgunner"] = D_LI,
["ShotgunSoldier"] = D_LI,
["npc_stalker"] = D_LI,
["npc_strider"] = D_LI,
}
function FACTION:OnSpawn(client)
local character = client:GetCharacter()
timer.Simple(0.1, function()
local hull = Vector(10, 10, 10)
client:SetHull(-Vector(hull.x / 2, hull.y / 2, 0), Vector(hull.x / 2, hull.y / 2, hull.z))
client:SetHullDuck(-Vector(hull.x / 2, hull.y / 2, 0), Vector(hull.x / 2, hull.y / 2, hull.z))
client:SetViewOffset(Vector(0,0,10))
client:SetViewOffsetDucked(Vector(0,0,10))
client:SetCurrentViewOffset(Vector(0,10,0))
client:SetWalkSpeed(25)
client:SetRunSpeed(50)
client:SetMaxHealth(ix.config.Get("birdHealth", 2))
client:SetHealth(ix.config.Get("birdHealth", 2))
timer.Simple(1, function() -- Eh...
client:StripWeapons()
end)
local birdData = character:GetData("babyBird", 0)
if (birdData > os.time()) then
client:SetModelScale(0.5)
end
end)
end
FACTION_BIRD = FACTION.index

View File

@@ -0,0 +1,33 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
ITEM.name = "Bird Egg"
ITEM.model = "models/willardnetworks/food/egg2.mdl"
ITEM.description = "A small, fertile egg. There may be tiny traces of excrement on it, if it has not been cleaned."
ITEM.functions.Hatch = {
icon = "icon16/briefcase.png",
OnRun = function(item)
if (item:GetData("hatchTime", 0) < os.time()) then
net.Start("birdEggHatch")
net.Send(item.player)
return false
else
item.player:Notify("This egg is not ready to hatch yet!")
return false
end
end,
OnCanRun = function(item)
return item.player:Team() == FACTION_BIRD
end
}

View File

@@ -0,0 +1,59 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
ITEM.name = "Wood Stick"
ITEM.model = "models/props_debris/wood_splinters01a.mdl"
ITEM.description = "A tiny wooden stick. It's probably not useful to anyone."
ITEM.birdDescription = "A tiny wooden stick. You can use this to make a nest. If you are looking at a nest, you will put the stick(s) in it. Otherwise, you will create a new one."
ITEM.category = "Junk"
ITEM.maxStackSize = 16
function ITEM:GetDescription()
return LocalPlayer():Team() == FACTION_BIRD and self.birdDescription or self.description
end
ITEM.functions.BuildNest = {
name = "Build Nest",
icon = "icon16/basket.png",
OnRun = function(item)
local client = item.player
local target = client:GetEyeTraceNoCursor().Entity
if (target and target:GetClass() == "ix_birdnest") then
local progress = target:GetNetVar("progress", 0)
local stackSize = item:GetStackSize()
target:SetProgress(progress + stackSize)
target:EmitSound("physics/cardboard/cardboard_box_break" .. math.random(1, 3) .. ".wav")
local position = target:LocalToWorld(target:OBBCenter())
local effect = EffectData()
effect:SetStart(position)
effect:SetOrigin(position)
effect:SetScale(1)
util.Effect("GlassImpact", effect)
item:RemoveStack(stackSize)
else
client.isBuildingNest = true
net.Start("toggleBuildingNest")
net.WriteBool(true)
net.Send(client)
end
return false
end,
OnCanRun = function(item)
return !IsValid(item.entity) and item.player:Team() == FACTION_BIRD
end
}

View File

@@ -0,0 +1,97 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
ix.command.Add("BirdMount", {
description = "Attempt to mount a character.",
OnRun = function(self, client)
if (client:GetModel() != "models/seagull.mdl") then
if (client:GetCharacter():GetData("babyBird", 0) < os.time()) then
local target = client:GetEyeTraceNoCursor().Entity
if (target and target:IsPlayer() and target:Team() != FACTION_BIRD and client:GetPos():Distance(target:GetPos()) <= 100) then
if (!client:GetNetVar("ixBirdMounting") and !target:GetNetVar("ixBirdMounted")) then
client:Notify("Mount request sent.")
net.Start("BirdMountRequest")
net.WriteEntity(client)
net.Send(target)
target.ixBirdMountRequester = client
else
client:Notify("You are already mounting someone, or that character is already being mounted.")
end
else
client:Notify("That is not a valid character or that character is too far away!")
end
else
client:Notify("You cannot mount humans as a baby!")
end
else
client:Notify("You cannot mount a human as a seagull!")
end
end,
OnCheckAccess = function(self, client)
return client:Team() == FACTION_BIRD
end
})
ix.command.Add("LayEgg", {
description = "Lay an egg.",
OnRun = function(self, client)
if (client:Team() == FACTION_BIRD) then
local target = client:GetEyeTraceNoCursor().Entity
if (target and target:IsPlayer() and target:Team() == FACTION_BIRD and client:GetModel() == target:GetModel() and client:GetPos():Distance(target:GetPos()) <= 100) then
local character = client:GetCharacter()
local targetCharacter = target:GetCharacter()
local realTime = os.time()
if (character:GetData("nextEgg", 0) < realTime and targetCharacter:GetData("nextEgg", 0) < realTime) then
if (character:GetHunger() <= 25 and character:GetThirst() <= 25 and targetCharacter:GetHunger() <= 25 and targetCharacter:GetThirst() <= 25) then
character:GetInventory():Add("birdegg", 1, {hatchTime = realTime + 86400}) -- 24 hours
character:SetData("nextEgg", realTime + 604800) -- 1 week
targetCharacter:SetData("nextEgg", realTime + 604800) -- 1 week
character:SetHunger(character:GetHunger() + 25)
character:SetThirst(character:GetThirst() + 25)
targetCharacter:SetHunger(targetCharacter:GetHunger() + 25)
targetCharacter:SetThirst(targetCharacter:GetThirst() + 25)
client:Notify("You lay a fresh egg.")
targetCharacter:Notify("Your partner has layed a fresh egg.")
else
client:Notify("You and/or your partner are too hungry or thirsty to lay an egg!")
end
else
client:Notify("You and/or your partner cannot lay another egg just yet!")
end
else
client:Notify("You must be looking at and be close enough to a valid bird of the same species to lay an egg!")
end
else
client:Notify("You try really hard to lay an egg. Alas, humans do not lay eggs, so nothing happens.")
end
end
})
ix.command.Add("ToggleFlight", {
description = "Enable or disable flying.",
OnRun = function(self, client)
if (client:Team() == FACTION_BIRD) then
local state = client:GetNetVar("noFlying")
client:SetNetVar("noFlying", !state)
client:Notify(state and "You have enabled flying. You can now fly around." or "You have disabled flying. You can now hop around.")
else
client:Notify("You spread your arms and begin flapping them up and down. Alas, humans cannot fly, so you end up just looking like an idiot.")
end
end
})

View File

@@ -0,0 +1,244 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
local ix = ix
local math = math
local string = string
local table = table
local PLUGIN = PLUGIN
local randomBirdWords = {"chirp", "caw", "squawk", "cheep", "tweet", "shriek", "crow"}
function PLUGIN:InitializedChatClasses()
ix.chat.Register("icbird", {
format = " \"%s\"",
icon = "willardnetworks/chat/message_icon.png",
indicator = "chatTalking",
GetColor = function(self, speaker, text)
-- If you are looking at the speaker, make it greener to easier identify who is talking.
if (LocalPlayer():GetEyeTrace().Entity == speaker) then
return ix.config.Get("chatListenColor")
end
-- Otherwise, use the normal text color.
return color_white
end,
OnChatAdd = function(self, speaker, text, anonymous, info)
local color = self:GetColor(speaker, text, info)
local name = anonymous and L"someone" or hook.Run("GetCharacterName", speaker, "ic") or (IsValid(speaker) and speaker:Name() or "Console")
local translated = L2("icWNFormat", text)
local bToYou = speaker:GetEyeTraceNoCursor().Entity == LocalPlayer()
if (LocalPlayer():Team() != FACTION_BIRD) then
text = string.Split(text, " ")
for i = 1, #text do
text[i] = randomBirdWords[math.random(#randomBirdWords)]
end
text = table.concat(text, " ")
end
text = ix.chat.Format(text)
if (ix.option.Get("standardIconsEnabled")) then
chat.AddText(ix.util.GetMaterial(self.icon), Color(255, 254, 153, 255), name, " says", bToYou and " (to you)" or "", color, translated or string.format(self.format, text))
else
chat.AddText(Color(255, 254, 153, 255), name, " says", bToYou and " (to you)" or "", color, translated or string.format(self.format, text))
end
end,
CanHear = ix.config.Get("chatRange", 280)
})
ix.chat.Register("wbird", {
format = "%s whispers \"%s\"",
icon = "willardnetworks/chat/whisper_icon.png",
color = Color(158, 162, 191, 255),
CanHear = ix.config.Get("chatRange", 280) * 0.25,
OnChatAdd = function(self, speaker, text, bAnonymous, data)
local color = self.color
local name = anonymous and L"someone" or hook.Run("GetCharacterName", speaker, "wbird") or (IsValid(speaker) and speaker:Name() or "Console")
local translated = L2("wbird" .." Format", name, text)
if (LocalPlayer():Team() != FACTION_BIRD) then
text = string.Split(text, " ")
for i = 1, #text do
text[i] = randomBirdWords[math.random(#randomBirdWords)]
end
text = table.concat(text, " ")
end
text = ix.chat.Format(text)
if (ix.option.Get("standardIconsEnabled")) then
chat.AddText(ix.util.GetMaterial(self.icon), color, translated or string.format(self.format, name, text))
else
chat.AddText(color, translated or string.format(self.format, name, text))
end
end
})
ix.chat.Register("ybird", {
format = "%s yells \"%s\"",
color = Color(254, 171, 103, 255),
icon = "willardnetworks/chat/yell_icon.png",
CanHear = ix.config.Get("chatRange", 280) * 2,
OnChatAdd = function(self, speaker, text, bAnonymous, data)
local color = self.color
local name = anonymous and L"someone" or hook.Run("GetCharacterName", speaker, "ybird") or (IsValid(speaker) and speaker:Name() or "Console")
local translated = L2("ybird" .. "Format", name, text)
if (LocalPlayer():Team() != FACTION_BIRD) then
text = string.Split(text, " ")
for i = 1, #text do
text[i] = randomBirdWords[math.random(#randomBirdWords)]
end
text = table.concat(text, " ")
end
text = ix.chat.Format(text)
if (ix.option.Get("standardIconsEnabled")) then
chat.AddText(ix.util.GetMaterial(self.icon), color, translated or string.format(self.format, name, text))
else
chat.AddText(color, translated or string.format(self.format, name, text))
end
end
})
end
function PLUGIN:SetupMove(client, mv, cmd)
if (client:Team() == FACTION_BIRD and !client:OnGround() and !client:GetNetVar("noFlying")) then
local speed = ix.config.Get("birdFlightSpeed", 50)
local angs = mv:GetAngles()
if (cmd:KeyDown(IN_JUMP) and client:GetLocalVar("stm", 0) > 0) then
angs.p = -30
mv:SetVelocity(angs:Forward() * (100 * ((speed / 100) + 1)))
elseif (cmd:KeyDown(IN_DUCK)) then
angs.p = 30
mv:SetVelocity(angs:Forward() * (100 * ((speed / 100) + 1)))
else
angs.p = 10
mv:SetVelocity(angs:Forward() * (150 * ((speed / 100) + 1)))
end
end
end
-- Makes the player soar if they're falling down. Taken out for now because CalcMainActivity is awful.
--[[
function PLUGIN:CalcMainActivity(client, velocity)
if (SERVER and client:Team() == FACTION_BIRD) then
if (client:GetNetVar("forcedSequence") and client:GetNetVar("forcedSequence") != 4) then
client:LeaveSequence()
end
if (!client:OnGround()) then
if (!client:GetNetVar("forcedSequence")) then
client:ForceSequence("soar", nil, nil, true)
end
end
end
end
--]]
local birdPainSounds = {"npc/crow/pain2.wav", "npc/crow/pain1.wav"}
local birdDeathSounds = {"npc/crow/die1.wav", "npc/crow/die2.wav"}
function PLUGIN:GetPlayerPainSound(client)
if (client:Team() == FACTION_BIRD) then return birdPainSounds[math.random(#birdPainSounds)] end
end
function PLUGIN:GetPlayerDeathSound(client)
if (client:Team() == FACTION_BIRD) then return birdDeathSounds[math.random(#birdDeathSounds)] end
end
function PLUGIN:IsCharacterRecognized(character, id)
local client = character:GetPlayer()
local other = ix.char.loaded[id]:GetPlayer()
if (other and ix.config.Get("birdRecogniseEachother", true) and (client:Team() == FACTION_BIRD and other:Team() == FACTION_BIRD)) then
return true
end
end
function PLUGIN:PrePlayerMessageSend(client, chatType, message, anonymous)
if (client:Team() == FACTION_BIRD) then
if (chatType == "ic" or chatType == "w" or chatType == "y") and ix.config.Get("birdChat", true) then
ix.chat.Send(client, chatType .. "bird", message)
ix.log.Add(client, "chat", string.upper(chatType), message)
return false
elseif ((chatType == "me" or chatType == "it") and !ix.config.Get("birdActions", true)) then
client:Notify("You are not able to use this command as a Bird!")
return false
elseif (chatType == "ooc" and !ix.config.Get("birdOOC", true)) then
client:Notify("You are not able to use this command as a Bird!")
return false
end
end
end
function PLUGIN:CanTransferItem(item, oldInv, newInv)
local client = item.player or item.GetOwner and item:GetOwner() or item.playerID and player.GetBySteamID64(item.playerID) or nil -- what the fuck? Why is this so inconsistent?
if (client and client:Team() == FACTION_BIRD and oldInv != newInv and client:GetCharacter():GetInventory().id == newInv.id) then
if (table.Count(client:GetCharacter():GetInventory():GetItems()) > 0) then
client:Notify("You can only carry one item at a time!")
return false
elseif (item.width > 1 or item.height > 1) then
client:Notify("That item is too heavy for you to carry!")
return false
end
end
end
function PLUGIN:CanPlayerUseCharacter(client, character)
if (character:GetFaction() == FACTION_BIRD) then
local ratio = ix.config.Get("birdRatio", 10)
local playerCount = player.GetCount()
local birdCount = #team.GetPlayers(FACTION_BIRD)
if (birdCount >= math.floor(playerCount / ratio)) then
return false, "There are not enough players online for you to use your bird character at this time!"
end
if (character:GetData("babyBird") and !character:GetData("banned")) then
return true -- Bad, I know, but, eh.
end
end
end
function PLUGIN:InitializedPlugins()
if (ix.plugin.list.inventoryslosts and FACTION_BIRD) then
ix.plugin.list.inventoryslots.noEquipFactions[FACTION_BIRD] = true
end
if (SERVER and ix.saveEnts) then
ix.saveEnts:RegisterEntity("ix_birdnest", true, true, true, {
OnSave = function(entity, data)
data.progress = entity:GetNetVar("progress", 0)
end,
OnRestore = function(entity, data)
entity:SetNetVar("progress", data.progress)
end
})
end
end

View File

@@ -0,0 +1,80 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
local ix = ix
local PLUGIN = PLUGIN
PLUGIN.name = "Bird"
PLUGIN.author = "Aspect™ & Arny"
PLUGIN.description = "Adds the Bird faction, along with some other bird mechanics."
ix.util.Include("cl_hooks.lua")
ix.util.Include("cl_plugin.lua")
ix.util.Include("sh_commands.lua")
ix.util.Include("sh_hooks.lua")
ix.util.Include("sv_hooks.lua")
ix.util.Include("sv_plugin.lua")
-- Thanks Whitehole
ix.anim.bird = {
normal = {
[ACT_MP_STAND_IDLE] = {ACT_IDLE, ACT_IDLE},
[ACT_MP_CROUCH_IDLE] = {ACT_IDLE, ACT_IDLE},
[ACT_MP_WALK] = {ACT_WALK, ACT_WALK},
[ACT_MP_CROUCHWALK] = {ACT_WALK, ACT_WALK},
[ACT_MP_RUN] = {ACT_RUN, ACT_RUN},
[ACT_MP_JUMP] = {ACT_HOP, ACT_HOP},
[ACT_MP_SWIM] = {ACT_FLY, ACT_FLY}
}
}
ix.anim.SetModelClass("models/crow.mdl", "bird")
ix.anim.SetModelClass("models/pigeon.mdl", "bird")
ix.anim.SetModelClass("models/seagull.mdl", "bird")
ix.container.Register("models/fless/exodus/gnezdo.mdl", {
name = "Bird Nest",
description = "A small bird nest, made of wooden sticks, leaves, etc.",
width = 3,
height = 3
})
ix.config.Add("birdRecogniseEachother", true, "Can birds recognise eachother?.", nil, {
category = "Bird"
})
ix.config.Add("birdFlightSpeed", 100, "The speed at which a bird can fly.", nil, {
data = {min = 0, max = 100},
category = "Bird"
})
ix.config.Add("birdHealth", 5, "The default health of birds.", nil, {
data = {min = 1, max = 100},
category = "Bird"
})
ix.config.Add("birdChat", true, "Allow the birds to talk?", nil, {
category = "Bird"
})
ix.config.Add("birdActions", true, "Allow the birds use /me and /it?", nil, {
category = "Bird"
})
ix.config.Add("birdOOC", true, "Allow the birds use OOC?", nil, {
category = "Bird"
})
ix.config.Add("birdRatio", 10, "How many other characters have to be on for a bird to be able to be played.", nil, {
data = {min = 1, max = 100},
category = "Bird"
})

View File

@@ -0,0 +1,209 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
local IsValid = IsValid
local Vector = Vector
local ix = ix
local PLUGIN = PLUGIN
function PLUGIN:PrePlayerLoadedCharacter(client, character, currentChar)
if (IsValid(currentChar) and currentChar:GetFaction() != FACTION_BIRD) then return end
client:SetMaxHealth(100)
client:SetViewOffset(Vector(0, 0, 64))
client:SetViewOffsetDucked(Vector(0, 0, 32))
client:ResetHull()
client:SetWalkSpeed(ix.config.Get("walkSpeed"))
client:SetRunSpeed(ix.config.Get("runSpeed"))
end
local birdSounds = {
["models/crow.mdl"] = {
"npc/crow/alert2.wav",
"npc/crow/idle1.wav",
"npc/crow/idle3.wav",
"npc/crow/alert3.wav"
},
["models/pigeon.mdl"] = {
"ambient/creatures/pigeon_idle1.wav",
"ambient/creatures/pigeon_idle2.wav",
"ambient/creatures/pigeon_idle3.wav",
"ambient/creatures/pigeon_idle4.wav"
},
["models/seagull.mdl"] = {
"ambient/creatures/seagull_idle1.wav",
"ambient/creatures/seagull_idle2.wav",
"ambient/creatures/seagull_idle3.wav"
}
}
function PLUGIN:KeyPress(client, key)
if (client:Team() == FACTION_BIRD) then
if (key == IN_ATTACK) then
if (client.isBuildingNest and client:OnGround()) then
local stickItem = client:GetCharacter():GetInventory():HasItem("woodstick")
if (stickItem) then
local nest = ents.Create("ix_birdnest")
nest:SetPos(client:GetPos() + Angle(0, client:EyeAngles().y, 0):Forward() * 20 + Angle(0, client:EyeAngles().y, 0):Up() * -0.1)
nest:SetAngles(Angle(0, client:EyeAngles().y + 180, 0):SnapTo("y", 1))
nest:Spawn()
nest:SetProgress(1)
stickItem:Remove()
end
client.isBuildingNest = false
net.Start("toggleBuildingNest")
net.WriteBool(false)
net.Send(client)
else
if (!client.nextBirdSound or client.nextBirdSound < CurTime()) then
client.nextBirdSound = CurTime() + 5
client:EmitSound(birdSounds[client:GetModel()][math.random(1, #birdSounds[client:GetModel()])])
end
end
elseif (key == IN_ATTACK2) then
if (client.isBuildingNest) then
client.isBuildingNest = false
net.Start("toggleBuildingNest")
net.WriteBool(false)
net.Send(client)
else
if (client:OnGround()) then
if (!client.lastPeck or client.lastPeck < CurTime()) then
client.lastPeck = CurTime() + 60
client:Notify("You begin pecking the ground for hints of crumbs or other edible food...")
client:ForceSequence("Eat_A", function()
if (math.random(1, 2) == 1) then
local character = client:GetCharacter()
client:Notify("You found some hints of food on the ground.")
character:SetHunger(math.Clamp(character:GetHunger() - 5, 0, 100))
character:SetThirst(math.Clamp(character:GetThirst() - 5, 0, 100))
else
client:Notify("You did not find anything edible.")
end
end)
else
client:Notify("You can't peck the ground again for another " .. math.ceil(client.lastPeck - CurTime()) .. " seconds!")
end
else
client:Notify("You must be on the ground in order to look for food!")
end
end
elseif (key == IN_JUMP and client:GetNetVar("ixBirdMounting")) then
local target = client:GetNetVar("ixBirdMounting")
self:BirdMountCharacter(client, target, false)
elseif (key == IN_RELOAD) then
local character = client:GetCharacter()
if (character:GetHunger() < 50 and character:GetThirst() < 50) then
character:SetHunger(character:GetHunger() + 25)
character:SetThirst(character:GetThirst() + 25)
util.Decal("BirdPoop", client:GetPos(), client:GetPos() + Vector(0, 0, -2000), client)
client:EmitSound("weapons/bugbait/bugbait_squeeze" .. math.random(1, 3) .. ".wav")
else
client:Notify("You are too hungry or thirsty to defecate.")
end
end
end
end
function PLUGIN:CanPlayerTakeItem(client, entity)
local item = ix.item.instances[entity.ixItemID]
if (client:Team() == FACTION_BIRD) then
if (table.Count(client:GetCharacter():GetInventory():GetItems()) > 0) then
client:Notify("You can only carry one item at a time!")
return false
elseif (item.width > 1 or item.height > 1) then
client:Notify("That item is too heavy for you to carry!")
return false
end
end
end
function PLUGIN:PlayerDeath(client)
if (client:Team() == FACTION_BIRD) then
local character = client:GetCharacter()
if (character:GetData("babyBird")) then -- Auto-PK non-donator birds on death.
character:SetData("banned", true)
character:Kick()
character:Save()
end
else
local bird = client:GetNetVar("ixBirdMounted")
if (bird and IsValid(bird)) then
self:BirdMountCharacter(bird, client, false)
end
end
end
-- Don't let the player farm food.
function PLUGIN:PostDropCharacterInventory(client, items, container, inventory)
if (client:Team() == FACTION_BIRD and client:GetCharacter():GetData("babyBird", 0) < os.time()) then
local character = client:GetCharacter()
inventory:Add("ing_bird_meat")
inventory:HasItem("ing_bird_meat").playerID = client:SteamID64()
inventory:HasItem("ing_bird_meat").characterID = 0 -- This has to be networked, or it gets stuck in your inv if you take it. ...I think I'll leave it. Punishment for those who try to exploit. :troll:
end
end
function PLUGIN:PlayerDisconnected(client)
local bird = client:GetNetVar("ixBirdMounted")
if (bird and IsValid(bird)) then
self:BirdMountCharacter(bird, client, false)
end
end
function PLUGIN:CharacterLoaded(character)
local client = character:GetPlayer()
local bird = client:GetNetVar("ixBirdMounted")
if (bird and IsValid(bird)) then
self:BirdMountCharacter(bird, client, false)
end
if (character:GetFaction() == FACTION_BIRD and character:GetData("babyBird", 0) > os.time() and !character:GetData("firstTimeBirdLoaded")) then
character:SetData("firstTimeBirdLoaded", true)
timer.Simple(3, function()
client:Notify("Please update your description to more accurately describe your character.")
timer.Simple(2, function()
client:Notify("Also, please reach out to a member of staff to update your name.")
end)
end)
end
end
function PLUGIN:OnCharacterKicked(character)
local client = character:GetPlayer()
local bird = client:GetNetVar("ixBirdMounted")
if (bird and IsValid(bird)) then
self:BirdMountCharacter(bird, client, false)
end
end

View File

@@ -0,0 +1,278 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
local PLUGIN = PLUGIN
util.AddNetworkString("toggleBuildingNest")
util.AddNetworkString("BirdMountRequest")
util.AddNetworkString("BirdMountAllow")
util.AddNetworkString("BirdMountDecline")
util.AddNetworkString("BirdMountTimeout")
util.AddNetworkString("birdEggHatch")
local angleLookup = {
["models/willardnetworks/citizens/male_"] = {
bone = "ValveBiped.Bip01_R_Trapezius",
upOffset = 1.8,
forwardOffset = 1.5,
rightOffset = -1.3,
forwardAxisRot = -110,
rightAxisRot = -90
},
["models/thomask_110/male_"] = {
bone = "ValveBiped.Bip01_R_Trapezius",
upOffset = 1.8,
forwardOffset = 1.5,
rightOffset = -1.3,
forwardAxisRot = -110,
rightAxisRot = -90
},
["models/willardnetworks/citizens/female_"] = {
bone = "ValveBiped.Bip01_R_Trapezius",
upOffset = 0,
forwardOffset = 0.5,
rightOffset = 0,
forwardAxisRot = -100,
rightAxisRot = -90
},
["models/thomask_110/female_"] = {
bone = "ValveBiped.Bip01_R_Trapezius",
upOffset = 0,
forwardOffset = 0.5,
rightOffset = 0,
forwardAxisRot = -100,
rightAxisRot = -90
},
["models/wn7new/metropolice/male_"] = {
bone = "ValveBiped.Bip01_R_Clavicle",
upOffset = 0.8,
forwardOffset = 1.5,
rightOffset = 4.5,
forwardAxisRot = -100,
rightAxisRot = -90
},
["models/wn7new/metropolice/female_"] = {
bone = "ValveBiped.Bip01_R_Clavicle",
upOffset = 0.8,
forwardOffset = 1.5,
rightOffset = 4.5,
forwardAxisRot = -100,
rightAxisRot = -90
},
["models/wn7new/metropolice_c8/male_"] = {
bone = "ValveBiped.Bip01_R_Clavicle",
upOffset = 0.8,
forwardOffset = 1.5,
rightOffset = 4.5,
forwardAxisRot = -100,
rightAxisRot = -90
},
["models/wn7new/metropolice_c8/female_"] = {
bone = "ValveBiped.Bip01_R_Clavicle",
upOffset = 0.8,
forwardOffset = 1.5,
rightOffset = 4.5,
forwardAxisRot = -100,
rightAxisRot = -90
},
["models/wichacks/"] = {
bone = "ValveBiped.Bip01_R_Clavicle",
upOffset = 0.5,
forwardOffset = 1.5,
rightOffset = 4,
forwardAxisRot = -110,
rightAxisRot = -90
},
["models/models/army/female_"] = {
bone = "ValveBiped.Bip01_R_Clavicle",
upOffset = -0.5,
forwardOffset = 1.5,
rightOffset = 3.8,
forwardAxisRot = -100,
rightAxisRot = -90
},
["models/willardnetworks/vortigau"] = { -- lol
bone = "ValveBiped.neck1",
upOffset = 3.5,
forwardOffset = 0,
rightOffset = 0,
forwardAxisRot = 90,
rightAxisRot = 0
}
}
function PLUGIN:BirdMountCharacter(bird, human, state)
if (state) then
local model = human:GetModel()
local isConscript = string.find(model, "wichacks") -- They just HAD to NOT name them properly, didn't they?
local modelData = isConscript and angleLookup["models/wichacks/"] or angleLookup[string.Left(model, #model - 6)]
if (!modelData) then
client:Notify("You cannot mount this character!")
return
end
local humanPos = human:GetPos()
bird.fakeBird = ents.Create("prop_dynamic")
bird.fakeBird:SetModel(bird:GetModel())
bird.fakeBird:ResetSequence("idle01")
local boneID = human:LookupBone(modelData.bone)
local bonePos = human:GetBonePosition(boneID)
if (bonePos == humanPos) then
bonePos = human:GetBoneMatrix(boneID):GetTranslation()
end
bird.fakeBird:FollowBone(human, boneID)
bird.fakeBird:SetPos(bonePos + human:GetUp() * modelData.upOffset + human:GetForward() * modelData.forwardOffset + human:GetRight() * modelData.rightOffset)
local humanAngles = human:GetAngles()
humanAngles:RotateAroundAxis(human:GetForward(), modelData.forwardAxisRot)
humanAngles:RotateAroundAxis(human:GetRight(), modelData.rightAxisRot)
bird.fakeBird:SetAngles(humanAngles)
bird:StripWeapons()
bird:SetMoveType(MOVETYPE_OBSERVER)
bird:SetNoDraw(true)
bird:SetNotSolid(true)
bird:Spectate(OBS_MODE_CHASE)
bird:SpectateEntity(human)
bird:SetNetVar("ixBirdMounting", human)
human:SetNetVar("ixBirdMounted", bird)
local timerName = "ixBirdPosFix_" .. bird:SteamID()
timer.Create(timerName, 5, 0, function() -- I don't like this, but helix does it for ragdolls, so, meh.
if (IsValid(human) and IsValid(bird)) then
bird:SetPos(human:GetPos())
else
timer.Remove(timerName)
end
end)
else
bird:SetMoveType(MOVETYPE_WALK)
bird:SetNoDraw(false)
bird:SetNotSolid(false)
bird:Spectate(OBS_MODE_NONE)
bird:UnSpectate()
if (human and IsValid(human)) then
human:SetNetVar("ixBirdMounted", false)
end
bird:SetNetVar("ixBirdMounting", false)
local timerName = "ixBirdPosFix_" .. bird:SteamID()
if (timer.Exists(timerName)) then
timer.Remove(timerName)
end
local fakeBird = bird.fakeBird
if (fakeBird and IsValid(fakeBird)) then
bird:SetPos(fakeBird:GetPos() + Vector(0, 0, 15))
fakeBird:Remove()
bird.fakeBird = nil
end
end
end
net.Receive("BirdMountAllow", function(_, client)
local requester = client.ixBirdMountRequester
if (!IsValid(requester)) then return end
PLUGIN:BirdMountCharacter(requester, client, true)
client.ixBirdMountRequester = nil
end)
net.Receive("BirdMountDecline", function(_, client)
local requester = client.ixBirdMountRequester
if (!IsValid(requester)) then return end
requester:Notify(hook.Run("GetCharacterName", client, "ic") or client:GetName() .. " declined your mount request.")
client.ixBirdMountRequester = nil
end)
net.Receive("BirdMountTimeout", function(_, client)
local requester = client.ixBirdMountRequester
if (!IsValid(requester)) then return end
requester:Notify(hook.Run("GetCharacterName", client, "ic") or client:GetName() .. " did not respond to your mount request.")
client.ixBirdMountRequester = nil
end)
net.Receive("birdEggHatch", function(_, client)
if (client:Team() != FACTION_BIRD) then return end
local egg = client:GetCharacter():GetInventory():HasItem("birdegg")
local receiver = net.ReadEntity()
if (!egg or !receiver:IsPlayer()) then return end
if (client == receiver) then
client:Notify("You cannot target yourself!")
return
end
local receiverWhitelists = receiver:GetData("whitelists", {})
if (receiverWhitelists[FACTION_BIRD]) then
client:Notify("This player already has a bird whitelist!")
return
end
local payload = {
canread = true,
description = "A regular bird surviving on scrap and food.",
faction = "bird",
gender = "female",
glasses = false,
model = client:GetModel(),
name = "Bird #" .. math.random(111, 999),
steamID = receiver:SteamID64()
}
ix.char.Create(payload, function(id)
if (IsValid(receiver)) then
ix.char.loaded[id]:SetData("babyBird", os.time() + 86400) -- 24 hours
ix.char.loaded[id]:SetData("pos", {client:GetPos(), client:EyeAngles(), game.GetMap()})
ix.char.loaded[id]:Sync(receiver)
net.Start("ixCharacterAuthed")
net.WriteUInt(id, 32)
net.WriteUInt(#receiver.ixCharList, 6)
for _, v in ipairs(receiver.ixCharList) do
net.WriteUInt(v, 32)
end
net.Send(receiver)
egg:Remove()
receiver:Notify(client:SteamName() .. " has selected you to receive a single-life bird whitelist. A character has automatically been created for you.")
MsgN("Created bird character '" .. id .. "' for " .. receiver:SteamName() .. ".")
hook.Run("OnCharacterCreated", receiver, ix.char.loaded[id])
end
end)
end)