script_name("phoneBomber")
script_author("flyingbaby")
script_version("001")

require 'lib.sampfuncs'
require 'lib.moonloader'

local encoding = require 'encoding'
encoding.default = 'CP1251'
u8 = encoding.UTF8

-- local sampev = require('lib.samp.events')
local memory = require('memory')
-- local ffi = require("ffi")
local socket = require 'socket'

local defaultDelaySms = 100
local defaultTimerSms = math.huge
local defaultTextSms = 'превет, любиш вишню???'
local lastTickTime = -1
local stopSmsKey = 221
local defaultTickLimit = math.huge

local defaultDelayCall = 100
local defaultTimerCall = math.huge
local stopCallKey = 221

local defaultWaitingTimeout = 500

function main()
	if not isSampfuncsLoaded() or not isSampLoaded() then return end
	while not isSampAvailable() do wait(100) end
	--sampRegisterChatCommand("callb", function(arg) lua_thread.create(callBomb, arg) end)
	--sampRegisterChatCommand("smsb", function(arg) lua_thread.create(smsBomb, arg) end) 
	sampRegisterChatCommand("testik", function(arg) lua_thread.create(dialogProcessor, arg) end)
	while true do
	
		if floodIsActive then	
			renderDrawBox( 100, 100, 100, 100, 0xFFD00000)
			if isKeyDown(80) then
				floodIsActive = false
			end
		end
		
		wait(0)
	end
end

