Initial commit

This commit is contained in:
pavetr
2026-03-15 14:54:49 +03:00
commit 64f8029c06
4027 changed files with 254888 additions and 0 deletions

View File

@@ -0,0 +1,122 @@
local localplayer
local hudText
local textCol1, textCol2 = Color(0, 0, 0, 200), Color(128, 30, 30, 255)
local plyMeta = FindMetaTable("Player")
local activeHitmen = {}
local postPlayerDraw
local minHitDistanceSqr = GM.Config.minHitDistance * GM.Config.minHitDistance
--[[---------------------------------------------------------------------------
Interface functions
---------------------------------------------------------------------------]]
function plyMeta:drawHitInfo()
activeHitmen[self] = true
hook.Add("PostPlayerDraw", "drawHitInfo", postPlayerDraw)
end
function plyMeta:stopHitInfo()
activeHitmen[self] = nil
if table.IsEmpty(activeHitmen) then
hook.Remove("PostPlayerDraw", "drawHitInfo")
end
end
--[[---------------------------------------------------------------------------
Hooks
---------------------------------------------------------------------------]]
function DarkRP.hooks:onHitAccepted(hitman, target, customer)
if not IsValid(hitman) then return end
hitman:drawHitInfo()
end
function DarkRP.hooks:onHitCompleted(hitman, target, customer)
if not IsValid(hitman) then return end
hitman:stopHitInfo()
end
function DarkRP.hooks:onHitFailed(hitman, target, reason)
if not IsValid(hitman) then return end
hitman:stopHitInfo()
end
hook.Add("EntityRemoved", "hitmenu", function(ent)
activeHitmen[ent] = nil
end)
hook.Add("HUDPaint", "DrawHitOption", function()
localplayer = localplayer or LocalPlayer()
hudText = hudText or GAMEMODE.Config.hudText
local x, y
local ply = localplayer:GetEyeTrace().Entity
if IsValid(ply) and ply:IsPlayer() and ply:isHitman() and not ply:hasHit() and localplayer:GetPos():DistToSqr(ply:GetPos()) < minHitDistanceSqr then
x, y = ScrW() / 2, ScrH() / 2 + 30
draw.DrawNonParsedText(hudText, "Roboto20", x + 1, y + 1, textCol1, 1)
draw.DrawNonParsedText(hudText, "Roboto20", x, y, textCol2, 1)
end
if localplayer:isHitman() and localplayer:hasHit() and IsValid(localplayer:getHitTarget()) then
x, y = chat.GetChatBoxPos()
local text = DarkRP.getPhrase("current_hit", localplayer:getHitTarget():Nick())
draw.DrawNonParsedText(text, "HUDNumber5", x + 1, y + 1, textCol1, 0)
draw.DrawNonParsedText(text, "HUDNumber5", x, y, textCol2, 0)
end
end)
local lastKeyPress = 0
hook.Add("KeyPress", "openHitMenu", function(ply, key)
if key ~= IN_USE or lastKeyPress > CurTime() - 0.2 then return end
lastKeyPress = CurTime()
localplayer = localplayer or LocalPlayer()
local hitman = localplayer:GetEyeTrace().Entity
if not IsValid(hitman) or not hitman:IsPlayer() or not hitman:isHitman() or localplayer:GetPos():DistToSqr(hitman:GetPos()) > minHitDistanceSqr then return end
local canRequest, message = hook.Call("canRequestHit", DarkRP.hooks, hitman, ply, nil, hitman:getHitPrice())
if not canRequest then
GAMEMODE:AddNotify(DarkRP.getPhrase("cannot_request_hit", message or ""), 1, 4)
surface.PlaySound("buttons/lightswitch2.wav")
return
end
DarkRP.openHitMenu(hitman)
end)
hook.Add("InitPostEntity", "HitmanMenu", function()
for _, v in ipairs(player.GetAll()) do
if IsValid(v) and v:isHitman() and v:hasHit() then
v:drawHitInfo()
end
end
end)
function postPlayerDraw(ply)
if not activeHitmen[ply] then return end
local pos, ang = ply:GetShootPos(), ply:EyeAngles()
ang.p = 0
ang:RotateAroundAxis(ang:Up(), 90)
ang:RotateAroundAxis(ang:Forward(), 90)
cam.Start3D2D(pos, ang, 0.3)
draw.DrawNonParsedText(GAMEMODE.Config.hitmanText, "Roboto20", 1, -100, textCol1, 1)
draw.DrawNonParsedText(GAMEMODE.Config.hitmanText, "Roboto20", 0, -101, textCol2, 1)
cam.End3D2D()
end
--[[---------------------------------------------------------------------------
Networking
---------------------------------------------------------------------------]]
net.Receive("onHitAccepted", function(len)
hook.Call("onHitAccepted", DarkRP.hooks, net.ReadEntity(), net.ReadEntity(), net.ReadEntity())
end)
net.Receive("onHitCompleted", function(len)
hook.Call("onHitCompleted", DarkRP.hooks, net.ReadEntity(), net.ReadEntity(), net.ReadEntity())
end)
net.Receive("onHitFailed", function(len)
hook.Call("onHitFailed", DarkRP.hooks, net.ReadEntity(), net.ReadEntity(), net.ReadString())
end)

