Skip to content

Commit 3a4f242

Browse files
committed
Readd grenade code as ctf_grenades
1 parent 5880f52 commit 3a4f242

File tree

23 files changed

+551
-14
lines changed

23 files changed

+551
-14
lines changed
Lines changed: 282 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,282 @@
1+
local S = minetest.get_translator(minetest.get_current_modname())
2+
3+
local function remove_flora(pos, radius)
4+
local pos1 = vector.subtract(pos, radius)
5+
local pos2 = vector.add(pos, radius)
6+
7+
for _, p in ipairs(minetest.find_nodes_in_area(pos1, pos2, {
8+
"group:flora", "group:mushroom", "default:snow", "group:grenade_breakable"
9+
})) do
10+
if vector.distance(pos, p) <= radius then
11+
minetest.remove_node(p)
12+
end
13+
end
14+
end
15+
16+
local function check_hit(pos1, pos2, obj)
17+
local ray = minetest.raycast(pos1, pos2, true, false)
18+
local hit = ray:next()
19+
20+
-- Skip over non-normal nodes like ladders, water, doors, glass, leaves, etc
21+
-- Also skip over all objects that aren't the target
22+
-- Any collisions within a 1 node distance from the target don't stop the grenade
23+
while hit and (
24+
(
25+
hit.type == "node"
26+
and
27+
(
28+
hit.intersection_point:distance(pos2) <= 1
29+
or
30+
not minetest.registered_nodes[minetest.get_node(hit.under).name].walkable
31+
)
32+
)
33+
or
34+
(
35+
hit.type == "object" and hit.ref ~= obj
36+
)
37+
) do
38+
hit = ray:next()
39+
end
40+
41+
if hit and hit.type == "object" and hit.ref == obj then
42+
return true
43+
end
44+
end
45+
46+
local fragdef = {
47+
description = S("Frag grenade (Kills anyone near blast)"),
48+
image = "grenades_frag.png",
49+
explode_radius = 10,
50+
explode_damage = 26,
51+
on_collide = function()
52+
return true
53+
end,
54+
on_explode = function(def, obj, pos, name)
55+
if not name or not pos then return end
56+
57+
local player = minetest.get_player_by_name(name)
58+
if not player then return end
59+
60+
local radius = def.explode_radius
61+
62+
minetest.add_particlespawner({
63+
amount = 20,
64+
time = 0.5,
65+
minpos = vector.subtract(pos, radius),
66+
maxpos = vector.add(pos, radius),
67+
minvel = {x = 0, y = 5, z = 0},
68+
maxvel = {x = 0, y = 7, z = 0},
69+
minacc = {x = 0, y = 1, z = 0},
70+
maxacc = {x = 0, y = 1, z = 0},
71+
minexptime = 0.3,
72+
maxexptime = 0.6,
73+
minsize = 7,
74+
maxsize = 10,
75+
collisiondetection = true,
76+
collision_removal = false,
77+
vertical = false,
78+
texture = "grenades_smoke.png",
79+
})
80+
81+
minetest.add_particle({
82+
pos = pos,
83+
velocity = {x=0, y=0, z=0},
84+
acceleration = {x=0, y=0, z=0},
85+
expirationtime = 0.3,
86+
size = 15,
87+
collisiondetection = false,
88+
collision_removal = false,
89+
object_collision = false,
90+
vertical = false,
91+
texture = "grenades_boom.png",
92+
glow = 10
93+
})
94+
95+
minetest.sound_play("grenades_explode", {
96+
pos = pos,
97+
gain = 1.0,
98+
max_hear_distance = 64,
99+
})
100+
101+
remove_flora(pos, radius/2)
102+
103+
for _, v in pairs(minetest.get_objects_inside_radius(pos, radius)) do
104+
if v:is_player() and v:get_hp() > 0 and v:get_properties().pointable then
105+
local footpos = vector.offset(v:get_pos(), 0, 0.1, 0)
106+
local headpos = vector.offset(v:get_pos(), 0, v:get_properties().eye_height, 0)
107+
local footdist = vector.distance(pos, footpos)
108+
local headdist = vector.distance(pos, headpos)
109+
local target_head = false
110+
111+
if footdist >= headdist then
112+
target_head = true
113+
end
114+
115+
local hit_pos1 = check_hit(pos, target_head and headpos or footpos, v)
116+
117+
-- Check the closest distance, but if that fails try targeting the farther one
118+
if hit_pos1 or check_hit(pos, target_head and footpos or headpos, v) then
119+
v:punch(player, 1, {
120+
punch_interval = 1,
121+
damage_groups = {
122+
grenade = 1,
123+
fleshy = def.explode_damage - ( (radius/3) * (target_head and headdist or footdist) )
124+
}
125+
}, nil)
126+
end
127+
end
128+
end
129+
end,
130+
}
131+
132+
grenades.register_grenade("ctf_grenades:frag", fragdef)
133+
134+
-- Smoke Grenade
135+
136+
local sounds = {}
137+
local SMOKE_GRENADE_TIME = 30
138+
139+
local register_smoke_grenade = function(name, description, image, damage)
140+
grenades.register_grenade("ctf_grenades:"..name, {
141+
description = description,
142+
image = image,
143+
on_collide = function()
144+
return true
145+
end,
146+
on_explode = function(def, obj, pos, pname)
147+
local player = minetest.get_player_by_name(pname)
148+
if not player or not pos then return end
149+
150+
local pteam = ctf_teams.get(pname)
151+
local duration_multiplier = 1
152+
-- it gets multiplied with the default duration
153+
154+
if pteam then
155+
for flagteam, team in pairs(ctf_map.current_map.teams) do
156+
if not ctf_modebase.flag_captured[flagteam] and team.flag_pos then
157+
local distance_from_flag = vector.distance(pos, team.flag_pos)
158+
if distance_from_flag <= 15 and (damage or pteam == flagteam) then
159+
minetest.chat_send_player(pname, S("You can't explode smoke grenades so close to a flag!"))
160+
if player:get_hp() <= 0 then
161+
-- Drop the nade at its explode point if the thrower is dead
162+
-- Fixes https://github.com/MT-CTF/capturetheflag/issues/1160
163+
minetest.add_item(pos, ItemStack("ctf_grenades:"..name))
164+
else
165+
-- Add the nade back into the thrower's inventory
166+
player:get_inventory():add_item("main", "ctf_grenades:"..name)
167+
end
168+
return
169+
elseif damage and distance_from_flag <= 26 then
170+
duration_multiplier = 0.5
171+
end
172+
end
173+
end
174+
end
175+
176+
minetest.sound_play("grenades_glasslike_break", {
177+
pos = pos,
178+
gain = 1.0,
179+
max_hear_distance = 32,
180+
})
181+
182+
local hiss = minetest.sound_play("grenades_hiss", {
183+
pos = pos,
184+
gain = 1.0,
185+
loop = true,
186+
max_hear_distance = 32,
187+
})
188+
sounds[hiss] = true
189+
local stop = false
190+
if damage then
191+
local function damage_fn()
192+
local thrower = minetest.get_player_by_name(pname)
193+
194+
if thrower then
195+
for _, target in pairs(minetest.get_connected_players()) do
196+
if vector.distance(target:get_pos(), pos) <= 6 then
197+
local dname = target:get_player_name()
198+
local dteam = ctf_teams.get(dname)
199+
if dname ~= pname and dteam ~= pteam then
200+
target:punch(thrower, 1, {
201+
damage_groups = {
202+
fleshy = 2,
203+
grenade = 1,
204+
poison_grenade = 1,
205+
}
206+
})
207+
end
208+
end
209+
end
210+
end
211+
212+
if not stop then
213+
minetest.after(1, damage_fn)
214+
end
215+
end
216+
damage_fn()
217+
end
218+
219+
minetest.after(SMOKE_GRENADE_TIME * duration_multiplier, function()
220+
sounds[hiss] = nil
221+
minetest.sound_stop(hiss)
222+
stop = true
223+
end)
224+
225+
local p = "grenades_smoke.png^["
226+
local particletexture
227+
if pteam and damage then
228+
particletexture = p .. "colorize:" .. ctf_teams.team[pteam].color .. ":76^[noalpha"
229+
else
230+
particletexture = p .. "noalpha"
231+
end
232+
233+
for i = 0, 5, 1 do
234+
minetest.add_particlespawner({
235+
amount = 40,
236+
time = (SMOKE_GRENADE_TIME * duration_multiplier) + (damage and 1 or 3),
237+
minpos = vector.subtract(pos, 2),
238+
maxpos = vector.add(pos, 2),
239+
minvel = {x = 0, y = 2, z = 0},
240+
maxvel = {x = 0, y = 3, z = 0},
241+
minacc = {x = 1, y = 0.2, z = 1},
242+
maxacc = {x = 1, y = 0.2, z = 1},
243+
minexptime = 1,
244+
maxexptime = 1,
245+
minsize = 125,
246+
maxsize = 140,
247+
collisiondetection = false,
248+
collision_removal = false,
249+
vertical = false,
250+
texture = particletexture,
251+
})
252+
end
253+
end,
254+
particle = {
255+
image = "grenades_smoke.png".. (damage and "^[multiply:#00ff00" or ""),
256+
life = 1,
257+
size = 4,
258+
glow = 0,
259+
interval = 0.3,
260+
}
261+
})
262+
end
263+
264+
register_smoke_grenade(
265+
"smoke",
266+
S("Smoke grenade (Generates smoke around blast site)"),
267+
"grenades_smoke_grenade.png",
268+
false
269+
)
270+
register_smoke_grenade(
271+
"poison",
272+
S("Poison grenade (Generates poisonous smoke around blast site)"),
273+
"grenades_smoke_grenade.png^[multiply:#00ff00",
274+
true
275+
)
276+
277+
ctf_api.register_on_match_end(function()
278+
for sound in pairs(sounds) do
279+
minetest.sound_stop(sound)
280+
end
281+
sounds = {}
282+
end)
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2019-2025 LoneWolfHT
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
name = ctf_grenades
2+
depends = grenades, default, ctf_teams, ctf_map, ctf_modebase, ctf_api
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# ctf_grenades
2+
A heavily modified version of the basic_grenades mod
13.3 KB
Binary file not shown.
Binary file not shown.
34.5 KB
Binary file not shown.

0 commit comments

Comments
 (0)