function dialogProcessor()
	
	local categoryFlag		 = false
	local floodModeList		 = false
	local geotagModeFlag	 = false
	local victimPhoneNumber	 = false
	local timerLimit		 = false
	local tickLimit			 = false
	local waitingTimeout	 = false
	local messageContent	 = false
	
	local dialogActive = true
	
	while dialogActive do
		while sampIsDialogActive() do wait(100) end
		
		sampShowDialog(1488, 'Создание спам-атаки', "Название\tЗначение" ..
			"\n{4a86b6}- {ffffff}Категория{FFFF00}*\t{4a86b6}" .. (categoryFlag and "Звонки" or "Сообщения") ..
			"\n{4a86b6}- {ffffff}Режим{FFFF00}*\t{4a86b6}" .. (floodModeList == 1 and "Только чат" or (floodModeList == 2 and "Диалоги/текстдравы" or (floodModeList == 3 and "Комбинированный" or "Выберите режим"))) ..
			--"\n{4a86b6}- {ffffff}Тег в диалогах\t{4a86b6}" .. (geotagModeFlag and "Включено" or "Выключено") ..
			"\n{4a86b6}- {ffffff}Тег в диалогах\t{2d516e}В разработке" ..
			"\n{4a86b6}- {ffffff}Номер жертвы{FFFF00}*\t{4a86b6}" .. (victimPhoneNumber or "Введите номер") ..
			"\n{4a86b6}- {ffffff}Время работы\t{4a86b6}" .. (timerLimit and (type(timerLimit) == "string" and (#timerLimit > 8 and timerLimit:sub(1, 8).."..." or timerLimit) or tostring(timerLimit)) .. " секунд(ы)" or "Неограниченное") ..
			"\n{4a86b6}- {ffffff}Кол-во тиков\t{4a86b6}" .. (tickLimit and (type(tickLimit) == "string" and (#tickLimit > 8 and tickLimit:sub(1, 8).."..." or tickLimit) or tostring(tickLimit)) .. " секунд(ы)" or "Неограниченное") ..
			"\n{4a86b6}- {ffffff}Таймаут ожидания\t{4a86b6}" .. (waitingTimeout and tostring(waitingTimeout) .. "мс." or "По умолчанию (" .. defaultWaitingTimeout .. "мс.)") ..
			"\n{4a86b6}- {ffffff}Текст сообщения\t{4a86b6}" .. (messageContent and (#messageContent > 25 and messageContent:sub(1, 25).."..." or messageContent) or "По умолчанию") ..
			"\n{33AA33}> Начать выполнение\t \n" ..
			"\n{AA3333}> Закрыть меню\t \n", 'Выбрать', 'Назад', 5)
		
		while sampIsDialogActive(1488) do wait(100) end
		
		local _, button, list, _ = sampHasDialogRespond(1488)
		
		--Категория(флаг) Режим(лист) Тег(флаг) Номер(инпут) Время(инпут) Кол-во(инпут) Таймаут(инпут) Текст(инпут) 
		if button == 1 then 
			if list == 0 then
				categoryFlag = not categoryFlag
			elseif list == 1 then
				while sampIsDialogActive() do wait(100) end
				sampShowDialog(1489, 'Выбор режима работы скрипта',
					"{4a86b6}- {ffffff}Только чат" ..
					"\n{4a86b6}- {ffffff}Диалоги/текстдравы" ..
					"\n{4a86b6}- {ffffff}Комбинированный", 'Выбрать', 'Назад', 4)
				while sampIsDialogActive(1489) do wait(100) end
				local _, button, list, _ = sampHasDialogRespond(1489)
				
				if button == 1 then 
					if list == 0 then
						floodModeList = 1
					elseif list == 1 then
						floodModeList = 2
					elseif list == 2 then
						if not categoryFlag then
							floodModeList = 3
						else
							sampAddChatMessage("{AA3333}| {ffffff} Комбинированный режим недоступен для звонков!", -1)
							floodModeList = false 
						end
					end
				else
				end
			elseif list == 2 then
				sampAddChatMessage("{AA3333}| {ffffff} Режим отправки гео-позиции в разработке, следите за обновлениями!", -1)
				-- geotagModeFlag = not geotagModeFlag
			elseif list == 3 then
				local dialog3Active = true
				local textdrawInfobarColor = "{33AA33}"
				local textdrawErrorMessage = ""
				while dialog3Active do
					while sampIsDialogActive() do wait(100) end
					sampShowDialog(1490, 'Ввод номера жертвы', textdrawInfobarColor .. "| {ffffff}Введите номер жертвы." .. textdrawErrorMessage , 'Выбрать', 'Назад', 1)
					while sampIsDialogActive(1490) do wait(100) end
					local result, button, list, input = sampHasDialogRespond(1490)
					if button == 1 then
						if input and input:match("^%d%d%d%d%d%d$") then
							victimPhoneNumber = input
							dialog3Active = false
						elseif input == "" then
							victimPhoneNumber = false
							dialog3Active = false
						else
							textdrawInfobarColor = "{FFFF00}"
							textdrawErrorMessage = "\n\n{AA3333}|{ffffff} Неправильный формат номера!"
						end
					else
						dialog3Active = false
					end
				end
			elseif list == 4 then
				local dialog4Active = true
				local textdrawInfobarColor = "{33AA33}"
				local textdrawErrorMessage = ""
				while dialog4Active do
					while sampIsDialogActive() do wait(100) end
					sampShowDialog(1491, 'Ввод лимита по времени', textdrawInfobarColor .. "| {ffffff}Введите ограничение по времени {4a86b6}(в секундах.) {ffffff}работы спам-атаки.\n{4a86b6}| {ffffff}Оставьте поле пустым, чтобы убрать лимит." .. textdrawErrorMessage , 'Выбрать', 'Назад', 1)
					while sampIsDialogActive(1491) do wait(100) end
					local result, button, list, input = sampHasDialogRespond(1491)
					if button == 1 then
						if input and input ~= "" and tonumber(input) and #input < 8 then
							timerLimit = input
							dialog4Active = false
						elseif input == "" then
							timerLimit = false
							dialog4Active = false
						elseif not input or #input >= 8 or not tonumber(input) then
							textdrawInfobarColor = "{FFFF00}"
							textdrawErrorMessage = "\n\n{AA3333}|{ffffff} Введите корректное число!"
						end
					else
						dialog4Active = false
					end
				end
			elseif list == 5 then
				local dialog5Active = true
				local textdrawInfobarColor = "{33AA33}"
				local textdrawErrorMessage = ""
				while dialog5Active do
					while sampIsDialogActive() do wait(100) end
					sampShowDialog(1492, 'Ввод лимита по звонкам/сообщениям', textdrawInfobarColor .. "| {ffffff}Введите ограничение по количеству звонков/сообщений произведенных во время спам-атаки.\n{4a86b6}| {ffffff}Оставьте поле пустым, чтобы убрать лимит." .. textdrawErrorMessage , 'Выбрать', 'Назад', 1)
					while sampIsDialogActive(1492) do wait(100) end
					local result, button, list, input = sampHasDialogRespond(1492)
					if button == 1 then
						if input and input ~= "" and tonumber(input) and #input < 120 then
							tickLimit = input
							dialog5Active = false
						elseif input == "" then
							tickLimit = false
							dialog5Active = false
						elseif not input or #input >= 120 or not tonumber(input) then
							textdrawInfobarColor = "{FFFF00}"
							textdrawErrorMessage = "\n\n{AA3333}|{ffffff} Введите корректное число!"
						end
					else
						dialog5Active = false
					end
				end
			elseif list == 6 then
				local dialog6Active = true
				local textdrawInfobarColor = "{33AA33}"
				local textdrawErrorMessage = ""
				while dialog6Active do
					while sampIsDialogActive() do wait(100) end
					sampShowDialog(1493, 'Ввод лимита ожидания', textdrawInfobarColor .. "| {ffffff}Введите максимальное время ожидания ответа от сервера.\n{4a86b6}| {ffffff}Оставьте поле пустым, чтобы вернуть значение по умолчанию." .. textdrawErrorMessage , 'Выбрать', 'Назад', 1)
					while sampIsDialogActive(1493) do wait(100) end
					local result, button, list, input = sampHasDialogRespond(1493)
					if button == 1 then
						if input and input ~= "" and tonumber(input) and #input < 16 then
							waitingTimeout = input
							dialog6Active = false
						elseif input == "" then
							waitingTimeout = false
							dialog6Active = false
						elseif not input or #input >= 16 or not tonumber(input) then
							textdrawInfobarColor = "{FFFF00}"
							textdrawErrorMessage = "\n\n{AA3333}|{ffffff} Введите корректное число!"
						end
					else
						dialog6Active = false
					end
				end
			elseif list == 7 then
				local dialog7Active = true
				local textdrawInfobarColor = "{33AA33}"
				local textdrawErrorMessage = ""
				while dialog7Active do
					while sampIsDialogActive() do wait(100) end
					sampShowDialog(1494, 'Ввод текста сообщения', textdrawInfobarColor .. "| {ffffff}Введите текст отправляемого сообщеня.\n{4a86b6}| {ffffff}Оставьте поле пустым, чтобы вернуть текст по умолчанию." .. textdrawErrorMessage , 'Выбрать', 'Назад', 1)
					while sampIsDialogActive(1494) do wait(100) end
					local result, button, list, input = sampHasDialogRespond(1494)
					if button == 1 then
						if input and input ~= "" and #input < 120 then
							messageContent = input
							dialog7Active = false
						elseif input == "" then
							messageContent = false
							dialog7Active = false
						elseif not input or #input >= 120 then
							textdrawInfobarColor = "{FFFF00}"
							textdrawErrorMessage = "\n\n{AA3333}|{ffffff} Сообщение слишком длинное!"
						end
					else
						dialog7Active = false
					end
				end
			elseif list == 8 then
			
			-- local categoryFlag		  =	 false
			-- local floodModeFlag		  =	 false
			local geotagModeFlag	  =	 false
			local victimPhoneNumber	  =	 victimPhoneNumber or 111111
			local timerLimit		  =	 timerLimit or defaultTimerSms
			local tickLimit			  =	 tickLimit or defaultTickLimit
			local waitingTimeout	  =	 waitingTimeout or defaultWaitingTimeout
			local messageContent	  =	 messageContent or defaultTextSms
			
			lua_thread.create(dialogMessageSender, geotagModeFlag, victimPhoneNumber, timerLimit, tickLimit, waitingTimeout, messageContent)
			-- categoryFlag, floodModeFlag, geotagModeFlag, victimPhoneNumber, timerLimit, tickLimit, waitingTimeout, messageContent) 
			
			
			
			
			dialogActive = false
			
			elseif list == 9 then
				dialogActive = false
			end
		end
	end
end

function dialogMessageSender(geotagModeFlag, victimPhoneNumber, timerLimit, tickLimit, waitingTimeout, messageContent)
    local currentTime = socket.gettime
    floodIsActive = true
    local sendedMessages = 0
    local contactsId = nil
    local dialogCaption = nil
    local dialogText = nil

	while floodIsActive do	
	
		-- if isKeyDown(80) then
			-- floodIsActive = false
			-- break
		-- end
		
        sampSendClickTextdraw(175) -- Отправить клик по текстдраву

        if not contactsId then
            for textdrawId = 2206, 2227 do
                local textdrawText = sampTextdrawGetString(textdrawId)
                if textdrawText:match("CONTACTS") then
                    contactsId = textdrawId
                    break
                end
            end
        end

        if contactsId then
            sampSendClickTextdraw(contactsId) -- Отправить клик по кнопке контактов

            local startTime = currentTime()
            while not (dialogCaption and dialogCaption:match("Телефонная книга")) do
                if (currentTime() - startTime) * 1000 >= waitingTimeout then
                    floodIsActive = false
                    sampAddChatMessage("{FFFF00}| {ffffff}Тайм-аут ожидания открытия диалога", -1)
                    break
                end
                dialogCaption = sampGetDialogCaption()
                wait(0)
            end

            while floodIsActive do
				
				-- if isKeyDown(80) then
					-- floodIsActive = false
					-- break
				-- end
				
                local victimContactsPos = nil
                local victimContactsName = nil

                local startTime = currentTime()
                dialogCaption = sampGetDialogCaption()

                while not dialogCaption:find("Телефонная книга") do
                    if (currentTime() - startTime) * 1000 >= waitingTimeout then
                        floodIsActive = false
                        sampAddChatMessage("{FFFF00}| {ffffff}Тайм-аут повторного ожидания открытия диалога тел. книги", -1)
                        break
                    end
                    wait(0)
                    dialogCaption = sampGetDialogCaption()
                end

                dialogText = sampGetDialogText()

                for digit, number, name in dialogText:gmatch("%{4a86b6%}(.)%..-%{FFFFFF%}%s(%d%d%d%d%d%d)%s%{4a86b6%}(.-)%s*") do
                    if number == string.gsub(tonumber(victimPhoneNumber), "%s+", "") then
                        victimContactsPos = tonumber(digit)
                        victimContactsName = name
                        break
                    end
                end

                if victimContactsPos then
                    sampSendDialogResponse(32700, 1, victimContactsPos, nil)
                    memory.setint32(sampGetDialogInfoPtr() + 40, 0, true)

                    local startTime2 = currentTime()
                    while not dialogText or not dialogText:find("{FFFFFF}Написать сообщение") do
                        if (currentTime() - startTime2) * 1000 >= waitingTimeout then
                            floodIsActive = false
                            sampAddChatMessage("{FFFF00}| {ffffff}Тайм-аут ожидания открытия диалога написания сообщения", -1)
                            break
                        end
                        dialogText = sampGetDialogText()
                        wait(0)
                    end

                    if floodIsActive then
                        sampSendDialogResponse(32700, 1, 1)

                        local startTime3 = currentTime()
                        while not dialogText or not dialogText:find("{FFFF00}| {ffffff}Получатель: {FFFFFF}") do
                            if (currentTime() - startTime3) * 1000 >= waitingTimeout then
                                floodIsActive = false
                                sampAddChatMessage("{FFFF00}| {ffffff}Тайм-аут ожидания открытия диалога выбора получателя", -1)
                                break
                            end
                            dialogText = sampGetDialogText()
                            wait(0)
                        end

                        if floodIsActive then
                            sampSendDialogResponse(32700, 1, 0, messageContent)
                            sendedMessages = sendedMessages + 1
                            if sendedMessages < tonumber(tickLimit) then
								floodIsActive = false
                                startTime = currentTime()
                                while not dialogCaption or not dialogCaption:match("Телефонная книга") do
                                    if (currentTime() - startTime) * 1000 >= waitingTimeout then
                                        floodIsActive = false
                                        sampAddChatMessage("{FFFF00}| {ffffff}Тайм-аут ожидания открытия диалога телефонной книги", -1)
                                        break
                                    end
                                    dialogCaption = sampGetDialogCaption()
                                    wait(0)
								end
                            else
							    sampAddChatMessage("{33AA33}| {ffffff} Лимит сообщений в {4a86b6}" .. tickLimit .. "{ffffff} штук достигнут! Завершение работы...", -1)
                                
                                
                            end
                        end
                    end
                else
                    sampAddChatMessage("{AA3333}| {ffffff} Жертва {4a86b6}" .. victimPhoneNumber .. "{ffffff} не найдена, создайте новый контакт!", -1)
                    floodIsActive = false
                end
                wait(0)
            end
        else
            wait(0)
        end
        wait(0)
    end
end

--[[
TODO:
- проверять не открытый у клиента диалог, а синхру о показе диалога от сервера
- возможность скрыть диалоги во время работы скрипта (вытекает из прошлого пункта)
- режим отправки тега вместо сообщения, мб более понятно названный пункт
- основной диалог закрывающийся на кнопку назад, но только если прожать ее N-ное количество раз за N-ное время
- всякие (почти)бесполезные счетчики на gxt текстах, вроде количества сообщений в секунду/минуту/все время, среднего/последнего времени ожидания/выполнения на разных этапах
- возможность флудить не одному номеру, а сразу пачке указанных
- возможность рассылать сообщения по объявлениям с джи-бая(скорее всего на отдельную команду отдельным окном, возможно с выбором отдельных категорий и поиском по ключ словам)
- возможность отправлять несколько текстов случайно/последовательно выбираемыми
- банальное доведение до работоспособного состония
- многочисленные багфиксы, всех тех дыр, что обязательно вылезут с моим говнокодом
]]