Пасты (фрагменты кода)

Небольшие вырезки кода, который может быть применен для решения некоторых задач

Замена модельки подарка

Небольшой костыль, позволяющий изменить модельку дропнутого предмета. Скорее всего, это временное решение и в будущем возможность изменения модельки будет реализована в основном функционале

P.S. Возможен баг с прокручиванием новой модельки, словно она - шарик

hook.Add("OnEntityCreated", "IGS_ChangeGiftModel", function(ent)
	if IsValid(ent) and ent:GetClass() == "ent_igs" then
		timer.Simple(1, function()
			ent:SetModel("string modelName")
		end)
	end
end)

Команда покупки кастомного количества игровой валюты

Изначально была написана для темы Ползунок выбора суммы валюты для покупки. В идеале для нее нужен интерфейс, где игрок вводит сколько он хочет валюты.

concommand.Add("igsbuymoney", function(pl, _, args)
	local sum = tonumber(args[1])
	if not sum then return end

	local ttw = 30 - (os.time() - (pl.last_igsbuymoney or 0))
	if ttw > 0 then
		IGS.Notify("Повторите через " .. string.NiceTime(ttw))
		return
	end

	local price_rub = math.Round(sum / 1000, 2) -- 1000 игровой за 1 рубль
	if price_rub <= 10 then
		IGS.Notify(pl, "Минимальная сумма заказа не достигнута")
		return
	end

	pl.last_igsbuymoney = os.time()
	if IGS.CanAfford(pl, price_rub) then
		pl:AddIGSFunds(-price_rub, "Покупка " .. string.Comma(sum) .. " игровой валюты", function()
			if not IsValid(pl) then return end
			pl:addMoney(sum)
		end)
	else
		IGS.Notify(pl, "Недостаточно денег на донат счету. Введите /IGSDeposit для пополнения")
	end
end)

За публикацию подобных штуковин вы можете получить награду “Моддер” на форуме

1 лайк

Не связано с GMD, но может пригодиться:

Запрет использования указанных тулов на нужных энтити

local limited_tools = {
	["material"] = true,
	["color"] = true
}

local disabled_ents = {
	["derma_printer"] = true,
}

hook.Add("CanTool", "disable_for_ents", function(_, tr, tool)
	if limited_tools[tool]
	and IsValid( tr.Entity )
	and disabled_ents[tr.Entity:GetClass()] then
		return false
	end
end)

Запрет делать прозрачные с одной стороны пропы

local restricted_props = {
	["models/props_building_details/storefront_template001a_bars.mdl"] = true,
	["models/props_combine/combine_window001.mdl"] = true,
	["models/props_combine/combine_fence01a.mdl"] = true,
	["models/props_combine/combine_fence01b.mdl"] = true
}

local material_tools = {
	["material"]    = true,
	["submaterial"] = true
}


local GetWeapon = PLAYER.GetActiveWeapon
local GetModel  = ENTITY.GetModel

hook.Add("CanTool","FuckCheatWalls",function(pl,tr,tool)
	-- Прозрачные с одной стороны пропы
	if (material_tools[tool] and restricted_props[GetModel(tr.Entity)])

	-- Режим "свечение мира". trigon.im/index.php?posts/36895/
	or (tool == "colour" and GetWeapon(pl)["Tool"] and GetWeapon(pl)["Tool"]["colour"]:GetClientNumber("mode",0) == 9)

	-- Админам + разрешаем
	and !pl:IsAdmin() then
		pl:ChatPrint("Извините, но на нашем сервере нельзя делать читерные укрытия")
		return false
	end
end)
1 лайк

Кешбек 20% с каждой покупки (не тестировался)

hook.Add("IGS.PlayerPurchasedItem", "cashback", function(pl, ITEM)
	pl:AddIGSFunds(ITEM.price * .2, "Кешбек за покупку " .. ITEM:Name())
end)

Разрешение активации только одного итема из категории

