Sleash

[Pawn][PHP] Привязка ВК к игровому аккаунту

В теме 4 сообщения

Итак, всем доброго времени суток.

Сегодня я хочу рассказать и показать, как грамотно подключить систему привязки VK к игровым аккаунтам.

Для начала рассмотрим настройку Вашей группы в ВК, которая будет присылать сообщения пользователям в ВК:

1. Переходим в Вашу группу в ВК

2. Переходим в управление сообществом:

Спойлер

655b4a44261b8__2023-11-20_150003610.png.f8dd4908a5c52e3839cf9dbd720a3607.png

3. Переходим в раздел "Сообщения", и разрешаем сообщения сообществу, сохраняем

Спойлер

655b4bfe0c62b__2023-11-20_150725657.png.b105b8084347a75305b98c611527745d.png

4. Переходим в "Настройки" -> "Работа с API" и создаём ключ (если он у вас уже создан, то просто копируем его)

Спойлер

655b4c7cac9f3__2023-11-20_150931965.png.99e019aab0519d0c72a5cfed833d667c.png

5. В высветившемся списке выбираем "Разрешить приложению доступ к сообщениям сообщества" и нажимаем "Создать"

Спойлер

655b4cd029259__2023-11-20_151055669.png.1f0b99be396d9ecef004b6531dfb61e9.png

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

Спойлер

655b4d457f7a4__2023-11-20_151253063.png.8cf1386523dbf9a8c694da81b93e4541.png

7. Переходим на главную страницу сообщества и разрешаем сообщения

Спойлер

655b4e2cdf8c3__2023-11-20_151643741.png.d2af8cd760c298fa8193a6172a4b1741.png

Далее нам надо создать и залить на веб-хостинг наш PHP-файл, который будет обрабатывать запрос от хостинга

Перейдём к созданию PHP файла:

<?php // Объявляем PHP-файл
$token_vk = "vk1.a.Pl1D4M...";                          // Сюда вводим токен, полученный в группе ВК
$msg = $_GET["msg"];                                    // Получаем сообщение из GET-запроса (msg=...) 
$msg = iconv('Windows-1251''UTF-8'$msg);            // Делаем нужную кодировку сообщения (Из-за кириллицы)
$msg = urlencode($msg);                                 // Заного кодируем строку для запроса в ВК
$def_id = $_GET["id"];                                  // Получаем ID пользователя из GET-запроса (id=...)
if(stripos($def_id"/") !== false)                     // Проверка на наличие слешей в ID
    $def_id = substr($def_id, strrpos($def_id"/")+1); // Удаляем всё, что до последнего слеша, и сам слеш
    // Код выше способствует следующим преображениям:
    // vk.com/olegsleash            ->      olegsleash
    // https://vk.com/id405249405   ->      id405249405
if(stripos($def_id"@") !== false)                     // Проверка на наличие "собачки" в ID
    $def_id = substr($def_id, strrpos($def_id"@")+1); // Удаляем всё, что до последней "собачки", и саму "собачку"
    // Код выше способствует следующим преображениям:
    // @olegsleash      ->      olegsleash
    // @id405249405     ->      id405249405
if(stripos($def_id"id") === 0)                        // Проверка на "id" в началае строки
    $def_id = substr($def_id2);                       // Удаление "id" из начала строки
    // Код выше способствует следующим преображениям:
    // id405249405  ->      405249405

// Отправка сообщений в ВК невозможна при помощи короткого имени (olegsleash)
// Поэтому для нормальной и красивой работы получаем имя и числовое ID пользователя:
// Генерируем и отправляем запрос в ВК о получении данных пользователя по его короткому имени/ID:
$httpsfile1 = file_get_contents("https://api.vk.com/method/users.get?access_token=$token_vk&fields=maiden_name&name_case=nom&v=5.154&user_id=$def_id");
$id_data = json_decode($httpsfile1true);              // Переводим строку, которую получили в JSON-таблицу
$def_id = $id_data['response'][0]['id'];                // получаем числовое ID пользователя из овтета ВК
$fn = iconv('UTF-8','Windows-1251'$id_data['response'][0]['first_name']);     // Получаем имя пользователя из овтета ВК
$ln = iconv('UTF-8','Windows-1251'$id_data['response'][0]['last_name']);      // Получаем фамилию пользователя из овтета ВК
// Теперь, когда у нас есть числово ID пользователя, можно отправить сообщение:
// Генерируем и отправляем запрос в ВК с сообщением пользователю:
file_get_contents("https://api.vk.com/method/messages.send?random_id=0&v=5.154&message=$msg&user_id=$def_id&access_token=$token_vk");
print "$def_id,$fn,$ln"// Выводим на страницу ID, имя и фамилию пользователя для callback'a в Pawn
// Завершаем PHP-файл
?>

