mirror of
https://github.com/a-bad-dev/simple-shooter-game.git
synced 2026-06-09 12:26:29 +00:00
309 lines
8.3 KiB
Lua
309 lines
8.3 KiB
Lua
match_start_job = nil
|
|
loading_tips = {
|
|
"Open the inventory to change class!",
|
|
"Short-range is good for small/dense maps!",
|
|
"Mid-range is good on maps with long tunnels or open areas!",
|
|
"Long-range is good for maps with really open and large areas!",
|
|
"Ambushing can be powerful assuming your not found!",
|
|
"Players may sneak up on you from behind!",
|
|
"You *can't* be shot under water!",
|
|
"The Short-range class can one-shot from 6 to 7 nodes away!",
|
|
"Using torches may allow enemies to sneak up on you in the dark!",
|
|
"Turns out if you get a sniper and zoom with it. you can zoom no matter what after that...", -- how
|
|
"e s p i o n a g e",
|
|
}
|
|
|
|
-- Functions for SSG
|
|
function make_player_invisible(player) -- Hide a player (pre-match and spectator)
|
|
save_player_data(player)
|
|
player:set_properties({
|
|
pointable = false,
|
|
visual = "mesh",
|
|
textures = {"blank.png"},
|
|
})
|
|
|
|
playertag.set(player, playertag.TYPE_BUILTIN, {a = 0})
|
|
end
|
|
|
|
function give_player_items(player) -- Give the player their initial stuff
|
|
local class = player:get_meta():get_string("class")
|
|
local inv = player:get_inventory()
|
|
|
|
inv:set_list("main", {})
|
|
|
|
if class == "1" then
|
|
for i = 1, #map_data.classes.class_1.initial_items do
|
|
inv:add_item("main", map_data.classes.class_1.initial_items[i])
|
|
end
|
|
|
|
elseif class == "2" then
|
|
for i = 1, #map_data.classes.class_2.initial_items do
|
|
inv:add_item("main", map_data.classes.class_2.initial_items[i])
|
|
end
|
|
|
|
elseif class == "3" then
|
|
for i = 1, #map_data.classes.class_3.initial_items do
|
|
inv:add_item("main", map_data.classes.class_3.initial_items[i])
|
|
end
|
|
end
|
|
end
|
|
|
|
function set_player_mode(player, mode) -- Set player mode (spectator, pre-match, normal, etc)
|
|
player:get_meta():set_string("mode", mode)
|
|
|
|
local player_name = player:get_player_name()
|
|
local privs = core.get_player_privs(player_name)
|
|
|
|
if mode == "normal" then
|
|
player:set_properties({
|
|
pointable = true, -- allow players to be killable after the match starts
|
|
})
|
|
|
|
load_player_data(player)
|
|
privs.noclip, privs.fast, privs.fly, privs.interact, privs.debug = false, false, false, true, false
|
|
|
|
playertag.set(player, playertag.TYPE_ENTITY, {a = 255, r = 255, g = 255, b = 255})
|
|
|
|
player:set_inventory_formspec([[
|
|
size[8,4]
|
|
list[current_player;main;0,0;8,1;]
|
|
list[current_player;main;0,1.25;8,3;8]
|
|
listring[current_player;main]
|
|
]])
|
|
|
|
player:hud_set_flags({
|
|
hotbar = true,
|
|
healthbar = true,
|
|
breathbar = true,
|
|
})
|
|
elseif mode == "spectator" then
|
|
privs.noclip, privs.fast, privs.fly, privs.interact, privs.debug = true, true, true, false, true
|
|
|
|
make_player_invisible(player)
|
|
|
|
core.chat_send_player(player_name, core.colorize("#0574fc", "You are now a spectator."))
|
|
|
|
player:set_inventory_formspec([[
|
|
size[8,4]
|
|
list[current_player;main;0,0;8,1;]
|
|
list[current_player;main;0,1.25;8,3;8]
|
|
listring[current_player;main]
|
|
]])
|
|
|
|
player:hud_set_flags({
|
|
hotbar = false,
|
|
healthbar = false,
|
|
breathbar = false,
|
|
})
|
|
|
|
elseif mode == "pre_match" then
|
|
privs.noclip, privs.fast, privs.fly, privs.interact = false, true, false, false -- allow fast movement to get to a specific point on the large map
|
|
|
|
make_player_invisible(player)
|
|
|
|
player:set_inventory_formspec([[
|
|
size[8,6]
|
|
|
|
label[3,0.1;Change class:]
|
|
|
|
button[0.3,1;2.5,1;class_sniper;]] .. map_data.classes.class_1.name .. [[]
|
|
button[2.8,1;2.5,1;class_assault;]] .. map_data.classes.class_2.name .. [[]
|
|
button[5.3,1;2.5,1;class_shotgun;]] .. map_data.classes.class_3.name .. [[]
|
|
|
|
list[current_player;main;0,2;8,1;]
|
|
list[current_player;main;0,3.25;8,3;8]
|
|
listring[current_player;main]
|
|
]])
|
|
|
|
player:hud_set_flags({
|
|
hotbar = true,
|
|
healthbar = false,
|
|
breathbar = false,
|
|
})
|
|
end
|
|
|
|
core.change_player_privs(player_name, privs)
|
|
end
|
|
|
|
function start_match(map) -- Start the match
|
|
if match_state ~= "not_started" then
|
|
return
|
|
end
|
|
|
|
place_map(map or "forest") -- default to forest if no map is specified
|
|
|
|
if map_data == nil then
|
|
return "nope :("
|
|
end
|
|
|
|
set_match_state("pre_match")
|
|
|
|
local map_loading_images = {}
|
|
for _, player in pairs(core.get_connected_players()) do
|
|
set_player_mode(player, "pre_match")
|
|
|
|
map_loading_images[player:get_player_name()] = {
|
|
loading = player:hud_add({
|
|
type = "image",
|
|
position = {x=0.5, y=0.5},
|
|
image_scale = 100,
|
|
text = "map_loading.png",
|
|
scale = {x=-100, y=-100},
|
|
z_index = 1000,
|
|
}),
|
|
|
|
info = player:hud_add({
|
|
type = "text",
|
|
position = {x=0.5, y=0.7},
|
|
text = loading_tips[math.random(1, #loading_tips)],
|
|
number = 0xFFFFFF,
|
|
z_index = 1000,
|
|
})
|
|
}
|
|
|
|
give_player_items(player)
|
|
|
|
player:set_pos(map_data.spawn)
|
|
|
|
player:set_hp(20)
|
|
end
|
|
|
|
core.after(3, function()
|
|
for _, player in pairs(core.get_connected_players()) do
|
|
player:set_pos(map_data.spawn)
|
|
|
|
for _, id in pairs(map_loading_images[player:get_player_name()]) do
|
|
player:hud_remove(id)
|
|
end
|
|
end
|
|
|
|
|
|
if map_data.on_start then
|
|
map_data.on_start()
|
|
end
|
|
|
|
core.chat_send_all(core.colorize("#b011f9", string.format("Match about to start in %d seconds!\nOpen inventory to change class!", map_data.start_time)))
|
|
|
|
for i = 10, 1, -1 do -- count down from 10 to 1 (yes you are free to set me on fire for this horrible solution)
|
|
core.after(map_data.start_time - 10 + i, function()
|
|
core.chat_send_all(core.colorize("green", string.format("Match starts in %d second%s.", 11 - i, 11 - i == 1 and "" or "s"))) -- <- RIP readability
|
|
end)
|
|
end
|
|
|
|
match_start_job = core.after(map_data.start_time, function()
|
|
match_start_job = nil
|
|
set_match_state("in_progress")
|
|
core.chat_send_all(core.colorize("green", "Match started!"))
|
|
|
|
remove_barrier()
|
|
|
|
alive_players = {}
|
|
|
|
for _, player in pairs(core.get_connected_players()) do
|
|
local player_name = player:get_player_name()
|
|
local inv = player:get_inventory()
|
|
|
|
inv:set_list("main", {})
|
|
|
|
give_player_items(player)
|
|
|
|
player:set_properties({
|
|
pointable = true, -- allow players to be killable after the match starts
|
|
})
|
|
alive_players[player_name] = "alive"
|
|
|
|
set_player_mode(player, "normal")
|
|
end
|
|
end)
|
|
end)
|
|
end
|
|
|
|
function end_match() -- End the match
|
|
set_match_state("not_started")
|
|
|
|
if match_start_job ~= nil then
|
|
match_start_job:cancel()
|
|
end
|
|
|
|
if map_data.on_end then
|
|
map_data.on_end()
|
|
end
|
|
|
|
for _, player in pairs(core.get_connected_players()) do
|
|
player:set_pos(spawn_pos)
|
|
player:get_inventory():set_list("main", {})
|
|
|
|
player:set_inventory_formspec([[
|
|
size[8,4]
|
|
list[current_player;main;0,0;8,1;]
|
|
list[current_player;main;0,1.25;8,3;8]
|
|
listring[current_player;main]
|
|
]])
|
|
|
|
|
|
player:set_properties({pointable = false})
|
|
|
|
set_player_mode(player, "normal")
|
|
end
|
|
|
|
return true
|
|
end
|
|
|
|
function set_match_state(state) -- why on earth does this function exist
|
|
match_state = state
|
|
end
|
|
|
|
function save_player_data(player) -- Save the player's skin storing it in their metadata
|
|
local skins = player:get_properties().textures
|
|
|
|
-- probably the invisible skin so dont save it
|
|
if skins[1] == "blank.png" then
|
|
return
|
|
end
|
|
|
|
player:get_meta():set_string("skin", core.serialize(skins))
|
|
end
|
|
|
|
function load_player_data(player) -- Load the player's skin stored in their metadata
|
|
local skins = core.deserialize(player:get_meta():get_string("skin"))
|
|
|
|
player:set_properties({
|
|
visual = "mesh",
|
|
textures = skins
|
|
})
|
|
end
|
|
|
|
function kill_player(player, reason) -- Handle killed/disconnected players properly
|
|
local player_name = player:get_player_name()
|
|
|
|
if alive_players[player_name] ~= "alive" or match_state ~= "in_progress" then
|
|
return
|
|
end
|
|
|
|
alive_players[player_name] = "dead"
|
|
|
|
local alive_player_names = get_alive_players()
|
|
|
|
local message = string.format("%s has been eliminated! (%s) %d player%s left!", player_name, reason, #alive_player_names, #alive_player_names == 1 and "" or "s")
|
|
core.chat_send_all(core.colorize("red", message))
|
|
if #alive_player_names == 1 then
|
|
local winner_name = alive_player_names[1]
|
|
core.chat_send_all(core.colorize("green", winner_name .. " is the winner!"))
|
|
|
|
set_match_state("post_match")
|
|
|
|
core.after(5, end_match)
|
|
end
|
|
end
|
|
|
|
function get_alive_players() -- Get the names of the alive players
|
|
local alive_players_names = {}
|
|
|
|
for player_name, _ in pairs(alive_players) do
|
|
if alive_players[player_name] == "alive" then
|
|
table.insert(alive_players_names, player_name)
|
|
end
|
|
end
|
|
|
|
return alive_players_names
|
|
end
|