Город Мастеров
IPB

Здравствуйте, гость ( Вход | Регистрация )

 
Ответить в эту темуОткрыть новую тему
> Скрипты: списки, обмен идеями и скриптами
_kaa_
сообщение Nov 11 2004, 15:39
Сообщение #1


Level 9
Иконки Групп

Класс: Волшебник
Характер: Chaotic Good
Раса: Дракон
NWN: Скриптинг [PW]



Вашему вниманию представляется бета-версия маленькой библиотеки для работы со списками.
Списки храняться в БД (стандартной, переделать под mySQL - 5 минут)
Список - это просто некоторое количество строк, к которым можно обратиться по номеру или поискать в нем нужную подстроку
Есть несколько готовых функций - добавить строку к списку, удалить строку, показать список и т.п.
Список кэшируется в памяти, скорость работы приемлимая (Максимальные объемы не тестировались)

Для чего это нужно?
Для начала реальное использование:
Хранение "черного" списка IP (с использованием масок). ДМ из игры может занести кого надо в черный список или наоборот - удалить из списка.

Другие варианты использования:
Создание почтовой системы, досок объявлений, комментов и т.п. и т.д.

Списки дают возможность легко добавить данные, хранить их в БД, кэшировать и "перепаковывать" базу в случае большого числа удаленных записей.

Вот сама библиотека и чуть ниже будет рабочий пример.

Neverwinter Script Source
//::///////////////////////////////////////////////
//:: Name Списки
//:: FileName _inc_list.nss
//:: Copyright © 2004 by _kaa_ (Midgard)
//:://////////////////////////////////////////////
/*
*/

//:://////////////////////////////////////////////
//:: Created By: _kaa_
//:: Created On: 06/11/2004
//:: Version : 0.9b
//:://////////////////////////////////////////////

#include "_inc_cra_debug"              //Функции вывода DEBUG-сообщений

const string sListPre = "_list";      //Префикс имени БД со списками
const int debug = 1;                  //1 - включены debug-сообщениЯ по спискам

//:///////////////////////////////////////////////

//добавить запись sRecord в список sListName
void _list_AddRecord(string sListName,string sRecord);

//удалить запись с номером nRecord из списка sListName
void _list_DeleteRecord(string sListName,int nRecord);

//получить запись с номером nRecord из списка sListName
string _list_GetRecord(string sListName,int nRecord);

//предварительное кэширование списков,
//можно добавить в скрипт на событие onModuleLoad
void _list_ReadList(string sListName);

//получить весь список sListName как одну строку. каждый элемент идет со своим номером
string _list_GetAllAsString(string sListName);

//удалить список sListName
void _list_DeleteList(string sListName);

//найти подстроку sPattern в списке sListName.
//возвращает номер в списке или -1 если ничего не найдено
//список нумеруетсЯ с 1
//если nLike == FALSE - используетсЯ "жесткое" сравнение
//если nLike == TRUE вместо операции == используетсЯ функциЯ TestStringAgainstPattern(), котораЯ понимает ** и прочие символы.
//подробнее в лексиконе по функции TestStringAgainstPattern()
int _list_IsInList(string sListName,string sPattern,int nLike = FALSE);


//Упаковать базу.
//Упаковка баз происходит автоматически, если число удаленных элементов составило более 50% записей.
//ФункициЯ просто удалЯет старую БД и записывает в нее данные по новой, перенумеровываЯ их
//Поэтому вызовать ОБЯЗАТЕЛЬНО после функций _list_ReadList() или _list_GetRecord()
void _list_RepackList(string sListName);

//:///////////////////////////////////////////////

int _list_GetRecordCount(string sListName)
{
    int result = GetLocalInt(GetModule(),sListPre+sListName+"_count");
    if (result)
        return result;
    else
        return GetCampaignInt(sListPre+sListName,"_count");
}

