diff --git a/.gitignore b/.gitignore index a2fb45104d..9e132e18d3 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,3 @@ tags *.vim debug.txt - -## Files related to minetest development cycle -*.patch diff --git a/.luacheckrc b/.luacheckrc index b301ed904f..151f963d32 100644 --- a/.luacheckrc +++ b/.luacheckrc @@ -15,7 +15,8 @@ globals = { "crafting", "vector", "table", "minetest", "worldedit", "ctf", "ctf_flag", "ctf_colors", "hudkit", "default", "treasurer", "ChatCmdBuilder", "ctf_map", "ctf_match", "ctf_stats", "ctf_treasure", "ctf_playertag", "chatplus", "irc", - "armor", "vote", "give_initial_stuff", "hud_score", "physics", "tsm_chests" + "armor", "vote", "give_initial_stuff", "hud_score", "physics", "tsm_chests", + "armor", "shooter" } read_globals = { diff --git a/README.md b/README.md index e1fb578e63..0c1370d921 100644 --- a/README.md +++ b/README.md @@ -29,6 +29,10 @@ Created by [rubenwardy](https://rubenwardy.com/). Code: LGPLv2.1+ Textures: CC-BY-SA 3.0 +### Textures + +* ctf_classes_skin_* found and edited by GreenDimond/GreenXenith + ### Mods Check out [mods/](mods/) to see all the installed mods and their respective licenses. diff --git a/docs/accurate_statbar.patch b/docs/accurate_statbar.patch new file mode 100644 index 0000000000..8acf78b17a --- /dev/null +++ b/docs/accurate_statbar.patch @@ -0,0 +1,18 @@ +diff --git a/builtin/game/statbars.lua b/builtin/game/statbars.lua +index 46c947b6..f4372843 100644 +--- builtin/game/statbars.lua ++++ builtin/game/statbars.lua +@@ -24,12 +24,14 @@ local breath_bar_definition = { + local hud_ids = {} + + local function scaleToDefault(player, field) ++ return player["get_" .. field](player) +- -- Scale "hp" or "breath" to the default dimensions +- local current = player["get_" .. field](player) +- local nominal = core["PLAYER_MAX_".. field:upper() .. "_DEFAULT"] +- local max_display = math.max(nominal, +- math.max(player:get_properties()[field .. "_max"], current)) +- return current / max_display * nominal + end + + local function update_builtin_statbars(player) diff --git a/minetest.conf b/minetest.conf index 0eb278f54a..01019e1349 100644 --- a/minetest.conf +++ b/minetest.conf @@ -3,8 +3,8 @@ enable_pvp = true mg_name = singlenode vote.kick_vote = false barrier = 106 -regen_interval = 6 -regen_amount = 1 +hpregen.interval = 6 +hpregen.amount = 1 random_messages_interval = 60 sprint_stamina = 10 enable_lavacooling = false diff --git a/mods/ctf/ctf_alloc/init.lua b/mods/ctf/ctf_alloc/init.lua index e565a20969..f1449b1116 100644 --- a/mods/ctf/ctf_alloc/init.lua +++ b/mods/ctf/ctf_alloc/init.lua @@ -126,6 +126,6 @@ function ctf_alloc.set_all() give_initial_stuff(player) end - player:set_hp(20) + player:set_hp(player:get_properties().hp_max) end end diff --git a/mods/ctf/ctf_bandages/init.lua b/mods/ctf/ctf_bandages/init.lua index 2a95754ab2..37f9a95d98 100644 --- a/mods/ctf/ctf_bandages/init.lua +++ b/mods/ctf/ctf_bandages/init.lua @@ -3,7 +3,7 @@ local healing_limit = 15 minetest.register_craftitem("ctf_bandages:bandage", { - description = "Bandage, heals teammates for 3-4 HP until HP is equal to "..healing_limit, + description = "Bandage\n\nHeals teammates for 3-4 HP until HP is equal to "..healing_limit, inventory_image = "ctf_bandages_bandage.png", on_use = function(itemstack, player, pointed_thing) if pointed_thing.type ~= "object" then diff --git a/mods/ctf/ctf_classes/api.lua b/mods/ctf/ctf_classes/api.lua new file mode 100644 index 0000000000..6c9815db0f --- /dev/null +++ b/mods/ctf/ctf_classes/api.lua @@ -0,0 +1,139 @@ +function ctf_classes.register(cname, def) + assert(not ctf_classes.__classes[cname]) + def.name = cname + ctf_classes.__classes[cname] = def + table.insert(ctf_classes.__classes_ordered, def) + + def.pros = def.pros or {} + def.cons = def.cons or {} + + def.properties = def.properties or {} + if def.properties.can_capture == nil then + def.properties.can_capture = true + end + + def.properties.initial_stuff = def.properties.initial_stuff or {} + + if not def.properties.item_blacklist then + def.properties.item_blacklist = {} + for i=1, #def.properties.initial_stuff do + table.insert(def.properties.item_blacklist, def.properties.initial_stuff[i]) + end + end + + if def.properties.additional_item_blacklist then + for i=1, #def.properties.additional_item_blacklist do + table.insert(def.properties.item_blacklist, def.properties.additional_item_blacklist[i]) + end + end + + def.properties.speed = def.properties.speed or 1 + def.properties.max_hp = def.properties.max_hp or 20 +end + +local registered_on_changed = {} +function ctf_classes.register_on_changed(func) + table.insert(registered_on_changed, func) +end + +function ctf_classes.set_skin(player, color, class) + player:set_properties({ + textures = {"ctf_classes_skin_" .. class.name .. "_" .. (color or "blue") .. ".png"} + }) +end + +function ctf_classes.get(player) + if type(player) == "string" then + player = minetest.get_player_by_name(player) + end + + local cname = player:get_meta():get("ctf_classes:class") or ctf_classes.default_class + return ctf_classes.__classes[cname] +end + +function ctf_classes.set(player, new_name) + assert(type(new_name) == "string") + local new = ctf_classes.__classes[new_name] + assert(new) + + local meta = player:get_meta() + local old_name = meta:get("ctf_classes:class") + + meta:set_string("ctf_classes:class", new_name) + ctf_classes.update(player) + + if old_name == nil or old_name ~= new_name then + local old = old_name and ctf_classes.__classes[old_name] + for i=1, #registered_on_changed do + registered_on_changed[i](player, old, new) + end + end +end + +local function set_max_hp(player, max_hp) + local cur_hp = player:get_hp() + local old_max = player:get_properties().hp_max + local new_hp = cur_hp + max_hp - old_max + player:set_properties({ + hp_max = max_hp + }) + + if new_hp > max_hp then + minetest.log("error", string.format("New hp %d is larger than new max %d, old max is %d", new_hp, max_hp, old_max)) + new_hp = max_hp + end + + if cur_hp > max_hp then + player:set_hp(max_hp) + elseif new_hp > cur_hp then + player:set_hp(new_hp) + end +end + +function ctf_classes.update(player) + local name = player:get_player_name() + + local class = ctf_classes.get(player) + local color = ctf_colors.get_color(ctf.player(name)).text + + set_max_hp(player, class.properties.max_hp) + ctf_classes.set_skin(player, color, class) + + local speed = class.properties.speed + if ctf_flag.has_flag(name) and speed > 0.9 then + speed = 0.9 + end + + physics.set(player:get_player_name(), "ctf_classes:speed", { + speed = speed, + }) +end + +local function sqdist(a, b) + local x = a.x - b.x + local y = a.y - b.y + local z = a.z - b.z + return x*x + y*y + z*z +end + +local function get_flag_pos(player) + local tplayer = ctf.player(player:get_player_name()) + if not tplayer or not tplayer.team then + return nil + end + + local team = ctf.team(tplayer.team) + if team and team.flags[1] then + return vector.new(team.flags[1]) + end + return nil +end + +function ctf_classes.can_change(player) + local flag_pos = get_flag_pos(player) + if not flag_pos then + return false + end + + return sqdist(player:get_pos(), flag_pos) < 25 +end diff --git a/mods/ctf/ctf_classes/classes.lua b/mods/ctf/ctf_classes/classes.lua new file mode 100644 index 0000000000..13cf990b62 --- /dev/null +++ b/mods/ctf/ctf_classes/classes.lua @@ -0,0 +1,97 @@ +ctf_classes.default_class = "knight" + +ctf_classes.register("knight", { + description = "Knight", + pros = { "+50% Health Points" }, + cons = { "-10% speed" }, + color = "#ccc", + properties = { + max_hp = 30, + speed = 0.90, + + initial_stuff = { + "default:sword_steel", + }, + + allowed_guns = { + "shooter:pistol", + "shooter:smg", + "shooter:shotgun", + }, + }, +}) + +ctf_classes.register("shooter", { + description = "Sharp Shooter", + pros = { "+50% range", "+20% faster shooting" }, + cons = {}, + color = "#c60", + properties = { + allow_grapples = true, + + initial_stuff = { + "shooter:rifle", + "shooter:grapple_gun_loaded", + }, + + additional_item_blacklist = { + "shooter:grapple_gun", + "shooter:grapple_hook", + }, + + allowed_guns = { + "shooter:pistol", + "shooter:rifle", + "shooter:smg", + "shooter:shotgun", + }, + + shooter_multipliers = { + range = 1.5, + full_punch_interval = 0.8, + }, + }, +}) + +ctf_classes.register("medic", { + description = "Medic", + pros = { "x2 regen for nearby friendlies" }, + cons = {}, + color = "#0af", + properties = { + nearby_hpregen = true, + + initial_stuff = { + "ctf_bandages:bandage 20", + }, + + allowed_guns = { + "shooter:pistol", + "shooter:smg", + "shooter:shotgun", + }, + }, +}) + +ctf_classes.register("rocketeer", { + description = "Rocketeer", + pros = { "Can craft rockets" }, + cons = {}, + color = "#fa0", + properties = { + initial_stuff = { + "shooter:rocket_gun_loaded", + "shooter:rocket 4", + }, + + additional_item_blacklist = { + "shooter:rocket_gun", + }, + + allowed_guns = { + "shooter:pistol", + "shooter:smg", + "shooter:shotgun", + }, + }, +}) diff --git a/mods/ctf/ctf_classes/flags.lua b/mods/ctf/ctf_classes/flags.lua new file mode 100644 index 0000000000..41874d621f --- /dev/null +++ b/mods/ctf/ctf_classes/flags.lua @@ -0,0 +1,31 @@ +ctf_flag.register_on_pick_up(function(name) + ctf_classes.update(minetest.get_player_by_name(name)) +end) + +ctf_flag.register_on_drop(function(name) + ctf_classes.update(minetest.get_player_by_name(name)) +end) + +local old_func = ctf_flag.on_punch +local function on_punch(pos, node, player, ...) + local class = ctf_classes.get(player) + if not class.properties.can_capture then + local pname = player:get_player_name() + local flag = ctf_flag.get(pos) + local team = ctf.player(pname).team + if flag and flag.team and team and team ~= flag.team then + minetest.chat_send_player(pname, + "You need to change classes to capture the flag!") + return + end + end + + return old_func(pos, node, player, ...) +end + +local function show(_, _, player) + ctf_classes.show_gui(player:get_player_name(), player) +end + +ctf_flag.on_rightclick = show +ctf_flag.on_punch = on_punch diff --git a/mods/ctf/ctf_classes/gui.lua b/mods/ctf/ctf_classes/gui.lua new file mode 100644 index 0000000000..fcec7d0a31 --- /dev/null +++ b/mods/ctf/ctf_classes/gui.lua @@ -0,0 +1,93 @@ +function ctf_classes.show_gui(name, player) + player = player or minetest.get_player_by_name(name) + assert(player.get_player_name) + if not ctf_classes.can_change(player) then + minetest.chat_send_player(name, "Move closer to your flag to change classes!") + return + end + + local fs = { + "size[", #ctf_classes.__classes_ordered * 3 , ",3.4]" + } + + + local x = 0 + local y = 0 + for _, class in pairs(ctf_classes.__classes_ordered) do + fs[#fs + 1] = "container[" + fs[#fs + 1] = tostring(x*3) + fs[#fs + 1] = "," + fs[#fs + 1] = tostring(y*3.5) + fs[#fs + 1] = "]" + fs[#fs + 1] = "image[1,-0.1;1,1;ctf_classes_" + fs[#fs + 1] = class.name + fs[#fs + 1] = ".png]" + fs[#fs + 1] = "style[select_" + fs[#fs + 1] = class.name + fs[#fs + 1] = ";bgcolor=" + fs[#fs + 1] = class.color + fs[#fs + 1] = "]" + fs[#fs + 1] = "tableoptions[background=#00000000;highlight=#00000000;border=false]" + fs[#fs + 1] = "tablecolumns[color;text]" + fs[#fs + 1] = "table[0,0.9;2.8,1.7;;" + fs[#fs + 1] = class.color + fs[#fs + 1] = "," + fs[#fs + 1] = minetest.formspec_escape(class.description) + fs[#fs + 1] = ",," + for _, item in pairs(class.pros) do + fs[#fs + 1] = ",#cfc," .. minetest.formspec_escape(item) + end + for _, item in pairs(class.cons) do + fs[#fs + 1] = ",#fcc," .. minetest.formspec_escape(item) + end + fs[#fs + 1] = "]" + + for i, item in pairs(class.properties.initial_stuff) do + fs[#fs + 1] = "item_image[" + fs[#fs + 1] = tostring(i * 0.5 - 0.4) + fs[#fs + 1] = ",2.25;0.5,0.5;" + fs[#fs + 1] = minetest.formspec_escape(ItemStack(item):get_name()) + fs[#fs + 1] = "]" + + local desc = ItemStack(item):get_description():split("\n")[1] + + fs[#fs + 1] = "tooltip[" + fs[#fs + 1] = tostring(i * 0.5 - 0.4) + fs[#fs + 1] = ",2.25;0.5,0.5;" + fs[#fs + 1] = minetest.formspec_escape(desc) + fs[#fs + 1] = "]" + end + + + fs[#fs + 1] = "button_exit[0.5,2.9;2,1;select_" + fs[#fs + 1] = class.name + fs[#fs + 1] = ";Select]" + fs[#fs + 1] = "container_end[]" + + x = x + 1 + if x > 3 then + x = 0 + y = y + 1 + end + end + + minetest.show_formspec(name, "ctf_classes:select", table.concat(fs)) +end + +minetest.register_on_player_receive_fields(function(player, formname, fields) + if formname ~= "ctf_classes:select" then + return false + end + + if not ctf_classes.can_change(player) then + minetest.chat_send_player(player:get_player_name(), + "Move closer to the flag to change classes!") + end + + for name in pairs(ctf_classes.__classes) do + if fields["select_" .. name] then + ctf_classes.set(player, name) + return true + end + end +end) diff --git a/mods/ctf/ctf_classes/init.lua b/mods/ctf/ctf_classes/init.lua new file mode 100644 index 0000000000..da28846a9c --- /dev/null +++ b/mods/ctf/ctf_classes/init.lua @@ -0,0 +1,60 @@ +ctf_classes = { + __classes = {}, + __classes_ordered = {}, +} + +dofile(minetest.get_modpath("ctf_classes") .. "/api.lua") +dofile(minetest.get_modpath("ctf_classes") .. "/gui.lua") +dofile(minetest.get_modpath("ctf_classes") .. "/regen.lua") +dofile(minetest.get_modpath("ctf_classes") .. "/ranged.lua") +dofile(minetest.get_modpath("ctf_classes") .. "/items.lua") +dofile(minetest.get_modpath("ctf_classes") .. "/flags.lua") +dofile(minetest.get_modpath("ctf_classes") .. "/classes.lua") + + +minetest.register_on_joinplayer(function(player) + ctf_classes.update(player) + + if minetest.check_player_privs(player, { interact = true }) then + ctf_classes.show_gui(player:get_player_name()) + end +end) + +minetest.register_chatcommand("class", { + func = function(name, params) + local player = minetest.get_player_by_name(name) + if not player then + return false, "You must be online to do this!" + end + + if not ctf_classes.can_change(player) then + return false, "Move closer to your flag to change classes!" + end + + local cname = params:trim() + if params == "" then + ctf_classes.show_gui(name) + else + if ctf_classes.__classes[cname] then + ctf_classes.set(player, cname) + return true, "Set class to " .. cname + else + return false, "Class '" .. cname .. "' does not exist" + end + end + end +}) + +ctf_colors.set_skin = function(player, color) + ctf_classes.set_skin(player, color, ctf_classes.get(player)) +end + +ctf_classes.register_on_changed(function(player, old, new) + if not old then + return + end + + local pname = player:get_player_name() + ctf.chat_send_team(ctf.player(pname).team, + minetest.colorize("#ABCDEF", pname .. " is now a " .. new.description)) +end) diff --git a/mods/ctf/ctf_classes/items.lua b/mods/ctf/ctf_classes/items.lua new file mode 100644 index 0000000000..5422d98120 --- /dev/null +++ b/mods/ctf/ctf_classes/items.lua @@ -0,0 +1,66 @@ +local function stack_list_to_map(stacks) + local map = {} + for i = 1, #stacks do + map[ItemStack(stacks[i]):get_name()] = true + end + return map +end + +-- Returns true if the item shouldn't be allowed to be dropped etc +local function is_class_blacklisted(player, itemname) + local class = ctf_classes.get(player) + local items = stack_list_to_map(class.properties.item_blacklist or {}) + return items[itemname] +end + + +give_initial_stuff.register_stuff_provider(function(player) + local class = ctf_classes.get(player) + return class.properties.initial_stuff or {} +end, 1) + +ctf_classes.register_on_changed(function(player, old, new) + local inv = player:get_inventory() + + if old then + local items = old.properties.item_blacklist or {} + for i = 1, #items do + inv:remove_item("main", ItemStack(items[i])) + end + end + + do + assert(new) + + local items = new.properties.initial_stuff or {} + for i = 1, #items do + inv:add_item("main", ItemStack(items[i])) + end + end +end) + +local old_item_drop = minetest.item_drop +minetest.item_drop = function(itemstack, player, pos) + if is_class_blacklisted(player, itemstack:get_name()) then + minetest.chat_send_player(player:get_player_name(), + "You're not allowed to drop class items!") + return itemstack + else + return old_item_drop(itemstack, player, pos) + end +end + +local old_is_allowed = ctf_map.is_item_allowed_in_team_chest +ctf_map.is_item_allowed_in_team_chest = function(listname, stack, player) + if is_class_blacklisted(player, stack:get_name()) then + minetest.chat_send_player(player:get_player_name(), + "You're not allowed to put class items in the chest!") + return false + else + return old_is_allowed(listname, stack, player) + end +end + +dropondie.register_drop_filter(function(player, itemname) + return not is_class_blacklisted(player, itemname) +end) diff --git a/mods/ctf/ctf_classes/mod.conf b/mods/ctf/ctf_classes/mod.conf new file mode 100644 index 0000000000..0e9b5679ef --- /dev/null +++ b/mods/ctf/ctf_classes/mod.conf @@ -0,0 +1,3 @@ +name = ctf_classes +depends = ctf, ctf_flag, ctf_colors, ctf_map_core, physics, shooter, hpregen, give_initial_stuff, dropondie +description = Adds classes, including knight, shooter, and medic diff --git a/mods/ctf/ctf_classes/ranged.lua b/mods/ctf/ctf_classes/ranged.lua new file mode 100644 index 0000000000..628e68b4de --- /dev/null +++ b/mods/ctf/ctf_classes/ranged.lua @@ -0,0 +1,69 @@ +local specs_cache = {} + +local function get_shooter_specs(weapon_name, multiplier) + local spec = shooter.registered_weapons[weapon_name] + if not spec then + return nil + end + spec = spec.spec + + -- this will convert the multipler to a table pointer + local idx = ("%s:%s"):format(multiplier or "nil", weapon_name) + + if specs_cache[idx] then + return specs_cache[idx] + end + + spec = table.copy(spec) + specs_cache[idx] = spec + + for key, value in pairs(multiplier) do + spec[key] = spec[key] * value + end + + return spec +end + +shooter.get_weapon_spec = function(_, user, weapon_name) + local class = ctf_classes.get(user) + + if table.indexof(class.properties.allowed_guns or {}, weapon_name) == -1 then + minetest.chat_send_player(user:get_player_name(), + "Your class can't use that weapon! Change your class at spawn") + return nil + end + + local spec = get_shooter_specs(weapon_name, class.properties.shooter_multipliers) + spec.name = user and user:get_player_name() + + return spec +end + + +local function check_grapple(itemname) + local def = minetest.registered_items[itemname] + local old_func = def.on_use + minetest.override_item(itemname, { + on_use = function(itemstack, user, ...) + if not ctf_classes.get(user).properties.allow_grapples then + minetest.chat_send_player(user:get_player_name(), + "Your class can't use that weapon! Change your class at spawn") + + return itemstack + end + + if ctf_flag.has_flag(user:get_player_name()) then + minetest.chat_send_player(user:get_player_name(), + "You can't use grapples whilst carrying the flag") + + return itemstack + end + + return old_func(itemstack, user, ...) + end, + }) +end + +check_grapple("shooter:grapple_gun_loaded") +check_grapple("shooter:grapple_gun") +check_grapple("shooter:grapple_hook") diff --git a/mods/ctf/ctf_classes/regen.lua b/mods/ctf/ctf_classes/regen.lua new file mode 100644 index 0000000000..44f67a45c4 --- /dev/null +++ b/mods/ctf/ctf_classes/regen.lua @@ -0,0 +1,65 @@ +local function regen_update() + local get = ctf_classes.get + local players = minetest.get_connected_players() + local medic_by_team = { red = {}, blue = {} } + local tnames = {} + local found_medic = false + + -- First get medic positions and team names + for i=1, #players do + local player = players[i] + local pname = player:get_player_name() + local class = get(player) + local tname = ctf.player(pname).team + tnames[pname] = tname + if class.properties.nearby_hpregen then + if tname then + medic_by_team[tname][#medic_by_team[tname] + 1] = player:get_pos() + found_medic = true + end + end + end + + if not found_medic then + return + end + + -- Next, update hp + + local function sqdist(a, b) + local x = a.x - b.x + local y = a.y - b.y + local z = a.z - b.z + return x*x + y*y + z*z + end + + for i=1, #players do + local player = players[i] + local pname = player:get_player_name() + local tname = tnames[pname] + local hp = player:get_hp() + local max_hp = player:get_properties().hp_max + if tname and hp ~= max_hp and hp > 0 then + local pos = player:get_pos() + local medics = medic_by_team[tname] + for j=1, #medics do + if sqdist(pos, medics[j]) < 100 then + hp = hp + hpregen.amount + player:set_hp(hp) + break + end + end + end + end +end + +local update = hpregen.interval / 2 +minetest.register_globalstep(function(delta) + update = update + delta + if update < hpregen.interval then + return + end + update = update - hpregen.interval + + regen_update() +end) diff --git a/mods/ctf/ctf_classes/textures/ctf_classes_knight.png b/mods/ctf/ctf_classes/textures/ctf_classes_knight.png new file mode 100644 index 0000000000..54176327fc Binary files /dev/null and b/mods/ctf/ctf_classes/textures/ctf_classes_knight.png differ diff --git a/mods/ctf/ctf_classes/textures/ctf_classes_medic.png b/mods/ctf/ctf_classes/textures/ctf_classes_medic.png new file mode 100644 index 0000000000..901c6cb76c Binary files /dev/null and b/mods/ctf/ctf_classes/textures/ctf_classes_medic.png differ diff --git a/mods/ctf/ctf_classes/textures/ctf_classes_rocketeer.png b/mods/ctf/ctf_classes/textures/ctf_classes_rocketeer.png new file mode 100644 index 0000000000..3b2dc4d1cc Binary files /dev/null and b/mods/ctf/ctf_classes/textures/ctf_classes_rocketeer.png differ diff --git a/mods/ctf/ctf_classes/textures/ctf_classes_shooter.png b/mods/ctf/ctf_classes/textures/ctf_classes_shooter.png new file mode 100644 index 0000000000..451ed5f707 Binary files /dev/null and b/mods/ctf/ctf_classes/textures/ctf_classes_shooter.png differ diff --git a/mods/ctf/ctf_classes/textures/ctf_classes_skin_knight_blue.png b/mods/ctf/ctf_classes/textures/ctf_classes_skin_knight_blue.png new file mode 100644 index 0000000000..eba75f8d97 Binary files /dev/null and b/mods/ctf/ctf_classes/textures/ctf_classes_skin_knight_blue.png differ diff --git a/mods/ctf/ctf_classes/textures/ctf_classes_skin_knight_red.png b/mods/ctf/ctf_classes/textures/ctf_classes_skin_knight_red.png new file mode 100644 index 0000000000..e77b4c3142 Binary files /dev/null and b/mods/ctf/ctf_classes/textures/ctf_classes_skin_knight_red.png differ diff --git a/mods/ctf/ctf_classes/textures/ctf_classes_skin_medic_blue.png b/mods/ctf/ctf_classes/textures/ctf_classes_skin_medic_blue.png new file mode 100644 index 0000000000..15491c5a93 Binary files /dev/null and b/mods/ctf/ctf_classes/textures/ctf_classes_skin_medic_blue.png differ diff --git a/mods/ctf/ctf_classes/textures/ctf_classes_skin_medic_red.png b/mods/ctf/ctf_classes/textures/ctf_classes_skin_medic_red.png new file mode 100644 index 0000000000..b6294d6980 Binary files /dev/null and b/mods/ctf/ctf_classes/textures/ctf_classes_skin_medic_red.png differ diff --git a/mods/ctf/ctf_classes/textures/ctf_classes_skin_shooter_blue.png b/mods/ctf/ctf_classes/textures/ctf_classes_skin_shooter_blue.png new file mode 100644 index 0000000000..8d08d6a4d6 Binary files /dev/null and b/mods/ctf/ctf_classes/textures/ctf_classes_skin_shooter_blue.png differ diff --git a/mods/ctf/ctf_classes/textures/ctf_classes_skin_shooter_red.png b/mods/ctf/ctf_classes/textures/ctf_classes_skin_shooter_red.png new file mode 100644 index 0000000000..55649e1fa8 Binary files /dev/null and b/mods/ctf/ctf_classes/textures/ctf_classes_skin_shooter_red.png differ diff --git a/mods/ctf/ctf_crafting/init.lua b/mods/ctf/ctf_crafting/init.lua index deef651c44..36fd84c3c3 100644 --- a/mods/ctf/ctf_crafting/init.lua +++ b/mods/ctf/ctf_crafting/init.lua @@ -1,28 +1,33 @@ local full_ores = { - {"diamond", "default:diamond"}, - {"mese", "default:mese_crystal"}, - {"bronze", "default:bronze_ingot"}, - {"steel", "default:steel_ingot"}, - {"stone", "default:cobble"}, + diamond = "default:diamond", + mese = "default:mese_crystal", + bronze = "default:bronze_ingot", + steel = "default:steel_ingot", + stone = "default:cobble", +} + +local upgrades = { + steel = "mese", + mese = "diamond", } -- Swords -for _, orex in pairs(full_ores) do +for from, to in pairs(upgrades) do crafting.register_recipe({ type = "inv", - output = "default:sword_" .. orex[1], - items = { "default:stick", orex[2] .. " 2" }, + output = "default:sword_" .. to, + items = { "default:sword_" .. from, full_ores[to] .. " 2" }, always_known = true, level = 1, }) end -- Pickaxes -for _, orex in pairs(full_ores) do +for ore, ore_item in pairs(full_ores) do crafting.register_recipe({ type = "inv", - output = "default:pick_" .. orex[1], - items = { "default:stick 2", orex[2] .. " 3" }, + output = "default:pick_" .. ore, + items = { "default:stick 2", ore_item .. " 3" }, always_known = true, level = 1, }) @@ -187,22 +192,22 @@ crafting.register_recipe({ }) -- Shovels -for _, orex in pairs(full_ores) do +for ore, ore_item in pairs(full_ores) do crafting.register_recipe({ type = "inv", - output = "default:shovel_" .. orex[1], - items = { "default:stick 2", orex[2] }, + output = "default:shovel_" .. ore, + items = { "default:stick 2", ore_item }, always_known = true, level = 1, }) end -- Axes -for _, orex in pairs(full_ores) do +for ore, ore_item in pairs(full_ores) do crafting.register_recipe({ type = "inv", - output = "default:axe_" .. orex[1], - items = { "default:stick 2", orex[2] .. " 3" }, + output = "default:axe_" .. ore, + items = { "default:stick 2", ore_item .. " 3" }, always_known = true, level = 1, }) diff --git a/mods/ctf/ctf_flag/api.lua b/mods/ctf/ctf_flag/api.lua index 1420ecbe74..4fdeba2e68 100644 --- a/mods/ctf/ctf_flag/api.lua +++ b/mods/ctf/ctf_flag/api.lua @@ -50,13 +50,14 @@ function ctf_flag.collect_claimed() return claimed end -function ctf_flag.get_claimed_by_player(name) +function ctf_flag.has_flag(name) local claimed = ctf_flag.collect_claimed() for _, flag in pairs(claimed) do if flag.claimed.player == name then - return name + return true end end + return false end function ctf_flag.player_drop_flag(name) diff --git a/mods/ctf/ctf_flag/flags.lua b/mods/ctf/ctf_flag/flags.lua index a7a9d8ddff..776d06eaa2 100644 --- a/mods/ctf/ctf_flag/flags.lua +++ b/mods/ctf/ctf_flag/flags.lua @@ -20,8 +20,10 @@ minetest.register_node("ctf_flag:flag", { } }, groups = {immortal=1,is_flag=1,flag_bottom=1}, - on_punch = ctf_flag.on_punch, - on_rightclick = ctf_flag.on_rightclick, + + -- Wrap fuctions to allow overriding + on_punch = function(...) ctf_flag.on_punch(...) end, + on_rightclick = function(...) ctf_flag.on_rightclick(...) end, on_construct = ctf_flag.on_construct, after_place_node = ctf_flag.after_place_node, on_timer = ctf_flag.flag_tick diff --git a/mods/ctf/ctf_map/ctf_map_core/chest.lua b/mods/ctf/ctf_map/ctf_map_core/chest.lua index 70c9df2c5f..b0e86d45e9 100644 --- a/mods/ctf/ctf_map/ctf_map_core/chest.lua +++ b/mods/ctf/ctf_map/ctf_map_core/chest.lua @@ -6,9 +6,24 @@ local blacklist = { "default:aspen_leaves" } + +function ctf_map.is_item_allowed_in_team_chest(listname, stack, player) + if listname == "helper" then + return false + end + + for _, itemstring in ipairs(blacklist) do + if stack:get_name() == itemstring then + return false + end + end + + return true +end + local colors = {"red", "blue"} for _, chest_color in pairs(colors) do - minetest.register_node("ctf_map_core:chest_" .. chest_color, { + local def = { description = "Chest", tiles = { "default_chest_top_" .. chest_color .. ".png", @@ -22,185 +37,188 @@ for _, chest_color in pairs(colors) do legacy_facedir_simple = true, is_ground_content = false, sounds = default.node_sound_wood_defaults(), - on_construct = function(pos) - local meta = minetest.get_meta(pos) - meta:set_string("infotext", "Chest") - local inv = meta:get_inventory() - inv:set_size("main", 4 * 7) - inv:set_size("pro", 4 * 7) - inv:set_size("helper", 1 * 1) - end, - on_rightclick = function(pos, node, player) - local name = player:get_player_name() - if chest_color ~= ctf.player(name).team then - minetest.chat_send_player(name, "You're not on team " .. chest_color) - return - end - - local territory_owner = ctf.get_territory_owner(pos) - if chest_color ~= territory_owner then - if not territory_owner then - ctf.warning("ctf_map", "Unowned team chest") - minetest.set_node(pos, { name = "air" }) - return - end - ctf.warning("ctf_map", "Wrong chest, changing to " .. - territory_owner .. " from " .. chest_color) - minetest.set_node(pos, "ctf_map_core:chest_" .. territory_owner) - end + } + + function def.on_construct(pos) + local meta = minetest.get_meta(pos) + meta:set_string("infotext", "Chest") + local inv = meta:get_inventory() + inv:set_size("main", 4 * 7) + inv:set_size("pro", 4 * 7) + inv:set_size("helper", 1 * 1) + end + + function def.can_dig(pos, player) + return false + end + + function def.on_rightclick(pos, node, player) + local name = player:get_player_name() + if chest_color ~= ctf.player(name).team then + minetest.chat_send_player(name, "You're not on team " .. chest_color) + return + end - local formspec = table.concat({ - "size[8,12]", - default.gui_bg, - default.gui_bg_img, - default.gui_slots, - default.get_hotbar_bg(0,7.85), - "list[current_player;main;0,7.85;8,1;]", - "list[current_player;main;0,9.08;8,3;8]", - }, "") - - if ctf_stats.player(name).score < 10 then - local msg = "You need at least 10 score to access the team chest.\n" .. - "Try killing an enemy player, or at least try to capture the flag.\n" .. - "Find resources in chests scattered around the map." - formspec = formspec .. "label[0.75,3;" .. minetest.formspec_escape(msg) .. "]" - minetest.show_formspec(name, "ctf_map_core:no_access", formspec) + local territory_owner = ctf.get_territory_owner(pos) + if chest_color ~= territory_owner then + if not territory_owner then + ctf.warning("ctf_map", "Unowned team chest") + minetest.set_node(pos, { name = "air" }) return end + ctf.warning("ctf_map", "Wrong chest, changing to " .. + territory_owner .. " from " .. chest_color) + minetest.set_node(pos, "ctf_map_core:chest_" .. territory_owner) + end - local is_pro = ctf_stats.is_pro(name) - local chestinv = "nodemeta:" .. pos.x .. "," .. pos.y .. "," .. pos.z - - formspec = formspec .. "list[" .. chestinv .. ";main;0,0.3;4,7;]" .. - "background[4,-0.2;4.15,7.7;ctf_map_pro_section.png;false]" + local formspec = table.concat({ + "size[8,12]", + default.gui_bg, + default.gui_bg_img, + default.gui_slots, + default.get_hotbar_bg(0,7.85), + "list[current_player;main;0,7.85;8,1;]", + "list[current_player;main;0,9.08;8,3;8]", + }, "") + + if ctf_stats.player(name).score < 10 then + local msg = "You need at least 10 score to access the team chest.\n" .. + "Try killing an enemy player, or at least try to capture the flag.\n" .. + "Find resources in chests scattered around the map." + formspec = formspec .. "label[0.75,3;" .. minetest.formspec_escape(msg) .. "]" + minetest.show_formspec(name, "ctf_map_core:no_access", formspec) + return + end - if is_pro then - formspec = formspec .. "list[" .. chestinv .. ";pro;4,0.3;4,7;]" .. - "listring[" .. chestinv ..";pro]" .. - "listring[" .. chestinv .. ";helper]" .. - "label[5,-0.2;" .. - minetest.formspec_escape("Pro players only") .. "]" - else - formspec = formspec .. "label[4.75,3;" .. - minetest.formspec_escape("You need at least 10000" .. - "\nscore and 1.5+ KD to\naccess the pro section") .. "]" - end + local is_pro = ctf_stats.is_pro(name) + local chestinv = "nodemeta:" .. pos.x .. "," .. pos.y .. "," .. pos.z + + formspec = formspec .. "list[" .. chestinv .. ";main;0,0.3;4,7;]" .. + "background[4,-0.2;4.15,7.7;ctf_map_pro_section.png;false]" + + if is_pro then + formspec = formspec .. "list[" .. chestinv .. ";pro;4,0.3;4,7;]" .. + "listring[" .. chestinv ..";pro]" .. + "listring[" .. chestinv .. ";helper]" .. + "label[5,-0.2;" .. + minetest.formspec_escape("Pro players only") .. "]" + else + formspec = formspec .. "label[4.75,3;" .. + minetest.formspec_escape("You need at least 10000" .. + "\nscore and 1.5+ KD to\naccess the pro section") .. "]" + end - formspec = formspec .. - "listring[" .. chestinv ..";main]" .. - "listring[current_player;main]" + formspec = formspec .. + "listring[" .. chestinv ..";main]" .. + "listring[current_player;main]" - minetest.show_formspec(name, "ctf_map_core:chest", formspec) - end, + minetest.show_formspec(name, "ctf_map_core:chest", formspec) + end - allow_metadata_inventory_move = function(pos, from_list, from_index, - to_list, to_index, count, player) - local name = player:get_player_name() - if chest_color ~= ctf.player(name).team then - minetest.chat_send_player(name, "You're not on team " .. chest_color) - return 0 - end + function def.allow_metadata_inventory_move(pos, from_list, from_index, + to_list, to_index, count, player) + local name = player:get_player_name() + if chest_color ~= ctf.player(name).team then + minetest.chat_send_player(name, "You're not on team " .. chest_color) + return 0 + end - if ctf_stats.player(name).score < 10 then - return 0 - end + if ctf_stats.player(name).score < 10 then + return 0 + end - if (from_list ~= "pro" and to_list ~= "pro") or ctf_stats.is_pro(name) then - if to_list == "helper" then - -- handle move & overflow - local chestinv = minetest.get_inventory({type = "node", pos = pos}) - local playerinv = player:get_inventory() - local stack = chestinv:get_stack(from_list, from_index) - local leftover = playerinv:add_item("main", stack) - local n_stack = stack - n_stack:set_count(stack:get_count() - leftover:get_count()) - chestinv:remove_item("helper", stack) - chestinv:remove_item("pro", n_stack) - return 0 - elseif from_list == "helper" then - return 0 - else - return count - end - else + if (from_list ~= "pro" and to_list ~= "pro") or ctf_stats.is_pro(name) then + if to_list == "helper" then + -- handle move & overflow + local chestinv = minetest.get_inventory({type = "node", pos = pos}) + local playerinv = player:get_inventory() + local stack = chestinv:get_stack(from_list, from_index) + local leftover = playerinv:add_item("main", stack) + local n_stack = stack + n_stack:set_count(stack:get_count() - leftover:get_count()) + chestinv:remove_item("helper", stack) + chestinv:remove_item("pro", n_stack) return 0 - end - end, - allow_metadata_inventory_put = function(pos, listname, index, stack, player) - if listname == "helper" then + elseif from_list == "helper" then return 0 + else + return count end + else + return 0 + end + end - local name = player:get_player_name() - if chest_color ~= ctf.player(name).team then - minetest.chat_send_player(name, "You're not on team " .. chest_color) - return 0 - end + function def.allow_metadata_inventory_put(pos, listname, index, stack, player) + local name = player:get_player_name() + if chest_color ~= ctf.player(name).team then + minetest.chat_send_player(name, "You're not on team " .. chest_color) + return 0 + end - for _, itemstring in ipairs(blacklist) do - if stack:get_name() == itemstring then - return 0 - end - end + local pstat = ctf_stats.player(name) + if not pstat or not pstat.score or pstat.score < 10 then + return 0 + end - local pstat = ctf_stats.player(name) - if not pstat or not pstat.score or pstat.score < 10 then - return 0 - end + if not ctf_map.is_item_allowed_in_team_chest(listname, stack, player) then + return 0 + end - if listname ~= "pro" or ctf_stats.is_pro(name) then - local chestinv = minetest.get_inventory({type = "node", pos = pos}) - if chestinv:room_for_item("pro", stack) then - return stack:get_count() - else - -- handle overflow - local playerinv = player:get_inventory() - local leftovers = chestinv:add_item("pro", stack) - local leftover = chestinv:add_item("main", leftovers) - local n_stack = stack - n_stack:set_count(stack:get_count() - leftover:get_count()) - playerinv:remove_item("main", n_stack) - return 0 - end + if listname ~= "pro" or ctf_stats.is_pro(name) then + local chestinv = minetest.get_inventory({type = "node", pos = pos}) + if chestinv:room_for_item("pro", stack) then + return stack:get_count() else + -- handle overflow + local playerinv = player:get_inventory() + local leftovers = chestinv:add_item("pro", stack) + local leftover = chestinv:add_item("main", leftovers) + local n_stack = stack + n_stack:set_count(stack:get_count() - leftover:get_count()) + playerinv:remove_item("main", n_stack) return 0 end - end, - allow_metadata_inventory_take = function(pos, listname, index, stack, player) - if listname == "helper" then - return 0 - end + else + return 0 + end + end - local name = player:get_player_name() - if chest_color ~= ctf.player(name).team then - minetest.chat_send_player(name, "You're not on team " .. chest_color) - return 0 - end + function def.allow_metadata_inventory_take(pos, listname, index, stack, player) + if listname == "helper" then + return 0 + end - if ctf_stats.player(name).score < 10 then - return 0 - end + local name = player:get_player_name() + if chest_color ~= ctf.player(name).team then + minetest.chat_send_player(name, "You're not on team " .. chest_color) + return 0 + end - if listname ~= "pro" or ctf_stats.is_pro(name) then - return stack:get_count() - else - return 0 - end - end, - can_dig = function(pos, player) - return false - end, - on_metadata_inventory_put = function(pos, listname, index, stack, player) - minetest.log("action", player:get_player_name() .. - " moves " .. (stack:get_name() or "stuff") .. " " .. - (stack:get_count() or 0) .. " to chest at " .. - minetest.pos_to_string(pos)) - end, - on_metadata_inventory_take = function(pos, listname, index, stack, player) - minetest.log("action", player:get_player_name() .. - " takes " .. (stack:get_name() or "stuff") .. " " .. - (stack:get_count() or 0) .. " from chest at " .. - minetest.pos_to_string(pos)) - end - }) + if ctf_stats.player(name).score < 10 then + return 0 + end + + if listname ~= "pro" or ctf_stats.is_pro(name) then + return stack:get_count() + else + return 0 + end + end + + function def.on_metadata_inventory_put(pos, listname, index, stack, player) + minetest.log("action", player:get_player_name() .. + " moves " .. (stack:get_name() or "stuff") .. " " .. + (stack:get_count() or 0) .. " to chest at " .. + minetest.pos_to_string(pos)) + end + + function def.on_metadata_inventory_take(pos, listname, index, stack, player) + minetest.log("action", player:get_player_name() .. + " takes " .. (stack:get_name() or "stuff") .. " " .. + (stack:get_count() or 0) .. " from chest at " .. + minetest.pos_to_string(pos)) + end + + minetest.register_node("ctf_map_core:chest_" .. chest_color, def) end diff --git a/mods/ctf/ctf_map/ctf_map_core/give_initial_stuff.lua b/mods/ctf/ctf_map/ctf_map_core/give_initial_stuff.lua deleted file mode 100644 index 7a313bdd2b..0000000000 --- a/mods/ctf/ctf_map/ctf_map_core/give_initial_stuff.lua +++ /dev/null @@ -1,35 +0,0 @@ -give_initial_stuff = {} - -setmetatable(give_initial_stuff, { - __call = function(self, player) - minetest.log("action", "Giving initial stuff to player " - .. player:get_player_name()) - local inv = player:get_inventory() - inv:set_list("main", {}) - inv:set_list("craft", {}) - - inv:set_size("craft", 1) - inv:set_size("craftresult", 0) - inv:set_size("hand", 0) - - local items = give_initial_stuff.get_stuff() - - for _, item in pairs(items) do - inv:add_item("main", item) - end - end -}) - -function give_initial_stuff.get_stuff() - return ctf_map.map and ctf_map.map.initial_stuff or { - "default:pick_stone", - "default:sword_stone", - "default:torch 3", - } -end - -minetest.register_on_joinplayer(function(player) - player:set_hp(20) - give_initial_stuff(player) -end) -minetest.register_on_respawnplayer(give_initial_stuff) diff --git a/mods/ctf/ctf_map/ctf_map_core/init.lua b/mods/ctf/ctf_map/ctf_map_core/init.lua index ccb3734baf..ca88a73fb5 100644 --- a/mods/ctf/ctf_map/ctf_map_core/init.lua +++ b/mods/ctf/ctf_map/ctf_map_core/init.lua @@ -34,10 +34,17 @@ dofile(modpath .. "/barrier.lua") if minetest.get_modpath("ctf") then dofile(modpath .. "/base.lua") dofile(modpath .. "/chest.lua") - dofile(modpath .. "/give_initial_stuff.lua") dofile(modpath .. "/meta_helpers.lua") dofile(modpath .. "/schem_map.lua") dofile(modpath .. "/maps_catalog.lua") ctf_match.register_on_build_time_end(ctf_map.remove_middle_barrier) + + give_initial_stuff.register_stuff_provider(function(player) + return ctf_map.map and ctf_map.map.initial_stuff or { + "default:pick_stone", + "default:sword_stone", + "default:torch 3", + } + end) end diff --git a/mods/ctf/ctf_map/ctf_map_core/meta_helpers.lua b/mods/ctf/ctf_map/ctf_map_core/meta_helpers.lua index 186609a651..cbd5106b05 100644 --- a/mods/ctf/ctf_map/ctf_map_core/meta_helpers.lua +++ b/mods/ctf/ctf_map/ctf_map_core/meta_helpers.lua @@ -98,7 +98,7 @@ function ctf_map.register_treasures(map) end else -- If treasure is a part of map's initial stuff, don't register it - local blacklist = ctf_map.map.initial_stuff or give_initial_stuff.get_stuff() + local blacklist = ctf_map.map.initial_stuff or {} for _, def in pairs(ctf_treasure.get_default_treasures()) do local is_valid = true for _, b_item in pairs(blacklist) do diff --git a/mods/ctf/ctf_map/ctf_map_core/mod.conf b/mods/ctf/ctf_map/ctf_map_core/mod.conf index 3f6139ba00..f6f0c72e62 100644 --- a/mods/ctf/ctf_map/ctf_map_core/mod.conf +++ b/mods/ctf/ctf_map/ctf_map_core/mod.conf @@ -1,3 +1,3 @@ name = ctf_map_core depends = default -optional_depends = ctf, ctf_match, ctf_stats, ctf_treasure, stairs, wool, irc, physics +optional_depends = ctf, ctf_match, ctf_stats, ctf_treasure, stairs, wool, irc, physics, give_initial_stuff diff --git a/mods/ctf/ctf_marker/init.lua b/mods/ctf/ctf_marker/init.lua index d020602e58..58b5053955 100644 --- a/mods/ctf/ctf_marker/init.lua +++ b/mods/ctf/ctf_marker/init.lua @@ -37,6 +37,7 @@ local function add_marker(name, tname, pos, str) players = {}, time = 0 } + for pname, _ in pairs(team.players) do local tplayer = minetest.get_player_by_name(pname) if tplayer then diff --git a/mods/ctf/ctf_stats/chat.lua b/mods/ctf/ctf_stats/chat.lua index 9e02d5b066..a327c5ff2e 100644 --- a/mods/ctf/ctf_stats/chat.lua +++ b/mods/ctf/ctf_stats/chat.lua @@ -194,3 +194,22 @@ minetest.register_chatcommand("transfer_rankings", { return true, "Stats of '" .. src .. "' have been transferred to '" .. dest .. "'." end }) + + +minetest.register_chatcommand("makepro", { + description = "Make self a pro", + privs = {ctf_admin = true}, + func = function(name, param) + local stats, _ = ctf_stats.player(name) + + if stats.kills < 1.5 * (stats.deaths + 1) then + stats.kills = 1.51 * (stats.deaths + 1) + end + + if stats.score < 10000 then + stats.score = 10000 + end + + return true, "Done" + end +}) diff --git a/mods/ctf/ctf_treasure/init.lua b/mods/ctf/ctf_treasure/init.lua index dbbe0ade72..0a4542b423 100644 --- a/mods/ctf/ctf_treasure/init.lua +++ b/mods/ctf/ctf_treasure/init.lua @@ -10,7 +10,6 @@ function ctf_treasure.get_default_treasures() { "ctf_traps:damage_cobble", 0.3, 4, { 10, 20 } }, { "default:pick_steel", 0.5, 5, { 1, 10 } }, - { "default:sword_steel", 0.4, 5, { 1, 4 } }, { "default:shovel_stone", 0.6, 5, { 1, 10 } }, { "default:shovel_steel", 0.3, 5, { 1, 10 } }, { "default:axe_steel", 0.4, 5, { 1, 10 } }, @@ -21,11 +20,10 @@ function ctf_treasure.get_default_treasures() { "shooter:machine_gun", 0.02, 2, 1 }, { "shooter:crossbow", 0.5, 2, { 1, 5 } }, { "shooter:pistol", 0.4, 2, { 1, 5 } }, - { "shooter:rifle", 0.1, 2, { 1, 2 } }, + { "shooter:ammo", 0.3, 2, { 1, 10 } }, { "shooter:arrow_white", 0.5, 2, { 2, 18 } }, { "medkits:medkit", 0.8, 5, 2 }, - { "ctf_bandages:bandage", 0.8, 2, { 2, 4 } } } end diff --git a/mods/other/crafting b/mods/other/crafting index 89f41763da..c6cd6ad62d 160000 --- a/mods/other/crafting +++ b/mods/other/crafting @@ -1 +1 @@ -Subproject commit 89f41763da5a6aa3048d90694c39bdd2d5ba1ba7 +Subproject commit c6cd6ad62d9f4076a22d985defc8a966a17f569d diff --git a/mods/other/give_initial_stuff/init.lua b/mods/other/give_initial_stuff/init.lua new file mode 100644 index 0000000000..bd1936c2a3 --- /dev/null +++ b/mods/other/give_initial_stuff/init.lua @@ -0,0 +1,53 @@ +give_initial_stuff = {} + +setmetatable(give_initial_stuff, { + __call = function(self, player) + minetest.log("action", "Giving initial stuff to player " + .. player:get_player_name()) + local inv = player:get_inventory() + inv:set_list("main", {}) + inv:set_list("craft", {}) + + inv:set_size("craft", 1) + inv:set_size("craftresult", 0) + inv:set_size("hand", 0) + + local items = give_initial_stuff.get_stuff(player) + + for _, item in pairs(items) do + inv:add_item("main", item) + end + end +}) + +local registered_stuff_providers = {} +function give_initial_stuff.register_stuff_provider(func, priority) + table.insert(registered_stuff_providers, + priority or (#registered_stuff_providers + 1), + func) +end + +function give_initial_stuff.get_stuff(player) + local seen_stuff = {} + + local stuff = {} + for i=1, #registered_stuff_providers do + local new_stuff = registered_stuff_providers[i](player) + assert(new_stuff) + + for j=1, #new_stuff do + local name = ItemStack(new_stuff[j]):get_name() + if not seen_stuff[name] then + seen_stuff[name] = true + stuff[#stuff + 1] = new_stuff[j] + end + end + end + return stuff +end + +minetest.register_on_joinplayer(function(player) + player:set_hp(player:get_properties().hp_max) + give_initial_stuff(player) +end) +minetest.register_on_respawnplayer(give_initial_stuff) diff --git a/mods/other/give_initial_stuff/mod.conf b/mods/other/give_initial_stuff/mod.conf new file mode 100644 index 0000000000..3fae27e782 --- /dev/null +++ b/mods/other/give_initial_stuff/mod.conf @@ -0,0 +1,2 @@ +name = give_initial_stuff +description = API to give give_initial_stuff diff --git a/mods/other/random_messages/init.lua b/mods/other/random_messages/init.lua index ac4a5c4582..6d0f049577 100644 --- a/mods/other/random_messages/init.lua +++ b/mods/other/random_messages/init.lua @@ -73,7 +73,9 @@ function random_messages.read_messages() "Use bandages on team-mates to heal them by 3-4 HP if their health is below 15 HP.", "Use /m to add a team marker at pointed location, that's visible only to team-mates.", "Use /summary to check scores of the current match and the previous match.", - "Use /maps to view the maps catalog. It also contains license info and attribution details." + "Use /maps to view the maps catalog. It also contains license info and attribution details.", + "Change your class in your base by right clicking the home flag or typing /class.", + "Medics cause troops within 10 metres to regenerate health faster.", } end diff --git a/mods/pvp/dropondie/init.lua b/mods/pvp/dropondie/init.lua index 202121067b..11dc85143d 100644 --- a/mods/pvp/dropondie/init.lua +++ b/mods/pvp/dropondie/init.lua @@ -1,13 +1,26 @@ +dropondie = {} + +local registered_drop_filters = {} + +-- return true to drop, false to destroy +function dropondie.register_drop_filter(func, priority) + table.insert(registered_drop_filters, + priority or (#registered_drop_filters + 1), + func) +end + local blacklist_drop = {} +dropondie.register_drop_filter(function(player, itemname) + return table.indexof(blacklist_drop, itemname) == -1 +end) -local function drop(pos, itemstack) +local function drop(player, pos, itemstack) local it = itemstack:take_item(itemstack:get_count()) local sname = it:get_name() - for _, item in pairs(blacklist_drop) do - if sname == item then - minetest.log("info", "[dropondie] Not dropping " .. sname) - return + for i=1, #registered_drop_filters do + if not registered_drop_filters[i](player, sname) then + return itemstack end end @@ -24,9 +37,9 @@ local function drop(pos, itemstack) return itemstack end -local function drop_list(pos, inv, list) +local function drop_list(player, pos, inv, list) for i = 1, inv:get_size(list) do - drop(pos, inv:get_stack(list, i)) + drop(player, pos, inv:get_stack(list, i)) inv:set_stack(list, i, nil) end end @@ -36,11 +49,11 @@ local function drop_all(player) pos.y = math.floor(pos.y + 0.5) local inv = player:get_inventory() - for _, item in pairs(give_initial_stuff.get_stuff()) do + for _, item in pairs(give_initial_stuff.get_stuff(player)) do inv:remove_item("main", ItemStack(item)) end - drop_list(pos, inv, "main") - drop_list(pos, inv, "craft") + drop_list(player, pos, inv, "main") + drop_list(player, pos, inv, "craft") end minetest.register_on_dieplayer(drop_all) diff --git a/mods/pvp/dropondie/mod.conf b/mods/pvp/dropondie/mod.conf index 09918c0081..4c1f8b533f 100644 --- a/mods/pvp/dropondie/mod.conf +++ b/mods/pvp/dropondie/mod.conf @@ -1,3 +1,3 @@ name = dropondie -depends = ctf_map_core +depends = give_initial_stuff description = With this mod, players will drop all their items in their inventory on the ground when they die. diff --git a/mods/pvp/gauges/init.lua b/mods/pvp/gauges/init.lua index 3a03494c8e..d6ea7d93ec 100644 --- a/mods/pvp/gauges/init.lua +++ b/mods/pvp/gauges/init.lua @@ -33,8 +33,8 @@ function hp_bar:on_step(dtime) return end - local hp = wielder:get_hp() - local breath = wielder:get_breath() + local hp = math.floor(20 * wielder:get_hp() / wielder:get_properties().hp_max) + local breath = math.floor(11 * wielder:get_breath() / wielder:get_properties().breath_max) self.object:set_properties({ textures = { "health_" .. tostring(hp) .. ".png^breath_" .. tostring(breath) .. ".png", diff --git a/mods/pvp/hpregen/init.lua b/mods/pvp/hpregen/init.lua index 57bffa07f9..3b83e7e24d 100644 --- a/mods/pvp/hpregen/init.lua +++ b/mods/pvp/hpregen/init.lua @@ -1,23 +1,37 @@ -local regen_interval = tonumber(minetest.settings:get("regen_interval")) -if regen_interval <= 0 then - regen_interval = 6 +hpregen = {} + +hpregen.interval = tonumber(minetest.settings:get("hpregen.interval")) +if hpregen.interval <= 0 then + hpregen.interval = 6 end -local regen_amount = tonumber(minetest.settings:get("regen_amount")) -if regen_amount <= 0 then - regen_amount = 1 +hpregen.amount = tonumber(minetest.settings:get("hpregen.amount")) +if hpregen.amount <= 0 then + hpregen.amount = 1 end local function regen_all() for _, player in pairs(minetest.get_connected_players()) do local oldhp = player:get_hp() if oldhp > 0 then - local newhp = oldhp + regen_amount - if newhp > 20 then - newhp = 20 + local newhp = oldhp + hpregen.amount + if newhp > player:get_properties().hp_max then + newhp = player:get_properties().hp_max + end + if oldhp ~= newhp then + player:set_hp(newhp) end - player:set_hp(newhp) end end - minetest.after(regen_interval, regen_all) end -minetest.after(regen_interval, regen_all) + + +local update = 0 +minetest.register_globalstep(function(delta) + update = update + delta + if update < hpregen.interval then + return + end + update = update - hpregen.interval + + regen_all() +end) diff --git a/mods/pvp/medkits/init.lua b/mods/pvp/medkits/init.lua index 9450b29e97..791ae3359e 100644 --- a/mods/pvp/medkits/init.lua +++ b/mods/pvp/medkits/init.lua @@ -8,7 +8,7 @@ local players = {} local regen_max = 20 -- Max HP provided by one medkit local regen_interval = 0.5 -- Time in seconds between each iteration -local regen_timer = 0 -- Timer to keep track of regen_interval +local regen_timer = 0 -- Timer to keep track of hpregen.interval local regen_step = 1 -- Number of HP added every iteration -- Boolean function for use by other mods to check if a player is healing @@ -54,7 +54,7 @@ local function stop_healing(player, interrupted) players[name] = nil if interrupted then minetest.chat_send_player(name, minetest.colorize("#FF4444", - "Your healing was interrupted!")) + "Your healing was interrupted!")) player:set_hp(info.hp) player:get_inventory():add_item("main", ItemStack("medkits:medkit 1")) end diff --git a/mods/pvp/shooter/grapple.lua b/mods/pvp/shooter/grapple.lua index cca920666f..d0011ec198 100644 --- a/mods/pvp/shooter/grapple.lua +++ b/mods/pvp/shooter/grapple.lua @@ -74,6 +74,7 @@ minetest.register_tool("shooter:grapple_hook", { if pointed_thing.type ~= "nothing" then return itemstack end + itemstack:add_wear(65536 / 16) throw_hook(itemstack, user, 14) return "" end, @@ -83,13 +84,16 @@ minetest.register_tool("shooter:grapple_gun", { description = "Grappling Gun", inventory_image = "shooter_hook_gun.png", on_use = function(itemstack, user, pointed_thing) + local ent = pointed_thing.ref and pointed_thing.ref:get_luaentity() + if ent and ent.name == "__builtin:item" then + return ent:on_punch(user) + end + local inv = user:get_inventory() - if inv:contains_item("main", "shooter:grapple_hook") and - inv:contains_item("main", "tnt:gunpowder") then - inv:remove_item("main", "tnt:gunpowder") + if inv:contains_item("main", "shooter:grapple_hook") then minetest.sound_play("shooter_reload", {object=user}) local stack = inv:remove_item("main", "shooter:grapple_hook") - itemstack = "shooter:grapple_gun_loaded 1 "..stack:get_wear() + itemstack = ItemStack("shooter:grapple_gun_loaded 1 "..stack:get_wear()) else minetest.sound_play("shooter_click", {object=user}) end @@ -107,6 +111,7 @@ minetest.register_tool("shooter:grapple_gun_loaded", { end minetest.sound_play("shooter_pistol", {object=user}) itemstack = ItemStack("shooter:grapple_hook 1 "..itemstack:get_wear()) + itemstack:add_wear(65536 / 8) throw_hook(itemstack, user, 20) return "shooter:grapple_gun" end, diff --git a/mods/pvp/shooter/shooter.lua b/mods/pvp/shooter/shooter.lua index 27ae7d5cd9..55aa068b4d 100644 --- a/mods/pvp/shooter/shooter.lua +++ b/mods/pvp/shooter/shooter.lua @@ -229,18 +229,20 @@ function shooter:register_weapon(name, def) inventory_image = def.inventory_image, on_use = function(itemstack, user, pointed_thing) if itemstack:get_wear() < max_wear then - def.spec.name = user:get_player_name() - if shots > 1 then - local step = def.spec.tool_caps.full_punch_interval - for i = 0, step * shots, step do - minetest.after(i, function() - shooter:fire_weapon(user, pointed_thing, def.spec) - end) + local spec = shooter:get_weapon_spec(user, name) + if spec then + if shots > 1 then + local step = spec.tool_caps.full_punch_interval + for i = 0, step * shots, step do + minetest.after(i, function() + shooter:fire_weapon(user, pointed_thing, spec) + end) + end + else + shooter:fire_weapon(user, pointed_thing, spec) end - else - shooter:fire_weapon(user, pointed_thing, def.spec) + itemstack:add_wear(wear) end - itemstack:add_wear(wear) else local inv = user:get_inventory() if inv then @@ -259,6 +261,16 @@ function shooter:register_weapon(name, def) }) end +function shooter:get_weapon_spec(user, name) + local spec = shooter.registered_weapons[name] + if not spec then + return nil + end + spec = spec.spec + spec.name = user:get_player_name() + return spec +end + function shooter:fire_weapon(user, pointed_thing, def) if shooter.shots[def.name] then if shooter.time < shooter.shots[def.name] then @@ -466,9 +478,8 @@ if not singleplayer and SHOOTER_ADMIN_WEAPONS then if player:get_player_control().LMB then local name = player:get_player_name() if minetest.check_player_privs(name, {server=true}) then - local spec = shooter.registered_weapons[player:get_wielded_item():get_name()] + local spec = shooter:get_weapon_spec(player, player:get_wielded_item():get_name()) if spec then - spec = spec.spec shooter.shots[name] = false spec.name = name shooter:fire_weapon(player, {}, spec)