commit e5a2b43054c18ec9b14329656356360c42ec7fce Author: Billy S Date: Tue Jul 24 15:02:08 2018 -0400 First commit diff --git a/api.lua b/api.lua new file mode 100644 index 0000000..df9bdf2 --- /dev/null +++ b/api.lua @@ -0,0 +1,12 @@ +-- toolname is the name of the tool (ex "default:pick_wood") +-- chance is the chance that the target will be knocked out when hit with the tool +-- (A value betwen 1 and 0; 1 = will happen every time; 0 = will never happed. Note that a chance of 1 may fail to knock players out if the tool is not used wiht a full punch) +-- max_health is the maximum health the player will have to be knocked out with the tool +-- (If the player's health is greater then max_health, they won't be knocked out, regardless of chance) +-- max_time is the maximum time (in seconds) that the player will be knocked out for +-- the minimum time the player will be knocked out for is half of max_time +-- The actual time the player is knocked out for is calculated by the following equation: +-- time knocked out = ((current health / max_health) + 1) * max_time / 2 +knockout.register_tool = function(toolname, chance, max_health, max_time) + knockout.tools[toolname] = {chance = chance, max_health = max_health, max_time = max_time} +end diff --git a/depends.txt b/depends.txt new file mode 100644 index 0000000..4ad96d5 --- /dev/null +++ b/depends.txt @@ -0,0 +1 @@ +default diff --git a/handlers.lua b/handlers.lua new file mode 100644 index 0000000..925b667 --- /dev/null +++ b/handlers.lua @@ -0,0 +1,84 @@ +local function carrierQuit(pName) + if knockout.carrying[pName] then + local cName = knockout.carrying[pName] + local carried = minetest.get_player_by_name(cName) + if carried then + carried:set_detach() + end + knockout.knockout(cName) + knockout.carrying[pName] = nil + end +end + +-- Globalstep to revive players +local gs_time = 0 +minetest.register_globalstep(function(dtime) + -- Decrease knockout time + gs_time = gs_time + dtime + if gs_time >= 1 then + gs_time = 0 + for name, _ in pairs(knockout.knocked_out) do + knockout.decrease_knockout_time(name, 1) + end + end + -- Check for player drop + for name, _ in pairs(knockout.carrying) do + local p = minetest.get_player_by_name(name) + if p:get_player_control().jump then + carrierQuit(name) + end + end +end) + +-- If the player is killed, they "wake up" +minetest.register_on_dieplayer(function(p) + local pName = p:get_player_name() + knockout.wake_up(pName) + -- If the player is carrying another player, drop them + carrierQuit(pName) +end) + +-- If the player was carrying another player, drop them +minetest.register_on_leaveplayer(function(p, _) + carrierQuit(p:get_player_name()) +end) + +-- Catch those pesky players that try to leave/join to get un-knocked out +minetest.register_on_joinplayer(function(p) + local koed = false + local pname = p:get_player_name() + for name, _ in pairs(knockout.knocked_out) do + if name == pname then + koed = true + break + end + end + if koed then + knockout.knockout(pname) + end +end) + +-- Catch whacks with various tools and calculate if the victim should be knocked out +minetest.register_on_punchplayer(function(player, hitter, time_from_last_punch, tool_capabilities, dir, damage) + local tool = hitter:get_wielded_item():get_name() -- Get tool used + local def = nil + -- Get tool knockout def + for name, tdef in pairs(knockout.tools) do + if name == tool then + def = tdef + break + end + end + if def == nil then return end + -- Calculate + local currHp = player:get_hp() + if currHp <= def.max_health then + local chanceMult = time_from_last_punch / tool_capabilities.full_punch_interval -- You can't knock people out with lots of love taps + if chanceMult > 1 then chanceMult = 1 end + if math.random() < def.chance * chanceMult then + -- Knocked out + local koTime = ((currHp / def.max_health) + 1) * def.max_time / 2 + knockout.knockout(player:get_player_name(), koTime) + end + end +end) diff --git a/init.lua b/init.lua new file mode 100644 index 0000000..86dd28c --- /dev/null +++ b/init.lua @@ -0,0 +1,139 @@ +local path = minetest.get_modpath(minetest.get_current_modname()) +dofile(path .. "/overrides.lua") + +-- Create globals +knockout = {} +knockout.knocked_out = {} +knockout.carrying = {} +knockout.tools = {} + +-- Create mod storage +knockout.storage = minetest.get_mod_storage() + +-- Register "nothing" entity +minetest.register_entity("knockout:entity", { + hp_max = 1000, + physical = true, + weight = 5, + collisionbox = {-0.35, 0, -0.35, 0.35, 1.8, 0.35}, + visual = "cube", + textures = {"doors_blank.png", "doors_blank.png", "doors_blank.png", "doors_blank.png", "doors_blank.png", "doors_blank.png"}, + is_visible = true, + makes_footstep_sound = false, + automatic_rotate = false, + on_activate = function(e, sdata, dtime) + e.grabbed_name = sdata + e.object:set_armor_groups({immortal = 1}) + local p = minetest.get_player_by_name(e.grabbed_name) + if p ~= nil then + e.object:set_yaw(p:get_look_horizontal()) + end + end, + on_punch = function(e, puncher, time_from_last_punch, tool_capabilities, dir) + -- The player can't punch themselves + if puncher:get_player_name() == e.grabbed_name then return end + -- If punched with a water bucket revive + local tool = puncher:get_wielded_item():get_name() + if tool == "bucket:bucket_water" then + knockout.wake_up(e.grabbed_name) + return + end + -- Otherwise hurt the player + local p = minetest.get_player_by_name(e.grabbed_name) + if p == nil then + e.object:remove() + else + p:set_detach() + p:punch(puncher, time_from_last_punch, tool_capabilities, dir) + p:set_attach(e.object, "", {x = 0, y = 10, z = 0}, {x = 0, y = 0, z = 0}) + end + end, + on_rightclick = function(e, clicker) + local cName = clicker:get_player_name() + for carryer, carried in pairs(knockout.carrying) do + if carryer == cName or carried == e.grabbed_name then return end + end + victim = minetest.get_player_by_name(e.grabbed_name) + if victim then + victim:set_detach() + victim:set_attach(clicker, "", {x = 0, y = 0, z = -15}, {x = 0, y = 0, z = 0}) + knockout.carrying[cName] = e.grabbed_name + e.object:remove() + end + end, + on_step = function(e, dtime) + if knockout.knocked_out[e.grabbed_name] == nil or minetest.get_player_by_name(e.grabbed_name) == nil then + e.object:remove() + end + end +}) + +-- Load knocked out players +knockout.load = function() + local ko = knockout.storage:get_string("knocked_out") + if ko ~= "" then + knockout.knocked_out = minetest.deserialize(ko) + end +end + +-- Save knocked out players +knockout.save = function() + knockout.storage:set_string("knocked_out", minetest.serialize(knockout.knocked_out)) +end + +-- Knock out player +knockout.knockout = function(pName, duration) + local p = minetest.get_player_by_name(pName) + if duration == nil then + if knockout.knocked_out[pName] == nil then return end + else + knockout.knocked_out[pName] = duration + end + -- Incase player is riding a horse or something + p:set_detach() + -- Freeze player using entites + local pos = p:get_pos() + local e = minetest.add_entity(pos, "knockout:entity", pName) + p:set_attach(e, "", {x = 0, y = 10, z = 0}, {x = 0, y = 0, z = 0}) + -- Make player lay down + default.player_attached[pName] = true + default.player_set_animation(p, "lay") +end + +-- Wake up player +knockout.wake_up = function(pName) + local p = minetest.get_player_by_name(pName) + knockout.knocked_out[pName] = nil + -- Un-freeze player + local e = p:get_attach() + if e ~= nil then + local pos = e:get_pos() + e:remove() + p:set_detach() + p:set_pos(pos) + end + -- Make player stand back up + default.player_attached[pName] = false + default.player_set_animation(p, "stand") + -- If the player was being carried, remove that + for name, carried in pairs(knockout.carrying) do + if carried == pName then + knockout.carrying[name] = nil + break + end + end +end + +-- Decrease knockout time +knockout.decrease_knockout_time = function(pName, by) + knockout.knocked_out[pName] = knockout.knocked_out[pName] - by + if knockout.knocked_out[pName] <= 0 then + knockout.wake_up(pName) + end +end + +-- Init +knockout.load() +dofile(path .. "/api.lua") +dofile(path .. "/handlers.lua") +dofile(path .. "/tools.lua") diff --git a/overrides.lua b/overrides.lua new file mode 100644 index 0000000..a5013a7 --- /dev/null +++ b/overrides.lua @@ -0,0 +1,11 @@ +-- No, you don't get to kill yourself +local oldKill = minetest.registered_chatcommands["killme"].func +minetest.override_chatcommand("killme", { + func = function(name, param) + if knockout.knocked_out[name] == nil then + oldKill(name, param) + else + minetest.chat_send_player(name, "You can't kill yourself!") + end + end +}) diff --git a/textures/knockout_bat.png b/textures/knockout_bat.png new file mode 100644 index 0000000..513224a Binary files /dev/null and b/textures/knockout_bat.png differ diff --git a/tools.lua b/tools.lua new file mode 100644 index 0000000..3adf627 --- /dev/null +++ b/tools.lua @@ -0,0 +1,27 @@ +--------------- +--DEFINITIONS-- +--------------- + +minetest.register_tool("knockout:bat", { + description = "Knockout Bat | Knocks out players with less then 4 hearts", + inventory_image = "knockout_bat.png", +}) + +minetest.register_craft({ + output = "knockout:bat", + recipe = { + {"", "group:wood", "group:wood"}, + {"", "default:steel_ingot", "group:wood"}, + {"group:wood", "", ""}, + } +}) + + + + + + +-------------- +--KNOCK OUT--- +-------------- +knockout.register_tool("knockout:bat", 0.8, 8, 120)