void _list_SetRecordCount(string sListName,int nCount)
{
    SetCampaignInt(sListPre+sListName,"_count",nCount);
    SetLocalInt(GetModule(),sListPre+sListName+"_count",nCount);
}

void _list_AddRecord(string sListName,string sRecord)
{
    int nCount = _list_GetRecordCount(sListName);
    nCount++;
    SetCampaignString(sListPre+sListName,"r"+IntToString(nCount)+"x",sRecord);
    SetLocalString(GetModule(),sListPre+sListName+"r"+IntToString(nCount)+"x",sRecord);
    _list_SetRecordCount(sListName,nCount);
    if (debug)
        WD2("LIST:ADD: ["+sListName+"] "+IntToString(nCount)+" = "+sRecord);
}

void _list_DeleteRecord(string sListName,int nRecord)
{
    DeleteCampaignVariable(sListPre+sListName,"r"+IntToString(nRecord)+"x");
    DeleteLocalString(GetModule(),sListPre+sListName+"r"+IntToString(nRecord)+"x");
    if (debug)
        WD2("LIST:DEL: ["+sListName+"] rec.num="+IntToString(nRecord));

}

void _list_RepackList(string sListName)
{
    int nCount = _list_GetRecordCount(sListName);
    if (!nCount)
    {
        if (debug)
            WD2("LIST:REPACK: Error, empty list ["+sListName+"]");
        return;
    }
    DestroyCampaignDatabase(sListPre+sListName);
    int k,newk=0;
    string sValue = "";
    for (k=1;k<=nCount;k++)
    {
        sValue = GetLocalString(GetModule(),sListPre+sListName+"r"+IntToString(k)+"x");
        if (sValue != "")
        {
            newk++;
            SetCampaignString(sListPre+sListName,"r"+IntToString(newk)+"x",sValue);
            if (debug)
                WD2("LIST:REPACK: ["+sListName+"] "+IntToString(newk)+". "+sValue);
        }
    }
    _list_SetRecordCount(sListName,newk);
    _list_ReadList(sListName);
}

void _list_ReadList(string sListName)
{
    int nCount = _list_GetRecordCount(sListName);
    if (!nCount)
    {
        if (debug)
            WD2("LIST:CACHE: empty ["+sListName+"]");
        return;
    }
    int k,deleted=0;
    string sValue = "";
    for (k=1;k<=nCount;k++)
    {
        sValue = GetCampaignString(sListPre+sListName,"r"+IntToString(k)+"x");
        if (sValue != "")
        {
            SetLocalString(GetModule(),sListPre+sListName+"r"+IntToString(k)+"x",sValue);
            if (debug)
                WD2("LIST:CACHE: ["+sListName+"] "+IntToString(k)+". "+sValue);
        }
        else deleted++;
    }
    if (debug)
        WD2("LIST:CACHE: done. "+IntToString(deleted)+" deleted records");

    if (deleted > nCount/2)
        _list_RepackList(sListName);

}

string _list_GetRecord(string sListName,int nRecord)
{
    if (!_list_GetRecordCount(sListName)) _list_ReadList(sListName);
    return GetLocalString(GetModule(),sListPre+sListName+"r"+IntToString(nRecord)+"x");
}

string _list_GetAllAsString(string sListName)
{
    string sResult ="";
    int nCount = _list_GetRecordCount(sListName);
    if (!nCount)
    {
        if (debug)
            WD2("LIST:SHOW: empty ["+sListName+"]");
        return sResult;
    }
    int k;
    string sValue = "";

    for (k=1;k<=nCount;k++)
    {
        sValue = _list_GetRecord(sListName,k);
        sResult += "\n"+col_green+IntToString(k)+". "+col_end+sValue;
    }
    return sResult;

}

void _list_DeleteList(string sListName)
{
    _list_SetRecordCount(sListName,0);
    DestroyCampaignDatabase(sListPre+sListName);
}