View File

@@ -0,0 +1,35 @@
DarkRP.openHitMenu = DarkRP.stub{
name = "openHitMenu",
description = "Open the menu that requests a hit.",
parameters = {
{
name = "hitman",
description = "The hitman to request the hit to.",
type = "Player",
optional = false
}
},
returns = {
},
metatable = DarkRP
}
DarkRP.PLAYER.drawHitInfo = DarkRP.stub{
name = "drawHitInfo",
description = "Start drawing the hit information above a hitman.",
parameters = {
},
returns = {
},
metatable = DarkRP.PLAYER
}
DarkRP.PLAYER.stopHitInfo = DarkRP.stub{
name = "stopHitInfo",
description = "Stop drawing the hit information above a hitman.",
parameters = {
},
returns = {
},
metatable = DarkRP.PLAYER
}

View File

@@ -0,0 +1,227 @@
local PANEL
local minHitDistanceSqr = GM.Config.minHitDistance * GM.Config.minHitDistance
--[[---------------------------------------------------------------------------
Hitman menu
---------------------------------------------------------------------------]]
PANEL = {}
AccessorFunc(PANEL, "hitman", "Hitman")
AccessorFunc(PANEL, "target", "Target")
AccessorFunc(PANEL, "selected", "Selected")
function PANEL:Init()
self.BaseClass.Init(self)
self.btnClose = vgui.Create("DButton", self)
self.btnClose:SetText("")
self.btnClose.DoClick = function() self:Remove() end
self.btnClose.Paint = function(panel, w, h) derma.SkinHook("Paint", "WindowCloseButton", panel, w, h) end
self.icon = vgui.Create("SpawnIcon", self)
self.icon:SetDisabled(true)
self.icon.PaintOver = function(icon) icon:SetTooltip() end
self.icon:SetTooltip()
self.title = vgui.Create("DLabel", self)
self.title:SetText(DarkRP.getPhrase("hitman"))
self.name = vgui.Create("DLabel", self)
self.price = vgui.Create("DLabel", self)
self.playerList = vgui.Create("DScrollPanel", self)
self.btnRequest = vgui.Create("HitmanMenuButton", self)
self.btnRequest:SetText(DarkRP.getPhrase("hitmenu_request"))
self.btnRequest.DoClick = function()
if IsValid(self:GetTarget()) then
RunConsoleCommand("darkrp", "requesthit", self:GetTarget():SteamID(), self:GetHitman():UserID())
self:Remove()
end
end
self.btnCancel = vgui.Create("HitmanMenuButton", self)
self.btnCancel:SetText(DarkRP.getPhrase("cancel"))
self.btnCancel.DoClick = function() self:Remove() end
self:SetSkin(GAMEMODE.Config.DarkRPSkin)
self:InvalidateLayout()
end
function PANEL:Think()
if not IsValid(self:GetHitman()) or self:GetHitman():GetPos():DistToSqr(LocalPlayer():GetPos()) > minHitDistanceSqr then
self:Remove()
return
end
-- update the price (so the hitman can't scam)
self.price:SetText(DarkRP.getPhrase("priceTag", DarkRP.formatMoney(self:GetHitman():getHitPrice()), ""))
self.price:SizeToContents()
end
function PANEL:PerformLayout()
local w, h = self:GetSize()
self:SetSize(500, 700)
self:Center()
self.btnClose:SetSize(24, 24)
self.btnClose:SetPos(w - 24 - 5, 5)
self.icon:SetSize(128, 128)
self.icon:SetModel(self:GetHitman():GetModel())
self.icon:SetPos(20, 20)
self.title:SetFont("ScoreboardHeader")
self.title:SetPos(20 + 128 + 20, 20)
self.title:SizeToContents(true)
self.name:SizeToContents(true)
self.name:SetText(DarkRP.getPhrase("name", self:GetHitman():Nick()))
self.name:SetPos(20 + 128 + 20, 20 + self.title:GetTall())
self.price:SetFont("HUDNumber5")
self.price:SetColor(Color(255, 0, 0, 255))
self.price:SetText(DarkRP.getPhrase("priceTag", DarkRP.formatMoney(self:GetHitman():getHitPrice()), ""))
self.price:SetPos(20 + 128 + 20, 20 + self.title:GetTall() + 20)
self.price:SizeToContents(true)
self.playerList:SetPos(20, 20 + self.icon:GetTall() + 20)
self.playerList:SetWide(self:GetWide() - 40)
self.btnRequest:SetPos(20, h - self.btnRequest:GetTall() - 20)
self.btnRequest:SetButtonColor(Color(0, 120, 30, 255))
self.btnCancel:SetPos(w - self.btnCancel:GetWide() - 20, h - self.btnCancel:GetTall() - 20)
self.btnCancel:SetButtonColor(Color(140, 0, 0, 255))
self.playerList:StretchBottomTo(self.btnRequest, 20)
self.BaseClass.PerformLayout(self)
end
function PANEL:Paint()
local w, h = self:GetSize()
surface.SetDrawColor(Color(0, 0, 0, 200))
surface.DrawRect(0, 0, w, h)
end
function PANEL:AddPlayerRows()
local players = table.Copy(player.GetAll())
table.sort(players, function(a, b)
local aTeam, bTeam, aNick, bNick = team.GetName(a:Team()), team.GetName(b:Team()), string.lower(a:Nick()), string.lower(b:Nick())
return aTeam == bTeam and aNick < bNick or aTeam < bTeam
end)
for _, v in ipairs(players) do
local canRequest = hook.Call("canRequestHit", DarkRP.hooks, self:GetHitman(), LocalPlayer(), v, self:GetHitman():getHitPrice())
if not canRequest then continue end
local line = vgui.Create("HitmanMenuPlayerRow")
line:SetPlayer(v)
self.playerList:AddItem(line)
line:SetWide(self.playerList:GetWide() - 100)
line:Dock(TOP)
line.DoClick = function()
self:SetTarget(line:GetPlayer())
if IsValid(self:GetSelected()) then
self:GetSelected():SetSelected(false)
end
line:SetSelected(true)
self:SetSelected(line)
end
end
end
vgui.Register("HitmanMenu", PANEL, "DPanel")
--[[---------------------------------------------------------------------------
Hitmenu button
---------------------------------------------------------------------------]]
PANEL = {}
AccessorFunc(PANEL, "btnColor", "ButtonColor")
function PANEL:PerformLayout()
self:SetSize(self:GetParent():GetWide() / 2 - 30, 100)
self:SetFont("HUDNumber5")
self:SetTextColor(color_white)
self.BaseClass.PerformLayout(self)
end
function PANEL:Paint()
local w, h = self:GetSize()
local col = self:GetButtonColor() or Color(0, 120, 30, 255)
surface.SetDrawColor(col.r, col.g, col.b, col.a)
surface.DrawRect(0, 0, w, h)
end
vgui.Register("HitmanMenuButton", PANEL, "DButton")
--[[---------------------------------------------------------------------------
Player row
---------------------------------------------------------------------------]]
PANEL = {}
AccessorFunc(PANEL, "player", "Player")
AccessorFunc(PANEL, "selected", "Selected", FORCE_BOOL)
function PANEL:Init()
self.lblName = vgui.Create("DLabel", self)
self.lblName:SetMouseInputEnabled(false)
self.lblName:SetColor(Color(255,255,255,200))
self.lblTeam = vgui.Create("DLabel", self)
self.lblTeam:SetMouseInputEnabled(false)
self.lblTeam:SetColor(Color(255,255,255,200))
self:SetText("")
self:SetCursor("hand")
end
function PANEL:PerformLayout()
local ply = self:GetPlayer()
if not IsValid(ply) then self:Remove() return end
self.lblName:SetFont("UiBold")
self.lblName:SetText(DarkRP.deLocalise(ply:Nick()))
self.lblName:SizeToContents()
self.lblName:SetPos(10, 1)
self.lblTeam:SetFont("UiBold")
self.lblTeam:SetText((ply.DarkRPVars and DarkRP.deLocalise(ply:getDarkRPVar("job") or "")) or team.GetName(ply:Team()))
self.lblTeam:SizeToContents()
self.lblTeam:SetPos(self:GetWide() / 2, 1)
end
function PANEL:Paint()
if not IsValid(self:GetPlayer()) then self:Remove() return end
local color = team.GetColor(self:GetPlayer():Team())
color.a = self:GetSelected() and 70 or 255
surface.SetDrawColor(color)
surface.DrawRect(0, 0, self:GetWide(), 20)
end
vgui.Register("HitmanMenuPlayerRow", PANEL, "Button")
--[[---------------------------------------------------------------------------
Open the hit menu
---------------------------------------------------------------------------]]
function DarkRP.openHitMenu(hitman)
local frame = vgui.Create("HitmanMenu")
frame:SetHitman(hitman)
frame:AddPlayerRows()
frame:SetVisible(true)
frame:MakePopup()
frame:ParentToHUD()
end

View File

@@ -0,0 +1,79 @@
local plyMeta = FindMetaTable("Player")
local hitmanTeams = {}
local minHitDistanceSqr = GM.Config.minHitDistance * GM.Config.minHitDistance
function plyMeta:isHitman()
return hitmanTeams[self:Team()]
end
function plyMeta:hasHit()
return self:getDarkRPVar("hasHit") or false
end
function plyMeta:getHitTarget()
return self:getDarkRPVar("hitTarget")
end
function plyMeta:getHitPrice()
return self:getDarkRPVar("hitPrice") or GAMEMODE.Config.minHitPrice
end
function DarkRP.addHitmanTeam(job)
if not job or not RPExtraTeams[job] then return end
if DarkRP.DARKRP_LOADING and DarkRP.disabledDefaults["hitmen"][RPExtraTeams[job].command] then return end
hitmanTeams[job] = true
end
DarkRP.getHitmanTeams = fp{fn.Id, hitmanTeams}
function DarkRP.hooks:canRequestHit(hitman, customer, target, price)
if not hitman:isHitman() then return false, DarkRP.getPhrase("player_not_hitman") end
if customer:GetPos():DistToSqr(hitman:GetPos()) > minHitDistanceSqr then return false, DarkRP.getPhrase("distance_too_big") end
if not customer:Alive() then return false, DarkRP.getPhrase("must_be_alive_to_do_x", DarkRP.getPhrase("place_a_hit")) end
if hitman == target then return false, DarkRP.getPhrase("hitman_no_suicide") end
if hitman == customer then return false, DarkRP.getPhrase("hitman_no_self_order") end
if not customer:canAfford(price) then return false, DarkRP.getPhrase("cant_afford", DarkRP.getPhrase("hit")) end
if price < GAMEMODE.Config.minHitPrice then return false, DarkRP.getPhrase("price_too_low") end
if hitman:hasHit() then return false, DarkRP.getPhrase("hitman_already_has_hit") end
if IsValid(target) and ((target:getDarkRPVar("lastHitTime") or -GAMEMODE.Config.hitTargetCooldown) > CurTime() - GAMEMODE.Config.hitTargetCooldown) then return false, DarkRP.getPhrase("hit_target_recently_killed_by_hit") end
if IsValid(customer) and ((customer.lastHitAccepted or -GAMEMODE.Config.hitCustomerCooldown) > CurTime() - GAMEMODE.Config.hitCustomerCooldown) then return false, DarkRP.getPhrase("customer_recently_bought_hit") end
return true
end
hook.Add("onJobRemoved", "hitmenuUpdate", function(i, job)
hitmanTeams[i] = nil
end)
--[[---------------------------------------------------------------------------
DarkRPVars
---------------------------------------------------------------------------]]
DarkRP.registerDarkRPVar("hasHit", net.WriteBit, fn.Compose{tobool, net.ReadBit})
DarkRP.registerDarkRPVar("hitTarget", net.WriteEntity, net.ReadEntity)
DarkRP.registerDarkRPVar("hitPrice", fn.Curry(fn.Flip(net.WriteInt), 2)(32), fn.Partial(net.ReadInt, 32))
DarkRP.registerDarkRPVar("lastHitTime", fn.Curry(fn.Flip(net.WriteInt), 2)(32), fn.Partial(net.ReadInt, 32))
--[[---------------------------------------------------------------------------
Chat commands
---------------------------------------------------------------------------]]
DarkRP.declareChatCommand{
command = "hitprice",
description = "Set the price of your hits",
condition = plyMeta.isHitman,
delay = 10
}
DarkRP.declareChatCommand{
command = "requesthit",
description = "Request a hit from the player you're looking at",
delay = 5,
condition = fn.Compose{fn.Not, fn.Null, fn.Curry(fn.Filter, 2)(plyMeta.isHitman), player.GetAll}
}
DarkRP.declareChatCommand{
command = "cancelhit",
description = "Cancel your on active hit",
delay = 5,
condition = plyMeta.hasHit
}

View File

@@ -0,0 +1,209 @@
DarkRP.PLAYER.isHitman = DarkRP.stub{
name = "isHitman",
description = "Whether this player is a hitman.",
parameters = {
},
returns = {
{
name = "answer",
description = "Whether this player is a hitman.",
type = "boolean"
}
},
metatable = DarkRP.PLAYER
}
DarkRP.PLAYER.hasHit = DarkRP.stub{
name = "hasHit",
description = "Whether this hitman has a hit.",
parameters = {
},
returns = {
{
name = "answer",
description = "Whether this player has a hit.",
type = "boolean"
}
},
metatable = DarkRP.PLAYER
}
DarkRP.PLAYER.getHitTarget = DarkRP.stub{
name = "getHitTarget",
description = "Get the target of a hitman.",
parameters = {
},
returns = {
{
name = "target",
description = "The target of the hit.",
type = "Player"
}
},
metatable = DarkRP.PLAYER
}
DarkRP.PLAYER.getHitPrice = DarkRP.stub{
name = "getHitPrice",
description = "Get the price the hitman demands for his work.",
parameters = {
},
returns = {
{
name = "price",
description = "The price of the next hit.",
type = "number"
}
},
metatable = DarkRP.PLAYER
}
DarkRP.addHitmanTeam = DarkRP.stub{
name = "addHitmanTeam",
description = "Make this team a hitman.",
parameters = {
{
name = "team number",
description = "The number of the team (e.g. TEAM_MOB)",
type = "number",
optional = false
}
},
returns = {
},
metatable = DarkRP
}
DarkRP.getHitmanTeams = DarkRP.stub{
name = "getHitmanTeams",
description = "Get all the hitman teams.",
parameters = {
},
returns = {
{
name = "tbl",
description = "A table in which the keys are TEAM_ numbers and the values are just true.",
type = "table"
}
},
metatable = DarkRP
}
DarkRP.hookStub{
name = "canRequestHit",
description = "Whether someone can request a hit.",
parameters = {
{
name = "hitman",
description = "The hitman performing the hit",
type = "Player"
},
{
name = "customer",
description = "The customer for the current hit.",
type = "Player"
},
{
name = "target",
description = "The target of the current hit",
type = "Player"
},
{
name = "price",
description = "The agreed upon price.",
type = "number"
}
},
returns = {
{
name = "canRequest",
description = "A yes or no as to whether the hit can be requested.",
type = "boolean"
},
{
name = "message",
description = "The message that is shown when they can't request the hit.",
type = "string"
},
{
name = "price",
description = "An override for the price of the hit.",
type = "number"
}
}
}
DarkRP.hookStub{
name = "onHitAccepted",
description = "When a hitman accepts a hit.",
parameters = {
{
name = "hitman",
description = "The hitman performing the hit.",
type = "Player"
},
{
name = "target",
description = "The target of the current hit.",
type = "Player"
},
{
name = "customer",
description = "The customer of the current hit.",
type = "Player"
}
},
returns = {
}
}
DarkRP.hookStub{
name = "onHitCompleted",
description = "When a hitman finishes a hit.",
parameters = {
{
name = "hitman",
description = "The hitman performing the hit.",
type = "Player"
},
{
name = "target",
description = "The target of the current hit.",
type = "Player"
},
{
name = "customer",
description = "The customer of the current hit.",
type = "Player"
}
},
returns = {
}
}
DarkRP.hookStub{
name = "onHitFailed",
description = "When a hit fails for some reason.",
parameters = {
{
name = "hitman",
description = "The hitman performing the hit.",
type = "Player"
},
{
name = "target",
description = "The target of the current hit.",
type = "Player"
},
{
name = "reason",
description = "why the hit failed.",
type = "string"
}
},
returns = {
}
}

View File

@@ -0,0 +1,271 @@
local plyMeta = FindMetaTable("Player")
local hits = {}
local questionCallback
--[[---------------------------------------------------------------------------
Net messages
---------------------------------------------------------------------------]]
util.AddNetworkString("onHitAccepted")
util.AddNetworkString("onHitCompleted")
util.AddNetworkString("onHitFailed")
--[[---------------------------------------------------------------------------
Interface functions
---------------------------------------------------------------------------]]
DarkRP.getHits = fp{fn.Id, hits}
function plyMeta:requestHit(customer, target, price)
local canRequest, msg, cost = hook.Call("canRequestHit", DarkRP.hooks, self, customer, target, price)
price = cost or price
if canRequest == false then
DarkRP.notify(customer, 1, 4, msg)
return false
end
DarkRP.createQuestion(DarkRP.getPhrase("accept_hit_request", customer:Nick(), target:Nick(), DarkRP.formatMoney(price)),
"hit" .. self:UserID() .. "|" .. customer:UserID() .. "|" .. target:UserID(),
self,
20,
questionCallback,
customer,
target,
price
)
DarkRP.notify(customer, 1, 4, DarkRP.getPhrase("hit_requested"))
return true
end
function plyMeta:placeHit(customer, target, price)
if hits[self] then DarkRP.error("This person has an active hit!", 2) end
if not customer:canAfford(price) then
DarkRP.notify(customer, 1, 4, DarkRP.getPhrase("cant_afford", DarkRP.getPhrase("hit")))
return
end
hits[self] = {}
hits[self].price = price -- the agreed upon price (as opposed to the price set by the hitman)
self:setHitCustomer(customer)
self:setHitTarget(target)
DarkRP.payPlayer(customer, self, price)
hook.Call("onHitAccepted", DarkRP.hooks, self, target, customer)
end
function plyMeta:setHitTarget(target)
if not hits[self] then DarkRP.error("This person has no active hit!", 2) end
self:setSelfDarkRPVar("hitTarget", target)
self:setDarkRPVar("hasHit", target and true or nil)
end
function plyMeta:setHitPrice(price)
self:setDarkRPVar("hitPrice", math.Min(GAMEMODE.Config.maxHitPrice or 50000, math.Max(GAMEMODE.Config.minHitPrice or 200, price)))
end
function plyMeta:setHitCustomer(customer)
if not hits[self] then DarkRP.error("This person has no active hit!", 2) end
hits[self].customer = customer
end
function plyMeta:getHitCustomer()
return hits[self] and hits[self].customer or nil
end
function plyMeta:abortHit(message)
if not hits[self] then DarkRP.error("This person has no active hit!", 2) end
message = message or ""
hook.Call("onHitFailed", DarkRP.hooks, self, self:getHitTarget(), message)
DarkRP.notifyAll(0, 4, DarkRP.getPhrase("hit_aborted", message))
self:finishHit()
end
function plyMeta:cancelHit()
if not hits[self] then DarkRP.error("This person has no active hit!", 2) end
if not self:canAfford(hits[self].price) then
DarkRP.notify(self, 1, 4, DarkRP.getPhrase("cant_afford", DarkRP.getPhrase("hit_cancel")))
return
end
DarkRP.payPlayer(self, hits[self].customer, hits[self].price)
self:abortHit(DarkRP.getPhrase("hit_cancelled"))
end
function plyMeta:finishHit()
self:setHitCustomer(nil)
self:setHitTarget(nil)
hits[self] = nil
end
function questionCallback(answer, hitman, customer, target, price)
if not IsValid(customer) then return end
if not IsValid(hitman) or not hitman:isHitman() then return end
if not IsValid(customer) then
DarkRP.notify(hitman, 1, 4, DarkRP.getPhrase("customer_left_server"))
return
end
if not IsValid(target) then
DarkRP.notify(hitman, 1, 4, DarkRP.getPhrase("target_left_server"))
return
end
if not tobool(answer) then
DarkRP.notify(customer, 1, 4, DarkRP.getPhrase("hit_declined"))
return
end
if hits[hitman] then return end
DarkRP.notify(hitman, 1, 4, DarkRP.getPhrase("hit_accepted"))
hitman:placeHit(customer, target, price)
end
--[[---------------------------------------------------------------------------
Chat commands
---------------------------------------------------------------------------]]
DarkRP.defineChatCommand("hitprice", function(ply, args)
if not ply:isHitman() then return "" end
local price = DarkRP.toInt(args) or 0
ply:setHitPrice(price)
price = ply:getHitPrice()
DarkRP.notify(ply, 2, 4, DarkRP.getPhrase("hit_price_set", DarkRP.formatMoney(price)))
return ""
end)
DarkRP.defineChatCommand("requesthit", function(ply, args)
args = string.Explode(' ', args)
local target = DarkRP.findPlayer(args[1])
local traceEnt = ply:GetEyeTrace().Entity
local hitman = IsValid(traceEnt) and traceEnt:IsPlayer() and traceEnt or Player(tonumber(args[2] or -1) or -1)
if not IsValid(hitman) or not IsValid(target) or not hitman:IsPlayer() then
DarkRP.notify(ply, 1, 4, DarkRP.getPhrase("invalid_x", DarkRP.getPhrase("arguments"), ""))
return ""
end
hitman:requestHit(ply, target, hitman:getHitPrice())
return ""
end)
DarkRP.defineChatCommand("cancelhit", function(ply, args)
if not hits[ply] then
DarkRP.notify(ply, 1, 4, DarkRP.getPhrase("no_active_hit"))
return ""
end
ply:cancelHit()
end)
--[[---------------------------------------------------------------------------
Hooks
---------------------------------------------------------------------------]]
function DarkRP.hooks:onHitAccepted(hitman, target, customer)
net.Start("onHitAccepted")
net.WriteEntity(hitman)
net.WriteEntity(target)
net.WriteEntity(customer)
net.Broadcast()
DarkRP.notify(customer, 0, 8, DarkRP.getPhrase("hit_accepted"))
customer.lastHitAccepted = CurTime()
DarkRP.log("Hitman " .. hitman:Nick() .. " accepted a hit on " .. target:Nick() .. ", ordered by " .. customer:Nick() .. " for " .. DarkRP.formatMoney(hits[hitman].price), Color(255, 0, 255))
end
function DarkRP.hooks:onHitCompleted(hitman, target, customer)
net.Start("onHitCompleted")
net.WriteEntity(hitman)
net.WriteEntity(target)
net.WriteEntity(customer)
net.Broadcast()
DarkRP.notifyAll(0, 6, DarkRP.getPhrase("hit_complete", hitman:Nick()))
local targetname = IsValid(target) and target:Nick() or "disconnected player"
local customername = IsValid(customer) and customer:Nick() or "disconnected player"
DarkRP.log("Hitman " .. hitman:Nick() .. " finished a hit on " .. targetname .. ", ordered by " .. customername .. " for " .. DarkRP.formatMoney(hits[hitman].price), Color(255, 0, 255))
target:setDarkRPVar("lastHitTime", CurTime())
hitman:finishHit()
end
function DarkRP.hooks:onHitFailed(hitman, target, reason)
net.Start("onHitFailed")
net.WriteEntity(hitman)
net.WriteEntity(target)
net.WriteString(reason)
net.Broadcast()
local targetname = IsValid(target) and target:Nick() or "disconnected player"
DarkRP.log("Hit on " .. targetname .. " failed. Reason: " .. reason, Color(255, 0, 255))
end
hook.Add("PlayerDeath", "DarkRP Hitman System", function(ply, inflictor, attacker)
if hits[ply] then -- player was hitman
ply:abortHit(DarkRP.getPhrase("hitman_died"))
end
if IsValid(attacker) and attacker:IsPlayer() and hits[attacker] and attacker:getHitTarget() == ply then
hook.Call("onHitCompleted", DarkRP.hooks, attacker, ply, hits[attacker].customer)
end
for hitman in pairs(hits) do
if not hitman or not IsValid(hitman) then hits[hitman] = nil continue end
if hitman:getHitTarget() == ply then
hitman:abortHit(DarkRP.getPhrase("target_died"))
end
end
end)
hook.Add("PlayerDisconnected", "Hitman system", function(ply)
if hits[ply] then
ply:abortHit(DarkRP.getPhrase("hitman_left_server"))
end
for hitman, hit in pairs(hits) do
if hitman:getHitTarget() == ply then
hitman:abortHit(DarkRP.getPhrase("target_left_server"))
end
if hit.customer == ply then
hitman:abortHit(DarkRP.getPhrase("customer_left_server"))
end
end
end)
hook.Add("playerArrested", "Hitman system", function(ply)
if not hits[ply] or not IsValid(hits[ply].customer) then return end
for _, v in ipairs(player.GetAll()) do
if not v:isCP() then continue end
DarkRP.notify(v, 0, 8, DarkRP.getPhrase("x_had_hit_ordered_by_y", ply:Nick(), hits[ply].customer:Nick()))
end
ply:abortHit(DarkRP.getPhrase("hitman_arrested"))
end)
hook.Add("OnPlayerChangedTeam", "Hitman system", function(ply, prev, new)
if hits[ply] then
ply:abortHit(DarkRP.getPhrase("hitman_changed_team"))
end
end)

View File

@@ -0,0 +1,164 @@
DarkRP.PLAYER.requestHit = DarkRP.stub{
name = "requestHit",
description = "Request a hit to a hitman.",
parameters = {
{
name = "customer",
description = "The customer who paid for the hit.",
type = "Player",
optional = false
},
{
name = "target",
description = "The target of the hit.",
type = "Player",
optional = false
},
{
name = "price",
description = "The price of the hit.",
type = "number",
optional = false
}
},
returns = {
{
name = "succeeded",
description = "Whether the hit request could be made.",
type = "boolean"
}
},
metatable = DarkRP.PLAYER
}
DarkRP.PLAYER.placeHit = DarkRP.stub{
name = "placeHit",
description = "Place an actual hit.",
parameters = {
{
name = "customer",
description = "The customer who paid for the hit.",
type = "Player",
optional = false
},
{
name = "target",
description = "The target of the hit.",
type = "Player",
optional = false
},
{
name = "price",
description = "The price of the hit.",
type = "number",
optional = false
}
},
returns = {
},
metatable = DarkRP.PLAYER
}
DarkRP.PLAYER.setHitTarget = DarkRP.stub{
name = "setHitTarget",
description = "Set the target of a hit",
parameters = {
{
name = "target",
description = "The target of the hit.",
type = "Player",
optional = false
}
},
returns = {
},
metatable = DarkRP.PLAYER
}
DarkRP.PLAYER.setHitPrice = DarkRP.stub{
name = "setHitPrice",
description = "Set the price of a hit",
parameters = {
{
name = "price",
description = "The price of the hit.",
type = "number",
optional = false
}
},
returns = {
},
metatable = DarkRP.PLAYER
}
DarkRP.PLAYER.setHitCustomer = DarkRP.stub{
name = "setHitCustomer",
description = "Set the customer who pays for the hit.",
parameters = {
{
name = "customer",
description = "The customer who paid for the hit.",
type = "Player",
optional = false
}
},
returns = {
},
metatable = DarkRP.PLAYER
}
DarkRP.PLAYER.getHitCustomer = DarkRP.stub{
name = "getHitCustomer",
description = "Get the customer for the current hit",
parameters = {
},
returns = {
{
name = "customer",
description = "The customer for the current hit",
type = "Player"
}
},
metatable = DarkRP.PLAYER
}
DarkRP.PLAYER.abortHit = DarkRP.stub{
name = "abortHit",
description = "Abort a hit",
parameters = {
{
name = "message",
description = "The reason why the hit was aborted",
type = "string",
optional = true
}
},
returns = {
},
metatable = DarkRP.PLAYER
}
DarkRP.PLAYER.finishHit = DarkRP.stub{
name = "finishHit",
description = "End a hit without a message",
parameters = {
},
returns = {
},
metatable = DarkRP.PLAYER
}
DarkRP.getHits = DarkRP.stub{
name = "getHits",
description = "Get all the active hits",
parameters = {
},
returns = {
{
name = "hits",
description = "A table in which the keys are hitmen and the values are hit information, like the customer.",
type = "table"
}
},
metatable = DarkRP
}