forked from minetest-mods/areas
-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathinteract.lua
More file actions
143 lines (122 loc) · 3.83 KB
/
Copy pathinteract.lua
File metadata and controls
143 lines (122 loc) · 3.83 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
local S = areas.S
local enable_damage = minetest.settings:get_bool("enable_damage")
local abs, max = math.abs, math.max
local vnormalize, vsubtract = vector.normalize, vector.subtract
local COOLDOWN = max(0.05, areas.config.pvp_cooldown)
local PUSH_UP = 4
local PUSH_BACK = 2.5
local old_is_protected = minetest.is_protected
function minetest.is_protected(pos, name)
if not areas:canInteract(pos, name) then
return true
end
return old_is_protected(pos, name)
end
minetest.register_on_protection_violation(function(pos, name)
if not areas:canInteract(pos, name) then
minetest.chat_send_player(name,
S("This area @1 is protected by another player.", minetest.pos_to_string(pos)))
-- Little damage player
local player = minetest.get_player_by_name(name)
if player and player:is_player() then
if enable_damage then
local hp = player:get_hp()
if hp and hp > 2 then
player:set_hp(hp - 2)
end
end
-- add_velocity stacks, so wait until the last lift has peaked
local vel = player:get_velocity()
if vel.y <= 0 then
local player_pos = player:get_pos()
local dir = vsubtract(player_pos, pos)
dir.y = 0
-- within half a node on both axes it is the player's own column
dir = (abs(dir.x) > 0.5 or abs(dir.z) > 0.5)
and vnormalize(dir) or {x = 0, y = 0, z = 0}
-- top up the outward speed instead of adding to it
local kb = max(0, PUSH_BACK - dir.x * vel.x - dir.z * vel.z)
player:add_velocity({
x = dir.x * kb,
y = pos.y <= player_pos.y and PUSH_UP or 0,
z = dir.z * kb
})
end
end
end
end)
local function can_pvp_at(pos)
local default = areas.config.pvp_by_default
for id in pairs(areas:getAreasAtPos(pos)) do
-- This uses areas:canPvP instead of area.canPvP in case areas:canPvP
-- is overridden
local value = areas:canPvP(id)
if value ~= default then
return value
end
end
return default
end
local function pvp_allowed(hitter, player)
return can_pvp_at(hitter:get_pos()) and can_pvp_at(player:get_pos())
end
local punch_pvp = {
hitter = nil, victim = nil, allowed = false, ms = 0
}
local last_kb = {}
minetest.register_on_punchplayer(function(player, hitter, time_from_last_punch)
if not enable_damage then
return true
end
-- If it's a mob, deal damage as usual
if not hitter or not hitter:is_player() then
return false
end
local player_name = hitter:get_player_name()
-- It is possible to use cheats
if time_from_last_punch < COOLDOWN then
minetest.chat_send_player(player_name, S("Wow, wow, take it easy!"))
return true
end
-- Allow PvP if both players are in a PvP area
local allowed = pvp_allowed(hitter, player)
punch_pvp.hitter = player_name
punch_pvp.victim = player:get_player_name()
punch_pvp.allowed = allowed
punch_pvp.ms = minetest.get_us_time() / 1000
if allowed then
return false
end
-- Otherwise, it doesn't do damage
minetest.chat_send_player(player_name, S("PvP is not allowed in this area!"))
return true
end)
local old_calculate_knockback = minetest.calculate_knockback
function minetest.calculate_knockback(player, hitter, time_from_last_punch, ...)
if player:is_player() and hitter and hitter:is_player() then
if time_from_last_punch < COOLDOWN then
return 0
end
local now = minetest.get_us_time() / 1000
local hname, vname = hitter:get_player_name(), player:get_player_name()
local allowed
if punch_pvp.hitter == hname and punch_pvp.victim == vname and
(now - punch_pvp.ms) < 1 then
allowed = punch_pvp.allowed
else
allowed = pvp_allowed(hitter, player)
end
if not allowed then
return 0
end
local prev = last_kb[vname]
if prev and (now - prev) < COOLDOWN * 1000 then
return 0
end
last_kb[vname] = now
end
return old_calculate_knockback(player, hitter, time_from_last_punch, ...)
end
minetest.register_on_leaveplayer(function(player)
last_kb[player:get_player_name()] = nil
end)