Advertisement
CrastAndNoob

Smart NPC

Apr 20th, 2019
1,064
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 16.87 KB | None | 0 0
  1. ypcall(function()
  2. -- Main Npc Setup
  3. math.randomseed(tick())
  4. local npc = Instance.new("Model",workspace)
  5. npc.Name = "NPC (Alpha Testing)"
  6. local hum = Instance.new("Humanoid",npc)
  7. script.Parent = npc
  8. -- Body Parts Setup
  9. local head = Instance.new("Part",npc)
  10. head.Name = "Head"
  11. head.BrickColor = BrickColor.new("Bright yellow")
  12. head.Size = Vector3.new(2,1,1)
  13. head.Position = Vector3.new(-6.139, 4.5, -11.435)
  14. head.Material = "SmoothPlastic"
  15. local headmesh = Instance.new("SpecialMesh",head)
  16. headmesh.Scale = Vector3.new(1.25,1.25,1.25)
  17. local face = Instance.new("Decal",head)
  18. face.Name = "face"
  19. face.Face = "Front"
  20. face.Texture = "rbxasset://textures/face.png"
  21. local larm = Instance.new("Part",npc)
  22. larm.Name = "Left Arm"
  23. larm.BrickColor = BrickColor.new("Bright yellow")
  24. larm.Position = Vector3.new(-7.639, 3, -11.435)
  25. larm.Size = Vector3.new(1,2,1)
  26. larm.Material = "SmoothPlastic"
  27. local rarm = Instance.new("Part",npc)
  28. rarm.Name = "Right Arm"
  29. rarm.BrickColor = BrickColor.new("Bright yellow")
  30. rarm.Position = Vector3.new(-4.639, 3, -11.435)
  31. rarm.Size = Vector3.new(1,2,1)
  32. rarm.Material = "SmoothPlastic"
  33. local torso = Instance.new("Part",npc)
  34. torso.Name = "Torso"
  35. torso.BrickColor = BrickColor.new("Bright blue")
  36. torso.Position = Vector3.new(-6.139, 3, -11.435)
  37. torso.Size = Vector3.new(2,2,1)
  38. torso.Material = "SmoothPlastic"
  39. local lleg = Instance.new("Part",npc)
  40. lleg.Name = "Left Leg"
  41. lleg.BrickColor = BrickColor.new("Br. yellowish green")
  42. lleg.Position = Vector3.new(-6.639, 1, -11.435)
  43. lleg.Size = Vector3.new(1,2,1)
  44. lleg.Material = "SmoothPlastic"
  45. local rleg = Instance.new("Part",npc)
  46. rleg.Name = "Right Leg"
  47. rleg.BrickColor = BrickColor.new("Br. yellowish green")
  48. rleg.Position = Vector3.new(-5.639, 1, -11.435)
  49. rleg.Size = Vector3.new(1,2,1)
  50. rleg.Material = "SmoothPlastic"
  51. -- Anchor parts to stop failing
  52. for _,i in pairs(npc:GetChildren())do
  53.     ypcall(function()i.Anchored = true end)
  54. end
  55. -- Motor Setups
  56. local lhip = Instance.new("Motor",torso)
  57. lhip.MaxVelocity = 0.1
  58. lhip.Part0 = torso
  59. lhip.Part1 = lleg
  60. lhip.Name = "Left Hip"
  61. local rhip = Instance.new("Motor",torso)
  62. rhip.MaxVelocity = 0.1
  63. rhip.Part0 = torso
  64. rhip.Part1 = rleg
  65. rhip.Name = "Right Hip"
  66. local lshou = Instance.new("Motor",torso)
  67. lshou.MaxVelocity = 0.15
  68. lshou.Part0 = torso
  69. lshou.Part1 = larm
  70. lshou.Name = "Left Shoulder"
  71. local rshou = Instance.new("Motor",torso)
  72. rshou.MaxVelocity = 0.15
  73. rshou.Part0 = torso
  74. rshou.Part1 = rarm
  75. rshou.Name = "Right Shoulder"
  76. local neck = Instance.new("Motor",torso)
  77. neck.MaxVelocity = 0.1
  78. neck.Part0 = torso
  79. neck.Part1 = head
  80. neck.Name = "Neck"
  81. -- CFrame Motor Setups
  82. neck.C0 = CFrame.new(0, 1, 0, -1, 0, 0, 0, 0, 1, 0, 1, -0)
  83. neck.C1 = CFrame.new(0, -0.5, 0, -1, 0, 0, 0, 0, 1, 0, 1, -0)
  84. lhip.C0 = CFrame.new(-1, -1, 0, 0, 0, -1, 0, 1, 0, 1, 0, 0)
  85. lhip.C1 = CFrame.new(-0.5, 1, 0, 0, 0, -1, 0, 1, 0, 1, 0, 0)
  86. rhip.C0 = CFrame.new(1, -1, 0, 0, 0, 1, 0, 1, -0, -1, 0, 0)
  87. rhip.C1 = CFrame.new(0.5, 1, 0, 0, 0, 1, 0, 1, -0, -1, 0, 0)
  88. lshou.C0 = CFrame.new(-1, 0.5, 0, 0, 0, -1, 0, 1, 0, 1, 0, 0)
  89. lshou.C1 = CFrame.new(0.5, 0.5, 0, 0, 0, -1, 0, 1, 0, 1, 0, 0)
  90. rshou.C0 = CFrame.new(1, 0.5, 0, 0, 0, 1, 0, 1, -0, -1, 0, 0)
  91. rshou.C1 = CFrame.new(-0.5, 0.5, 0, 0, 0, 1, 0, 1, -0, -1, 0, 0)
  92. -- Unanchor to release NPC
  93. for _,i in pairs(npc:GetChildren())do
  94.     ypcall(function()i.Anchored = false end)
  95. end
  96. -- Setup Walking Script
  97. local CurrentPart = nil
  98. local MaxInc = 16
  99.  
  100. function onTouched(hit)
  101.     if hit.Parent == nil then
  102.         return
  103.     end
  104.  
  105.     local humanoid = hit.Parent:findFirstChild("Humanoid")
  106.  
  107.     if humanoid == nil then
  108.         CurrentPart = hit
  109.     end
  110. end
  111.  
  112. function waitForChild(parent, childName)
  113.     local child = parent:findFirstChild(childName)
  114.  
  115.     if child then
  116.         return child
  117.     end
  118.  
  119.     while true do
  120.         print(childName)
  121.  
  122.         child = parent.ChildAdded:wait()
  123.  
  124.         if child.Name==childName then
  125.             return child
  126.         end
  127.     end
  128. end
  129.  
  130. local Figure = script.Parent
  131. local Humanoid = waitForChild(Figure, "Humanoid")
  132. local Torso = waitForChild(Figure, "Torso")
  133. local Left = waitForChild(Figure, "Left Leg")
  134. local Right = waitForChild(Figure, "Right Leg")
  135. Humanoid.Jump = true
  136. Left.Touched:connect(onTouched)
  137. Right.Touched:connect(onTouched)
  138. local loop1 = coroutine.wrap(function()
  139.     while true do
  140.         wait(math.random(2, 4))
  141.         if CurrentPart ~= nil then
  142.             if math.random(1, 2) == 1 then
  143.                 Humanoid.Jump = true
  144.             end
  145.    
  146.             Humanoid:MoveTo(Torso.Position + Vector3.new(math.random(-MaxInc, MaxInc), 0, math.random(-MaxInc, MaxInc)), CurrentPart)
  147.         end
  148.     end
  149. end)
  150. loop1()
  151. -- NPC Cleanup on Death
  152. hum.Died:connect(function()
  153.     wait(5)
  154.     npc:ClearAllChildren()
  155.     npc.Name = "null"
  156.     npc:Destroy()
  157. end)
  158. -- NPC Animation
  159. function   waitForChild(parent, childName)
  160.     local child = parent:findFirstChild(childName)
  161.     if child then return child end
  162.     while true do
  163.         child = parent.ChildAdded:wait()
  164.         if child.Name==childName then return child end
  165.     end
  166. end
  167. local Figure = script.Parent
  168. local Torso = waitForChild(Figure, "Torso")
  169. local RightShoulder = waitForChild(Torso, "Right Shoulder")
  170. local LeftShoulder = waitForChild(Torso, "Left Shoulder")
  171. local RightHip = waitForChild(Torso, "Right Hip")
  172. local LeftHip = waitForChild(Torso, "Left Hip")
  173. local Neck = waitForChild(Torso, "Neck")
  174. local Humanoid = waitForChild(Figure, "Humanoid")
  175. local pose = "Standing"
  176. local currentAnim = ""
  177. local currentAnimTrack = nil
  178. local currentAnimKeyframeHandler = nil
  179. local currentAnimSpeed = 1.0
  180. local animTable = {}
  181. local animNames = {
  182.     idle =  {  
  183.                 { id = "http://www.roblox.com/asset/?id=125750544", weight = 9 },
  184.                 { id = "http://www.roblox.com/asset/?id=125750618", weight = 1 }
  185.             },
  186.     walk =  {  
  187.                 { id = "http://www.roblox.com/asset/?id=125749145", weight = 10 }
  188.             },
  189.     run =   {
  190.                 { id = "run.xml", weight = 10 }
  191.             },
  192.     jump =  {
  193.                 { id = "http://www.roblox.com/asset/?id=125750702", weight = 10 }
  194.             },
  195.     fall =  {
  196.                 { id = "http://www.roblox.com/asset/?id=125750759", weight = 10 }
  197.             },
  198.     climb = {
  199.                 { id = "http://www.roblox.com/asset/?id=125750800", weight = 10 }
  200.             },
  201.     sit =   {
  202.                 { id = "http://www.roblox.com/asset/?id=178130996", weight = 10 }
  203.             }, 
  204.     toolnone = {
  205.                 { id = "http://www.roblox.com/asset/?id=125750867", weight = 10 }
  206.             },
  207.     toolslash = {
  208.                 { id = "http://www.roblox.com/asset/?id=129967390", weight = 10 }
  209.             },
  210.     toollunge = {
  211.                 { id = "http://www.roblox.com/asset/?id=129967478", weight = 10 }
  212.             },
  213.     wave = {
  214.                 { id = "http://www.roblox.com/asset/?id=128777973", weight = 10 }
  215.             },
  216.     point = {
  217.                 { id = "http://www.roblox.com/asset/?id=128853357", weight = 10 }
  218.             },
  219.     dance = {
  220.                 { id = "http://www.roblox.com/asset/?id=130018893", weight = 10 },
  221.                 { id = "http://www.roblox.com/asset/?id=132546839", weight = 10 },
  222.                 { id = "http://www.roblox.com/asset/?id=132546884", weight = 10 }
  223.             },
  224.     dance2 = {
  225.                 { id = "http://www.roblox.com/asset/?id=160934142", weight = 10 },
  226.                 { id = "http://www.roblox.com/asset/?id=160934298", weight = 10 },
  227.                 { id = "http://www.roblox.com/asset/?id=160934376", weight = 10 }
  228.             },
  229.     dance3 = {
  230.                 { id = "http://www.roblox.com/asset/?id=160934458", weight = 10 },
  231.                 { id = "http://www.roblox.com/asset/?id=160934530", weight = 10 },
  232.                 { id = "http://www.roblox.com/asset/?id=160934593", weight = 10 }
  233.             },
  234.     laugh = {
  235.                 { id = "http://www.roblox.com/asset/?id=129423131", weight = 10 }
  236.             },
  237.     cheer = {
  238.                 { id = "http://www.roblox.com/asset/?id=129423030", weight = 10 }
  239.             },
  240. }
  241. local emoteNames = { wave = false, point = false, dance = true, dance2 = true, dance3 = true, laugh = false, cheer = false}
  242. math.randomseed(tick())
  243. function configureAnimationSet(name, fileList)
  244.     if (animTable[name] ~= nil) then
  245.         for _, connection in pairs(animTable[name].connections) do
  246.             connection:disconnect()
  247.         end
  248.     end
  249.     animTable[name] = {}
  250.     animTable[name].count = 0
  251.     animTable[name].totalWeight = 0
  252.     animTable[name].connections = {}
  253.     local config = script:FindFirstChild(name)
  254.     if (config ~= nil) then
  255.         table.insert(animTable[name].connections, config.ChildAdded:connect(function(child) configureAnimationSet(name, fileList) end))
  256.         table.insert(animTable[name].connections, config.ChildRemoved:connect(function(child) configureAnimationSet(name, fileList) end))
  257.         local idx = 1
  258.         for _, childPart in pairs(config:GetChildren()) do
  259.             if (childPart:IsA("Animation")) then
  260.                 table.insert(animTable[name].connections, childPart.Changed:connect(function(property) configureAnimationSet(name, fileList) end))
  261.                 animTable[name][idx] = {}
  262.                 animTable[name][idx].anim = childPart
  263.                 local weightObject = childPart:FindFirstChild("Weight")
  264.                 if (weightObject == nil) then
  265.                     animTable[name][idx].weight = 1
  266.                 else
  267.                     animTable[name][idx].weight = weightObject.Value
  268.                 end
  269.                 animTable[name].count = animTable[name].count + 1
  270.                 animTable[name].totalWeight = animTable[name].totalWeight + animTable[name][idx].weight
  271.                 idx = idx + 1
  272.             end
  273.         end
  274.     end
  275.     if (animTable[name].count <= 0) then
  276.         for idx, anim in pairs(fileList) do
  277.             animTable[name][idx] = {}
  278.             animTable[name][idx].anim = Instance.new("Animation")
  279.             animTable[name][idx].anim.Name = name
  280.             animTable[name][idx].anim.AnimationId = anim.id
  281.             animTable[name][idx].weight = anim.weight
  282.             animTable[name].count = animTable[name].count + 1
  283.             animTable[name].totalWeight = animTable[name].totalWeight + anim.weight
  284.         end
  285.     end
  286. end
  287. function scriptChildModified(child)
  288.     local fileList = animNames[child.Name]
  289.     if (fileList ~= nil) then
  290.         configureAnimationSet(child.Name, fileList)
  291.     end
  292. end
  293. script.ChildAdded:connect(scriptChildModified)
  294. script.ChildRemoved:connect(scriptChildModified)
  295. for name, fileList in pairs(animNames) do
  296.     configureAnimationSet(name, fileList)
  297. end
  298. local toolAnim = "None"
  299. local toolAnimTime = 0
  300. local jumpAnimTime = 0
  301. local jumpAnimDuration = 0.3
  302. local toolTransitionTime = 0.1
  303. local fallTransitionTime = 0.3
  304. local jumpMaxLimbVelocity = 0.75
  305. function stopAllAnimations()
  306.     local oldAnim = currentAnim
  307.     if (emoteNames[oldAnim] ~= nil and emoteNames[oldAnim] == false) then
  308.         oldAnim = "idle"
  309.     end
  310.     currentAnim = ""
  311.     if (currentAnimKeyframeHandler ~= nil) then
  312.         currentAnimKeyframeHandler:disconnect()
  313.     end
  314.     if (currentAnimTrack ~= nil) then
  315.         currentAnimTrack:Stop()
  316.         currentAnimTrack:Destroy()
  317.         currentAnimTrack = nil
  318.     end
  319.     return oldAnim
  320. end
  321. function setAnimationSpeed(speed)
  322.     if speed ~= currentAnimSpeed then
  323.         currentAnimSpeed = speed
  324.         currentAnimTrack:AdjustSpeed(currentAnimSpeed)
  325.     end
  326. end
  327. function keyFrameReachedFunc(frameName)
  328.     if (frameName == "End") then
  329.         local repeatAnim = stopAllAnimations()
  330.         local animSpeed = currentAnimSpeed
  331.         playAnimation(repeatAnim, 0.0, Humanoid)
  332.         setAnimationSpeed(animSpeed)
  333.     end
  334. end
  335. function playAnimation(animName, transitionTime, humanoid)
  336.     local idleFromEmote = (animName == "idle" and emoteNames[currentAnim] ~= nil)
  337.     if (animName ~= currentAnim and not idleFromEmote) then      
  338.         if (currentAnimTrack ~= nil) then
  339.             currentAnimTrack:Stop(transitionTime)
  340.             currentAnimTrack:Destroy()
  341.         end
  342.         currentAnimSpeed = 1.0
  343.         local roll = math.random(1, animTable[animName].totalWeight)
  344.         local origRoll = roll
  345.         local idx = 1
  346.         while (roll > animTable[animName][idx].weight) do
  347.             roll = roll - animTable[animName][idx].weight
  348.             idx = idx + 1
  349.         end
  350.         local anim = animTable[animName][idx].anim
  351.         currentAnimTrack = humanoid:LoadAnimation(anim)
  352.         currentAnimTrack:Play(transitionTime)
  353.         currentAnim = animName
  354.         if (currentAnimKeyframeHandler ~= nil) then
  355.             currentAnimKeyframeHandler:disconnect()
  356.         end
  357.         currentAnimKeyframeHandler = currentAnimTrack.KeyframeReached:connect(keyFrameReachedFunc)
  358.     end
  359. end
  360. local toolAnimName = ""
  361. local toolAnimTrack = nil
  362. local currentToolAnimKeyframeHandler = nil
  363. function toolKeyFrameReachedFunc(frameName)
  364.     if (frameName == "End") then
  365.         local repeatAnim = stopToolAnimations()
  366.         playToolAnimation(repeatAnim, 0.0, Humanoid)
  367.     end
  368. end
  369. function playToolAnimation(animName, transitionTime, humanoid)
  370.     if (animName ~= toolAnimName) then       
  371.         if (toolAnimTrack ~= nil) then
  372.             toolAnimTrack:Stop()
  373.             toolAnimTrack:Destroy()
  374.             transitionTime = 0
  375.         end
  376.         local roll = math.random(1, animTable[animName].totalWeight)
  377.         local origRoll = roll
  378.         local idx = 1
  379.         while (roll > animTable[animName][idx].weight) do
  380.             roll = roll - animTable[animName][idx].weight
  381.             idx = idx + 1
  382.         end
  383.         local anim = animTable[animName][idx].anim
  384.         toolAnimTrack = humanoid:LoadAnimation(anim)
  385.         toolAnimTrack:Play(transitionTime)
  386.         toolAnimName = animName
  387.         currentToolAnimKeyframeHandler = toolAnimTrack.KeyframeReached:connect(toolKeyFrameReachedFunc)
  388.     end
  389. end
  390. function stopToolAnimations()
  391.     local oldAnim = toolAnimName
  392.     if (currentToolAnimKeyframeHandler ~= nil) then
  393.         currentToolAnimKeyframeHandler:disconnect()
  394.     end
  395.     toolAnimName = ""
  396.     if (toolAnimTrack ~= nil) then
  397.         toolAnimTrack:Stop()
  398.         toolAnimTrack:Destroy()
  399.         toolAnimTrack = nil
  400.     end
  401.     return oldAnim
  402. end
  403. function onRunning(speed)
  404.     if speed>0.01 then
  405.         playAnimation("walk", 0.1, Humanoid)
  406.         pose = "Running"
  407.     else
  408.         playAnimation("idle", 0.1, Humanoid)
  409.         pose = "Standing"
  410.     end
  411. end
  412. function onDied()
  413.     pose = "Dead"
  414. end
  415. function onJumping()
  416.     playAnimation("jump", 0.1, Humanoid)
  417.     jumpAnimTime = jumpAnimDuration
  418.     pose = "Jumping"
  419. end
  420. function onClimbing(speed)
  421.     playAnimation("climb", 0.1, Humanoid)
  422.     setAnimationSpeed(speed / 12.0)
  423.     pose = "Climbing"
  424. end
  425. function onGettingUp()
  426.     pose = "GettingUp"
  427. end
  428. function onFreeFall()
  429.     if (jumpAnimTime <= 0) then
  430.         playAnimation("fall", fallTransitionTime, Humanoid)
  431.     end
  432.     pose = "FreeFall"
  433. end
  434. function onFallingDown()
  435.     pose = "FallingDown"
  436. end
  437. function onSeated()
  438.     pose = "Seated"
  439. end
  440. function onPlatformStanding()
  441.     pose = "PlatformStanding"
  442. end
  443. function onSwimming(speed)
  444.     if speed>0 then
  445.         pose = "Running"
  446.     else
  447.         pose = "Standing"
  448.     end
  449. end
  450. function getTool() 
  451.     for _, kid in ipairs(Figure:GetChildren()) do
  452.         if kid.className == "Tool" then return kid end
  453.     end
  454.     return nil
  455. end
  456. function getToolAnim(tool)
  457.     for _, c in ipairs(tool:GetChildren()) do
  458.         if c.Name == "toolanim" and c.className == "StringValue" then
  459.             return c
  460.         end
  461.     end
  462.     return nil
  463. end
  464. function animateTool()
  465.     if (toolAnim == "None") then
  466.         playToolAnimation("toolnone", toolTransitionTime, Humanoid)
  467.         return
  468.     end
  469.     if (toolAnim == "Slash") then
  470.         playToolAnimation("toolslash", 0, Humanoid)
  471.         return
  472.     end
  473.     if (toolAnim == "Lunge") then
  474.         playToolAnimation("toollunge", 0, Humanoid)
  475.         return
  476.     end
  477. end
  478. function moveSit()
  479.     RightShoulder.MaxVelocity = 0.15
  480.     LeftShoulder.MaxVelocity = 0.15
  481.     RightShoulder:SetDesiredAngle(3.14 /2)
  482.     LeftShoulder:SetDesiredAngle(-3.14 /2)
  483.     RightHip:SetDesiredAngle(3.14 /2)
  484.     LeftHip:SetDesiredAngle(-3.14 /2)
  485. end
  486. local lastTick = 0
  487. function move(time)
  488.     local amplitude = 1
  489.     local frequency = 1
  490.     local deltaTime = time - lastTick
  491.     lastTick = time
  492.     local climbFudge = 0
  493.     local setAngles = false
  494.     if (jumpAnimTime > 0) then
  495.         jumpAnimTime = jumpAnimTime - deltaTime
  496.     end
  497.     if (pose == "FreeFall" and jumpAnimTime <= 0) then
  498.         playAnimation("fall", fallTransitionTime, Humanoid)
  499.     elseif (pose == "Seated") then
  500.         playAnimation("sit", 0.5, Humanoid)
  501.         return
  502.     elseif (pose == "Running") then
  503.         playAnimation("walk", 0.1, Humanoid)
  504.     elseif (pose == "Dead" or pose == "GettingUp" or pose == "FallingDown" or pose == "Seated" or pose == "PlatformStanding") then
  505.         stopAllAnimations()
  506.         amplitude = 0.1
  507.         frequency = 1
  508.         setAngles = true
  509.     end
  510.     if (setAngles) then
  511.         desiredAngle = amplitude * math.sin(time * frequency)
  512.         RightShoulder:SetDesiredAngle(desiredAngle + climbFudge)
  513.         LeftShoulder:SetDesiredAngle(desiredAngle - climbFudge)
  514.         RightHip:SetDesiredAngle(-desiredAngle)
  515.         LeftHip:SetDesiredAngle(-desiredAngle)
  516.     end
  517.     local tool = getTool()
  518.     if tool then
  519.         animStringValueObject = getToolAnim(tool)
  520.         if animStringValueObject then
  521.             toolAnim = animStringValueObject.Value
  522.             animStringValueObject.Parent = nil
  523.             toolAnimTime = time + .3
  524.         end
  525.         if time > toolAnimTime then
  526.             toolAnimTime = 0
  527.             toolAnim = "None"
  528.         end
  529.         animateTool()      
  530.     else
  531.         stopToolAnimations()
  532.         toolAnim = "None"
  533.         toolAnimTime = 0
  534.     end
  535. end
  536. Humanoid.Died:connect(onDied)
  537. Humanoid.Running:connect(onRunning)
  538. Humanoid.Jumping:connect(onJumping)
  539. Humanoid.Climbing:connect(onClimbing)
  540. Humanoid.GettingUp:connect(onGettingUp)
  541. Humanoid.FreeFalling:connect(onFreeFall)
  542. Humanoid.FallingDown:connect(onFallingDown)
  543. Humanoid.Seated:connect(onSeated)
  544. Humanoid.PlatformStanding:connect(onPlatformStanding)
  545. Humanoid.Swimming:connect(onSwimming)
  546. local runService = game:service("RunService");
  547. playAnimation("idle", 0.1, Humanoid)
  548. pose = "Standing"
  549. while Figure.Parent~=nil do
  550.     local _, time = wait(0.1)
  551.     move(time)
  552. end
  553. -- Auto Heal
  554. local loop2 = coroutine.wrap(function()
  555.     while true do
  556.         wait(1)
  557.         if hum.Health<hum.MaxHealth then
  558.             hum.Health = hum.Health + hum.MaxHealth / 100
  559.         end
  560.     end
  561. end)
  562. loop2()
  563. end)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement