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);
|