--[[ This file is part of Ice Lua Components. Ice Lua Components is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Ice Lua Components is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with Ice Lua Components. If not, see . ]] if client then mdl_nade = model_load({ kv6={bdir=DIR_PKG_KV6, name="nade.kv6", scale=6.0/128.0}, pmf={bdir=DIR_PKG_PMF, name="nade.pmf"}, }, {"kv6","pmf"}) mdl_nade_inst = mdl_nade {} end function nade_add(nade) nades.tail = nades.tail + 1 nades[nades.tail] = nade end function nade_prune(sec_current) local i for i=nades.head,nades.tail do if nades[i] and nades[i].dead then nades[i] = nil if i == nades.head then nades.head = nades.head + 1 end end end if nades.head > nades.tail then nades.head = 1 nades.tail = 0 end end function new_nade(settings) local this = { x = settings.x, y = settings.y, z = settings.z, x0 = settings.x, y0 = settings.y, z0 = settings.z, x1 = settings.x, y1 = settings.y, z1 = settings.z, vx = settings.vx, vy = settings.vy, vz = settings.vz, pid = settings.pid, trem = 0.0, fuse = settings.fuse, dead = false } this.this = this local function prv_advance() local d,x1,y1,z1,x2,y2,z2,_ this.x0 = this.x1 this.y0 = this.y1 this.z0 = this.z1 local db = math.sqrt(this.vx*this.vx+this.vy*this.vy+this.vz*this.vz) --print("a",this.x0,this.y0,this.z0,this.vx,this.vy,this.vz) --print("db",db) d,x1,y1,z1,x2,y2,z2 = trace_map_ray_dist( this.x0,this.y0,this.z0, this.vx/db,this.vy/db,this.vz/db, db) local df = 1.0 if d then df = math.max(0,d/db-0.001) --print("df",df,d,db) end this.x1 = this.x0 + this.vx*df this.y1 = this.y0 + this.vy*df this.z1 = this.z0 + this.vz*df if x1 then local bounce_vel = 0 if x1 ~= x2 then this.vx = -this.vx*MODE_NADE_BDAMP bounce_vel = math.max(bounce_vel, math.abs(this.vx)) end if y1 ~= y2 then this.vy = -this.vy*MODE_NADE_BDAMP bounce_vel = math.max(bounce_vel, math.abs(this.vy)) end if z1 ~= z2 then this.vz = -this.vz*MODE_NADE_BDAMP bounce_vel = math.max(bounce_vel, math.abs(this.vz)) end this.vx = this.vx * MODE_NADE_ADAMP this.vy = this.vy * MODE_NADE_ADAMP this.vz = this.vz * MODE_NADE_ADAMP if client and bounce_vel >= MODE_NADE_BOUNCE_SOUND_MIN then local vol = 1.0 if bounce_vel < MODE_NADE_BOUNCE_SOUND_FADE then vol = rescale_value(MODE_NADE_BOUNCE_SOUND_MIN, MODE_NADE_BOUNCE_SOUND_FADE, 0, 1, bounce_vel) end client.wav_play_global(wav_nade_bounce, this.x, this.y, this.z, vol) end end this.vy = this.vy + 5*MODE_GRAVITY*MODE_NADE_STEP*MODE_NADE_STEP end function this.explode_dmg() local hplr = this.pid and players[this.pid] if hplr and not hplr.has_permission("kill") then return end local x,y,z local x0,y0,z0 x0,y0,z0 = math.floor(this.x) , math.floor(this.y) , math.floor(this.z) local xlen,ylen,zlen xlen,ylen,zlen = common.map_get_dims() local vpls = nil if MODE_NADE_VPL_ENABLE then vpls = vpl_gen_from_sphere(this.x, this.y, this.z, MODE_NADE_VPL_MAX_COUNT, MODE_NADE_VPL_MAX_RANGE, MODE_NADE_VPL_MAX_TRIES) end local i for i=1,players.max do local plr = players[i] if plr and ((not hplr) or plr == hplr or plr.team ~= hplr.team) then if MODE_NADE_VPL_ENABLE then local dmg_acc = 0 local j vpls[#vpls+1] = {x = this.x, y = this.y, z = this.z, s = MODE_NADE_VPL_DIRECT_STRENGTH, d = 0.0, special = true} --print(#vpls) for j=1,#vpls do -- Get the VPL. local v = vpls[j] -- Get the delta vector to the player's head. local dx,dy,dz dx = plr.x-v.x dy = (plr.y+((plr.crouching and 0.6) or 0.9))-v.y dz = plr.z-v.z -- Get the distance. local dd = dx*dx+dy*dy+dz*dz dd = math.sqrt(dd) -- Compare it against the maximum distance. -- Incorporate the already-travelled distance of the VPL. if dd + v.d < MODE_NADE_VPL_MAX_RANGE then -- Normalise the delta vector. dx = dx/dd dy = dy/dd dz = dz/dd -- See if there's anything between you and the game^H^H^H^H VPL. local nd nd = trace_map_ray_dist(v.x,v.y,v.z, dx,dy,dz, dd) if not nd then -- Didn't hit anything. Calculate damage. dd = dd + v.d local dmg = MODE_NADE_VPL_DAMAGE_1*v.s/(dd*dd) dmg_acc = math.max(dmg_acc, dmg) end end end --print(dmg_acc) dmg_acc = math.floor(dmg_acc + 0.8) if dmg_acc >= 1 then plr.explosive_damage(dmg_acc, hplr) end else local dx,dy,dz dx = plr.x-this.x dy = (plr.y+0.9)-this.y dz = plr.z-this.z local dd = dx*dx+dy*dy+dz*dz if dd < MODE_NADE_RANGE*MODE_NADE_RANGE then dd = math.sqrt(dd) dx = dx/dd dy = dy/dd dz = dz/dd local nd nd = trace_map_ray_dist(this.x,this.y,this.z, dx,dy,dz, dd) if not nd then local dmg = (-(math.pow(dd / MODE_NADE_RANGE, 4)) + 1) * MODE_NADE_DAMAGE plr.explosive_damage(dmg, hplr) end end end end end if hplr and not hplr.has_permission("build") then return end if map_block_get(x0,y0,z0) ~= nil then if y0 < ylen-2 then map_block_break(x0,y0,z0) net_broadcast(nil, common.net_pack("BHHH" , PKT_BLK_RM1, x0,y0,z0)) end else for z=z0-1,z0+1 do for x=x0-1,x0+1 do for y=y0-1,y0+1 do if y < ylen-2 and map_block_break(x,y,z) then net_broadcast(nil, common.net_pack("BHHH" , PKT_BLK_RM1, x,y,z)) end end end end if MODE_NADE_VPL_ENABLE then local dmg_blks = {} for j=1,#vpls do local v = vpls[j] local x = v.cx --math.floor(v.x+0.5) local y = v.cy --math.floor(v.y+0.5) local z = v.cz --math.floor(v.z+0.5) local blk = {x,y,z} if y and y < ylen-2 then if not dmg_blks[blk] then dmg_blks[blk] = 0 end dmg_blks[blk] = dmg_blks[blk] + MODE_NADE_VPL_BLK_DAMAGE end end for blk,dmg in pairs(dmg_blks) do bhealth_damage(blk[1],blk[2],blk[3], dmg) net_broadcast(nil, common.net_pack("BHHHH", PKT_BLK_DAMAGE, blk[1],blk[2],blk[3], dmg)) end end end end function this.tick(sec_current, sec_delta) if this.dead then return end this.trem = this.trem - sec_delta local i = 10 while this.trem < 0 do prv_advance() this.trem = this.trem + MODE_NADE_STEP i = i - 1 if i <= 0 then break end end local lerp = 1-this.trem/MODE_NADE_STEP this.x = this.x1*lerp+this.x0*(1-lerp) this.y = this.y1*lerp+this.y0*(1-lerp) this.z = this.z1*lerp+this.z0*(1-lerp) this.fuse = this.fuse - sec_delta if this.fuse <= 0 then if client then client.wav_play_global(wav_nade_boom, this.x, this.y, this.z) if MODE_DEBUG_VPLTEST then VPLPOINT = {x = this.x, y = this.y, z = this.z} v(true) end local i local nade_particlecount = ( MODE_NADE_VPL_ENABLE and 1 ) or (math.random() * 10 + 20) local pvel = 2 nade_part_mdl = nade_part_mdl or new_particle_model(70, 70, 70) local mdl = nade_part_mdl --[[ local mdl = new_particle_model( 60 + math.random() * 20, 60 + math.random() * 20, 60 + math.random() * 20) ]] for i=1,nade_particlecount do particles_add(new_particle{ x = this.x, y = this.y-0.1, z = this.z, vx = pvel*(2*math.random()-1), vy = pvel*(2*math.random()-1.8), vz = pvel*(2*math.random()-1), size = 16 + math.random() * 32, model = mdl, }) end end if server then this.explode_dmg() end this.dead = true end end function this.render() if this.dead then return end mdl_nade_inst.render_global( this.x, this.y, this.z, 0.0, 0.0, 0.0, 1.0) end return this end