Сохраняем данный файл под любым названием на хостинг (инструкцию по загрузке файлов можете посмотреть на выбранном Вами хостинге)

Дальше нам надо создать столбцы в базе mysql следующими запросами:

ALTER TABLE `Таблица с акк-ами` ADD vkName TEXT NOT NULL, vkID TEXT NOT NULL, vkStatus INT NOT NULL;

Теперь перейдём к работе с модом:

Для начала импортируем нужные нам плагины и инклуды:

#include <a_samp>       // Думаю понятно для чего нужен a_samp
#include <a_http>       // a_http нужен для создания запросов на сайты
#include <sscanf2>      // sscanf нужен для извлечения данных из ответа сайта
#include <Pawn.CMD>     // Pawn.CMD нужен для использовния команд привязки и отвязки ВК
// Вы можете использовать любой коммандны процессор
#include <a_mysql>      // a_mysql нужен для взаимодействие информацией в базе данных
main(){}                // main как минимум нужен для предотвращения ошибки в консоле при запуске

Дальше пройдёмся по дефайнам, которые я создал для удобной работы:

#define VK_FILE             "yourSise.ru/vk_file.php?"              // Ссылка на ваш PHP-файл
                                                                    // Да, надо искать хостинг, можно бесплатный
                                                                    // Я могу посоветовать sprinthost (не реклама)
#define VK_GROUP            "{0099FF}vk.com/{ffffff}"               // Ссылка на группу сервера в ВК
#define COLOR_ERROR         0xE03F2DFF                              // Бардовый цвет для ошибки (красный не очень)) )
#define DLG_VK_LINK         3175                                    // ID диалога для ввода ссылки на свой ВК
#define DLG_VK_CODE         3176                                    // ID диалога для ввода кода привязки, который придёт в ВК
#define DLG_VK_UNLINK       3177                                    // ID диалога для отвязки ВК
#define DLG_VK_UNCODE       3178                                    // ID диалога для ввода кода отвязки, который придёт в ВК
#define DB_ACCOUNTS         "users"     // Таблица в MySQL-БД с данными аккаунтов   // Заменить на своё
#define DB_ACCOUNTS_NAME    "name"      // Столбец в MySQL-БД с ником аккаунта      // Заменить на своё

Далее создаём переменные для временного хранения информации о игроке:

new str_1[512];                         // Создаём строку для обработки
enum playerVK {                         // Создаём enum для хранения информации о данных ВК игрока
    vkName[64],                         // Имя игрока в ВК
    vkID[16],                           // ID игрока в ВК
    vkStatus                            // Статус привязки к ВК у икрока
}; new plVK[MAX_PLAYERS][playerVK];     // Создаём переменную под каждого игрока

Функции, которые я использовал для сокращения кода в дальнейшем:

