Leaderboard
Popular Content
Showing content with the highest reputation on 01/08/12 in Posts
-
2 points
-
I have personally never used it either. I've always used each server on its own screen (Screens: Login/Char/Map). Would be an interesting idea of athena-start automatically started all servers in their respective screens =]2 points
-
Quote Download Map : koth01.grf Download Script : King of the Hill.txt 4.69K 203 downloads King of the Hill.txt 4.6K 296 downloads Quote Quote Quote Quote King of the Hill.txt King of the Hill.txt1 point
-
On the Internet it is impossible to find a description of the format of this file type, namely Gravity Patch File. In developing KPatcher I gathered enough information that you could share it with the community. To simplify the writing and understanding of the text, we introduce a small definition for all GRF/GPF files and we will call them shortly - container. Version of the containers differ only by the methods encrypt the content. In his description, I will talk only about 0x200 version container. The description also is present code in C/C++ examples. So let's begin. To start analyze a simplified structure of the container: 1) Cap the container in which to store the number of files in a container, a compressed file table address container, the container version and a bit of official information; 2) The table container file contains the file name, file size, the compressed file size, compressed file size is aligned, the file position in the container and the attributes of a file in a container; 3) Compressed files. All this can be described as structures of the C/C++ To cap structure is as follows: struct grf_header { char Magic [16]; /// "Master of Magic" +\0 char Key [14]; /// 0x01 -> 0x0E, or 0x00 -> 0x00 (no encryption) uint32_t FileTableOffset; /// The location of the file table uint32_t Seed; /// What is the value of randomly uint32_t FilesCount; /// The actual number of files = FilesCount - Seed - 7 uint32_t Version; /// GRF file version: 0x102, 0x103, 0x200 }; We analyze this structure in more detail: 1) Magic [16] - an identifier that indicates the program running with a container that is in front of her GRF/GPF container, the keyword "Master of Magic"; 2) Key [14] - a key that tells what the data inside the container encryption, obsolete value is not used; 3) FileTableOffset - well, everything is clear, there is stored the offset location of the file table, I want to see that all the specified offset is not the beginning of the file, and the end cap of the container which is equal to 'sizeof (grf_header)' or 46; 4) Seed - a value that randomly invented by Koreans do not know why, probably used in conjunction with Key [14] in earlier versions of the container to protect the information inside the container, which is obsolete value is always 0; 5) FilesCount - the number of files in the container, this value is not absolute, but a bit distorted. The actual value can be obtained by doing a simple mathematical operation RealFilesCount = FilesCount - Seed - 7; 6) Version - this is how it was not hard to guess, the version container. Now, using this knowledge, try to read this information from any arbitrary container. To do this, I will use the programming language C/C++ #include <...> #include <...> #include <...> # Pragma pack (push, 1) /// Align in-memory structure of 1 byte struct grf_header { char Magic [16]; /// "Master of Magic" +\0 char Key [14]; /// 0x01 -> 0x0E, or 0x00 -> 0x00 (no encryption) uint32_t FileTableOffset; /// The location of the file table uint32_t Seed; /// What is the value of randomly uint32_t FilesCount; /// The actual number of files = FilesCount - Seed - 7 uint32_t Version; /// GRF file version: 0x102, 0x103, 0x200 }; # Pragma pack (pop) # Define GRF_HEADER "Master of Magic" # Define GRF_HEADER_SIZE 46 int main () { FILE * FD = NULL; struct grf_header Header = {0}; uint32_t RealFilesCount = 0; FD = fopen ("data.grf", "rb"); /// Read the header container fread (& Header, GRF_HEADER_SIZE, 1, FD); /// Check if this is a GRF/GPF container or not if (strncmp (Header.Magic, GRF_HEADER, 16) { return 0; } /// Now the structure is stored Header informations about current container /// And can easily access them /// The variable is now RealFilesCount the actual number of files in a container /// On this can start reading the information about files RealFilesCount = Header.FilesCount - Header.Seed - 7; return 0; } In this example, I make out the structure of GRF/GPF files and shows how to use the C/C++, you can determine that this is the GRF/GPF file, which version of the file and how many files are contained in this container. And so, to deal with the basic description of the container and having considered the example of obtaining information about the container down to work with the data container. The first thing to get a table with data in the file container. Fully describe the entire structure of the table files can be very simple: table: [<zsize>. l <size>. l [<fname>. s <fentry> .17 b] *] fentry: [<zsize>. l <zsizeal>. l <size>. l <flags>. b <offset>. l] .17 b From this simple circuit structure is visible to full data is located on the very structure of the file table and file table With this information, can easily get information about all files stored in the container. Table with a container files can also be described as a structure: struct grf_fentry { uint32_t zSize; /// Size of packed data uint32_t zSizeAl; /// The same thing only with alignment uint32_t Size; /// Size of uncompressed data uint8_t Flags; /// Flag file (GRF_FLAG_FILE, GRF_FLAG_MIXCRYPT, GRF_FLAG_DES) uint32_t Offset; /// offset into the GRF file (starts immediately after grf_header) }; Describe in detail the structure, I will not, in the comments should explain everything quite clear. #include <...> #include <...> #include <...> .................................................. ................. int main () { .................................................. ......... uint8_t * pBuffer = NULL, * pZBuffer = NULL; uint32_t TableSize = 0, zTableSize = 0; /// Move the file pointer at the beginning of the file table fseek (FD, FileTableOffset + GRF_HEADER_SIZE, SEEK_SET); /// Read compressed and the actual size of the MFT if (! fread (& zTableSize, 4, 1, FD) | |! fread (& TableSize, 4, 1, FD)) { return 0; } /// Allocate the necessary memory volume and read the file table pBuffer = new uint8_t [TableSize]; pZBuffer = new uint8_t [zTableSize]; if (! fread (pZBuffer, zTableSize, 1, FD)) { delete [] pBuffer, delete [] pZBuffer; return 0; } /// Extract the file table /// If you want to use the code presented here will have to connect the library zlib /// This function is part of GrfLib for KPatcher /// The variable pBuffer now stored unpacked and ready to read the file table if (zio:: zlib_uncompress (pBuffer, TableSize, pZBuffer, zTableSize)! = TableSize) { delete [] pBuffer, delete [] pZBuffer; return 0; } delete [] pZBuffer; return 0; } We now have a fully ready to read the file table. Now it remains the case for small, properly read and write to it, we will write to the memory of which optionally can be written to a file. For that would work with the data it was convenient to define another structure that will remind you what struct grf_fentry, but will carry more useful information: struct _FileNode { std:: string FileName; /// File Name uint32_t NameHash; /// Hash the file name uint32_t FileOffset; /// file offset in a container uint32_t FileSize; /// Size uint32_t zFileSize; /// compressed file size uint32_t zFileSizeAl; /// compressed file size aligned uint8_t FileFlags; /// Flags file int32_t Cycle; /// Cycle (used for encrypted files) }; This structure can sozherzhat information about only one file, and must keep information about all files, but it requires some realties store, which will be convenient to work: typedef std:: list <_FileNode> _FilesList; Now that is all that is necessary, we can begin reading the information about files #include <...> #include <...> #include <...> .................................................. ................. .................................................. ................. struct grf_fentry { uint32_t zSize; /// Size of packed data uint32_t zSizeAl; /// The same thing only with alignment uint32_t Size; /// Size of uncompressed data uint8_t Flags; /// Flag file (GRF_FLAG_FILE, GRF_FLAG_MIXCRYPT, GRF_FLAG_DES) uint32_t Offset; /// offset into the GRF file (starts immediately after grf_header) }; # Define GRF_TABLE_SIZE 17 # Define GRF_FLAG_FILE a # Define GRF_FLAG_MIXCRYPT 2 # Define GRF_FLAG_DES 4 struct _FileNode { std:: string FileName; /// File Name uint32_t NameHash; /// Hash the file name uint32_t FileOffset; /// file offset in a container uint32_t FileSize; /// Size uint32_t zFileSize; /// compressed file size uint32_t zFileSizeAl; /// compressed file size aligned uint8_t FileFlags; /// Flags file int32_t Cycle; /// Cycle (used for encrypted files) }; typedef std:: list <_FileNode> _FilesList; int main () { .................................................. ......... .................................................. ......... _FilesList FilesList; for (uint32_t Offset = 0; Offset <tablesize;) {="" get="" the="" file="" name="" length="" size_t="" fn_size="strlen" ((char="" *)="" (pbuffer="" +="" offset));="" if="" (fn_size=""> = 0x100) { delete [] pBuffer; return 0; } grf_file_table FileEntry = {0}; /// Get a pointer to the file name char * FileName = (char *) (pBuffer + Offset); Offset + = FN_Size + 1; /// Get the file information memcpy (& FileEntry, (pBuffer + Offset), GRF_TABLE_SIZE); Offset + = GRF_TABLE_SIZE; /// Skip the directories and files whose size is equal to 0 if (! (FileEntry.Flags & GRF_FLAG_FILE) | | FileEntry.Size == 0) continue; /// Fill the structure with the file information _FileNode Node; Node.FileName.append (FileName, FN_Size); Node.FileFlags = FileEntry.Flags; Node.NameHash = zio:: zlib_crc32 (FileName, FN_Size); Node.FileOffset = FileEntry.Offset; Node.FileSize = FileEntry.Size; Node.zFileSize = FileEntry.zSize; Node.zFileSizeAl = FileEntry.zSizeAl; Node.Cycle = -1; /// Get the information needed to decrypt the file if (Node.FileFlags & GRF_FLAG_MIXCRYPT) { Node.Cycle = 1; for (uint32_t i = 10; Node.zFileSize> = i; i = i * 10) Node.Cycle + +; } if (Node.FileFlags & GRF_FLAG_DES) Node.Cycle = 0; /// Add all the information on file in the repository. FilesList.push_back (Node); } return 0; } Now, the variable contains FilesList informations about each file in the container and can easily burn any data to a file. Now we can unite all that is written above together and we get: #include <stdio.h> #include <string.h> #include <string> #include <list> #include <stdint.h> #include <zlib.h> using namespace std; #pragma pack(push, 1) /// Align in-memory structure of 1 byte struct grf_header { char Magic[16]; /// "Master of Magic" +\0 char Key[14]; /// 0x01 -> 0x0E, or 0x00 -> 0x00 (no encryption) uint32_t FileTableOffset; /// The location of the file table uint32_t Seed; /// What is the value of randomly uint32_t FilesCount; /// The actual number of files = FilesCount - Seed - 7 uint32_t Version; /// GRF file version: 0x102, 0x103, 0x200 }; #pragma pack(pop) #define GRF_HEADER "Master of Magic" #define GRF_HEADER_SIZE 46 #pragma pack(push, 1) /// Align in-memory structure of 1 byte struct grf_fentry { uint32_t zSize; /// Size of packed data uint32_t zSizeAl; /// The same thing only with alignment uint32_t Size; /// Size of uncompressed data uint8_t Flags; /// Flag file (GRF_FLAG_FILE, GRF_FLAG_MIXCRYPT, GRF_FLAG_DES) uint32_t Offset; /// offset into the GRF file (starts immediately after grf_header) }; #pragma pack(pop) #define GRF_TABLE_SIZE 17 #define GRF_FLAG_FILE 1 #define GRF_FLAG_MIXCRYPT 2 #define GRF_FLAG_DES 4 struct _FileNode { std::string FileName; /// File Name uint32_t NameHash; /// Hash the file name uint32_t FileOffset; /// file offset in a container uint32_t FileSize; /// Size uint32_t zFileSize; /// compressed file size uint32_t zFileSizeAl; /// compressed file size aligned uint8_t FileFlags; /// Flags file int32_t Cycle; /// Cycle (used for encrypted files) }; typedef std::list <_FileNode> _FilesList; int main() { /// Some declarations FILE *FD = NULL; struct grf_header Header; uint32_t RealFilesCount = 0; uint8_t * pBuffer = NULL, * pZBuffer = NULL; uint32_t TableSize = 0, zTableSize = 0; _FilesList FilesList; FD = fopen("naoro.grf", "rb"); fread(&Header, GRF_HEADER_SIZE, 1, FD); if ( strncmp(Header.Magic, GRF_HEADER, 16) ) return 0; /// Now the structure is stored Header informations about current container /// And can easily access them /// The variable is now RealFilesCount the actual number of files in a container /// On this can start reading the information about files RealFilesCount = Header.FilesCount - Header.Seed - 7; /// Move the file pointer at the beginning of the file table fseek(FD, Header.FileTableOffset + GRF_HEADER_SIZE, SEEK_SET); /// Read compressed and the actual size of the MFT if ( !fread (&zTableSize, 4, 1, FD) || !fread (&TableSize, 4, 1, FD) ) { return 0; } /// Allocate the necessary memory volume and read the file table pBuffer = new uint8_t [TableSize]; pZBuffer = new uint8_t [zTableSize]; if( !fread (pZBuffer, zTableSize, 1, FD) ) { delete [] pBuffer, delete [] pZBuffer; return 0; } fclose(FD); /// Extract the file table /// If you want to use the code presented here will have to connect the library zlib /// This function is part of GrfLib for KPatcher /// The variable pBuffer now stored unpacked and ready to read the file table if ( uncompress((Bytef*)pBuffer, (uLongf*)&TableSize, (Bytef*)pZBuffer, zTableSize) != Z_OK ) { delete [] pBuffer, delete [] pZBuffer; return 0; } delete [] pZBuffer; for ( uint32_t Offset = 0; Offset < TableSize; ) { size_t FN_Size = strlen((char*)(pBuffer+Offset)); if ( FN_Size >= 0x100 ) { delete[] pBuffer; return 0; } grf_fentry FileEntry = {0}; /// Get a pointer to the file name char *FileName = (char*)(pBuffer+Offset); Offset += FN_Size + 1; /// Get the file information memcpy(&FileEntry, (pBuffer+Offset), GRF_TABLE_SIZE); Offset += GRF_TABLE_SIZE; /// Skip the directories and files whose size is equal to 0 if ( !(FileEntry.Flags&GRF_FLAG_FILE) || FileEntry.Size == 0 ) continue; /// Fill the structure with the file information _FileNode Node; Node.FileName.append(FileName, FN_Size); Node.FileFlags = FileEntry.Flags; Node.NameHash = crc32(0, (Bytef*)FileName, FN_Size); Node.FileOffset = FileEntry.Offset; Node.FileSize = FileEntry.Size; Node.zFileSize = FileEntry.zSize; Node.zFileSizeAl = FileEntry.zSizeAl; Node.Cycle = -1; /// Get the information needed to decrypt the file if ( Node.FileFlags&GRF_FLAG_MIXCRYPT ) { Node.Cycle = 1; for( uint32_t i = 10; Node.zFileSize >= i; i = i*10 ) Node.Cycle++; } if ( Node.FileFlags&GRF_FLAG_DES ) { Node.Cycle = 0; } /// Add all the information on file in the repository. FilesList.push_back(Node); } delete[] pBuffer; /// Creating empty file FD = fopen("files_list.txt", "w+"); _FilesList::iterator itr = FilesList.begin(); _FilesList::iterator itr_end = FilesList.end(); /// Fill the newly created file data. fprintf(FD, "FileName - FileSize - FilePos\n"); for ( ; itr != itr_end; itr++) fprintf(FD, "%s - %d - %d\n", itr->FileName.c_str(), itr->FileSize, itr->FileOffset+GRF_HEADER_SIZE); fclose(FD); return 0; } Fully working source code that reads the GRF/GPF file and prints the contents a file. main.rar1 point
-
The athena-start script could use some improvement, this is just a suggestion for a quick fix. What this does is basically telling the start script to sleep for 5 seconds before executing the map-server, I think this is useful due to the whole issue where you run restart and your map server doesnt get started because its still waiting for the old instance to close (cant bind Ip due to port in use.) that you generally experience upon calling a restart making the restart command not really do much unless the map server has actually crashed. edit: Adding a check to see if map server is already running, then posting new diff. edit2: Added check to see if the map server is already running, if it is the script will output this information to the user, wait for 5 seconds and then start the server, if its not found. It will start the map server normally. athena-start.diff1 point
-
Hai. I'm here to give you guys a explanation on r15390. We, developers, spent a reasonable amount of time discussing what'd be a more organized, less cluttered, manner to work with pre-re and re files, and thats' what we came with. If the changeset is not clear to you, run a svn update and see how it is now. should you have any comments regarding this you'd like to share, post below.1 point
-
conf/inter_athena.conf // Level range for sharing within a party party_share_level: 15 then Restart Server1 point
-
LOL...though it is just go through some Short Maintenance..... >.< Alot script havent back up.... seem like going to recreate those script again in the future when those member request again .... /$1 point
-
I call BS. It just closed down like poof? The heck? And here's hoping he has a back-up....or maybe not.1 point
-
Hola Ziu, Te recomiendo bastante este video para descompilar y organizar archivos lub. Saludos, Zwei1 point
-
To clearify on this matter, --prefix works, what isnt implemented is make install (And the initial map) actually putting the files in prefix instead of the folder its all been compiled in. I might install a patch file for configure.in/Makefile.in if i get around to fixing it.1 point
-
1 point
-
Here is the edited whoisonline.php that does not show Map: whoisonline.php These are the changes I made: --- D:/svn/cerescp/trunk/whoisonline.php Tue Mar 10 18:24:33 2009 +++ D:/svn/cerescp/trunk/whoisonline.php Sun Jan 8 06:46:56 2012 @@ -44,10 +44,12 @@ <td align="left" class="head">".$lang['CLASS']."</td> <td align="center" class="head">".$lang['BLVLJLVL']."</td> "; - if (isset($_SESSION[$CONFIG_name.'level']) && $_SESSION[$CONFIG_name.'level'] >= $CONFIG['cp_admin']) - echo "<td align="center" class="head">".$lang['WHOISONLINE_COORDS']."</td>"; + if (isset($_SESSION[$CONFIG_name.'level']) && $_SESSION[$CONFIG_name.'level'] >= $CONFIG['cp_admin']) { + echo "<td align="center" class="head">".$lang['WHOISONLINE_COORDS']."</td>"; + echo " + <td align="left" class="head">".$lang['MAP']."</td>"; + } echo " - <td align="left" class="head">".$lang['MAP']."</td> </tr> "; if ($result) { @@ -70,12 +72,13 @@ </td> <td align="center">$line[2]/$line[3]</td> "; - if (isset($_SESSION[$CONFIG_name.'level']) && $_SESSION[$CONFIG_name.'level'] >= $CONFIG['cp_admin']) + if (isset($_SESSION[$CONFIG_name.'level']) && $_SESSION[$CONFIG_name.'level'] >= $CONFIG['cp_admin']) { echo "<td align="center">$line[4],$line[5]</td>"; - echo " + echo " <td align="left">$line[6]</td> </tr> "; + } } } echo "</table>";1 point
-
[script][npc] Advanced Tombstone v1.03 Зачастую игроки хотят знать, когда воскреснет MVP, да и кто такой супер-крутой его смог забить, а многим админам хотелось бы иметь удобный инструмент для работы с MVP (отключить не залезая в конфиги, убить, чтобы игроки могли спокойно бегать по локации или оживить убитого MVP для соискателей приключений). Описание Скрипт позволяет управлять MVP (и не только, при желание), получать информацию о состояние MVP. Скачать Скрипт версии 1.03: скачать (в базе монстров все mvp от 13.2, Maya Purple и один тестовый квестовый моб) (Используя скрипт вы обязуетесь следовать лицензионному соглашению указанному в скрипте) Вот список возможностей: После смерти Монстра создаётся Tombstone с информацией о монстре, кто его убил и времени его воскрешения; Имеется несколько режимов состояние монстра (Живой, мёртвый и ждёт воскрешения, отлючен); Запоминание режима даже после перезагрузки (координаты Tombstone так же запоминаются); При отключение выставляется в стандартно установленное место (Координаты прописываются в таблицу скрипта); Координаты respawn'а выставляются как и в map monster (а не как в areamonster, кому интересна разница читайте doc'и); Время respawn'а указывается как в map monster (а не как в оригинальном Tombstone); Можно указывать имя моба, а не брать стандартное из mobdb; Специальный NPC с помощью которого GM'ы могут управлять режимом монстров (Убить монстра, оживить немедленно, отключить) и получить некоторые сведения о состояние монстра; После смерти монстра создаётся NPC Tombstone с окном чата сообщающим когда монстр оживёт, что он отключен или был убит и квест завершён; При разговоре с NPC Tombstone сообщается имя убившего (отключившего) его персонажа, для GM'ов есть функция мгновенного оживления монстра; Создание монстра можно вызывать из любого скрипта (методом вызова глобальной функции), что позволяет делать квесты. Недостатки и ошибки Я могу назвать только одну ошибку — при использование GM команды @killmonster скрипт работает некорректно. Так же не работает зеркало (будет говорить, что MVP на карте необнаружены, imho, не критично, т.к. Tombstone показывает нужную информацию и без того). Если что-то найдёте — отписывайтесь. Скриншоты Примечание Базы монстров скрипта настроены на обычный сервер, не Renewal, если вам нужно для Renewal, то боюсь придётся немного потрудиться базы сильно отличаются. Вы так же должны очистить(закомментировать) все записи о расположение текущих монстров в скриптах NPC. Для доступа к MVP Master и функции оживления монстра из Tomb'а нужен GM уровень не ниже 50ого, иначе NPC вас будут просто троллить Таблица монстров скрипта Массивы данных: setarray .mvpbmid[0],0; // Mob ID setarray .mvpbdl1[0],0; // Respawn Delay1 (in seconds, if is 0 - then mob consider as Quest Mob and not creating on first OnInit) setarray .mvpbdl2[0],0; // Respawn Delay2 (in seconds, if is 0 - then not create Tomb and Chat Room) // Default Tombstone coordinates X,Y setarray .mvpbcdx[0],0; setarray .mvpbcdy[0],0; // Area coordinates to spawn X,Y,X1,Y1 (if X and Y = 0 - get random area) setarray .mvpbcx[0],0; setarray .mvpbcy[0],0; setarray .mvpbcx1[0],0; setarray .mvpbcy1[0],0; setarray .mvpbaname$[0],""; // Name for Admins NPC (if empty then get from MobDB) setarray .mvpbmname$[0],""; // Mob name setarray .mvpbevent$[0],""; // Do Event on Kill Monster (empty to nothing todo) mvpbmid — MobID (идентификатор монстра) соответствующий идентификатору в базе - mob_db.txt mvpbdl1 — Время респауна (указывается в секундах!), через какое минимальное кол-во времени монстр воскреснит, если значение установлено равное 0, то монстр считается квестовым и после своей смерти он не пересоздаётся, чат комната так же имеет иное содержание, а не время до следующего респауна mvpbdl2 — Разница во времени респауна (в большую сторону, указывается в секундах), если значение установлено равное 0, то после смерти монстра не создаётся его Tombstone mvpbcdx, mvpbcdy — Расположение по-умолчанию Tombstone (X, Y), это место, где будет установлен Tombstone при убийстве или отключение монстра через Admin NPC mvpbcx, mvpbcy, mvpbcx1, mvpbcy1 — X, Y - коордианты появления монстра (если координаты равны 0, то коордианты берутся случайным образом относительно всей локации), X1, Y1 - разброс в появление монстра (X, Y при этом являются центром зоны появления, а X1, Y1 - диаметром) mvpbaname$ — Название монстра для меню Admin NPC, если оставить пустым, то возьмётся имя из базы mvpbmname$ — Название монстра, можно указывать какое имя из базы брать ("--ja--" - корейское название, "--en--" - английское название, или указывать своё название) mvpbevent$ — Обработка Event после смерти моба, чаще всего необходима для создания квестов (смотрите пример в скрипте с Yggas'Worth) Пример для монстра Fallen Bishop: callsub(L_AddMobDB,1871,7200,600,238,73,236,78,21,18,"","--en--",""); Добавление монстра Добавление монстра проходит в две стадии — первая стадия включает в себя дубликата NPC на нужную локацию с определённым именем, вторая — прописывание данных в таблицу монстров скрипта. Итак, для начала добавляем дубликат NPC, тут ничего сложного, находим последнюю запись дубликатов, допустим, у нас всего два монстра и последняя запись, пусть будет примерно такая: prontera,0,0,0 duplicate(tombstone_dup) Tomb#2_mvp 565 Запоминаем, что название NPC — Tomb#2_mvp, сейчас нам очень важна скрытая часть названия «2_mvp» — здесь важная цифра, это «2», значит в таблице всего 2 монстра, добавляем нашего нового монстра, пусть это будет Beelzebub (#1873), заглядываем в npc/mobs/dungeons/abbey.txt и находим нашего монстра: abbey03,0,0,0,0 boss_monster Beelzebub 1873,1,43200000,600000,1 Комментируем эту строчку и добавляем после последнего найденного нами дубликата NPC в скрипте строчку, указывая в скрытом название NPC следующий номер (2_mvp был последним, значит теперь будет 3_mvp): abbey03,0,0,0 duplicate(tombstone_dup) Tomb#3_mvp 565 Отлично, теперь нам надо добавить информацию о монстре, добавляем в таблицу монстров скрипта строчку: callsub(L_AddMobDB,1873,43200,600,120,112,0,0,0,0,"","--en--",""); Монстр добавлен и при перезагрузке появится на указанной локации. Немного о глобальной функции Для взаимодействия самого скрипта монстров с внешними NPC было созданное небольшое API (не слишком хорошо написанное, но рабочее). Это функция tmvp_menu, она имеет входящие ключи для определения того, что именно вам нужно (getarg(0)), вот id ключей и их краткое описание: 0 - Вызывается при основном OnInit скрипта монстров, создаёт нужные переменные и устанавливает первый пункт для Admin NPC - «Nothing» 1 - Вызывается при OnInit скрипта монстров, запоминает нужные данные для последующей работы 2 - Возвращает созданное меню (список монстров со статусом, работает медленно, т.к. обращается к глобальным данным) 3 - Устанавливает режим монстра в «Суицид», входящим данным (getarg(1)) является номер пункта меню, возвращает 0 — если всё прошло успешно, 1 — монстр не может быть установлен в режим (режим уже установлен или монстр отключен) 4 - Устанавливает режим монстра в «Оживить», возвращает 0 — если монстр создан успешно, 1 — монстр уже создан и не может быть создан снова, входящим данным является номер монстра (mvpbid) в таблице монстров скрипта 5 - Возвращается текст из пункта меню (Обычно это имя монстра), входящим данным является номер пункта меню 6 - Устанавливает режим монстра в «Суицид», входящим данными является mvpbid и имя персонажа, которое будет установлено как имя убийцы монстра, возвращаемые данные такие же, как и для 3 7 - Возвращает состояние монстра (Текстовое сообщение), входящим данным является mvpbid 8 - Возвращается mvpbid, входящим данным является номер пункта меню 9 - Устанавливает режим монстра в «Убить и отключить», входяшими данными является mvpbid и имя персонажа, возвращает 0 — при успешном выполнение, 1 — если монстр уже отключён. Формат вызова функции: callfunc("tmvp_menu", <номер ключа>(, <входящие переменные>)); Входящие переменные: mvpbid — это ID монстра в таблице скрипта, это не одно и то же, что и MobID. номер пункта меню — это уникальный идентификатор пункта меню для Admin NPC, который создаётся в 0 и 1 ключах функции, вызывается такое меню ключом 2 charname — имя персонажа игрока Пример, убить монстра №2: callfunc("tmvp_menu", 6, 2, strcharinfo(0)); Пример, воскресить монстра №2: callfunc("tmvp_menu", 4, 2); Для наглядности в скрипт добавлен NPC Yggas'Worth, он создаёт Поринга с кастумным названием и ждёт пока вы его не убьёте. На самом деле это самый простой пример, но вы можете добавлять каких-либо сложных монстров и создавать на этой основе квесты. Немного о глобальных переменных Их несколько, но вы можете использовать их в своих скриптах для создания квестов: $tmvp<mvpbid>_state — Признак состояния монстра (см ниже) $tmvp<mvpbid>_nick$ — Имя персонажа убившего монстра (учтите, что при измененеие состояния эта переменная не очищается) $tmvp<mvpbid>_x и $tmvp<mvpbid>_y — Координаты где расположен Tombstone (учтите, что при измененеие состояния эта переменная не очищается) $tmvp<mvpbid>_time — Время (указан tick с момента начала эпохи) до начала действия признака события (используется только для подсчёта времени respawn'а монстра) $tmvp<mvpbid>_created — Создан ли монстр (необходимо для некоторых проверок) (0 - нет, не создан, 1 - создан и бегает) $tmvp<mvpbid>_frun — Первый или нет запуск (0 - первый запуск, 1 - запуск уже был), необходимо для квестовых мобов, чтобы они не создавались Признаки состояния монстров: 0 — Монстр жив и где-то бегает 1 — Признак на суицид 2 — Монстр убит и ожидает времени respawn'а 3 — Признак на немедленное оживление 4 — Признак на суицид и отключение 5 — Монстр отключён и ждёт включения 6 — Для квестового монстра, состояние его смерти (убит и ожидает оживления через квест) Вы можете использовать эти данные для написания скриптов квестов (смотрите пример в скрипте на Yggas'Worth). Механика Скрипт работает на режимах, это так называемые признаки событий, действия происходят не мгновенно, а только создают признак этого события. К примеру, вы выставляете монстру признак события на суицид, обработка этого события произойдёт в течени 5 секунд, когда внутренний обработчки скрипта распознает этот признак и примет решение о том, что нужно сделать. Итерация обработчика - 5 секунд (OnTimer5000), вы можете поменять это значение на другое, но на свой страх и риск, учтите, что чем меньше вы делаете время обработки, тем больше нагрузок создаётся на ваш сервер (я считаю идеальным обработку каждые 10 секунд, но выставил 5, чтобы задержка составляла минимальную серверную). Благодарности Своей девушке, что разрешала работать над скриптом по ночам Sanasol — автору основного скрипта, я взял кусочек его кода (функция вывода времени, копирайт указан в скрипте, прошу прощения, было лень писать точно такую же функцию). Heler'у — за то, что оказывал некоторую помощь. nndsl — за подкинутую идею.1 point
-
1 point
-
#!/bin/sh # athena starting script by rowla # modified by [email protected] (NL101541) PATH=./:$PATH L_SRV=login-server_sql C_SRV=char-server_sql M_SRV=map-server_sql print_start() { # more << EOF echo "Athena Starting..." echo " (c) 2003 Athena Project" echo " modified by [email protected]" echo "" #echo "Debug informations will appear," #echo "since this is a test release." #echo "" echo "checking..." #EOF } check_files() { for i in ${L_SRV} ${C_SRV} ${M_SRV} do if [ ! -f ./$i ]; then echo "$i does not exist, or can't run." echo "Stop. Check your compile." exit 1; fi done # more << EOF echo "Check complete." echo "Looks good, a nice Athena!" #EOF } case $1 in 'start') print_start check_files exec screen -d -m -S login .{L_SRV}& exec screen -d -m -S char ./${C_SRV}& exec screen -d -m -S map ./${M_SRV}& echo "Now Started Athena." echo "To view one of the servers type as shown:" echo "Login: screen -r login" echo "Char : screen -r char" echo "Map : screen -r map" echo "To stop viewing a screen hold Ctrl+A and tap D" ;; 'stop') ps ax | grep -E "${L_SRV}|${C_SRV}|${M_SRV}" | awk '{print $1}' | xargs kill ;; 'restart') $0 stop $0 start ;; *) echo "Usage: athena-start { start | stop | restart }" ;; esac as you wish sir.1 point
-
I havent ever used the athena-start file without modifying it to use screen. Perhaps something that should be considered.1 point
-
Double topic/more improved topic exists. http://rathena.org/board/topic/56677-new-gm-system/1 point
-
^Thx Yes its just simple mod and i already use this on my server for long time . I hope there are better ways but still digging on what can be change.1 point
-
Currently, i got 2 ways to make the client not to auto close when wrong password detected. All changes are done to server-side. Make sure your add this on your login conf. //Set this to yes to make client not to auto close when user input wrong password. //Usefull for Client 2011+ re_client: yes First patch will make server send "Rejected from the server" and will not auto close the client. For second patch use "dummy" value and will make client receive "Fail to connect" if the user spam any wrong password on any account. rejected.patch fail_to_connect.patch1 point
-
1 point
-
@Yommy Nice to see you decided to release your lua decompiler tool to the public. Even tho its not complete, it far more better then any other decompiler ive ever seen. @everyone To use this you need php support. You can download from this link and install.... http://windows.php.net/downloads/releases/php-5.3.8-nts-Win32-VC9-x86.msi When installing itl ask if you want to install a server. Choose not to install any server and just click next the entire way. When it shows which components to install be sure not to touch any of that and just hit next. Once complete youll also want to download and install Notepad++ as it greatly helps with fixing the small errors in the outputed files from the decompiler. To install and use the decompiler just make a folder anywhere and name it what you want. Then place the following files in the folder.... LuaTool.bat LuaTool ToFile.bat lua.inc.php LuaTool.php You will also need to make a folder in the same folder you placed those files in and name it lubs. Once done, you can use the decompiler. To use it youll need to place 1 lub file (Thats right. It can only do 1 at a time. Attempting to do more then 1 can mess up the output) in the lubs folder. Then you click the LuaTool ToFile.bat to run it. It will generate a output.txt file which will contain the decompiled code. Be sure to do something with the output file before you continue, like open it and save as with a different name, or just rename the file. If you want to decompile another file youll need to remove the lub file from the lubs folder before you place another in there or else the decompiler will try to read multiple files and mess up. No matter what file you decompile the output will always be saved to output.txt which is why you should do something with the data before decompiling another. Next is cleaning the data. Right click any of the decompiled files and click Edit With Notepad++. Once opened youll need to remove the first 4 lines as their not part of the script. After that comes the tricky part. On the menu bar above click Search -> Find. A window will open. Click the Replace tab. Here's where you will do commands to cleanup the script. How you clean each file depends on the output. For example youll notice in files like skillinfolist something like this....1 = "SN_WINDWALK". Every skill info entry will have one like that, but that 1 = part shouldnt be there and will cause errors. To remove them use the replace window you opened. First type in the Find What : 1 = . Thats 1(space)=(space). In the Replace With : keep it empty. Then click the Replace All button and itl remove all those 1 = things. This is a example of how to clean the files. Other things that may need to be done is removing unneeded [ ] or { } or adding needed { }, or other things. Its a bit tricky but it can be done and it can greatly help and reduce the amount of time needed to cleanup a file. You can make changes and test the files with a RO client while having the file in your data/lua files/whatever folder. Some of the error's the client will spit out may be confusing and hard to figure out and fix. If you run into any issues, feel free to use my lua files release as a reference to compare and see if you missed anything. I hope this help everyone on the decompiler. I type this kinda quick.1 point
-
This is a mini event that player can sign the number to the setting number. As long as player reach the target number ,he can get the prize. My idea from there and due to the new year 2012 come ,so my default lucky number is 2012 sign_number_event.txt1 point
-
File Name: Advanced common drop system File Submitter: dreamunreal File Submitted: 26 Dec 2011 File Category: Source Modifications Ind's Special item drop system can't do it. so. I base on Ind's work to finish this to solve xazax's probrom. this patch. base on eAthena r15049 trunk. that is all,. enjoy it. Click here to download this file1 point
-
1 point
-
@ Chris : I remembered an Arena (Summoner) like that from MoonlightRO and then I scripted it for the people,who need a MVP Arena (Summoner).And yes,I know that with the arrays,but I prefer scripting without arrays,because most of the time when I had a script with arrays it was erroring me. @manabeast : Thank you,and enjoy the Script.1 point