int _list_IsInList(string sListName,string sPattern,int nLike = FALSE)
{
    if (debug)
        WD2("LIST:FIND: looking for '"+sPattern+"' in ["+sListName+"]");

    if (sPattern == "")
    {
        if (debug)
            WD2("LIST:FIND: empty string ["+sListName+"]");
        return -1;
    }
    int nCount = _list_GetRecordCount(sListName);
    if (!nCount)
    {
        if (debug)
            WD2("LIST:FIND: empty ["+sListName+"]");
        return -1;
    }
    int k,result=0;
    string sValue = "";

    for (k=1;k<=nCount;k++)
    {
        if (nLike)
        {
            result = TestStringAgainstPattern(_list_GetRecord(sListName,k),sPattern);
            if (debug && result)
                WD2("LIST:FIND: "+_list_GetRecord(sListName,k)+" LIKE "+sPattern);
            if (result) return result;
        }
        else
        {
            result = _list_GetRecord(sListName,k) == sPattern;
            if (debug && result)
                WD2("LIST:FIND: "+_list_GetRecord(sListName,k)+" == "+sPattern);
            if (result) return result;
        }
    }
    if (debug)
        WD2("LIST:FIND: not found "+sPattern+" ["+sListName+"]");
    return -1;

}


Вот простой пример. Берем НПС, убираем ему все скрипты
На событие onSpawn ставим скрипт:
Neverwinter Script Source
void main()
{
    SetListening(OBJECT_SELF, TRUE);
    SetListenPattern(OBJECT_SELF,"(show**|Show**|SHOW**)",3000);
    SetListenPattern(OBJECT_SELF,"(add|Add|ADD)*w(**)",3001);
    SetListenPattern(OBJECT_SELF,"(del|Del|DEL)*w(*n|all)",3002);
    SetListenPattern(OBJECT_SELF,"(repack|Repack|REPACK)",3003);
}


На событие onConversation:
Neverwinter Script Source
#include "_inc_list"

//Слушаем только тех, кто в пределах 8 метров
int _list_CheckDistance(object oToPC)
{
    return GetDistanceBetween(oToPC,OBJECT_SELF) < 8.0;
}

void main()
{
    int nMatch = GetListenPatternNumber();
    int nCount = GetMatchedSubstringsCount();

    //имЯ списка получаем из тега НПС (так очень удобно)
    string sListName = GetTag(OBJECT_SELF);

    object oShouter = GetLastSpeaker();

    //Показать список
    //Список тут выводитсЯ в чат только длЯ того, чтобы был потом виден в логах.
    //Можно заменить SpeakString на SendMessageToPC() если не нужно показывать другим
    if(nMatch == 3000)
    {
        if (!_list_CheckDistance(oShouter)) return;
        SpeakString(_list_GetAllAsString(sListName));
    }

    //Добавить запись
    if(nMatch == 3001)
    {
    if (!_list_CheckDistance(oShouter)) return;
    string sString = GetMatchedSubstring(2);
    _list_AddRecord(sListName,sString);
    SpeakString("Добавлено значение: "+sString);
    }

    //Удалить запись
    if(nMatch == 3002)
    {
        if (!_list_CheckDistance(oShouter)) return;
        int nNumber=0;
        string sParse = GetMatchedSubstring(2);
        if (sParse == "all" || sParse =="ALL")
        {
            _list_DeleteList(sListName);
            SpeakString("Список очищен");
            return;
        }
        else
        {
            nNumber = StringToInt(sParse);
            _list_DeleteRecord(sListName,nNumber);
            SpeakString("Запись "+IntToString(nNumber)+" удалена.");
        }
    }

    //Перепаковать БД
    if(nMatch == 3003)
    {
        if (!_list_CheckDistance(oShouter)) return;
        _list_RepackList(sListName);
        SpeakString("Упаковка списка");
    }


    if (nMatch == -1 && GetCommandable(OBJECT_SELF))
    {
        ClearAllActions();
        BeginConversation();
    }

}


