balls = {} hideTool = 0 function init() throw = LoadSound("throw/m0.ogg") snd = LoadSound("tools/snowball0.ogg") RegisterTool("snowball", "loc@SNOWBALL", "vox/snowball.vox") end function rnd(mi, ma) return math.random()*(ma-mi)+mi end function rndVec(length) local v = VecNormalize(Vec(math.random()-0.5, math.random()-0.5, math.random()-0.5)) return VecScale(v, length) end function impact(shape, point, normal, velocity) local r = math.random() if r < 0.33 then AddSnow(shape, point, 0.22) elseif r < 0.66 then AddSnow(shape, point, 0.24) else AddSnow(shape, point, 0.26) end PlaySound(snd, point) ParticleReset() ParticleTile(4) ParticleCollide(1) ParticleSticky(0.1) local vel = VecSub(velocity, VecScale(normal, VecDot(normal, velocity))) for i=1, 150 do local dir = VecNormalize(VecAdd(normal, rndVec(0.7))) local p = VecAdd(point, VecScale(VecNormalize(VecSub(dir, VecScale(normal, VecDot(normal, dir)))), 0.2)) local v = VecAdd(VecScale(vel, rnd(0, 0.5)), VecScale(dir, rnd(0, 2))) ParticleRadius(rnd(0.02, 0.06)) ParticleGravity(rnd(-10, -5)) SpawnParticle(p, v, rnd(2,3)) end ParticleReset() ParticleType("smoke") ParticleCollide(0) for i=1, 20 do local dir = VecNormalize(VecAdd(normal, rndVec(0.9))) local p = VecAdd(point, VecScale(VecNormalize(VecSub(dir, VecScale(normal, VecDot(normal, dir)))), 0.2)) local v = VecScale(dir, rnd(0, 2)) ParticleAlpha(0.3, 0) ParticleRadius(0.15, 0.25) ParticleGravity(rnd(-2, -1)) SpawnParticle(p, v, rnd(2,4)) end end function tick(dt) if GetString("game.player.tool") == "snowball" then SetInt("game.tool.snowball.ammo", 9999) SetToolTransform(Transform(Vec(0.3, -0.3-hideTool*0.5, -0.5+hideTool*0.5))) if GetBool("game.player.canusetool") and InputPressed("usetool") then local t = GetCameraTransform() local fwd = TransformToParentVec(t, Vec(0,0,-1)) local pos = TransformToParentPoint(t, Vec(0.3, -0.3, -0.5)) local vel = VecAdd(VecScale(fwd, 16), Vec(0, 4, 0)) local entities = Spawn("", Transform(pos)) local body = entities[1] local shape = entities[2] SetShapeCollisionFilter(shape, 0, 0) SetBodyVelocity(body, vel) SetBodyAngularVelocity(body, Vec(rnd(-5, 5), rnd(-5, 5), rnd(-5, 5))) balls[#balls+1] = body PlaySound(throw) hideTool = 1 SetValue("hideTool", 0, "easeout", 0.3) end end end function update(dt) if #balls > 0 then local newBalls = {} for i=1, #balls do local body = balls[i] local pos = GetBodyTransform(body).pos if pos[2] < -5 then Delete(body) else QueryRejectBody(body) local hit, point, normal, shape = QueryClosestPoint(pos, 0.3) if hit then point = VecAdd(point, VecScale(normal, 0.05)) impact(shape, point, normal, GetBodyVelocity(body)) Delete(body) else newBalls[#newBalls+1] = body end end end balls = newBalls end end