This commit is contained in:
lifestorm
2024-08-04 22:55:00 +03:00
parent 8064ba84d8
commit 73479cff9e
7338 changed files with 1718883 additions and 14 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("Clique GAUCHE pour placer", "DermaLarge", ScrW() / 2, ScrH()-230, Color(250,250,250), TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER, 1, Color(25, 25, 25, 250))
draw.SimpleTextOutlined("Clique DROIT pour annuler", "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("Appuyez sur ESPACE pour vous envoler", "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 .. " tente de se poser sur vous. Vous le laissez ?", "Requête d'oiseau",
"Autoriser", function()
net.Start("BirdMountAllow")
net.SendToServer()
end,
"Refuser", function()
net.Start("BirdMountDecline")
net.SendToServer()
end,
"Bloquer", 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("Menu d'éclosion des oeufs")
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("Sélectionner un joueur qui sera WL temporairement :")
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("Nid d'oiseau")
name:SizeToContents()
local description = container:AddRow("description")
description:SetText("Un petit nid d'oiseau, composé de batons et de feuilles...")
description:SizeToContents()
local progress = container:AddRow("progress")
progress:SetText("Batons : " .. 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 = "Oiseau"
FACTION.description = "Un oiseau vivant dans un nid et cherchant de la nourriture."
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,35 @@
--[[
| 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 = "Oeuf d'oiseau"
ITEM.model = "models/willardnetworks/food/egg2.mdl"
ITEM.description = "Cet objet fragile et délicat semble avoir été tout juste pondu. Sa coquille est lisse et possède une teinte délicate, comme si elle avait été peinte à l'aquarelle. On peut facilement imaginer les petits piaillements de l'oisillon qui grandira à l'intérieur de cet œuf."
ITEM.category = "Nourriture"
ITEM.functions.Hatch = {
name = "Éclore",
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("L'oeuf n'est pas encore prêt d'éclore !")
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 = "Bâton"
ITEM.model = "models/props_debris/wood_splinters01a.mdl"
ITEM.description = "Un petit bâton de bois. Totalement inutile pour vous."
ITEM.birdDescription = "Un petit bâton en bois, lisse et poli, de la taille d'un doigt, avec une extrémité pointue et l'autre légèrement incurvée. Cet objet est souvent utilisé par les oiseaux pour construire leur nid."
ITEM.category = "Déchets"
ITEM.maxStackSize = 10
function ITEM:GetDescription()
return LocalPlayer():Team() == FACTION_BIRD and self.birdDescription or self.description
end
ITEM.functions.BuildNest = {
name = "Constuire un nid",
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 = "Tenter de vous poser sur une personne.",
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("Requête envoyée.")
net.Start("BirdMountRequest")
net.WriteEntity(client)
net.Send(target)
target.ixBirdMountRequester = client
else
client:Notify("Vous êtes déjà sur une personne.")
end
else
client:Notify("Ce n'est pas une personne ou elle est trop loin !")
end
else
client:Notify("Vous ne pouvez pas vous poser en tant que bébé !")
end
else
client:Notify("Vous ne pouvez pas vous poser en tant que mouette !")
end
end,
OnCheckAccess = function(self, client)
return client:Team() == FACTION_BIRD
end
})
ix.command.Add("LayEgg", {
description = "Pondre un oeuf.",
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("Vous avez pondu un oeuf.")
targetCharacter:Notify("Votre partenaire a pondu un oeuf.")
else
client:Notify("Vous et/ou votre partenaire êtes trop affamé ou assoifé pour pondre !")
end
else
client:Notify("Vous et/ou votre partenaire ne pouvez pas pondre encore un oeuf !")
end
else
client:Notify("Vous devez regarder de près un oiseau de la même race pour pondre.")
end
else
client:Notify("Vous essayez très fort de pondre un oeuf. Hélas, les humains ne pondent pas d'oeufs, alors rien ne se passe.")
end
end
})
ix.command.Add("ToggleFlight", {
description = "Activer ou pas le vol.",
OnRun = function(self, client)
if (client:Team() == FACTION_BIRD) then
local state = client:GetNetVar("noFlying")
client:SetNetVar("noFlying", !state)
client:Notify(state and "Vous avez activé le vol. Vous pouvez maintenant vous déplacer en volant" or "Vous avez désactivé le vol. Vous pouvez maintenant sauter partout.")
else
client:Notify("Vous étendez vos bras et commencez à les battre de haut en bas. Hélas, les humains ne peuvent pas voler, alors vous finissez par avoir l'air d'un 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, " dit", bToYou and " (à vous)" or "", color, translated or string.format(self.format, text))
else
chat.AddText(Color(255, 254, 153, 255), name, " dit", bToYou and " (à vous)" or "", color, translated or string.format(self.format, text))
end
end,
CanHear = ix.config.Get("chatRange", 280)
})
ix.chat.Register("wbird", {
format = "%s chuchotte \"%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 crie \"%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("Vous ne pouvez pas utiliser cette commande comme un oiseau !")
return false
elseif (chatType == "ooc" and !ix.config.Get("birdOOC", true)) then
client:Notify("Vous ne pouvez pas utiliser cette commande comme un oiseau !")
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("Vous ne pouvez transporter qu'un seul article à la fois !")
return false
elseif (item.width > 1 or item.height > 1) then
client:Notify("Cet article est trop lourd pour que vous le portiez !")
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, "Il n'y a pas assez de joueurs en ligne pour que vous puissiez utiliser votre oiseau en ce moment !"
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 = "Nid d'oiseau",
description = "Un petit nid d'Oiseaux, fait de bâtons de bois, de feuilles, etc.",
width = 3,
height = 3
})
ix.config.Add("birdRecogniseEachother", true, "Les Oiseauxx peuvent-ils se reconnaître entre eux ?.", nil, {
category = "Oiseaux"
})
ix.config.Add("birdFlightSpeed", 100, "La vitesse à laquelle un Oiseaux peut voler.", nil, {
data = {min = 0, max = 100},
category = "Oiseaux"
})
ix.config.Add("birdHealth", 5, "La santé par défaut des Oiseauxx.", nil, {
data = {min = 1, max = 100},
category = "Oiseaux"
})
ix.config.Add("birdChat", true, "Permettre aux Oiseauxx de parler ?", nil, {
category = "Oiseaux"
})
ix.config.Add("birdActions", true, "Les Oiseauxx peuvent-ils utiliser /moi et /c'est ?", nil, {
category = "Oiseaux"
})
ix.config.Add("birdOOC", true, "Permettre aux Oiseauxx d'utiliser l'OOC ?", nil, {
category = "Oiseaux"
})
ix.config.Add("birdRatio", 10, "Joueurs en ligne minimum", nil, {
data = {min = 1, max = 100},
category = "Oiseaux"
})

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("Vous commencez à picorer le sol pour trouver des miettes ou de la nourriture comestible...")
client:ForceSequence("Eat_A", function()
if (math.random(1, 2) == 1) then
local character = client:GetCharacter()
client:Notify("Vous avez trouvé des traces de nourriture sur le sol.")
character:SetHunger(math.Clamp(character:GetHunger() - 5, 0, 100))
character:SetThirst(math.Clamp(character:GetThirst() - 5, 0, 100))
else
client:Notify("Vous n'avez rien trouvé de comestible.")
end
end)
else
client:Notify("Vous ne pouvez pas picorer le sol à nouveau pour " .. math.ceil(client.lastPeck - CurTime()) .. " secondes !")
end
else
client:Notify("Vous devez être au sol pour chercher de la nourriture !")
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("Vous avez trop faim ou trop soif pour déféquer.")
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("Vous ne pouvez porter qu'un seul objet à la fois !")
return false
elseif (item.width > 1 or item.height > 1) then
client:Notify("Cet objet est trop lourd pour que vous le portiez !")
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("Veuillez mettre à jour votre description pour décrire plus précisément votre personnage.")
timer.Simple(2, function()
client:Notify("Veuillez également contacter un membre du staff pour mettre à jour votre nom.")
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,246 @@
--[[
| 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/willardnetworks/citizens/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/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("Vous ne pouvez pas monter ce personnage !")
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() .. " a refusé votre demande")
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() .. " n'a pas répondu à votre demande.")
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("Vous ne pouvez pas vous cibler vous-même !")
return
end
local receiverWhitelists = receiver:GetData("whitelists", {})
if (receiverWhitelists[FACTION_BIRD]) then
client:Notify("Ce joueur a déjà une WL d'oiseaux !")
return
end
local payload = {
canread = true,
description = "Un oiseau ordinaire qui survit grâce aux déchets et à la nourriture.",
faction = "bird",
gender = "female",
glasses = false,
model = client:GetModel(),
name = "Oiseau #" .. 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() .. " vous a sélectionné pour recevoir une WL d'oiseaux à vie unique. Un personnage a été automatiquement créé pour vous.")
MsgN("A crée l'oiseau " .. id .. " pour " .. receiver:SteamName() .. ".")
hook.Run("OnCharacterCreated", receiver, ix.char.loaded[id])
end
end)
end)