Skip to content

Commit

Permalink
Add player contributed bounties to the game
Browse files Browse the repository at this point in the history
  • Loading branch information
farooqkz committed Dec 3, 2024
1 parent 826afe2 commit 27bfbb9
Show file tree
Hide file tree
Showing 4 changed files with 221 additions and 57 deletions.
188 changes: 173 additions & 15 deletions mods/ctf/ctf_modebase/bounties.lua
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,37 @@ local timer = nil
local bounties = {}

ctf_modebase.bounties = {}
-- ^ This is for game's own bounties
ctf_modebase.contributed_bounties = {
--[[
["player_name"] = {
total = score,
contributors = {["player1"] = amount, ["player2"] = amount, ...}
}, a total bounty of `total` score is on `player_name` player contributed
by those in the list(`player1`, `player2`, ...)
...
--]]
}
-- ^ This is for player contributed bounties

local function get_contributors(name)
local bounty = ctf_modebase.contributed_bounties[name]
if not bounty then
return ""
else
local list = ""
local first = true
for contributor, score in pairs(bounty.contributors) do
if first then
list = list .. contributor
first = false
else
list = "," .. list .. contributor
end
end
return list
end
end

local function get_reward_str(rewards)
local ret = ""
Expand All @@ -21,7 +52,7 @@ local function set(pname, pteam, rewards)
-- -- bounty_kills(int) which is usually 1
-- -- score(int) which is the amount of score given to the one
-- -- -- who claims the bounty
local bounty_message = minetest.colorize(CHAT_COLOR, string.format(
local bounty_message = core.colorize(CHAT_COLOR, string.format(
"[Bounty] %s. Rewards: %s",
pname, get_reward_str(rewards)
))
Expand All @@ -36,23 +67,52 @@ local function set(pname, pteam, rewards)
end

local function remove(pname, pteam)
minetest.chat_send_all(minetest.colorize(CHAT_COLOR, string.format("[Bounty] %s is no longer bountied", pname)))
core.chat_send_all(core.colorize(CHAT_COLOR, string.format("[Bounty] %s is no longer bountied", pname)))
bounties[pteam] = nil
end

function ctf_modebase.bounties.claim(player, killer)
local pteam = ctf_teams.get(player)

if not (pteam and bounties[pteam] and bounties[pteam].name == player) then
local is_bounty = not (pteam and bounties[pteam] and bounties[pteam].name == player)
if is_bounty and not ctf_modebase.contributed_bounties[player] then
-- checking if there is bounty on this player
return
end

local rewards = bounties[pteam].rewards
local bounty_kill_text = string.format("[Bounty] %s killed %s and got %s", killer, player, get_reward_str(rewards))
minetest.chat_send_all(minetest.colorize(CHAT_COLOR, bounty_kill_text))
core.chat_send_all(core.colorize(CHAT_COLOR, bounty_kill_text))
ctf_modebase.announce(bounty_kill_text)
local rewards = { bounty_kills = 0, score = 0 }
if bounties[pteam] and bounties[pteam].rewards then
rewards = bounties[pteam].rewards
local bounty_kill_text =
string.format(
"[Bounty] %s killed %s and got %s from the game!",
killer,
player,
get_reward_str(rewards)
)
core.chat_send_all(core.colorize(CHAT_COLOR, bounty_kill_text))
ctf_modebase.announce(bounty_kill_text)

bounties[pteam] = nil
bounties[pteam] = nil
end
if ctf_modebase.contributed_bounties[player] then
local score = ctf_modebase.contributed_bounties[player].total
rewards.score = rewards.score + score
local bounty_kill_text =
string.format(
"[Player bounty] %s killed %s and got %d from %s!",
killer,
player,
score,
get_contributors(player)
)
core.chat_send_all(core.colorize(CHAT_COLOR, bounty_kill_text))
ctf_modebase.announce(bounty_kill_text)
ctf_modebase.contributed_bounties[player] = nil
end
return rewards
end

Expand Down Expand Up @@ -94,7 +154,7 @@ function ctf_modebase.bounties.reassign()
end

function ctf_modebase.bounties.reassign_timer()
timer = minetest.after(math.random(180, 360), function()
timer = core.after(math.random(180, 360), function()
ctf_modebase.bounties.reassign()
ctf_modebase.bounties.reassign_timer()
end)
Expand Down Expand Up @@ -134,7 +194,7 @@ ctf_teams.register_on_allocplayer(function(player, new_team, old_team)
end

if #output > 0 then
minetest.chat_send_player(pname, table.concat(output, "\n"))
core.chat_send_player(pname, table.concat(output, "\n"))
end
end)

Expand All @@ -145,14 +205,14 @@ ctf_core.register_chatcommand_alias("list_bounties", "lb", {
local output = {}
local x = 0
for tname, bounty in pairs(bounties) do
local player = minetest.get_player_by_name(bounty.name)
local player = core.get_player_by_name(bounty.name)

if player and pteam ~= tname then
local label = string.format(
"label[%d,0.1;%s: %s score]",
x,
bounty.name,
minetest.colorize("cyan", bounty.rewards.score)
core.colorize("cyan", bounty.rewards.score)
)

table.insert(output, label)
Expand All @@ -166,19 +226,40 @@ ctf_core.register_chatcommand_alias("list_bounties", "lb", {
x = x + 4.5
end
end
for pname, bounty in pairs(ctf_modebase.contributed_bounties) do
local player = core.get_player_by_name(pname)
if player then
local label = string.format(
"label[%d,0.1;%s: %s score]",
x,
pname,
core.colorize("cyan", bounty.total)
)
table.insert(output, label)

local model = "model[%d,1;4,6;player;character.b3d;%s;{0,160};;;]"
model = string.format(
model,
x,
player:get_properties().textures[1]
)
table.insert(output, model)
x = x + 4.5
end
end

if #output <= 0 then
return false, "There are no bounties you can claim"
end
x = x - 1.5
local formspec = "size[" .. x .. ",6]\n" .. table.concat(output, "\n")
minetest.show_formspec(name, "ctf_modebase:lb", formspec)
core.show_formspec(name, "ctf_modebase:lb", formspec)
return true, ""
end
end,
})

ctf_core.register_chatcommand_alias("put_bounty", "pb", {
description = "Put bounty on some player",
ctf_core.register_chatcommand_alias("place_bounty", "pb", {
description = "Place bounty on some player",
params = "<player> <amount>",
privs = { ctf_admin = true },
func = function(name, param)
Expand All @@ -202,9 +283,86 @@ ctf_core.register_chatcommand_alias("put_bounty", "pb", {
pteam,
{ bounty_kills=1, score=amount }
)
return true, "Successfully placed a bounty of " .. amount .. " on " .. minetest.colorize(team_colour, player) .. "!"
return true, "Successfully placed a bounty of " .. amount .. " on " .. core.colorize(team_colour, player) .. "!"
else
return false, "Invalid Amount"
end
end,
})



ctf_core.register_chatcommand_alias("bounty", "b", {
description = "Place a bounty on someone using your match score.\n" ..
"The score is returned to you if the match ends and nobody kills.\n" ..
"Use negative score to revoke a bounty",
params = "<player> <score>",
func = function(name, params)
local bname, amount = string.match(params, "([^%s]*) ([^%s]*)")
if not (amount and bname) then
return false, "Missing argument(s)"
end
amount = math.floor(amount)
local bteam = ctf_teams.get(bname)
if not bteam then
return false, "This player isn't online or isn't in a team"
end
if bteam == ctf_teams.get(name) then
return false, "You cannot place a bounty on your teammate!"
end
local current_mode = ctf_modebase:get_current_mode()
if amount <= 0 then
local contributors = ctf_modebase.contribued_bounties[bname]
local contributed_amount = contributors[bname] or 0
if math.abs(amount) > contributed_amount then
contributed_amount = math.abs(amount)
end
ctf_modebase.contributed_bounties[bname][name] = ctf_modebase.contributed_bounties[bname][name] - contributed_amount
current_mode.recent_rankings.add(name, { score = contributed_amount }, true)
return true, tostring(contributed_amount) .. " points returned to you."
end

if amount < 5 then
return false, "Your bounty needs to be of at least 5 points"
end
if amount > 100 then
return false, "Your bounty cannot be of more than 100 points"
end

if not current_mode or not ctf_modebase.match_started then
return false, "Match has not started yet."
end
local cur_score = current_mode.recent_rankings.get(name).score or 0
if amount > cur_score then
return false, "You haven't got enough points"
end
current_mode.recent_rankings.add(name, {score=-amount}, true)
if not ctf_modebase.contributed_bounties[bname] then
local contributors = {}
contributors[name] = amount
ctf_modebase.contributed_bounties[bname] = { total = amount, contributors = contributors }
else
if not ctf_modebase.contributed_bounties[bname].contributors[name] then
ctf_modebase.contributed_bounties[bname].contributors[name] = amount
else
ctf_modebase.contributed_bounties[bname].contributors[name] =
ctf_modebase.contributed_bounties[bname].contributors[name] + amount
end
ctf_modebase.contributed_bounties[bname].total = ctf_modebase.contributed_bounties[bname].total + amount
end
local total = ctf_modebase.contributed_bounties[bname].total
core.chat_send_all(
core.colorize(
CHAT_COLOR,
string.format("%s placed %d bounty on %s!", get_contributors(bname), total, bname)))
end,
})

ctf_api.register_on_match_end(function()
local current_mode = ctf_modebase:get_current_mode()
for pname, bounty in pairs(ctf_modebase.contributed_bounties) do
for contributor, amount in pairs(bounty.contributors) do
current_mode.recent_rankings.add(contributor, {score=amount}, true)
end
end
end)
6 changes: 6 additions & 0 deletions mods/ctf/ctf_modebase/recent_rankings.lua
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,12 @@ return {
on_match_end = function()
rankings_players = {}
rankings_teams = {}
local current_mode = ctf_modebase:get_current_mode()
for _, bounties in pairs(ctf_modebase.contributed_bounties) do
for bounty_donator, bounty_amount in pairs(bounties["contributors"]) do
current_mode.recent_rankings.add(bounty_donator, {score=bounty_amount}, true)
end
end
end,
players = function() return rankings_players end,
teams = function()
Expand Down
82 changes: 41 additions & 41 deletions mods/ctf/ctf_rankings/default.lua
Original file line number Diff line number Diff line change
@@ -1,57 +1,57 @@
return function(top)
local modstorage = assert(core.get_mod_storage(), "Can only init rankings at runtime!")
local modstorage = assert(core.get_mod_storage(), "Can only init rankings at runtime!")

for k, v in pairs(modstorage:to_table()["fields"]) do
local rank = core.parse_json(v)
if rank ~= nil and rank.score then
top:set(k, rank.score)
end
for k, v in pairs(modstorage:to_table()["fields"]) do
local rank = core.parse_json(v)
if rank ~= nil and rank.score then
top:set(k, rank.score)
end
end

return {
backend = "default",
top = top,
modstorage = modstorage,

get = function(self, pname)
pname = PlayerName(pname)
return {
backend = "default",
top = top,
modstorage = modstorage,

local rank_str = self.modstorage:get_string(pname)
get = function(self, pname)
pname = PlayerName(pname)

if not rank_str or rank_str == "" then
return false
end
local rank_str = self.modstorage:get_string(pname)

return core.parse_json(rank_str)
end,
set = function(self, pname, newrankings, erase_unset)
pname = PlayerName(pname)
if not rank_str or rank_str == "" then
return false
end

if not erase_unset then
local rank = self:get(pname)
if rank then
for k, v in pairs(newrankings) do
rank[k] = v
end
return core.parse_json(rank_str)
end,
set = function(self, pname, newrankings, erase_unset)
pname = PlayerName(pname)

newrankings = rank
if not erase_unset then
local rank = self:get(pname)
if rank then
for k, v in pairs(newrankings) do
rank[k] = v
end
end

self.top:set(pname, newrankings.score or 0)
self.modstorage:set_string(pname, core.write_json(newrankings))
end,
add = function(self, pname, amounts)
pname = PlayerName(pname)
newrankings = rank
end
end

local newrankings = self:get(pname) or {}
self.top:set(pname, newrankings.score or 0)
self.modstorage:set_string(pname, core.write_json(newrankings))
end,
add = function(self, pname, amounts)
pname = PlayerName(pname)

for k, v in pairs(amounts) do
newrankings[k] = (newrankings[k] or 0) + v
end
local newrankings = self:get(pname) or {}

self.top:set(pname, newrankings.score or 0)
self.modstorage:set_string(pname, core.write_json(newrankings))
for k, v in pairs(amounts) do
newrankings[k] = (newrankings[k] or 0) + v
end
}

self.top:set(pname, newrankings.score or 0)
self.modstorage:set_string(pname, core.write_json(newrankings))
end
}
end

0 comments on commit 27bfbb9

Please sign in to comment.