local function canActivate(pl, categ)
	for uid in pairs(IGS.PlayerPurchases(pl) or {}) do
		local ITEM = IGS.GetItemByUID(uid)
		if ITEM:Category() == categ then
			return "У вас уже есть покупка в этой категории"
		end
	end
end

IGS("Нож 1", "knife_1", 123)
	:SetDescription("Вы сможете активировать только 1 нож. Выбирайте с умом")
	:SetWeapon("class_knife_1")
	:SetCategory("Ножи")
	:SetCanActivate(function(pl)
		return canActivate(pl, "Ножи")
	end)

IGS("Нож 2", "knife_2", 123)
	:SetDescription("Вы сможете активировать только 1 нож. Выбирайте с умом")
	:SetWeapon("class_knife_2")
	:SetCategory("Ножи")
	:SetCanActivate(function(pl)
		return canActivate(pl, "Ножи")
	end)

А, ну раз такое дело то у меня тут репо полное сниппетов, примеров и мелких библиотек

1 лайк

Обновлено. Если используете – обязательно обновитесь

Выдача оружия при спавне всем, кто купил его, даже если игрок снимал галочку

-- Установить по пути:
-- addons/igs-modification/lua/autorun/server/force_weps_on_spawn.lua

local function bibuid(pl, ITEM)
	return "igs:gos:" .. pl:UniqueID() .. ":" .. ITEM:UID()
end

local function SetShouldPlayerReceiveWep(pl, ITEM, bGive)
	pl:SetNWBool("igs.gos." .. ITEM:ID(), bGive)
	bib.setBool(bibuid(pl, ITEM), bGive)
end

hook.Add("IGS.PlayerPurchasesLoaded", "force_give_weps_on_spawn", function(pl, purchases_)
	for uid in pairs(purchases_ or {}) do
		local ITEM = IGS.GetItemByUID(uid)
		if ITEM.swep then
			SetShouldPlayerReceiveWep(pl, ITEM, true)
		end
	end
end)

Откат транзакций за 7 дней (настраиваемо)

IGS.GetPlayerTransactionsBypassingLimit(function(txs)
	for i, tx in ipairs(txs) do
		local note = tx.Note or ""
		if note:StartWith("A: ") then continue end -- пропускаем реальные пополнения

		if (os.time() - tx.Time) >= 60 * 60 * 24 * 7 then
			print("Останавливаемся. Дальше пошли транзакции старее 7 дней")
			break
		end

		local s64, sum, id = tx.SteamID, tx.Sum, tx.ID
		local new_note = "Откат транзакции #" .. id .. "(" .. note .. ")"
		IGS.Transaction(s64, sum * -1, new_note, function()
			print("Транзакция #" .. id .. " отменена")
		end)
	end
end, nil, 10000)

Управление покупками игрока через Lua код

Удаление с инвентаря

-- inventory_id можно узнать через IGS.FetchInventory(fCallback, s64).
-- Функция вернет список предметов игрока. Например {{ID = 1234, Item = "uid"}, ...}
-- Функция IGS.StoreInventoryItem(fCallback, s64, sUid) добавляет предмет в инвентарь и в callback также возвращает inventory_id
local inventory_id = 1234
IGS.DeleteInventoryItem(function(bSuccessful)
	if bSuccessful then
		print("Предмет удален с инвентаря")
	else
		print("Предмет не удален. Возможно, ид предмета принадлежит другому проекту, либо предмет уже удален ранее")
	end
end, inventory_id)

Если игрок онлайн, то нужно также обновить его локальный инвентарь, чтобы игроку не отображался предмет, которого у него уже нет.

local pl = player.GetBySteamID("STEAM_0:1:23456789")
IGS.DeletePlayerInventoryItemLocally(pl, inventory_id)
-- /\ эта функция, используется когда игрок нажимает кнопку "Выбросить", либо "Активировать" на предмете в инвентаре, чтобы он больше там не отображался