stock SendError(playerid, text[]) {                             // Функция отправки ошибки игроку
    format(str_1, sizeof(str_1), "[Ошибка] {ffffff}%s", text);  // Форматирование строки с ошибкой
    return SendClientMessage(playerid, COLOR_ERROR, str_1);     // Отравка ошибки игроку
}
stock SendVKMessage(playerid, msg[], id[], callback[] = "") {   // Отправка сообщения игроку в ВК
    new buf_msg[512]; strmid(buf_msg, msg, 0, strlen(msg));     // Создаём буфер для сообщения, ибо кодировка удлиняет строку
    new buf_id[64];   strmid(buf_id,  id,  0, strlen(id));      // Создаём буфер для ID игрока, ибо кодировка удлиняет строку
    StringURLEncode(buf_msg);                                   // Кодируем сообщение
    StringURLEncode(buf_id);                                    // Кодируем ID игрока
    // Кодировка нужна для того, что бы наша ссылка с HTTP-запросом воспринималась верно
    format(str_1, sizeof(str_1), "%smsg=%s&id=%s",VK_FILE, buf_msg, buf_id);
    // Выше мы составляем строку с запросом к нашему PHP-файлу
    HTTP(playerid, HTTP_GET, str_1, "", callback);              // Создаём GET-Запрос, мне GET как-то ближе))
}
// Данная функция кодировки была позимствована у другого скриптера))
stock StringURLEncode(string[], size = sizeof(string))
{
    for(new i = 0, l = strlen(string), hex[8]; i < l; i++)
    {
        switch(string[i]) {
            case '!','(',')','\'','*','0'..'9','A'..'Z','a'..'z'continue;
            case ' ': {string[i] = '+'continue;}
        }
        if(i+3 >= size) {string[i] = EOS; return 0;}
        if(l+3 >= size) string[size-3] = EOS;
        format(hex, sizeof(hex), "%02h", string[i]);
        string[i] = '%';
        strins(string, hex, i + 1, size);
        l += 2; i += 2;
        if (l > size - 1) l = size - 1;
    }
    return 1;
}

Следующим шагом создаём коллбэки для получения информации о созданных запросах к нашему PHP файлу:

