374 lines
11 KiB
Lua

ctf_gui.init()
local cooldowns = ctf_core.init_cooldowns()
local CLASS_SWITCH_COOLDOWN = 30
local readable_class_list = {"Knight", "Ranged", "Support"}
local class_list = {"knight", "ranged", "support"}
local classes = {
knight = {
name = "Knight",
description = "High HP class with a sword capable of strong damage bursts",
hp_max = 28,
visual_size = vector.new(1.1, 1.1, 1.1),
items = {
"ctf_mode_classes:knight_sword",
}
},
support = {
name = "Support",
description = "Normal HP class with healing bandages, an immunity ability, and building tools",
items = {
"ctf_mode_classes:support_bandage",
"ctf_mode_classes:support_paxel",
"default:cobble 99",
}
},
ranged = {
name = "Ranged",
description = "Low HP ranged class with a rifle/grenade launcher gun, and a scaling ladder for reaching high places",
hp_max = 10,
physics = {speed = 1.1},
visual_size = vector.new(0.95, 0.95, 0.95),
items = {
"ctf_mode_classes:ranged_rifle_loaded",
"ctf_mode_classes:scaling_ladder"
}
}
}
local function dist_from_flag(player)
local tname = ctf_teams.get(player)
if not tname then return 0 end
return vector.distance(ctf_map.current_map.teams[tname].flag_pos, player:get_pos())
end
--
--- Knight Sword
--
local KNIGHT_COOLDOWN_TIME = 42
local KNIGHT_USAGE_TIME = 12
ctf_melee.simple_register_sword("ctf_mode_classes:knight_sword", {
description = "Knight Sword\n" .. minetest.colorize("gold",
"Rightclick to use Rage ability (Lasts "..
KNIGHT_USAGE_TIME.."s, "..KNIGHT_COOLDOWN_TIME.."s cooldown)"),
inventory_image = "default_tool_bronzesword.png",
inventory_overlay = "ctf_modebase_special_item.png",
wield_image = "default_tool_bronzesword.png",
damage_groups = {fleshy = 7},
full_punch_interval = 0.7,
rightclick_func = function(itemstack, user, pointed)
local pname = user:get_player_name()
if itemstack:get_wear() == 0 then
local step = math.floor(65534 / KNIGHT_USAGE_TIME)
ctf_modebase.update_wear.start_update(pname, "ctf_melee:sword_diamond", step, false, function()
local player = minetest.get_player_by_name(pname)
if player then
local pinv = player:get_inventory()
local pos = ctf_modebase.update_wear.find_item(pinv, "ctf_melee:sword_diamond")
if pos then
local newstack = ItemStack("ctf_mode_classes:knight_sword")
newstack:set_wear(65534)
player:get_inventory():set_stack("main", pos, newstack)
local dstep = math.floor(65534 / KNIGHT_COOLDOWN_TIME)
ctf_modebase.update_wear.start_update(pname, "ctf_mode_classes:knight_sword", dstep, true)
end
end
end)
return "ctf_melee:sword_diamond"
end
end,
})
--
--- Ranged Gun
--
local RANGED_COOLDOWN_TIME = 36
ctf_ranged.simple_register_gun("ctf_mode_classes:ranged_rifle", {
type = "rifle",
description = "Rifle\n" .. minetest.colorize("gold",
"Rightclick to launch grenade ("..RANGED_COOLDOWN_TIME.."s cooldown)"),
texture = "ctf_mode_classes_ranged_rifle.png",
texture_overlay = "ctf_modebase_special_item.png^[transformFX",
wield_texture = "ctf_mode_classes_ranged_rifle.png",
fire_sound = "ctf_ranged_rifle",
rounds = 0,
range = 150,
damage = 5,
fire_interval = 0.8,
liquid_travel_dist = 4,
rightclick_func = function(itemstack, user, pointed)
if itemstack:get_wear() == 0 then
grenades.throw_grenade("grenades:frag", 24, user)
itemstack:set_wear(65534)
local step = math.floor(65534 / RANGED_COOLDOWN_TIME)
ctf_modebase.update_wear.start_update(user:get_player_name(), "ctf_mode_classes:ranged_rifle_loaded", step, true)
return itemstack
end
end
})
--
--- Scaling Ladder
--
local SCALING_TIMEOUT = 4
-- Code borrowed from minetest_game default/nodes.lua -> default:ladder_steel
local scaling_def = {
description = "Scaling Ladder\n"..
minetest.colorize("gold", "(Infinite usage, self-removes after "..SCALING_TIMEOUT.."s)"),
tiles = {"default_ladder_steel.png"},
drawtype = "signlike",
inventory_image = "default_ladder_steel.png",
inventory_overlay = "ctf_modebase_special_item.png",
wield_image = "default_ladder_steel.png",
paramtype = "light",
paramtype2 = "wallmounted",
sunlight_propagates = true,
walkable = false,
climbable = true,
is_ground_content = false,
groups = {},
selection_box = {
type = "wallmounted",
},
sounds = default.node_sound_metal_defaults(),
on_place = function(itemstack, placer, pointed_thing, ...)
if pointed_thing.type == "node" then
itemstack:set_count(2)
minetest.item_place(itemstack, placer, pointed_thing, ...)
end
end,
on_construct = function(pos)
minetest.get_node_timer(pos):start(SCALING_TIMEOUT)
end,
on_timer = function(pos)
minetest.remove_node(pos)
end,
}
minetest.register_node("ctf_mode_classes:scaling_ladder", scaling_def)
--
--- Medic Paxel
--
minetest.register_tool("ctf_mode_classes:support_paxel", {
description = "Paxel",
inventory_image = "default_tool_bronzepick.png^default_tool_bronzeshovel.png",
tool_capabilities = {
full_punch_interval = 1.0,
max_drop_level=1,
groupcaps={
cracky = {times={[1]=4.00, [2]=1.60, [3]=0.80}, uses=0, maxlevel=2},
crumbly = {times={[1]=1.50, [2]=0.90, [3]=0.40}, uses=0, maxlevel=2},
choppy={times={[1]=2.50, [2]=1.40, [3]=1.00}, uses=0, maxlevel=2},
},
damage_groups = {fleshy=4},
punch_attack_uses = 0,
},
groups = {pickaxe = 1, tier = 3},
sound = {breaks = "default_tool_breaks"},
})
--
--- Medic Bandage
--
local IMMUNITY_TIME = 6
local IMMUNITY_COOLDOWN = 46
local HEAL_PERCENT = 0.8
ctf_healing.register_bandage("ctf_mode_classes:support_bandage", {
description = string.format(
"Bandage\nHeals teammates for 4-5 HP until target's HP is equal to %d%% of their maximum HP\n" ..
minetest.colorize("gold", "Rightclick to become immune to damage for %ds (%ds cooldown)"),
HEAL_PERCENT * 100,
IMMUNITY_TIME, IMMUNITY_COOLDOWN
),
inventory_image = "ctf_healing_bandage.png",
inventory_overlay = "ctf_modebase_special_item.png",
wield_image = "ctf_healing_bandage.png",
heal_percent = HEAL_PERCENT,
heal_min = 4,
heal_max = 5,
rightclick_func = function(itemstack, user, pointed)
local pname = user:get_player_name()
if itemstack:get_wear() == 0 then
local old_textures = user:get_properties().textures
user:set_properties({pointable = false, textures = {old_textures[1].."^[brighten^[multiply:#7ba5ff"}})
itemstack:set_wear(1)
local step = math.floor(65534 / IMMUNITY_TIME)
ctf_modebase.update_wear.start_update(pname, "ctf_mode_classes:support_bandage", step, false,
function()
local player = minetest.get_player_by_name(pname)
if player then
player:set_properties({pointable = true, textures = old_textures})
local dstep = math.floor(65534 / IMMUNITY_COOLDOWN)
ctf_modebase.update_wear.start_update(pname, "ctf_mode_classes:support_bandage", dstep, true)
end
end,
function()
local player = minetest.get_player_by_name(pname)
if player then
player:set_properties({pointable = true, textures = old_textures})
end
end)
return itemstack
end
end
})
return {
finish = function()
for _, player in pairs(minetest.get_connected_players()) do
player:set_properties({hp_max = minetest.PLAYER_MAX_HP_DEFAULT, visual_size = vector.new(1, 1, 1)})
physics.remove(player:get_player_name(), "ctf_mode_classes:class_physics")
end
end,
set = function(player, classname)
local meta = player:get_meta()
local pteam = ctf_teams.get(player)
local oldclassname = meta:get_string("class")
if classname == oldclassname then
return
end
if not classname then
classname = oldclassname
end
if not classes[classname] then
classname = "knight"
end
meta:set_string("class", classname)
ctf_modebase.update_wear.cancel_player_updates(player)
local pinv = player:get_inventory()
for pos, stack in pairs(pinv:get_list("main")) do
if ctf_modebase.modes.classes.is_bound_item(player, stack) then
pinv:set_stack("main", pos, "")
end
end
player:set_properties({
textures = {ctf_cosmetics.get_colored_skin(player, pteam and ctf_teams.team[pteam].color or "white")},
hp_max = classes[classname].hp_max or minetest.PLAYER_MAX_HP_DEFAULT,
visual_size = classes[classname].visual_size or vector.new(1, 1, 1)
})
player:set_hp(classes[classname].hp_max or minetest.PLAYER_MAX_HP_DEFAULT)
if classes[classname].physics then
physics.set(player:get_player_name(), "ctf_mode_classes:class_physics", {
speed = classes[classname].physics.speed or 1,
jump = classes[classname].physics.jump or 1,
gravity = classes[classname].physics.gravity or 1,
})
else
physics.remove(player:get_player_name(), "ctf_mode_classes:class_physics")
end
give_initial_stuff(player, true)
end,
get = function(player)
local cname = player:get_meta():get_string("class")
return cname and (classes[cname] or {}) or false
end,
get_name = function(player)
return player:get_meta():get_string("class") or false
end,
select_class = function(self, player, classname)
player = PlayerObj(player)
if not player then return end
if dist_from_flag(player) <= 5 then
cooldowns:set(player, CLASS_SWITCH_COOLDOWN)
self.set(player, classname)
end
end,
show_class_formspec = function(self, player, selected)
player = PlayerObj(player)
if not player then return end
if not selected then
local name = self.get_name(player)
if name then
selected = table.indexof(class_list, name)
end
end
selected = selected or 1
if not cooldowns:get(player) then
if dist_from_flag(player) > 5 then
minetest.chat_send_player(player:get_player_name(), "You can only change class at your flag!")
return
end
local elements = {}
elements.class_select = {
type = "dropdown",
items = readable_class_list,
default_idx = selected,
pos = {x = 0, y = 0.5},
func = function(playername, fields, field_name)
local new_idx = table.indexof(readable_class_list, fields[field_name])
if new_idx ~= selected then
self:show_class_formspec(playername, new_idx)
end
end,
}
elements.select_class = {
type = "button",
exit = true,
label = "Choose Class",
pos = {x = ctf_gui.ELEM_SIZE.x + 0.5, y = 0.5},
func = function(playername, fields, field_name)
self:select_class(playername, class_list[selected])
end,
}
ctf_gui.show_formspec(player, "ctf_mode_classes:class_form", {
size = {x = (ctf_gui.ELEM_SIZE.x * 2) + 1, y = 3.5},
title = classes[class_list[selected]].name,
description = classes[class_list[selected]].description,
privs = {interact = true},
elements = elements,
})
else
minetest.chat_send_player(
player:get_player_name(),
"You can only change your class every "..CLASS_SWITCH_COOLDOWN.." seconds"
)
end
end,
}