Пример поиска и удаления предмета с инвентаря игрока

Если игрок оффлайн

local sid64 = "76561111111111111" -- steamid игрока
local item_uid_for_deletion = "some_item_uid" -- uid предмета, который нужно удалить. Если в инвентаре несколько предметов с таким uid, то в примере удалятся все

IGS.FetchInventory(function(dat)
	for _, it in ipairs(dat) do
		local item_uid, item_id = it.Item, it.ID

		if item_uid == item_uid_for_deletion then
			IGS.DeleteInventoryItem(function(bOk)
				print(bOk and "Итем удален" or "Ошибка удаления")
			end, item_id)
		end
	end
end, sid64)

Если игрок на сервере (онлайн)


local pl = player.GetBySteamID("STEAM_0:1:23456789")
local item_uid_for_deletion = "some_item_uid"

local inv = IGS.Inventory(pl) -- возвращает табличку формата {{ID = 123, Item = "uid"}, {ID = 321, Item = "uid2"}, ...}, где ID это уникальное число - ид в БД ГМД
if not inv then return end -- игрок не донатер или в инвентаре пусто

for _, it in ipairs(inv) do
	local item_uid, item_id = it.Item, it.ID
	if item_uid == item_uid_for_deletion then
		local tDeletedItem = IGS.DeletePlayerInventoryItemLocally(pl, item_id) -- чтобы предмет пропал в самой донат менюшке (визуально)
		assert(tDeletedItem, "Ошибка удаления локального итема")

		IGS.DeleteInventoryItem(function(bOk) -- удаляем предмет "по настоящему", с БД гмд
			print(bOk and "Итем удален с БД" or "Ошибка удаления")
		end, item_id)
	end
end


Удаление активной покупки

Покупку можно только отключить. Запись останется в Базе Данных, но покупка больше не будет активной.

-- purchase_id можно узнать в момент выдачи предмета игроку функцией IGS.StoreLocalPurchase(s64, sItemUID, iDaysTerm_, fCallback)
-- Либо через IGS.GetPlayerPurchases(steamid64, fCallback) -> Список покупок: {{`ID`,`Server`,`Item`,`Purchase`,`Expire`(таймштамп),`SteamID`,`Nick`}, ...}
local purchase_id = 1234
IGS.DisablePurchase(purchase_id, function(bDisabled)
	print(bDisabled and "Покупка отключена" or "Услуга уже отключена")
end)

Если игрок онлайн, то действие услуги не отключится автоматически. Нужно перезагрузить список покупок

local pl = player.GetBySteamID("STEAM_0:1:23456789")
IGS.LoadPlayerPurchases(pl, function()
	IGS.Notify(pl, "Покупки перезагружены") -- уведомление в чат игроку
end)

Выдача бонусного предмета при активации

Когда игрок активирует в инвентаре предмет utime_5h, ему в инвентарь поместится предмет sponsor_30d

IGS("+5 часов", "utime_5h", 300)
	:SetMeta("bonus_items", {"sponsor_30d"})
	:SetStackable()
	:SetOnActivate(function(pl)
		pl:SetUTime( pl:GetUTime() + 60 * 60 * 5 )
	end)

IGS("Sponsor на 30 дней", "sponsor_30d", 123)
	:SetSAMGroup("Sponsor")
	:SetDescription("Вы получите услугу 'спонсор' на 30 дней")



hook.Add(SERVER and "IGS.PlayerActivatedItem" or "", "bonus_items", function(pl, ITEM)
	local bonus_uids = ITEM:GetMeta("bonus_items")
	if bonus_uids then
		for _, uid in ipairs(bonus_uids) do
			IGS.AddToInventory(pl, uid, function()
				IGS.Notify("В качестве бонуса в ваш донат инвентарь помещен " .. uid)
			end)
		end
	end
end)

