mysql = exports.mysql local useShopsWithNoItems = false local profitRate = tonumber(get( "profitRate" )) or 5 -- respawn dead npcs after two minute --[[ addEventHandler("onPedWasted", getResourceRootElement(), function() setTimer( function( source ) local x,y,z = getElementPosition(source) local rotation = getElementData(source, "rotation") local interior = getElementInterior(source) local dimension = getElementDimension(source) local dbid = getElementData(source, "dbid") local shoptype = getElementData(source, "shoptype") local skin = getElementModel(source) local sPendingWage = getElementData(source, "sPendingWage") local sIncome = getElementData(source, "sIncome") local sCapacity = getElementData(source, "sCapacity") local currentCap = getElementData(source, "currentCap") local sSales = getElementData(source, "sSales") local pedName = getElementData(source, "name") destroyElement(source) createShopKeeper(x,y,z,interior,dimension,dbid,shoptype,rotation,skins, sPendingWage, sIncome, sCapacity, currentCap, sSales, pedName) end, 120000, 1, source ) end ) ]] local skins = { { 211, 217 }, { 179 }, false, { 178 }, { 82 }, { 80, 81 }, { 28, 29 }, { 169 }, { 171, 172 }, { 142 }, { 171 }, { 171, 172 }, {71}, { 50 }, { 1 }, { 118 }, {118} } function createShopKeeper(x,y,z,interior,dimension,id,shoptype,rotation, skin, sPendingWage, sIncome, sCapacity, currentCap, sSales, pedName, sContactInfo, faction_belong, faction_access) if not g_shops[shoptype] then outputDebugString("Trying to locate shop #" .. id .. " with invalid shoptype " .. shoptype) return end if shoptype == 17 then if tonumber(dimension) == 0 and tonumber(interior) == 0 then return false end end if not skin then skin = 0 if shoptype == 3 then skin = 168 -- needs differences for burgershot etc if interior == 5 then skin = 155 elseif interior == 9 then skin = 167 elseif interior == 10 then skin = 205 end -- interior 17 = donut shop elseif shoptype == 16 then skin = 27 else -- clothes, interior 5 = victim -- clothes, interior 15 = binco -- clothes, interior 18 = zip skin = skins[shoptype][math.random( 1, #skins[shoptype] )] end end local ped = createPed(skin, x, y, z) setElementRotation(ped, 0, 0, rotation) setElementDimension(ped, dimension) setElementInterior(ped, interior) exports.pool:allocateElement(ped) if shoptype == 17 then setElementData(ped, "customshop", true) elseif shoptype == 18 or shoptype == 19 then --Faction Drop NPCs exports.anticheat:changeProtectedElementDataEx(ped, "faction_belong", faction_belong, true) exports.anticheat:changeProtectedElementDataEx(ped, "faction_access", faction_access, true) end setElementData(ped, "talk", 1, true) setElementData(ped, "name", pedName, true) setElementData(ped, "shopkeeper", true) setElementFrozen(ped, true) setElementData(ped, "dbid", tonumber(id), true) setElementData(ped, "ped:type", "shop", false) setElementData(ped, "shoptype", shoptype, false) setElementData(ped, "rotation", rotation, false) setElementData(ped, "sPendingWage", sPendingWage, true) setElementData(ped, "sIncome", (shoptype == 14 and 0 or tonumber(sIncome)), true) setElementData(ped, "sCapacity", sCapacity, true) setElementData(ped, "currentCap", currentCap, true) setElementData(ped, "sSales", sSales, true) setElementData(ped, "sContactInfo", sContactInfo, true) end function delNearbyGeneralshops(thePlayer, commandName) if (exports.integration:isPlayerTrialAdmin(thePlayer)) then local posX, posY, posZ = getElementPosition(thePlayer) outputChatBox("Deleting Nearby Shop NPC(s):", thePlayer, 255, 126, 0) local count = 0 local dimension = getElementDimension(thePlayer) for k, thePed in ipairs(getElementsByType("ped", resourceRoot)) do local pedType = getElementData(thePed, "ped:type") if (pedType) then if (pedType=="shop") then local x, y = getElementPosition(thePed) local distance = getDistanceBetweenPoints2D(posX, posY, x, y) local cdimension = getElementDimension(thePed) if (distance<=10) and (dimension==cdimension) then local dbid = getElementData(thePed, "dbid") local shoptype = getElementData(thePed, "shoptype") if deleteGeneralShop(thePlayer, "delshop" , dbid) then --outputChatBox(" Deleted Shop with ID #" .. dbid .. " and type "..shoptype..".", thePlayer, 255, 126, 0) count = count + 1 end end end end end if (count==0) then outputChatBox(" Deleted None.", thePlayer, 255, 126, 0) else outputChatBox(" Deleted "..count.." None.", thePlayer, 255, 126, 0) end end end addCommandHandler("delnearbyshops", delNearbyGeneralshops, false, false) addCommandHandler("delnearbynpcs", delNearbyGeneralshops, false, false) -- function createDynamic(x,y,z,interior,dimension,id,rotation,skin ~= -1 and skin, products) -- if not skin then -- skin = skins[8][math.random( 1, #skins[8] )] -- end -- local ped = createPed(skin, x, y, z) -- setElementDimension(ped, dimension) -- setElementInterior(ped, interior) -- exports.pool:allocateElement(ped) -- setElementData(ped, "shopkeeper", true) -- setElementFrozen(ped, true) -- setElementData(ped, "dbid", id, false) -- setElementData(ped, "ped:type", "shop", false) -- setElementData(ped, "shoptype", 0, false) -- setElementData(ped, "rotation", rotation, false) -- end function SmallestID() -- finds the smallest ID in the SQL instead of auto increment local result1 = dbPoll(dbQuery(mysql:getConnection(), "SELECT MIN(e1.id+1) AS nextID FROM shops AS e1 LEFT JOIN shops AS e2 ON e1.id +1 = e2.id WHERE e2.id IS NULL"), -1) if result1 then local id1 = tonumber(result1["nextID"]) or 1 return id1 end return false end function createGeneralshop(thePlayer, commandName, shoptype, skin, ...) if (exports.integration:isPlayerTrialAdmin(thePlayer)) then local shoptype = tonumber(shoptype) if not shoptype or not g_shops[shoptype] then outputChatBox("SYNTAX: /" .. commandName .. " [shop type] [skin, -1 = random] [Firstname Lastname, -1 = random]", thePlayer, 255, 194, 14) for k, v in ipairs(g_shops) do outputChatBox("TYPE " .. k .. " = " .. v.name, thePlayer, 200, 200, 200) end return false end local skin = tonumber(skin) if not skin or skin == -1 then --Random skin = exports.global:getRandomSkin() end if skin then local ped = createPed(skin, 0, 0, 3) if not ped then outputChatBox("Invalid Skin.", thePlayer, 255, 0, 0) return else destroyElement(ped) end else skin = -1 end local x, y, z = getElementPosition(thePlayer) local dimension = getElementDimension(thePlayer) local interior = getElementInterior(thePlayer) local _, _, rotation = getElementRotation(thePlayer) if shoptype == 17 then if dimension == 0 and interior == 0 then outputChatBox("Custom shop must be created in a business interior.", thePlayer, 255, 0, 0) return false end end local pedName = table.concat({...}, "_") or false if not pedName or pedName=="" or (tonumber(pedName) and tonumber(pedName) == -1) then pedName = exports.global:createRandomMaleName() pedName = string.gsub(pedName, " ", "_") end local iCan, why = canIUseThisName(pedName) if not iCan then outputChatBox(why, thePlayer, 255, 0, 0) return false end local id = false id = dbExec(mysql:getConnection(), "INSERT INTO shops SET pedName='"..exports.global:toSQL(pedName).."', x='" .. (x) .. "', y='" .. (y) .. "', z='" .. (z) .. "', dimension='" .. (dimension) .. "', interior='" .. (interior) .. "', shoptype='" .. (shoptype) .. "', rotationz='" .. (rotation) .. "', skin='".. (skin).."' ") dbQuery( function(qh) local res, rows, err = dbPoll(qh, 0) if rows > 0 then local id = res[1]['id'] createShopKeeper(x,y,z,interior,dimension,id,tonumber(shoptype),rotation,skin ~= -1 and skin, 0, 0, 10, 0, "", pedName, {"", "", "", ""}, 0, 0) end end, mysql:getConnection(), "SELECT id FROM shops WHERE id = LAST_INSERT_ID()") end end function getNearbyGeneralshops(thePlayer, commandName) if (exports.integration:isPlayerTrialAdmin(thePlayer) or exports.integration:isPlayerSupporter(thePlayer)) then local posX, posY, posZ = getElementPosition(thePlayer) outputChatBox("Nearby Shop NPC(s):", thePlayer, 255, 126, 0) local count = 0 local dimension = getElementDimension(thePlayer) for k, thePed in ipairs(getElementsByType("ped", resourceRoot)) do local pedType = getElementData(thePed, "ped:type") if (pedType) then if (pedType=="shop") then local x, y = getElementPosition(thePed) local distance = getDistanceBetweenPoints2D(posX, posY, x, y) local cdimension = getElementDimension(thePed) if (distance<=10) and (dimension==cdimension) then local dbid = getElementData(thePed, "dbid") local shoptype = getElementData(thePed, "shoptype") local pedName = getElementData(thePed, "name") or "Unnamed" outputChatBox(" Shop ID #" .. dbid .. ", type "..shoptype..", name: "..tostring(pedName):gsub("_", " "), thePlayer, 255, 126, 0) count = count + 1 end end end end if (count==0) then outputChatBox(" None.", thePlayer, 255, 126, 0) end end end addCommandHandler("nearbyshops", getNearbyGeneralshops, false, false) addCommandHandler("nearbynpcs", getNearbyGeneralshops, false, false) function moveNPCshop(thePlayer, commandName, value) if (exports.integration:isPlayerTrialAdmin(thePlayer) or exports.integration:isPlayerSupporter(thePlayer)) then if not tonumber(value) then outputChatBox("SYNTAX: /" .. commandName .. " [Shop ID]", thePlayer, 255, 194, 14) return end local dimension = getElementDimension(thePlayer) local possibleShops = getElementsByType("ped", resourceRoot) local foundShop = false for _, shop in ipairs(possibleShops) do if getElementData(shop,"shopkeeper") and (tonumber(getElementData(shop, "dbid")) == tonumber(value)) then foundShop = shop break end end if not foundShop then outputChatBox("No shop founded with ID #"..value, thePlayer, 255, 0, 0) return end local x, y, z = getElementPosition(thePlayer) local dim = getElementDimension(thePlayer) local int = getElementInterior(thePlayer) local rot, rot1, rot2 = getElementRotation(thePlayer) change = dbExec(mysql:getConnection(), "UPDATE shops SET x='" .. (x) .. "', y='" .. (y) .. "', z='" .. (z) .. "', dimension='" .. (dim) .. "', interior='" .. (int) .. "', rotationz='" .. (rot2) .. "' WHERE id=".. (tonumber(value))) setElementPosition(foundShop, x, y, z) setElementDimension(foundShop, dim) setElementInterior(foundShop, int) setElementRotation(foundShop, rot, rot1, rot2) outputChatBox("Updated shop position.", thePlayer, 0, 255, 0) end end addCommandHandler("moveshop", moveNPCshop) addCommandHandler("moveNPC", moveNPCshop) addCommandHandler("movenpc", moveNPCshop) function gotoShop(thePlayer, commandName, shopID) if (exports.integration:isPlayerTrialAdmin(thePlayer)) then if not tonumber(shopID) then outputChatBox("SYNTAX: /" .. commandName .. " [Shop ID]", thePlayer, 255, 194, 14) else local possibleShops = getElementsByType("ped", resourceRoot) local foundShop = false for _, shop in ipairs(possibleShops) do if getElementData(shop,"shopkeeper") and (tonumber(getElementData(shop, "dbid")) == tonumber(shopID)) then foundShop = shop break end end if not foundShop then outputChatBox("No shop founded with ID #"..shopID, thePlayer, 255, 0, 0) return false end local x, y, z = getElementPosition(foundShop) local dim = getElementDimension(foundShop) local int = getElementInterior(foundShop) local _, _, rot = getElementRotation(foundShop) startGoingToShop(thePlayer, x,y,z,rot,int,dim,shopID) end end end addCommandHandler("gotoshop", gotoShop, false, false) function startGoingToShop(thePlayer, x,y,z,r,interior,dimension,shopID) -- Maths calculations to stop the player being stuck in the target x = x + ( ( math.cos ( math.rad ( r ) ) ) * 2 ) y = y + ( ( math.sin ( math.rad ( r ) ) ) * 2 ) setCameraInterior(thePlayer, interior) if (isPedInVehicle(thePlayer)) then local veh = getPedOccupiedVehicle(thePlayer) setElementAngularVelocity(veh, 0, 0, 0) setElementInterior(thePlayer, interior) setElementDimension(thePlayer, dimension) setElementInterior(veh, interior) setElementDimension(veh, dimension) setElementPosition(veh, x, y, z + 1) warpPedIntoVehicle ( thePlayer, veh ) setTimer(setElementAngularVelocity, 50, 20, veh, 0, 0, 0) else setElementPosition(thePlayer, x, y, z) setElementInterior(thePlayer, interior) setElementDimension(thePlayer, dimension) end outputChatBox(" You have teleported to shop ID#"..shopID, thePlayer) end function restoreGeneralShop(thePlayer, commandName, id) if (exports.integration:isPlayerTrialAdmin(thePlayer)) then if not (id) then id = getElementData(thePlayer, "shop:mostRecentDeleteShop") or false if not id then outputChatBox("SYNTAX: /" .. commandName .. " [ID]", thePlayer, 255, 194, 14) return false end end local dbid = id dbQuery( function(qh, thePlayer) local res, rows, err = dbPoll(qh, 0) if rows > 0 then for index, row in ipairs(res) do if not (row) then outputChatBox("Shop ID #" .. dbid .. " isn't found in deleted shop database.", thePlayer, 255, 0, 0) return false end dbExec(mysql:getConnection(),"UPDATE `shops` SET `deletedBy` = '0' WHERE id='" .. (dbid) .. "' LIMIT 1") loadOneShop(dbid) outputChatBox("Restored shop with ID #" .. dbid .. ".", thePlayer, 0, 255, 0) end end end, {thePlayer}, mysql:getConnection(), "SELECT `id` FROM `shops` WHERE `id`='"..tostring(dbid).."' AND `deletedBy` != '0'") end end addCommandHandler("restoreshop", restoreGeneralShop, false, false) addCommandHandler("restorenpc", restoreGeneralShop, false, false) addCommandHandler("restoreped", restoreGeneralShop, false, false) function deleteGeneralShop(thePlayer, commandName, id) if (exports.integration:isPlayerTrialAdmin(thePlayer)) then if not (id) then outputChatBox("SYNTAX: /" .. commandName .. " [ID]", thePlayer, 255, 194, 14) else local counter = 0 for k, thePed in ipairs(getElementsByType("ped", resourceRoot)) do local pedType = getElementData(thePed, "ped:type") if (pedType) then if (pedType=="shop") then local dbid = getElementData(thePed, "dbid") if (tonumber(id)==dbid) then destroyElement(thePed) local adminID = getElementData(thePlayer,"account:id") dbExec(mysql:getConnection(),"UPDATE `shops` SET `deletedBy` = '"..tostring(adminID).."' WHERE id='" .. (dbid) .. "' LIMIT 1") --dbExec(mysql:getConnection(),"DELETE FROM shop_products WHERE npcID='" .. (dbid) .. "' ") --dbExec(mysql:getConnection(),"DELETE FROM shop_contacts_info WHERE npcID='" .. (dbid) .. "' ") outputChatBox(" Deleted shop with ID #" .. id .. ".", thePlayer, 0, 255, 0) counter = counter + 1 setElementData(thePlayer, "shop:mostRecentDeleteShop",dbid, true ) end end end end if (counter==0) then outputChatBox("No shops with such an ID exists.", thePlayer, 255, 0, 0) return false end return true end end end addCommandHandler("delshop", deleteGeneralShop, false, false) addCommandHandler("deleteshop", deleteGeneralShop, false, false) function removeGeneralShop(thePlayer, commandName, id) if (exports.integration:isPlayerSeniorAdmin(thePlayer)) then if not (id) then id = getElementData(thePlayer, "shop:mostRecentDeleteShop") or false if not id then outputChatBox("SYNTAX: /" .. commandName .. " [ID]", thePlayer, 255, 194, 14) return false end end local dbid = id dbQuery( function(qh, thePlayer) local res, rows, err = dbPoll(qh, 0) if rows > 0 then for index, row in ipairs(res) do if not (row) then outputChatBox("Shop ID #" .. dbid .. " isn't found in deleted shop database, /delshop first.", thePlayer, 255, 0, 0) return false end if dbExec(mysql:getConnection(),"DELETE FROM shops WHERE id='" .. (dbid) .. "' LIMIT 1") and dbExec(mysql:getConnection(),"DELETE FROM shop_products WHERE npcID='" .. (dbid) .. "' ") and dbExec(mysql:getConnection(),"DELETE FROM shop_contacts_info WHERE npcID='" .. (dbid) .. "' ") then outputChatBox("Removed shop ID #" .. dbid .. " from SQL.", thePlayer, 0, 255, 0) setElementData(thePlayer, "shop:mostRecentDeleteShop",false, true ) else outputChatBox("No shops with such an ID exists.", thePlayer, 255, 0, 0) end end end end, {thePlayer}, "SELECT `id` FROM `shops` WHERE `id`='"..tostring(dbid).."' AND `deletedBy` != '0'") end end addCommandHandler("removeshop", removeGeneralShop, false, false) addCommandHandler("removenpc", removeGeneralShop, false, false) addCommandHandler("removeped", removeGeneralShop, false, false) function loadAllGeneralshops(res) dbQuery( function(qh) local res, rows, err = dbPoll(qh, 0) if rows > 0 then for index, row in ipairs(res) do local id = tonumber(row["id"]) local x = tonumber(row["x"]) local y = tonumber(row["y"]) local z = tonumber(row["z"]) local dimension = tonumber(row["dimension"]) local interior = tonumber(row["interior"]) local shoptype = tonumber(row["shoptype"]) local rotation = tonumber(row["rotationz"]) local skin = tonumber(row["skin"]) local sPendingWage = tonumber(row["sPendingWage"]) local sIncome = tonumber(row["sIncome"]) local sCapacity = tonumber(row["sCapacity"]) local currentCap = 0 local sSales = row["sSales"] local pedName = row["pedName"] or false local sContactInfo = {row["sOwner"],row["sPhone"],row["sEmail"],row["sForum"]} local faction_belong = tonumber(row["faction_belong"]) local faction_access = tonumber(row["faction_access"]) createShopKeeper(x,y,z,interior,dimension,id,shoptype,rotation,skin ~= -1 and skin, sPendingWage, sIncome, sCapacity, currentCap, sSales, pedName, sContactInfo, faction_belong, faction_access) end end end, mysql:getConnection(), "SELECT `shops`.`id` AS `id`, `x`, `y`, `z`, `dimension`, `interior`, `shoptype`, `rotationz`, `skin`, `sPendingWage`, `sIncome`, `sCapacity`, `sSales`, `pedName`, `sOwner`, `sPhone`, `sEmail`, `sForum`, `faction_belong`, `faction_access` FROM `shops` LEFT JOIN `shop_contacts_info` ON `shops`.`id` = `shop_contacts_info`.`npcID` WHERE `shops`.`deletedBy` = '0'") end addEventHandler("onResourceStart", getResourceRootElement(), loadAllGeneralshops) function loadOneShop(shopID) dbQuery( function(qh) local res, rows, err = dbPoll(qh, 0) if rows > 0 then for index, row in ipairs(res) do local id = tonumber(row["id"]) local x = tonumber(row["x"]) local y = tonumber(row["y"]) local z = tonumber(row["z"]) local dimension = tonumber(row["dimension"]) local interior = tonumber(row["interior"]) local shoptype = tonumber(row["shoptype"]) local rotation = tonumber(row["rotationz"]) local skin = tonumber(row["skin"]) local sPendingWage = tonumber(row["sPendingWage"]) local sIncome = tonumber(row["sIncome"]) local sCapacity = tonumber(row["sCapacity"]) local currentCap = 0 local sSales = row["sSales"] local pedName = row["pedName"] or false local sContactInfo = {row["sOwner"],row["sPhone"],row["sEmail"],row["sForum"]} local faction_belong = tonumber(row["faction_belong"]) local faction_access = tonumber(row["faction_access"]) createShopKeeper(x,y,z,interior,dimension,id,shoptype,rotation,skin ~= -1 and skin, sPendingWage, sIncome, sCapacity, currentCap, sSales, pedName, sContactInfo, faction_belong, faction_access) end end end, mysql:getConnection(), "SELECT COUNT(*) as `currentCap` FROM `shop_products` WHERE `npcID` = '"..tostring(id).."' ") return true end function reloadGeneralShop(thePlayer, commandName, id) if (exports.integration:isPlayerTrialAdmin(thePlayer)) then if not (id) then id = getElementData(thePlayer, "shop:mostRecentDeleteShop") or false if not id then outputChatBox("SYNTAX: /" .. commandName .. " [ID]", thePlayer, 255, 194, 14) return false end end if loadOneShop(id) then outputChatBox("Reloaded shop ID#"..id..".",thePlayer, 0,255,0) else outputChatBox("Reloaded shop ID#"..id..".",thePlayer, 255,0,0) end end end addCommandHandler("reloadshop", reloadGeneralShop, false, false) addCommandHandler("reloadnpc", reloadGeneralShop, false, false) addCommandHandler("reloadped", reloadGeneralShop, false, false) function renamePed(thePlayer, commandName, id, ...) if (exports.integration:isPlayerTrialAdmin(thePlayer) or exports.integration:isPlayerSupporter(thePlayer)) then if not tonumber(id) or not (...) then outputChatBox("SYNTAX: /" .. commandName .. " [Shop ID] [Firstname LastName]", thePlayer, 255, 194, 14) return false end id = math.floor(tonumber(id)) local pedName = table.concat({...}, "_") if pedName == "" then outputChatBox("SYNTAX: /" .. commandName .. " [Shop ID] [Firstname LastName]", thePlayer, 255, 194, 14) return false end local iCan, why = canIUseThisName(pedName) if not iCan then outputChatBox(why, thePlayer, 255, 0, 0) return false end if not dbExec(mysql:getConnection(),"UPDATE `shops` SET `pedName`='"..tostring(pedName):gsub("'","''").."' WHERE `id`='"..tostring(id).."' ") then outputChatBox("Failed to rename this NPC, please contact Maxime.",thePlayer, 255,0,0) return false end for k, thePed in ipairs(getElementsByType("ped", resourceRoot)) do local pedType = getElementData(thePed, "ped:type") if (pedType) then if (pedType=="shop") then local dbid = getElementData(thePed, "dbid") if (tonumber(id)==dbid) then destroyElement(thePed) end end end end if loadOneShop(id) then outputChatBox("Renamed shop ID#"..id.." to '"..tostring(pedName):gsub("_"," ").."'.",thePlayer, 0,255,0) else outputChatBox("Failed to reload this NPC, please contact Maxime.",thePlayer, 255,0,0) end end end addCommandHandler("renameped", renamePed, false, false) addCommandHandler("renamenpc", renamePed, false, false) addCommandHandler("renameshop", renamePed, false, false) -- end of loading shops, this be store keeper thing below -- local function getDiscount( player, shoptype ) local discount = 1 if shoptype == 7 and tonumber( getElementData( player, "faction" ) ) == 125 then discount = discount * 0.5 elseif shoptype == 14 and tonumber( getElementData( player, "faction" ) ) == 30 then discount = discount * 0.5 end if exports.donators:hasPlayerPerk( player, 8 ) then discount = discount * 0.8 end return discount end function clickStoreKeeper() local success, currentUser = canIAccessThisShop(source, client) if not success then outputChatBox(currentUser.." is currently using this NPC, please wait a moment.", client, 255,0,0) return false end local shoptype = getElementData(source, "shoptype") local id = getElementData(source, "dbid") local race, gender = nil, nil if(shoptype == 5) then -- if its a clothes shop, we also need the players race gender = getElementData(client,"gender") race = getElementData(client,"race") end if tonumber(shoptype) == 17 then local products = {} dbQuery( function(qh, client, source) local res, rows, err = dbPoll(qh, 0) if rows > 0 then for index, pRow in ipairs(res) do table.insert(products, { id, pRow["pItemID"], pRow["pItemValue"], pRow["pDesc"], pRow["pPrice"], pRow["pDate"], pRow["pID"] } ) end if setShopCurrentUser(source, client) then triggerClientEvent(client, "showGeneralshopUI", source, shoptype, race, gender, 0, products) else outputDebugString("setShopCurrentUser failed.") end end end, {client, source}, mysql:getConnection(), "SELECT * FROM `shop_products` WHERE `npcID`='"..id.."' ORDER BY `pDate` DESC") elseif tonumber(shoptype) == 18 then --Faction Drop NPC - General Items elseif tonumber(shoptype) == 19 then -- Faction Drop NPC - WEAPONS local products = {} dbQuery( function(qh, client, source) local res, rows, err = dbPoll(qh, 0) if rows > 0 then for index, pRow in ipairs(res) do table.insert(products, pRow ) end if setShopCurrentUser(source, client) then triggerClientEvent(client, "showGeneralshopUI", source, shoptype, race, gender, 0, products) else outputDebugString("setShopCurrentUser failed.") end end end, {client, source}, mysql:getConnection(), "SELECT `npcID`, `pItemID`, `pItemValue`, `pDesc`, `pPrice`, `pDate`, `pID`, `pQuantity`, `pSetQuantity`, `pRestockInterval`, `pRestockedDate`, DATEDIFF((`pRestockedDate` + interval `pRestockInterval` day),NOW()) AS `pRestockIn` FROM `shop_products` WHERE `npcID`='"..id.."' ORDER BY `pID` DESC") else if setShopCurrentUser(source, client) then -- perk 8 = 20% discount in shops triggerClientEvent(client, "showGeneralshopUI", source, shoptype, race, gender, getDiscount(client, shoptype)) else outputDebugString("setShopCurrentUser failed.") end end end addEvent("shop:keeper", true) addEventHandler("shop:keeper", getResourceRootElement(), clickStoreKeeper) function calcSupplyCosts(thePlayer, itemID, isWeapon, supplyCost) if not isweapon and id ~= 68 then if exports.donators:hasPlayerPerk(thePlayer, 8) then return math.ceil( 0.8 * supplyCost ) end end return supplyCost end function getInteriorOwner( dimension ) if dimension == 0 then return nil, nil end local dbid, theEntrance, theExit, interiorType, interiorElement = exports["interior-system"]:findProperty(source) interiorStatus = getElementData(interiorElement, "status") local owner = interiorStatus[4] for key, value in ipairs(exports.pool:getPoolElementsByType("player")) do local id = getElementData(value, "dbid") if (id==owner) then return owner, value end end return owner, nil -- no player found end -- source = the ped clicked -- client = the player -- this has no code for the out-of-date lottery. addEvent("shop:buy", true) addEventHandler( "shop:buy", resourceRoot, function( index ) local shoptype = getElementData( source, "shoptype") local error = "S-" .. tostring( shoptype ) .. "-" .. tostring( getElementData( source, "dbid") ) local shop = g_shops[ shoptype or -1 ] _G['shop'] = shop if not shop then outputChatBox("Error " .. error .. "-NE, report at www.owlgaming.net/mantis.", client, 255, 0, 0 ) return end local race = getElementData( client, "race" ) local gender = getElementData( client, "gender" ) updateItems( shoptype, race, gender ) -- should modify /shop/ too, as shop is a reference to g_shops[type]. -- fetch the selected item local item = getItemFromIndex( shoptype, index ) if not item then outputChatBox("Error " .. error .. "-NEI-" .. index .. ", report at www.owlgaming.net/mantis.", client, 255, 0, 0 ) return end if item.minimum_age and getElementData(client, "age") < item.minimum_age then outputChatBox( "You need to be " .. item.minimum_age .. " years or older to buy this.", client, 255, 0, 0 ) return end --[[Check if its a generic, and if they have approval yet if item.name == "Other" and item.itemID == 80 and not getElementData(client, "shop:generic:pending") then triggerClientEvent(client, "shop:generic:buy", client, index) return end]] -- check for monies local price = math.ceil( getDiscount( client, shoptype ) * item.price ) if not exports.global:hasMoney( client, price ) then outputChatBox( "You lack the money to buy this " .. item.name .. ".", client, 255, 0, 0 ) return end -- @@ -- -- do some item-specific stuff, such as assigning a serial. -- @@ -- local wonTheLottery = false local itemID, itemValue = item.itemID, item.itemValue or 1 if itemID == 2 then local attempts = 0 while true do attempts = attempts + 1 itemValue = math.random(100000, attempts < 20 and 899999 or 8999999) end elseif itemID == 68 then -- Lottery Tickets --[[ if not exports.integration:isPlayerScripter(client) then outputChatBox( "This item is temporarily disabled by scripters.", client, 255, 0, 0 ) return end ]] local dimension = getElementDimension( source ) local suppliesToTake = 0 suppliesToTake = item.supplies or math.ceil( 3.5 * exports['item-system']:getItemWeight( itemID, itemValue ) ) if not suppliesToTake then outputChatBox( "Error " .. error .. "-SE-I" .. index .. "-" .. tostring( suppliesToTake ) ) return false end local success, why = solveSupplies(source, client, suppliesToTake, dimension) if not success then outputChatBox( why, client, 255, 0, 0 ) return false end if not exports["lottery-system"]:canThisPlayerBuyTicket(client) then outputChatBox( "One player now can only buy one lottery ticket every 20 minutes.", client, 255, 0, 0 ) outputChatBox( "You've already bought another lottery ticket not long ago, please try again later.", client, 255, 0, 0 ) return false end local lotteryJackpot = exports['lottery-system']:getLotteryJackpot() if tonumber(lotteryJackpot) == -1 then outputChatBox( "Sorry, someone already won the lottery. Please wait for the next draw.", client, 255, 0, 0 ) return elseif not exports.global:hasSpaceForItem( client, itemID, itemValue ) then outputChatBox("Your inventory is full.", client, 255, 0, 0) else local updatedJackpot = tonumber(lotteryJackpot) + math.ceil(price * 2 / 3) exports['lottery-system']:updateLotteryJackpot(updatedJackpot) local lotteryTicketNumber = 0 local lotteryTicketNumber = getElementData(client, 'test:nextPickedLotteryNumber') or math.random(2,48) -- Pick a random number for the lottery ticket number between 2 and 48 itemValue = tonumber(lotteryTicketNumber) if tonumber(lotteryTicketNumber) == tonumber(exports['lottery-system']:getLotteryNumber()) then setTimer(function(player, jp) exports['global']:giveMoney(player, jp) end, 100, 1, client, updatedJackpot) outputChatBox( "You won! Jackpot: $" .. exports.global:formatMoney(updatedJackpot) .. ".", client, 0, 255, 0 ) exports['lottery-system']:lotteryDraw() for key, value in ipairs(exports.pool:getPoolElementsByType("player")) do if (getElementData(value, "loggedin")==1) then outputChatBox("[NEWS] " .. getPlayerName(client):gsub("_"," ") .. " won the lottery jackpot of $" .. exports.global:formatMoney(updatedJackpot) .. ".", value, 200, 100, 200) end end exports['lottery-system']:updateLotteryJackpot(-1) -- Timer to re-enable lottery 10 minutes after a ticket has been drawn. setTimer(function () exports['lottery-system']:updateLotteryJackpot(0) end, 600000, 1) wonTheLottery = true else outputChatBox( "Sorry, your number did not get picked. You lost. You got number " .. lotteryTicketNumber .. ".", client, 255, 0, 0 ) end lotteryTicketNumber = 0 end elseif itemID == 115 or itemID == 116 then -- now here's the trick. If item.license is set, it checks for a gun license, if item.ammo is set it gives as much ammo if item.license and getElementData( client, "license.gun" ) ~= 1 then outputChatBox( "You lack a weapon license.", client, 255, 0, 0 ) return else local w = itemValue if itemID == 115 then local serial = "1" if item.license then -- licensed weapon, thus needs a serial local characterDatabaseID = getElementData(client, "account:character:id") serial = exports.global:createWeaponSerial( 3, characterDatabaseID, characterDatabaseID ) end itemValue = itemValue .. ":" .. serial .. ":" .. getWeaponNameFromID( itemValue ) addPurchaseLogs(tonumber(getElementData(source, "dbid")), client, tostring( getWeaponNameFromID( w ) ), itemValue, price, serial, "N/A", FORUM_AMMUNATION) elseif itemID == 116 then local amount = item.ammo or exports.weaponcap:getGTACap( itemValue ) or 1 itemValue = itemValue .. ":" .. amount .. ":" .. getWeaponNameFromID( itemValue ) addPurchaseLogs(tonumber(getElementData(source, "dbid")), client, "Ammo for " .. tostring( getWeaponNameFromID( w ) ), amount .. " Ammo for " .. tostring( getWeaponNameFromID( w ) ), price, nil, "N/A", FORUM_AMMUNATION) end end end local dimension = getElementDimension( source ) local suppliesToTake = 0 if dimension > 0 then -- is even in any interior -- calculate the supplies amount /MAXIME --suppliesToTake = item.supplies or math.ceil(item.price/(profitRate*2)) or math.ceil( 3.5 * exports['item-system']:getItemWeight( itemID, itemValue ) ) suppliesToTake = item.supplies or math.ceil( 3.5 * exports['item-system']:getItemWeight( itemID, itemValue ) ) if not suppliesToTake then outputChatBox( "Error " .. error .. "-SE-I" .. index .. "-" .. tostring( suppliesToTake ) ) return false end -- get the current supply count and check for enough supplies local success, why = solveSupplies(source, client, suppliesToTake, dimension) if not success then outputChatBox( why, client, 255, 0, 0 ) return false end end if wonTheLottery or exports.global:giveItem( client, itemID, itemValue ) then -- Money local playerMoney = getElementData(client, "money") for i = 134, 134 do while exports['item-system']:takeItem(client, i) do end end if tonumber(playerMoney) > 0 then exports.global:giveItem(client, 134, tonumber(playerMoney)-tonumber(price)) end exports.global:takeMoney( client, price ) -- this is assumed not to fail as we checked with :hasMoney before. -- and now for what happens after buying? outputChatBox( "You bought this " .. item.name .. " for $" .. exports.global:formatMoney( price ) .. ".", client, 0, 255, 0 ) -- some post-buying things, item-specific if itemID == 2 then dbExec(mysql:getConnection(),"INSERT INTO `phones` (`phonenumber`, `boughtby`) VALUES ('"..tostring(itemValue).."', '"..(tostring(getElementData(client, "account:character:id") or 0)).."')") outputChatBox("Your number is #" .. itemValue .. ".", client, 255, 194, 14 ) elseif itemID == 16 and item.fitting then -- it's a skin, so set it. setElementModel( client, itemValue ) dbExec(mysql:getConnection(),"UPDATE characters SET skin = " .. ( itemValue ) .. " WHERE id = " .. (getElementData( client, "dbid" )) ) elseif itemID == 114 then -- vehicle mods outputChatBox("To add this item to any vehicle, go into a garage and double-click the item while sitting inside.", client, 255, 194, 14 ) elseif itemID == 115 then -- log weapon purchases exports.logs:dbLog( client, 36, client, "bought WEAPON - " .. itemValue ) local govMoney = math.floor( price / 2 ) exports.global:giveMoney(getTeamFromName("Government of Los Santos"), govMoney) price = price - govMoney -- you'd obviously get less if the gov asks for percentage. elseif itemID == 116 then -- log weapon purchases exports.logs:dbLog( client, 36, client, "bought AMMO - " .. itemValue ) local govMoney = math.floor( price / 2 ) exports.global:giveMoney(getTeamFromName("Government of Los Santos"), govMoney) price = price - govMoney -- you'd obviously get less if the gov asks for percentage. end -- What's left undone? Giving shop owner money! if price > 0 and dimension > 0 then local currentIncome = tonumber(getElementData(source, "sIncome")) or 0 setElementData(source, "sIncome", currentIncome + price, true) playBuySound(source) local playerGender = getElementData(client,"gender") local pedName = tostring(getElementData(source, "name")) if string.sub(pedName, 1, 8) == "userdata" then pedName = "The Storekeeper" end pedName = string.gsub(pedName,"_", " ") local playerName = getPlayerName(client):gsub("_", " ") if playerGender == 0 then triggerEvent('sendAme', client, "takes out a couple of dollar notes from his wallet, hands it over to "..pedName) else triggerEvent('sendAme', client, "takes out a couple of dollar notes from her wallet, hands it over to "..pedName) end local r = getRealTime() local timeString = ("%02d/%02d/%04d %02d:%02d"):format(r.monthday, r.month + 1, r.year+1900, r.hour, r.minute) local ownerNoti = "A customer bought a "..item.name.." for $"..exports.global:formatMoney(price).."." local logString = "- "..timeString.." : A customer bought a "..item.name.." for $"..exports.global:formatMoney(price)..".\n" exports.global:sendLocalText(client, "* "..pedName.." gave "..playerName.." a "..item.name..".", 255, 51, 102, 30, {}, true) storeKeeperSay(client, "Here you are. And..", pedName) if playerGender == 0 then storeKeeperSay(client, "Thank you sir, Have a nice day!", pedName) else storeKeeperSay(client, "Thank you ma'ma, Have a nice day!", pedName) end --notifyAllShopOwners(source, ownerNoti.." Come and collect the money when you got time ;)") local previousSales = getElementData(source, "sSales") or "" logString = string.sub(logString..previousSales,1,5000) setElementData(source, "sSales", logString, true) dbExec(mysql:getConnection(),"UPDATE `shops` SET `sIncome` = `sIncome` + '" .. tostring(price) .. "', `sSales` = '"..logString:gsub("'","''").."' WHERE `id` = '"..tostring(getElementData(source,"dbid")).."'") end else outputChatBox( "You do not have enough space to carry this " .. item.name .. ".", client, 255, 0, 0 ) end end ) function solveSupplies(source, client, suppliesToTake, dimension) for key, interior in pairs(getElementsByType("interior")) do if getElementData(interior, "dbid") == dimension then local status = getElementData(interior, "status") local currentSupplies = status[6] or 0 local ownerID = status[4] local interiorType = tonumber(status[1] or 2) if ownerID == getElementData(client, "dbid") then --suppliesToTake = suppliesToTake*profitRate --ownerPlayer = ownerID --outputChatBox( "Buying items from your own shop will not make you profit.", client, 255, 0, 0 ) end local remainingSupplies = currentSupplies - suppliesToTake --outputDebugString(currentSupplies.."-"..suppliesToTake) if remainingSupplies < 0 and (interiorType ~= 2) then return false, "This item is out of stock." else status[6] = remainingSupplies setElementData(interior, "status", status, true) if remainingSupplies < 50 and ownerID == getElementData(client, "dbid") then outputChatBox( "Supplies in your business #" .. dimension .. " are low. Fill 'em up. ((use /ordersupplies))", client, 255, 194, 14 ) end -- take the outstanding supplies dbExec(mysql:getConnection(),"UPDATE `interiors` SET `supplies` = '"..remainingSupplies.."' WHERE id = " .. (dimension)) return true, "Cool." end return false, "Error code 'ESDAFE1241', please report to Maxime" end end end globalSupplies = 0 function updateGlobalSupplies(value) globalSupplies = globalSupplies + value dbExec(mysql:getConnection(),"UPDATE settings SET value='" .. (tostring(globalSupplies)) .. "' WHERE name='globalsupplies'") end addEvent("updateGlobalSupplies", true) addEventHandler("updateGlobalSupplies", getRootElement(), updateGlobalSupplies) addEvent("shop:handleSupplies", true) function handleSupplies(element, slot, event, worldItem) return false end addEventHandler("shop:handleSupplies", getRootElement(), handleSupplies) function canIUseThisName(pedName) return true, "This name is cool" end function shopRemoteOrderSupplies(thePlayer, dim, weight) return success end addEvent("shop:shopRemoteOrderSupplies", true) addEventHandler("shop:shopRemoteOrderSupplies", getRootElement(), shopRemoteOrderSupplies) function resStart() dbQuery( function(qh) local res, rows, err = dbPoll(qh, 0) if rows > 0 then for index, row in ipairs(res) do globalSupplies = tonumber(row["value"]) or 0 end end end, mysql:getConnection(), "SELECT value FROM settings WHERE name='globalsupplies' LIMIT 1") end addEventHandler("onResourceStart", getResourceRootElement(), resStart)