Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- local ENT = {}
- ENT.Type = "anim"
- ENT.Base = "base_anim"
- ENT.ClassName = "fairy"
- if CLIENT then
- ENT.Size = 1
- function ENT:VectorRandSphere()
- return Angle(math.Rand(-180,180),math.Rand(-180,180),math.Rand(-180,180)):Up()
- end
- function ENT:SetFairyColorEasy(hue)
- self:SetFairyColor(HSVToColor(hue, 0.35, 1))
- end
- function ENT:SetFairyColor(color)
- self.Color = color
- local h,s,v = ColorToHSV(self.Color)
- self.Color2 = HSVToColor(h,0.5,1)
- end
- function ENT:PlayPhrase(text)
- text = text:lower()
- text = text .. " "
- local duration = 0
- local sounds = {}
- local question = text:find("%?") ~= nil
- local total_time = 0
- for chunk in text:gmatch("([%a][aeiou]+[bcdfghjklmnpqrstvwxz]-)") do
- local path = "alan/midna/speech"..tostring(math.max(tonumber(util.CRC(chunk))%47, 1))..".wav"
- local pitch = math.random(120,125)
- local len = SoundDuration(path) * (pitch / 100) - 0.05
- table.insert(
- sounds,
- {
- snd = CreateSound(self, path),
- pitch = pitch,
- len = len,
- }
- )
- total_time = total_time + len
- end
- self.AskingQuestion = question
- self.SoundQueueStart = CurTime()
- self.SoundQueueLength = total_time
- self.SoundQueue = sounds
- end
- function ENT:Ouch()
- local sounds = {}
- local path = "alan/nymph/NymphHit_0"..math.random(4)..".wav"
- local pitch = math.random(95,105)
- local len = SoundDuration(path) * (pitch / 100) - 0.05
- table.insert(
- sounds,
- {
- snd = CreateSound(self, path),
- pitch = pitch,
- len = len,
- }
- )
- self.SoundQueue = sounds
- self.Hurting = true
- timer.Simple(math.Rand(1,2), function() if self:IsValid() then self.Hurting = false end end)
- end
- function ENT:Bounce()
- local csp = CreateSound(self, "alan/bonk.wav")
- csp:PlayEx(100, math.random(95,105))
- end
- function ENT:Laugh()
- local sounds = {}
- local path = "alan/nymph/NymphGiggle_0"..math.random(9)..".wav"
- local pitch = math.random(95,105)
- local len = SoundDuration(path) * (pitch / 100) - 0.05
- table.insert(
- sounds,
- {
- snd = CreateSound(self, path),
- pitch = pitch,
- len = len,
- }
- )
- table.insert(sounds, {path = path, snd = CreateSound(self, path), pitch = math.random(95,105)})
- self.Laughing = true
- self.AskingQuestion = false
- self.SoundQueue = sounds
- end
- function ENT:CalcSoundQueue()
- if self.SoundQueue then
- self.sound_idx = self.sound_idx or 1
- local data = self.SoundQueue[self.sound_idx]
- --LocalPlayer():SetDSP(27)
- if not data then
- self.SoundQueue = nil
- self.question_pitch = 1
- self.sound_idx = 1
- --LocalPlayer():SetDSP(0)
- return
- end
- if not data.len then return end -- ????
- if not data.busy then
- data.busy = true
- data.snd:PlayEx(100, data.pitch)
- data.next = CurTime() + data.len * (100 / 120)
- self.SizePulse = math.Rand(1.3,1.8)
- end
- if self.AskingQuestion and self:GetPhraseFraction() > 0.7 then
- self.question_pitch = self.question_pitch or 1
- self.question_pitch = (self.question_pitch + (self.SoundQueueLength / 300) * (FrameTime() * 130)) ^ 1.056
- data.snd:ChangePitch(data.pitch + self.question_pitch)
- data.next = data.next - (self.question_pitch / 10000)
- end
- if data.next and data.next < CurTime() then
- data.snd:Stop()
- self.sound_idx = self.sound_idx + 1
- end
- end
- end
- local wing_mdl = Model("models/python1320/wing.mdl")
- local wing_mat = "alan/wing"
- ENT.WingSpeed = 6.3
- ENT.FlapLength = 50
- ENT.WingSize = 0.4
- ENT.SizePulse = 1
- local ClientsideModelEx = function(mdl) local ent = ents.Create("prop_physics") ent:SetModel(mdl) return ent end
- function ENT:Initialize()
- self.Emitter = ParticleEmitter(vector_origin)
- self.Emitter:SetNoDraw(true)
- self.leftwing = ClientsideModelEx(wing_mdl)
- self.rightwing = ClientsideModelEx(wing_mdl)
- self.bleftwing = ClientsideModelEx(wing_mdl)
- self.brightwing = ClientsideModelEx(wing_mdl)
- self.leftwing:SetNoDraw(true)
- self.rightwing:SetNoDraw(true)
- self.bleftwing:SetNoDraw(true)
- self.brightwing:SetNoDraw(true)
- self.leftwing:SetMaterial(wing_mat)
- self.rightwing:SetMaterial(wing_mat)
- self.bleftwing:SetMaterial(wing_mat)
- self.brightwing:SetMaterial(wing_mat)
- self.light = DynamicLight(self:EntIndex())
- self.flap = CreateSound(self, "alan/flap.wav")
- self.float = CreateSound(self, "alan/float.wav")
- self.flap:Play()
- self.float:Play()
- self.flap:ChangeVolume(0.2)
- self:SetFairyColorEasy(tonumber(util.CRC(self:EntIndex()))%360)
- self.Size = (tonumber(util.CRC(self:EntIndex()))%100/100) + 0.5
- end
- ENT.RenderGroup = RENDERGROUP_TRANSLUCENT
- function ENT:DrawTranslucent()
- self:CalcAngles()
- self:DrawParticles()
- self:DrawWings()
- self:DrawSprites()
- end
- function ENT:Think()
- self:CalcSounds()
- self:CalcLight()
- self:CalcPulse()
- self.leftwing:SetModelScale(Vector(1,0.5,1)*self.Size*self.WingSize)
- self.rightwing:SetModelScale(Vector(1,0.5,1)*self.Size*self.WingSize)
- self.bleftwing:SetModelScale(Vector()*(self.Size/3*self.WingSize))
- self.brightwing:SetModelScale(Vector()*(self.Size/3*self.WingSize))
- self:NextThink(CurTime())
- return true
- end
- function ENT:CalcPulse()
- self.SizePulse = math.Clamp(self.SizePulse + ((1 - self.SizePulse) * FrameTime() * 5), 1, 3)
- end
- function ENT:CalcAngles()
- if self.Hurting then return end
- local vel = self:GetVelocity()
- if vel:Length() > 2 then
- local ang = vel:Angle()
- self:SetAngles(ang)
- self.last_ang = ang
- elseif self.last_ang then
- self:SetAngles(self.last_ang)
- end
- end
- local function add_0(n)
- return n < 10 and "0"..n or n
- end
- function ENT:Say(txt)
- if LocalPlayer():EyePos():Distance(self:GetPos()) > 2000 then return end
- local tbl = {}
- if self.is_dead then
- table.insert( tbl, Color( 255, 30, 40 ) )
- table.insert( tbl, "*DEAD* " )
- end
- local time = os.date("*t")
- table.insert( tbl, Color(118, 170, 217) )
- table.insert( tbl, string.format("%s:%s", add_0(time.hour), add_0(time.min)) )
- table.insert( tbl, Color( 255, 255, 255 ) )
- table.insert( tbl, " - " )
- table.insert(tbl, self.Color)
- table.insert(tbl, "Fairy")
- table.insert(tbl, color_white)
- table.insert(tbl, ": " .. txt)
- chat.AddText(unpack(tbl))
- self:PlayPhrase(txt)
- end
- function ENT:GetPhraseFraction()
- return -(((self.SoundQueueLength - CurTime()) + self.SoundQueueStart - 1) / 2) + 1
- end
- function ENT:CalcSounds()
- self.speed = 6.3
- if self.Hurting then
- self.flap:Stop()
- else
- self.flap:Play()
- self.flap:ChangeVolume(0.2)
- end
- local length = self:GetVelocity():Length()
- self.float:ChangePitch(length/50+100)
- self.float:ChangeVolume(length/100)
- self.flap:ChangePitch((length/50+100) + self.SizePulse * 20)
- self:CalcSoundQueue()
- end
- function ENT:CalcLight()
- if self.light then
- self.light.Pos = self:GetPos()
- self.light.r = self.Color2.r
- self.light.g = self.Color2.g
- self.light.b = self.Color2.b
- self.light.Brightness = self.Size * 1
- self.light.Size = self.Size * 512
- self.light.Decay = self.Size * 32 * 5
- self.light.DieTime = CurTime() + 1
- end
- end
- local glow = Material("sprites/light_glow02_add")
- local warp = Material("particle/warp2_warp")
- local eye = Material("particle/warp1_warp")
- local blur = Material("sprites/heatwave")
- ENT.Blink = math.huge
- function ENT:DrawSprites()
- local pos = self:GetPos()
- local pulse = math.sin(CurTime()*2) * 0.5
- render.SetMaterial(warp)
- render.DrawSprite(
- pos, 12 * self.Size + pulse,
- 12 * self.Size + pulse,
- Color(self.Color.r, self.Color.g, self.Color.b, 100)
- )
- render.SetMaterial(blur)
- render.DrawSprite(
- pos, (1-self.SizePulse) * 20,
- (1-self.SizePulse) * 20,
- Color(10,10,10, 1)
- )
- render.SetMaterial(glow)
- render.DrawSprite(
- pos,
- 50 * self.Size,
- 50 * self.Size,
- Color(self.Color.r, self.Color.g, self.Color.b, 150)
- )
- render.DrawSprite(
- pos,
- 30 * self.Size,
- 30 * self.Size,
- self.Color
- )
- local fade_mult = math.Clamp(-self:GetForward():Dot((self:GetPos() - LocalPlayer():EyePos()):Normalize()), 0, 1)
- if fade_mult ~= 0 then
- render.SetMaterial(eye)
- if self.Blink > CurTime() then
- render.DrawSprite(
- pos + (self:GetRight() * 0.8 + self:GetUp() * 0.7) * self.Size,
- 0.5 * fade_mult * self.Size,
- 0.5 * fade_mult * self.Size,
- Color(10,10,10,200 * fade_mult)
- )
- render.DrawSprite(
- pos + (self:GetRight() * -0.8 + self:GetUp() * 0.7) * self.Size,
- 0.5 * fade_mult * self.Size,
- 0.5 * fade_mult * self.Size,
- Color(10,10,10,200 * fade_mult)
- )
- else
- self.Blink = math.random() < 0.99 and CurTime()-0.2 or math.huge
- end
- render.DrawSprite(
- pos + (self:GetRight() * -0.05 -self:GetUp() * 0.7) * self.Size,
- 0.8 * fade_mult * self.Size * self.SizePulse,
- 0.8 * fade_mult * self.Size * self.SizePulse,
- Color(10,10,10,200*fade_mult)
- )
- end
- end
- function ENT:DrawSunbeams()
- local pos = self:GetPos():ToScreen()
- if (pos.x > 0 and pos.x < ScrW()) and (pos.y > 0 and pos.y < ScrH()) then
- local mult = -math.Clamp((LocalPlayer():EyePos() - self:GetPos()):LengthSqr()*0.00001, 0, 1) + 1
- if mult ~= 0 then
- DrawSunbeams(0.8, mult * math.Clamp(0.1 * self.Size * self.SizePulse, 0.1, 0.3), 0.05, pos.x / ScrW(), pos.y / ScrH())
- end
- end
- end
- function ENT:DrawParticles()
- --for i=1, 3 do
- local particle = self.Emitter:Add("particle/Particle_Glow_05_AddNoFog", self:GetPos() + (self:VectorRandSphere() * self.Size * 4 * math.random()))
- local mult = math.Clamp((self:GetVelocity():Length() * 0.1), 0, 1)
- particle:SetDieTime(math.Rand(0.5, 2))
- particle:SetColor(self.Color.r, self.Color.g, self.Color.b)
- if self.Hurting then
- particle:SetGravity(physenv.GetGravity())
- particle:SetVelocity((self:GetVelocity() * 0.1) + (self:VectorRandSphere() * math.random(20, 30)))
- particle:SetAirResistance(math.Rand(1,3))
- else
- particle:SetAirResistance(math.Rand(5,15))
- particle:SetVelocity((self:GetVelocity() * 0.1) + (self:VectorRandSphere() * math.random(2, 5)))
- particle:SetGravity(VectorRand())
- end
- particle:SetStartAlpha(0)
- particle:SetEndAlpha(255)
- --particle:SetEndLength(self.Size * 3)
- particle:SetStartSize(math.Rand(1, self.Size*8))
- particle:SetEndSize(0)
- particle:SetCollide(true)
- particle:SetRoll(math.random())
- particle:SetBounce(0.8)
- particle:SetCollideCallback(function(...)
- hook.Call("FairyParticleCollide", nil, self, ...)
- end)
- --end
- self.Emitter:Draw()
- end
- function ENT:DrawWings(offset)
- offset = offset or 0
- self.WingSpeed = (6.3 + (self.SizePulse)) * (self.Hurting and 0 or 1)
- local offsetangle = Angle(0,0,-20)
- local leftposition, leftangles = LocalToWorld(Vector(0), Angle(0,TimedSin(self.WingSpeed,-self.FlapLength,0,offset), 0) + Angle(0,290,0) + offsetangle, self:GetPos(), self:GetAngles())
- local rightposition, rightangles = LocalToWorld(Vector(0), Angle(0,TimedCos(self.WingSpeed,0,self.FlapLength,offset), 0) + Angle(0,290,0) + offsetangle, self:GetPos(), self:GetAngles())
- self.leftwing:SetPos(leftposition)
- self.rightwing:SetPos(rightposition)
- self.leftwing:SetAngles(leftangles)
- self.rightwing:SetAngles(rightangles)
- local bleftposition, bleftangles = LocalToWorld(Vector(0), Angle(TimedSin(self.WingSpeed,-self.FlapLength,0,offset),0, 0) + Angle(20,260,60) + offsetangle, self:GetPos(), self:GetAngles())
- local brightposition, brightangles = LocalToWorld(Vector(0), Angle(TimedCos(self.WingSpeed,0,self.FlapLength,offset),0, 0) + Angle(20,260,60) + offsetangle, self:GetPos(), self:GetAngles())
- self.bleftwing:SetPos(bleftposition)
- self.brightwing:SetPos(brightposition)
- self.bleftwing:SetAngles(bleftangles)
- self.brightwing:SetAngles(brightangles)
- render.SuppressEngineLighting(true)
- render.SetColorModulation(self.Color2.r/200, self.Color2.g/200, self.Color2.b/200)
- self.leftwing:SetupBones()
- self.rightwing:SetupBones()
- self.bleftwing:SetupBones()
- self.brightwing:SetupBones()
- self.leftwing:DrawModel()
- self.rightwing:DrawModel()
- self.bleftwing:DrawModel()
- self.brightwing:DrawModel()
- render.SetColorModulation(0,0,0)
- render.SuppressEngineLighting(false)
- end
- function ENT:OnRemove()
- SafeRemoveEntity(self.leftwing)
- SafeRemoveEntity(self.rightwing)
- SafeRemoveEntity(self.bleftwing)
- SafeRemoveEntity(self.brightwing)
- self.flap:Stop()
- self.float:Stop()
- end
- hook.Add("RenderScreenspaceEffects", "fairy_sunbeams", function()
- if not render.SupportsPixelShaders_2_0() then error("your gpu does not support pixel shader 2.0!") end
- for key, ent in pairs(ents.FindByClass("fairy")) do
- ent:DrawSunbeams()
- end
- end)
- usermessage.Hook("fairy_func_call", function(umr)
- local ent = umr:ReadEntity()
- local func = umr:ReadString()
- local args = glon.decode(umr:ReadString())
- if ent:IsValid() then
- ent[func](ent, unpack(args))
- end
- end)
- end
- if SERVER then
- function ENT:Initialize()
- self:SetModel("models/dav0r/hoverball.mdl")
- self:PhysicsInit(SOLID_VPHYSICS)
- self:SetMoveType(MOVETYPE_VPHYSICS)
- self:SetSolid(SOLID_VPHYSICS)
- self:StartMotionController()
- self:PhysWake()
- self:GetPhysicsObject():EnableGravity(false)
- end
- function ENT:MoveTo(pos)
- self.MovePos = pos
- end
- function ENT:HasReachedTarget()
- return self.MovePos and self:GetPos():Distance(self.MovePos) < 50
- end
- function ENT:PhysicsSimulate(phys)
- if self.STOP_THAT then return end
- if self.GravityOn then return end
- if self.MovePos and not self:HasReachedTarget() then
- phys:AddVelocity(self.MovePos - phys:GetPos())
- phys:AddVelocity(self:GetVelocity() * -0.4)
- self.MovePos = nil
- else
- phys:AddVelocity(math.random() > 0.995 and VectorRand() * 100 or (phys:GetVelocity()*0.01))
- phys:AddVelocity(self:GetVelocity() * -0.05)
- end
- end
- function ENT:CalcMove()
- local pos = vector_origin
- local tbl = ents.FindByClass("fairy")
- if #tbl >= 2 then
- for idx, ent in pairs(tbl) do
- pos = pos + ent:GetPos() + VectorRand()
- end
- pos = pos/#tbl
- self:MoveTo(pos)
- end
- end
- function ENT:Think()
- if self.STOP_THAT then return end
- self:PhysWake()
- self:CalcMove()
- end
- function ENT:EnableGravity(time)
- local phys = self:GetPhysicsObject()
- phys:EnableGravity(true)
- self.GravityOn = true
- timer.Simple(time, function()
- if phys:IsValid() then
- phys:EnableGravity(false)
- self.GravityOn = false
- end
- end)
- end
- function ENT:CallClientFunction(func, ...)
- umsg.Start("fairy_func_call")
- umsg.Entity(self)
- umsg.String(func)
- umsg.String(glon.encode({...}))
- umsg.End()
- end
- function ENT:OnTakeDamage(dmg)
- if self.STOP_THAT then return end
- local phys = self:GetPhysicsObject()
- phys:AddVelocity(dmg:GetDamageForce())
- self:EnableGravity(math.Rand(1,2))
- self:CallClientFunction("Ouch")
- end
- function ENT:PhysicsCollide(data, phys)
- if self.STOP_THAT then return end
- if data.Speed > 50 and data.DeltaTime > 0.2 then
- self:CallClientFunction("Ouch")
- self:EnableGravity(math.Rand(0.5,1))
- end
- self:LaughAtMe()
- phys:SetVelocity(phys:GetVelocity():Normalize() * data.OurOldVelocity:Length() * 0.99)
- end
- function ENT:OnRemove()
- self:StopMotionController()
- self.STOP_THAT = true
- end
- function ENT:LaughAtMe()
- for key, ent in pairs(ents.FindByClass("fairy")) do
- if ent ~= self and math.random() > 0.5 then
- ent:CallClientFunction("Laugh")
- end
- end
- end
- end
- scripted_ents.Register(ENT, ENT.ClassName, true)
Advertisement
Add Comment
Please, Sign In to add comment