Мой аналог "Бесконечных патронов.
При перезарядке игрок, получит нужное колл патронов ( GetMaxClip1 -Clip1 ).

IGS("Бесконечные патроны", "AmmoInf")
	:SetPrice(100)
	:SetPerma()
	:SetDescription("Вы получите патроны при перезарядке")

hook.Add(SERVER and "KeyPress" or "", "InfAMMO", function(ply, key)--Sv часть но можно и в Sh
    if key ~= IN_RELOAD then return end
    if not ply:Alive() or not ply:HasPurchase("AmmoInf") then return end
    local wep = ply:GetActiveWeapon()
    if not IsValid(wep) then return end
    local ga = wep:GetMaxClip1() - wep:Clip1()
    if ga == 0 then return end
    ply:GiveAmmo(ga, wep:GetPrimaryAmmoType(), true)
end)
1 лайк

Сокрытие глобальных IGS сообщений: IGS.NotifyAll

В примере снизу скрывается сообщение об автовосстановлении ULX прав. Тема, из-за которой это реализовано: Как убрать сообщение об автовосстановлении

-- путь установки
-- addons/igs-modification/lua/autorun/server/igs_notify_override.lua

hook.Add("IGS.Initialized", "IGS_NotifyAllOverride", function()
	IGS.NotifyAll_ = IGS.NotifyAll_ or IGS.NotifyAll

	function IGS.NotifyAll(...)
		local args = {...}
		if args[1] and isstring(args[1]) and args[1]:StartWith("Автовосстановление ") then
			return
		end
		return IGS.NotifyAll_(unpack(args))
	end

	print("IGS. Оверрайд IGS.NotifyAll")
end)

Сокрытие персональных оповещений: IGS.Notify

От IGS.NotifyAll отличается тем, что приходит персонально одному игроку, а не всем сразу на сервере

Вопрос изначально был задан здесь: Как удалить сообщения "Вы можете потратить" и "Ваш Score" при входе на сервер?

-- путь установки
-- addons/igs-modification/lua/autorun/server/igs_notify_override.lua

hook.Add("IGS.Initialized", "igs_notify_override", function()
	IGS.Notify_orig = IGS.Notify_orig or IGS.Notify
	assert(IGS.Notify_orig, "IGS.Notify почему-то отсутствует на сервере")

	function IGS.Notify(pl, ...)
		local args = {...}
		if isstring(args[1]) and (args[1]:StartWith("Вы можете потратить") or args[1]:StartWith("Ваш Score")) then
			return
		end

		return IGS.Notify_orig(pl, unpack(args))
	end
end)

Добавление кнопки в донат меню

В примере ниже добавляется кнопка, открывающая поинтшоп. Автор: ✅ Кнопка в меню IGS, открывающая Pointshop 2 - #2 от пользователя doxzter

hook.Add('IGS.CatchActivities', 'PS', function(tabs)
    local dummy = vgui.Create('DPanel')
    dummy.Paint = function() end

    local btn = tabs:AddTab('PointShop', dummy, 'icon16/money.png')
    if not IsValid(btn) then return end

    btn.DoClick = function(self)
        Pointshop2:OpenMenu()
    end
end)

Оверрайд действия NPC

Подобным образом можно перезаписать любой метод любой энтити. Не только npc_igs

-- addons/igs-modification/lua/autorun/server/override_npc_action.lua

hook.Add("IGS.Initialized", "override_npc_action", function()
	local npc_igs = scripted_ents.GetStored("npc_igs")
	assert(npc_igs, "npc_igs нет на сервере. Это баг")

	local ENT = npc_igs.t

	function ENT:PlayerUse(pl)
		OpenDonateMenu(pl) -- заменить на свою функцию
	end

	print("Изменен NPC автодоната, чтобы открывал другое меню")
end)

Должен быть более красивый способ, но я его не знаю

Это ответ на такой вопрос: NPC - изменение меню

1 лайк