forward VKLinkAPI(playerid, resp, data[]);  // Создаём callback для получения данных
public VKLinkAPI(playerid, resp, data[]) {  // Используем callback для получения данных
    if(resp != 200) {                   // Если ответ от сервера НЕ равен 200
        return SendError(playerid, "{0099FF}[VK] {ffffff}Техническая ошибка сервера. Свяжитесь с разработчиком.");
        // Причины такого ответа:
        //  Ошибка в коде PHP-файла
        //  Неверно указана ссылка на PHP-файл
        //  Был удалён сайт с файлом (неуплата / неактив) на хостинге
    }
    new first_name[32], last_name[32];                                                      // Создаём переменные для получения информации о пользователе
    if(!sscanf(data, "p<,>s[16]s[32]s[32]", plVK[playerid][vkID], first_name, last_name)) { // Если от сервера полчен ожидаемый ответ
        // Можете не спрашивать, почему я сделал ID игрока строкой, а не числом, я так захотел))
        new full_name[64];                                                                  // Создаём переменную под полное имя игрока в ВК
        format(full_name, 64"%s %s", first_name, last_name);                              // Соеденяем имя и фамилию
        strmid(plVK[playerid][vkName], full_name, 0, strlen(full_name));                    // Записываем имя игрока в переменную
        // Форматируем строку и показываем игроук диалог
        format(str_1, sizeof(str_1), "{ffffff}На вашу страницу {0099FF}%s {ffffff}[{0099FF}%s{ffffff}] был отправлен код подтверждения\n\
                                              Пожалуйста, введите его в поле ниже:", plVK[playerid][vkName], plVK[playerid][vkID]);
        ShowPlayerDialog(playerid, DLG_VK_CODE, DIALOG_STYLE_INPUT, "Подтверждение VK", str_1, "Отправить""Отмена"); // Открываем диалог
    } else {        // Если же ответ от сервера не тот, что мы ожидает
        // print("(Слово удалено системой) выходит");
        return SendError(playerid, "{0099FF}[VK] {ffffff}Техническая ошибка сервера. Свяжитесь с разработчиком.");
    }
    return 1;
}
forward VKUnLinkAPI(playerid, resp, data[]);
public VKUnLinkAPI(playerid, resp, data[]) {
    if(resp != 200return SendError(playerid, "{0099FF}[VK] {ffffff}Техническая ошибка сервера. Свяжитесь с разработчиком.");
    new unused_str1[16], unused_str2[32], unused_str3[32]; // для обхода варнинга
    if(!sscanf(data, "p<,>s[16]s[32]s[32]", unused_str1, unused_str2, unused_str3)) {
        #pragma unused unused_str1 // Убираем строки из пользования
        #pragma unused unused_str2
        #pragma unused unused_str3
        format(str_1, sizeof(str_1), "{ffffff}На вашу страницу {0099FF}%s {ffffff}[{0099FF}%s{ffffff}] был отправлен код подтверждения\n\
                                              Пожалуйста, введите его в поле ниже:", plVK[playerid][vkName], plVK[playerid][vkID]);
        ShowPlayerDialog(playerid, DLG_VK_UNCODE, DIALOG_STYLE_INPUT, "Подтверждение VK", str_1, "Отправить""Отмена"); // Открываем диалог
    } else return SendError(playerid, "{0099FF}[VK] {ffffff}Техническая ошибка сервера. Свяжитесь с разработчиком.");
    return 1;
}

Так же не забываем добавить команды для активации диалога с привязкой/отвязкой ВК-Аккаунта:

CMD:linkvk(playerid) {                          // Команда для привязки ВК
    if(plVK[playerid][vkStatus]) return SendError(playerid, "{0099FF}[VK]{ffffff} У Вас уже привязан ВК-аккаунт"); // Ошибка, если у игрока уже привязан ВК
    new VK_code = 100000 + random(899999);      // Генерируем код для ВК
    SetPVarInt(playerid, "VKCode", VK_code);    // Привязываем код к игроку;
    // Форматируем текст диалога и открываем его для игрока
    format(str_1, sizeof(str_1), "{ffffff}Привязка VK\n\
                                          Для того, что привязать аккаунт ВК, выполните несколько действий:\n\
                                          \t1. Перейдите в нашу группу %s\n\
                                          \t2. Разрешите сообщение от группы\n\
                                          \t3. Введите ID/короткое имя/ссылку ваше страницы в ВК.\n\
                                          \t\tПримеры:\n\
                                          \t\t\t- {0099FF}405249405{ffffff}\n\
                                          \t\t\t- {0099FF}@olegsleash{ffffff}\n\
                                          \t\t\t- {0099FF}vk.com/id405249405{ffffff}\n\
                                          \t\t\t- {0099FF}https://vk.com/olegsleash{ffffff}\n\
                                          \t\t\t- И т.д.", VK_GROUP);
    ShowPlayerDialog(playerid, DLG_VK_LINK, DIALOG_STYLE_INPUT, "Привязка ВК", str_1, "Отправить""Отмена");
    return 1;
}
CMD:unlinkvk(playerid) {
    if(!plVK[playerid][vkStatus]) return SendError(playerid, "{0099FF}[VK]{ffffff} У Вас не привязан ВК-аккаунт"); // Ошибка, если у игрока не привязан ВК
    SetPVarInt(playerid, "VKCode"100000 + random(899999));    // Генерируем и привязываем код к игроку;
    // Форматируем текст диалога и открываем его для игрока
    format(str_1, sizeof(str_1), "Вы действительно хотите отвязать ВК-аккаунт {0099FF}%s {ffffff}[{0099FF}%s{ffffff}]?", plVK[playerid][vkName], plVK[playerid][vkID]);
    ShowPlayerDialog(playerid, DLG_VK_UNLINK, DIALOG_STYLE_MSGBOX, "Отвязка ВК", str_1, "Да""Отмена");
    return 1;
}

Соответственно добавляем работу с диалогами:

public OnDialogResponse(playerid, dialogid, response, listitem, inputtext[]) {
    switch(dialogid) {
        case DLG_VK_LINK: {
            if(!response) return false// Если игрок нажал "Отмена"
            if(!(5 <= strlen(inputtext) <= 50)) return SendError(playerid, "{0099FF}[VK]{ffffff} Длина ссылки не может быть меньше 6 и более 50 символов!");
            // Форматируем строку и отправляем сообщение в ВК игроку
            format(str_1, sizeof(str_1), "Используте следующий код для привязки ВК-Аккаунта для игрового аккаунта: %d", GetPVarInt(playerid, "VKCode"));
            SendVKMessage(playerid, str_1, inputtext, "VKLinkAPI"); // Отправляем запрос PHP-файлу с callback = VKLinkAPI
        } case DLG_VK_CODE: {
            if(!response) {
                strmid(plVK[playerid][vkName], "None"04);
                strmid(plVK[playerid][vkID],   "None"04);
                plVK[playerid][vkStatus]    = 0;
            } // Очищаем данные при отказе вводить код
            if(!strlen(inputtext) || !strval(inputtext)) {
                format(str_1, sizeof(str_1), "{ffffff}На вашу страницу {0099FF}%s {ffffff}[{0099FF}%s{ffffff}] был отправлен код подтверждения\n\
                                              Пожалуйста, введите его в поле ниже:", plVK[playerid][vkName], plVK[playerid][vkID]); // Форматируем строку для диалога
                return ShowPlayerDialog(playerid, DLG_VK_CODE, DIALOG_STYLE_INPUT, "Подстверждение VK", str_1, "Отправить""Отмена"); // Открываем диалог
            } // Если игрок ничего не ввёл или в строке не только цифры
            new input_code = strval(inputtext);
            if(input_code == GetPVarInt(playerid, "VKCode")) { // Если код тот, что отправили в ВК
                SendClientMessage(playerid, 0x0099FFFF"[VK] {ffffff}Вы успешно привязали свою страницу к аккаунту!");
                plVK[playerid][vkStatus] = 1// Статус привязкки ВК устанавливаем на "ДА"
                SaveVKData(playerid);            // Сохраняем данные ВК в базу данных
            } else { // Если код не совпадает
                SendError(playerid, "{0099FF}[VK]{ffffff} Вы ввели неверный код подтверждения!");
                format(str_1, sizeof(str_1), "{ffffff}На вашу страницу {0099FF}%s {ffffff}[{0099FF}%s{ffffff}] был отправлен код подтверждения\n\
                                              Пожалуйста, введите его в поле ниже:", plVK[playerid][vkName], plVK[playerid][vkID]); // Форматируем строку для диалога
                return ShowPlayerDialog(playerid, DLG_VK_CODE, DIALOG_STYLE_INPUT, "Подстверждение VK", str_1, "Отправить""Отмена"); // Открываем диалог
            }
        } case DLG_VK_UNLINK: {
            if(!response) return false// Если игрок нажал "Отмена"
            // Форматируем строку и отправляем сообщение в ВК игроку
            format(str_1, sizeof(str_1), "Используте следующий код для отвязки ВК-Аккаунта для игрового аккаунта: %d", GetPVarInt(playerid, "VKCode"));
            SendVKMessage(playerid, str_1, plVK[playerid][vkID], "VKUnLinkAPI"); // Отправляем запрос PHP-файлу с callback = VKUnLinkAPI
        } case DLG_VK_UNCODE: {
            if(!response) return false;
            if(!strlen(inputtext) || !strval(inputtext)) {
                format(str_1, sizeof(str_1), "{ffffff}На вашу страницу {0099FF}%s {ffffff}[{0099FF}%s{ffffff}] был отправлен код подтверждения\n\
                                              Пожалуйста, введите его в поле ниже:", plVK[playerid][vkName], plVK[playerid][vkID]); // Форматируем строку для диалога
                return ShowPlayerDialog(playerid, DLG_VK_UNCODE, DIALOG_STYLE_INPUT, "Подстверждение VK", str_1, "Отправить""Отмена"); // Открываем диалог
            } // Если игрок ничего не ввёл или в строке не только цифры
            new input_code = strval(inputtext);
            if(input_code == GetPVarInt(playerid, "VKCode")) { // Если код тот, что отправили в ВК
                SendClientMessage(playerid, 0x0099FFFF"[VK] {ffffff}Вы успешно отвязали свою страницу от аккаунта!");
                strmid(plVK[playerid][vkName], "None"04);
                strmid(plVK[playerid][vkID],   "None"04);
                plVK[playerid][vkStatus]    = 0;
                SaveVKData(playerid);            // Сохраняем данные ВК в базу данных
            } else { // Если код не совпадает
                SendError(playerid, "{0099FF}[VK]{ffffff} Вы ввели неверный код подтверждения!");
                format(str_1, sizeof(str_1), "{ffffff}На вашу страницу {0099FF}%s {ffffff}[{0099FF}%s{ffffff}] был отправлен код подтверждения\n\
                                              Пожалуйста, введите его в поле ниже:", plVK[playerid][vkName], plVK[playerid][vkID]); // Форматируем строку для диалога
                return ShowPlayerDialog(playerid, DLG_VK_UNCODE, DIALOG_STYLE_INPUT, "Подстверждение VK", str_1, "Отправить""Отмена"); // Открываем диалог
            }
        }
    }
    return 1;
}

Ну и само собой загрузка и сохранение данных ВК игроков в базу данных:

stock SaveVKData(playerid) {    // Функция созранения ВК-данных игрока
    new playerNName[MAX_PLAYER_NAME];
    GetPlayerName(playerid, playerNName, MAX_PLAYER_NAME);
    format(str_1, sizeof(str_1), "UPDATE `%s` SET `vkName` = '%s', `vkID` = '%s', `vkStatus` = '%d' WHERE `%s' = '%s' LIMIT 1",\
        DB_ACCOUNTS, plVK[playerid][vkName], plVK[playerid][vkID], plVK[playerid][vkStatus], DB_ACCOUNTS_NAME, playerNName);
    // Создаём запрос в базу данных
    mysql_query(1, str_1, false);
}
stock LoadVKData(playerid) {
    new playerNName[MAX_PLAYER_NAME];
    GetPlayerName(playerid, playerNName, MAX_PLAYER_NAME);
    format(str_1, sizeof(str_1), "SELECT `vkName`, `vkID`, `vkStatus` FROM `%s` WHERE `%s' = '%s' LIMIT 1", DB_ACCOUNTS, DB_ACCOUNTS_NAME, playerNName);
    // Создаём запрос в базу данных
    new Cache:vk_cache = mysql_query(1, str_1, true);
    cache_get_field_content(0"vkName", plVK[playerid][vkName]);       // Получаем имя аккаунта ВК
    cache_get_field_content(0"vkID", plVK[playerid][vkID]);           // Получаем ID аккаунта ВК
    plVK[playerid][vkStatus] = cache_get_field_content(0"vkStatus");  // Получаем статус привязки
    cache_delete(vk_cache);
    return 1;
}

Теперь перейдём к тестированию кода:

Скриншоты привязки ВК:

Спойлер

655b5751ed459__2023-11-20_155545292.png.ed128315059459445471637401a09262.png

655b575c75cf8__2023-11-20_155556102.png.3552953965941f0f2a4ec30ba98bbc81.png

655b5768b6bdc__2023-11-20_155608170.png.aaeee7e62f4754b7c66b851b624c18d7.png

655b57711da52__2023-11-20_155616691.png.41900e6a255d8edccbfd28249c771bd9.png

655b57d49d563__2023-11-20_155756186.png.e73d7034f514a9b1a8514518fcece4a4.png

Скриншоты отвязки ВК:

Спойлер

655b57f2aeba3__2023-11-20_155826274.png.f0de8ebbfa79fa5ff0795b47e4c2af40.png

655b580d920b6__2023-11-20_155853192.png.804f5f8610f218295ac732c8682952ff.png

655b5823d8b41__2023-11-20_155915192.png.3d25b1ffc024151ff40e6bee0c566568.png

655b583a8546e__2023-11-20_155938145.png.d93ea51672092727ff9199e9b15e11e2.png

На этом я бы хотел закончить свой урок, всем хорошего настроения!

P.S. Дядюшка Cawfee, пожалуйста не выдавай предупреждение за код, я не хочу, что бы моя темы выглядела как совокупность спойлеров)

Отредактировано пользователем Sleash

Заметка от Cawfee , создано

Дядюшка тебя услышал :)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

не хватает примера использования привязки

я думаю у многих ещё возникнут вопросы как добавить в авторизацию это

а так всё отлично, мне понравилась тема

Отредактировано пользователем trevison

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

скинь все это в блакноте в зип файле пж пж

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

@egorik_drugsik если вы копируете, вставляете в павн и у вас в тексте вопросики, то смените раскладку на русскую, скопируйте заново и вставьте

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Для публикации сообщений создайте учётную запись или авторизуйтесь

Вы должны быть пользователем, чтобы оставить комментарий

Создать учетную запись

Зарегистрируйте новую учётную запись в нашем сообществе. Это очень просто!


Регистрация нового пользователя

Войти

Уже есть аккаунт? Войти в систему.


Войти

  • Последние посетители   0 пользователей онлайн

    Ни одного зарегистрированного пользователя не просматривает данную страницу

  • Похожий контент

    • SheikhMAN
      От SheikhMAN
      Приветствую коллеги, не могли бы мне помочь? Не запускается сервер ( error 035: argument type mismatch (argument 4) )