Тег НПС - это и будет имя списка.
Подойдя к нему ближе 8 метров (без инвиза и прочего - чтобы он вас слышал) и сказав команду - вы можете управлять списком.
Команды:
show - показать список
add СТРОКА - добавит запись СТРОКА в список
del 1 - удалит 1-ю запись
del all - удалить весь список

В добавок приведу инклуд, что используется в _inc_list.nss
скрипт _inc_cra_debug:
Neverwinter Script Source
//colors
const string col_green    = "<c ю >";
const string col_blue    = "<czzю>";
const string col_red      = "<cю  >";
const string col_white    = "<cююю>";
const string col_yellow  = "<cюю >";
const string col_gray    = "<cZZZ>";
const string col_end      = "</c>";

//send debug string to oPC, to log, to DM
// if GetLocalInt(GetModule(),"DEBUG") & 1 == 1 - to logfile
// if GetLocalInt(GetModule(),"DEBUG") & 2 == 1 - to oPC
// if GetLocalInt(GetModule(),"DEBUG") & 4 == 1 - to allDM
void WD(object oPC,string sS);

//send debug string to log, to DM
// if GetLocalInt(GetModule(),"DEBUG") & 1 == 1 - to logfile
// if GetLocalInt(GetModule(),"DEBUG") & 4 == 1 - to allDM
void WD2(string sS);

//////////////////////////////////////////

void WD(object oPC,string sS)
{
    if (!GetIsObjectValid(oPC)) return;
    int nDEBUG = GetLocalInt(GetModule(),"DEBUG");
    if (nDEBUG)
    {
        if (! GetIsPC(oPC)) oPC = GetFirstPC();
        if (nDEBUG & 1) WriteTimestampedLogEntry("DEBUG: ["+GetName(oPC)+"]"+sS);
        if (nDEBUG & 2) SendMessageToPC(oPC,"DEBUG: "+sS);
        if (nDEBUG & 4) SendMessageToAllDMs("DEBUG: ["+GetName(oPC)+"]"+sS);
    }
}

void WD2(string sS)
{
    int nDEBUG = GetLocalInt(GetModule(),"DEBUG");
    if (nDEBUG)
    {
        if (nDEBUG & 1) WriteTimestampedLogEntry("DEBUG: "+sS);
        if (nDEBUG & 4) SendMessageToAllDMs("DEBUG: "+sS);
    }

}


Тут в зависимости от состояния глобальной переменной модуля DEBUG выводятся сообщения. Часто бывает очень полезно прямо в игре из ДМ_клиента включить отладку (dm_sevmodulevarint DEBUG 7)
Константы цветов можно использовать в выводе сообщений, диалогах и т.п., например вывести сообщение игроку красным цветом: SendMessageToPC(oPC,col_red+"Сообщение"+col_end);


Вернуться в начало страницы
Скопировать ник в поле быстрого ответа
+Ответить с цитированием данного сообщения
Аваддон
сообщение Nov 11 2004, 15:43
Сообщение #2


Level 10
***

Класс: Воин
Характер: Lawful Neutral
Раса: Человек
NWN: Скриптинг [PW]



_kaa_ GREAT RESPECT! Очень полезная вещь! Спасибо:) :good:
Вернуться в начало страницы
Скопировать ник в поле быстрого ответа
+Ответить с цитированием данного сообщения
Lex
сообщение Nov 12 2004, 19:36
Сообщение #3


Level 5
Иконки Групп

Класс: Обыватель
Характер: Lawful Neutral
Раса: Человек
NWN: Модмейкер
Проклятие Левора
Порядок Времени



Скопировал. Буду дома разбираться. (когда комп восстановлю)
Вернуться в начало страницы
Скопировать ник в поле быстрого ответа
+Ответить с цитированием данного сообщения

Ответить в эту темуОткрыть новую тему
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 



Текстовая версия Сейчас: 19th April 2024 - 20:12