Jump to content

Leaderboard

Popular Content

Showing content with the highest reputation on 10/15/22 in all areas

  1. with rAthena commit ac7292c instance system can do this just set the owner instance to IM_NONE and set the time limit of the instance to unlimited in the instance_db.yml sample entry in instance_db.yml. - Id: 777 Name: Payon Clone TimeLimit: 0 IdleTimeOut: 0 Enter: Map: payon X: 150 Y: 150 on the script for instance creation .@instance_name$ = "Prontera Clone"; .@instance_mode = IM_NONE; instance_create(.@instance_name$, .@instance_mode);
    2 points
  2. Version 1.8.9.7

    56373 downloads

    Hello everyone, GRF Editor is an open-source tool for editing GRF files (https://github.com/Tokeiburu/GRFEditor). It offers a wide variety of features and customizations. The software is very stable and responsive, it can handle large operations without lagging your computer. How to install Download the zip archive provided from the download link at the bottom of this description or directly from there: http://www.mediafire.com/?aflylbhblrzpz0h Install the application with GRF Editor Installer.exe; if you are missing a .NET Framework you will be prompted to download it. Once you are done, you can start the program from the link on your desktop. Key features Overall speed is faster (or at least equal) than any GRF tool. Common operations: add, delete, merge, extract, preview, save. Undo and redo for any operation. It can open any GRF file format. Clean and very interactive interface. Saving formats supported : 0x300, 0x200, 0x103 and 0x102 (through the Settings page) and conversion to the Thor format. Instant filter and search options (example : "map .gat"). File association and context menus integration for .grf, .gpf, .rgz and .thor (through the Settings page). Can rebuild separated images into one file easily. Drag and drop (with the ALT key, can be modified in the Settings page). This is a big part of the software; most of the items can be moved around within the application itself or from/to Windows Explorer. If drag and drop does not work, it is most likely because you've started the program using administrator privileges. GRF Editor does not requires administrator privileges to run. Tools Grf validation: allows you to validate a GRF with multiple settings. It can detect corrupted GRF entries, invalid sprites, empty files, non-GRF files, duplicate files and a lot more. Flat maps maker: generates flat maps from .gat and .rsw files. Useful to generate WoE maps or to fasten up the loading time. Patch maker: generates a GRF patch based on two different GRFs. Hash viewer: shows the hash code (both CRC32 and MD5) for files. Image converter: converts an image to any format requested (BMP, PNG, JPG, TGA). GrfCL: used to create batch files (.bat) which can automate tasks on GRF files. See the content in GrfCL.rar in the download for more information. This tool can be customized from the sources as well. Grf encryption The encryption feature has been enabled again. It's similar to what it used to be and it has been tested on client versions ranging from 2012-08-01 to 2024-01-01. Some error messages will be displayed if necessary. If you have an issue, copy the error message (with the code, if there's one) and send me the client executable with the cps.dll file generated by GRF Editor. There shouldn't be compatibility issues anymore though! Thor files Thor files are patches used by Thor Patcher ( https://github.com/rathena/rathena/wiki/Thor-Patcher ). Because of their similarity with the GRF file structure, they have been integrated within GRF Editor. The primary utility of this feature is that it allows you to add encrypted files to a Thor patch. All the other options can be achieved by using Thor Maker. You'll find the necessary steps below, but test your patches before sending them off to players (I've done a lot of testing on my end, but better be safe). If you're using SecureGRF, then make a new GRF, add the files and encrypt it. In GRF Editor, open the encrypted GRF you just made, use "Save as" and name the new file with a .thor extension. That's it, if you want to change the output directory, click on Edit > Edit Grf/Thor settings. You can select the output mode and the GRF to merge the patch with. Simply save again if you change these properties. If you're using GRF Editor's encryption, then make a new Thor file (File > New > New Thor) and add the files you want to patch it with. Right-click on the files you want to encrypt and use Encryption > Encrypt. Technical stuff Requires .Net Framework 4.0 to run (4.0 or more will work as well). Automatically converts file name encoding to the currently selected encoding (you can change the encoding in the Settings page). Data virtualization is used as much as possible to preview files, meaning the files aren't completely loaded. Right-clicking an item will bring up the available options with that file. Preview file formats: txt, log, xml, lua, lub, bmp, png, tga, jpp, db, ebm, pal, gnd, rsw, gat, rsm, str, spr, act, imf, fna, bson, csv, ezv and wav. Services are "crash ready", meaning that you will be warned about a failed operation and no work will be lost (the application won't close and crash). It tries to continue operating even if it meets unsual conditions. Operations can be cancelled by clicking on the button near the progress bar. The warning level can be changed to avoid messages like "Please select a folder first." When prompted with an error, use Ctrl-C to copy the current dialog's content. Some screenshots! 1) Previewing an act file, while showing the search feature 2) Preview of a model file (rsm or rsm2) 3) Preview of GrfCL 4) Preview of maps 5) Preview of Grf validation 6) Search feature (press Ctrl-F or Ctrl-H to bring up within a text editor) Got a feedback? I'd gladly hear you out and fix issues you have with the program.
    Free
    1 point
  3. currency that display in shop cant be change by NPC script, you need custom client hex modification. for multiple items purchase, it doesn't work if the item is equipment.
    1 point
  4. This feature allows you to clone maps ingame without having to reboot your server or do any changes client-side. The cloned maps will behave just like any other regular map, except players will not be able to save in them. If they log out, they will return to their spawn point. The commands: @clonemap source_map new_map @delmap new_map @clonemaplist This is useful if want to make an event on a map but there's an annoying NPC in the way (and you don't want to reboot your server just for that!). Another big upside being you don't need to send a patch for that either, the new map will be added 'live'. You can load scripts on these maps as well (they will be removed upon deleting the map). Usage example: @clonemap prontera newmap @addwarp newmap 150 150 test_portal (@unloadnpc test_portal) Have fun! These maps will be lost when rebooting the server. diff --git a/src/map/atcommand.c b/src/map/atcommand.c index d4b329c..25e4c8b 100644 --- a/src/map/atcommand.c +++ b/src/map/atcommand.c @@ -799,6 +799,11 @@ ACMD_FUNC(save) { nullpo_retr(-1, sd); + if( map[sd->bl.m].clone_id ) { + clif_displaymessage(fd, "You cannot create a savepoint in this map."); + return 1; + } + if( map[sd->bl.m].instance_id ) { clif_displaymessage(fd, msg_txt(sd,383)); // You cannot create a savepoint in an instance. return 1; @@ -5945,6 +5950,11 @@ ACMD_FUNC(autotrade) { return -1; } + if (map[sd->bl.m].clone_id) { + clif_displaymessage(fd, "You cannot use autotrade on cloned maps."); + return -1; + } + sd->state.autotrade = 1; if (battle_config.autotrade_monsterignore) sd->state.monster_ignore = 1; @@ -9937,6 +9947,111 @@ ACMD_FUNC(adopt) return -1; } +/** + * Clones an existing map without having to reboot your server. + * Usage: @clonemap <source_map_name> <new_map_name> + * @author Tokeiburu + */ +ACMD_FUNC(clonemap) +{ + int res; + char map_name_cur[MAP_NAME_LENGTH_EXT]; + char map_name_new[MAP_NAME_LENGTH_EXT]; + + memset(map_name_cur, '\0', sizeof(map_name_cur)); + memset(map_name_new, '\0', sizeof(map_name_new)); + + if (!message || !*message || sscanf(message, "%15s %15s", map_name_cur, map_name_new) < 2) { + clif_displaymessage(fd, "Usage: @clonemap <source_map_name> <new_map_name>"); + return -1; + } + + if (map_mapname2mapid(map_name_cur) < 0) { + sprintf(atcmd_output, "Source map not found: %s", map_name_cur); + clif_displaymessage(fd, atcmd_output); + return -1; + } + + if (map_mapname2mapid(map_name_new) >= 0) { // This will always show a warning in the console, but removing it is not worth the trouble. + sprintf(atcmd_output, "Destination map already exists: %s", map_name_new); + clif_displaymessage(fd, atcmd_output); + return -1; + } + + if ((res = map_addclonemap(map_name_cur, map_name_new)) < 0) { + sprintf(atcmd_output, "Failed to create a new map, error: %d", res); + clif_displaymessage(fd, atcmd_output); + return -1; + } + + sprintf(atcmd_output, "New map cloned (%s).", map_name_new); + clif_displaymessage(fd, atcmd_output); + return 0; +} + +/** + * Removes a cloned map. + * Usage: @delmap <map_name> + * @author Tokeiburu + */ +ACMD_FUNC(delmap) +{ + int res; + int m; + char map_name[MAP_NAME_LENGTH_EXT]; + + memset(map_name, '\0', sizeof(map_name)); + + if (!message || !*message || sscanf(message, "%15s", map_name) < 1) { + clif_displaymessage(fd, "Usage: @delmap <map_name>"); + return -1; + } + + if ((m = map_mapname2mapid(map_name)) < 0) { + sprintf(atcmd_output, "Map not found: %s", map_name); + clif_displaymessage(fd, atcmd_output); + return -1; + } + + if (map[m].clone_id == 0) { + clif_displaymessage(fd, "Only cloned maps can be removed."); + return -1; + } + + if ((res = map_delclonemap(map_name)) != 1) { + sprintf(atcmd_output, "Failed to remove map: %s", map_name); + clif_displaymessage(fd, atcmd_output); + return -1; + } + + sprintf(atcmd_output, "Cloned map removed (%s).", map_name); + clif_displaymessage(fd, atcmd_output); + return 0; +} + +/** + * Lists all cloned maps. + * Usage: @clonemaplist + * @author Tokeiburu + */ +ACMD_FUNC(clonemaplist) +{ + int i; + int count = 0; + + for (i = instance_start; i < MAX_MAP_PER_SERVER; i++) { + if (map[i].clone_id > 0) { + sprintf(atcmd_output, "%s (source: %s)", map[i].name, map[map[i].clone_id].name); + clif_displaymessage(fd, atcmd_output); + count++; + } + } + + sprintf(atcmd_output, "Found %d cloned map(s).", count); + clif_displaymessage(fd, atcmd_output); + return 0; +} + #include "../custom/atcommand.inc" /** @@ -10234,6 +10349,10 @@ void atcommand_basecommands(void) { ACMD_DEF(adopt), ACMD_DEF(agitstart3), ACMD_DEF(agitend3), + + ACMD_DEF(clonemap), + ACMD_DEF(delmap), + ACMD_DEF(clonemaplist), }; AtCommandInfo* atcommand; int i; diff --git a/src/map/chrif.c b/src/map/chrif.c index 4276434..cea689f 100644 --- a/src/map/chrif.c +++ b/src/map/chrif.c @@ -336,7 +336,7 @@ int chrif_save(struct map_session_data *sd, enum e_chrif_save_opt flag) { WFIFOB(char_fd,12) = (flag&CSAVE_QUIT) ? 1 : 0; //Flag to tell char-server this character is quitting. // If the user is on a instance map, we have to fake his current position - if( map[sd->bl.m].instance_id ){ + if( map[sd->bl.m].instance_id || map[sd->bl.m].clone_id ){ struct mmo_charstatus status; // Copy the whole status diff --git a/src/map/clif.c b/src/map/clif.c index 6c77044..97d8864 100644 --- a/src/map/clif.c +++ b/src/map/clif.c @@ -10352,7 +10352,7 @@ void clif_parse_LoadEndAck(int fd,struct map_session_data *sd) #endif // Instances do not need their own channels - if( channel_config.map_enable && channel_config.map_autojoin && !map[sd->bl.m].flag.chmautojoin && !map[sd->bl.m].instance_id ) + if( channel_config.map_enable && channel_config.map_autojoin && !map[sd->bl.m].flag.chmautojoin && !map[sd->bl.m].instance_id && !map[sd->bl.m].clone_id ) channel_mjoin(sd); //join new map } else if (sd->guild && (battle_config.guild_notice_changemap == 2 || guild_notice)) clif_guild_notice(sd); // Displays at end diff --git a/src/map/map.c b/src/map/map.c index c7e326b..37d65f1 100644 --- a/src/map/map.c +++ b/src/map/map.c @@ -2095,7 +2095,7 @@ int map_quit(struct map_session_data *sd) { unit_remove_map_pc(sd,CLR_RESPAWN); - if( map[sd->bl.m].instance_id ) { // Avoid map conflicts and warnings on next login + if( map[sd->bl.m].instance_id || map[sd->bl.m].clone_id ) { // Avoid map conflicts and warnings on next login int16 m; struct point *pt; if( map[sd->bl.m].save.map ) @@ -2728,6 +2728,133 @@ int map_delinstancemap(int m) return 1; } +/*========================================== + * Add a cloned map + *------------------------------------------*/ +int map_addclonemap(const char *name, const char *newname) +{ + int src_m = map_mapname2mapid(name); + int dst_m = -1, i; + size_t num_cell, size; + + if(src_m < 0) + return -1; + + if(strlen(name) >= MAP_NAME_LENGTH) { + // against buffer overflow + ShowError("map_addclonemap: can't add long map name \"%s\"\n", name); + return -2; + } + + if(strlen(newname) >= MAP_NAME_LENGTH) { + // against buffer overflow + ShowError("map_addclonemap: can't add long map name \"%s\"\n", newname); + return -2; + } + + for(i = instance_start; i < MAX_MAP_PER_SERVER; i++) { + if(!map[i].name[0]) + break; + } + if(i < map_num) // Destination map value overwrites another + dst_m = i; + else if(i < MAX_MAP_PER_SERVER) // Destination map value increments to new map + dst_m = map_num++; + else { + // Out of bounds + ShowError("map_addclonemap failed. map_num(%d) > map_max(%d)\n",map_num, MAX_MAP_PER_SERVER); + return -3; + } + + if (map[src_m].clone_id) { + ShowError("map_addclonemap failed. Cannot clone a cloned map.\n",map_num, MAX_MAP_PER_SERVER); + return -4; + } + + // Copy the map + memcpy(&map[dst_m], &map[src_m], sizeof(struct map_data)); + + // Alter the name + // Due to this being custom we only worry about preserving as many characters as necessary for accurate map distinguishing + // This also allows us to maintain complete independence with main map functions + strncpy(map[dst_m].name,newname,MAP_NAME_LENGTH); + + map[dst_m].m = dst_m; + map[dst_m].clone_id = src_m; + map[dst_m].users = 0; + + memset(map[dst_m].npc, 0, sizeof(map[dst_m].npc)); + map[dst_m].npc_num = 0; + + // Reallocate cells + num_cell = map[dst_m].xs * map[dst_m].ys; + CREATE( map[dst_m].cell, struct mapcell, num_cell ); + memcpy( map[dst_m].cell, map[src_m].cell, num_cell * sizeof(struct mapcell) ); + + // Remove ontouch NPC cells + for (i = 0; i < num_cell; i++) { + map[dst_m].cell[i].npc = 0; + } + + // Remove all mob spawners (these should not be copied over) + for (i = 0; i < MAX_MOB_LIST_PER_MAP; i++) { + map[dst_m].moblist[i] = NULL; + } + + // Do not copy PVP nightmare drops + memset(map[dst_m].drop_list, 0, sizeof(map[dst_m].drop_list)); + + // Remove quest information from the map + map[dst_m].qi_data = NULL; + + size = map[dst_m].bxs * map[dst_m].bys * sizeof(struct block_list*); + map[dst_m].block = (struct block_list **)aCalloc(1,size); + map[dst_m].block_mob = (struct block_list **)aCalloc(1,size); + + map[dst_m].index = mapindex_addmap(-1, map[dst_m].name); + map[dst_m].channel = NULL; + map[dst_m].mob_delete_timer = INVALID_TIMER; + + map_addmap2db(&map[dst_m]); + + return dst_m; +} + +/*========================================== + * Deleting a cloned map + *------------------------------------------*/ +int map_delclonemap(const char* mapname) +{ + int m = map_mapname2mapid(mapname); + + if(m < 0 || map[m].instance_id || map[m].clone_id <= 0) + return 0; + + // Kick everyone out + map_foreachinmap(map_instancemap_leave, m, BL_PC); + + // Do the unit cleanup + map_foreachinmap(map_instancemap_clean, m, BL_ALL); + + if( map[m].mob_delete_timer != INVALID_TIMER ) + delete_timer(map[m].mob_delete_timer, map_removemobs_timer); + + // Free memory + aFree(map[m].cell); + map[m].cell = NULL; + aFree(map[m].block); + map[m].block = NULL; + aFree(map[m].block_mob); + map[m].block_mob = NULL; + map_free_questinfo(m); + + mapindex_removemap( map[m].index ); + map_removemapdb(&map[m]); + memset(&map[m], 0x00, sizeof(map[0])); + map[m].mob_delete_timer = INVALID_TIMER; + return 1; +} + /*========================================= * Dynamic Mobs [Wizputer] *-----------------------------------------*/ @@ -2838,6 +2965,10 @@ void map_removemobs(int16 m) *------------------------------------------*/ const char* map_mapid2mapname(int m) { + if (map[m].clone_id) { // Clone map check + return map[map[m].clone_id].name; + } + if (map[m].instance_id) { // Instance map check struct instance_data *im = &instance_data[map[m].instance_id]; diff --git a/src/map/map.h b/src/map/map.h index ec0b2b0..762ab2d 100644 --- a/src/map/map.h +++ b/src/map/map.h @@ -705,6 +705,9 @@ struct map_data { unsigned short instance_id; int instance_src_map; + // Clone map system + unsigned short clone_id; + /* rAthena Local Chat */ struct Channel *channel; @@ -820,6 +823,10 @@ int map_addflooritem(struct item *item, int amount, int16 m, int16 x, int16 y, i int map_addinstancemap(const char *name, unsigned short instance_id); int map_delinstancemap(int m); +// Clone map system +int map_delclonemap(const char* mapname); +int map_addclonemap(const char *name, const char *newname); + // player to map session void map_addnickdb(int charid, const char* nick); void map_delnickdb(int charid, const char* nick); diff --git a/src/map/pc.c b/src/map/pc.c index 66a42f4..07d395b 100755 --- a/src/map/pc.c +++ b/src/map/pc.c @@ -5599,6 +5599,11 @@ bool pc_memo(struct map_session_data* sd, int pos) pos = 0; } + if( map[sd->bl.m].clone_id ) { + clif_displaymessage( sd->fd, "You cannot create a memo in this map." ); + return false; + } + if( map[sd->bl.m].instance_id ) { clif_displaymessage( sd->fd, msg_txt(sd,384) ); // You cannot create a memo in an instance. return false; diff --git a/src/map/script.c b/src/map/script.c index f53b799..9f59068 100644 --- a/src/map/script.c +++ b/src/map/script.c @@ -9607,6 +9607,11 @@ BUILDIN_FUNC(savepoint) y = script_getnum(st,4); m = map_mapindex2mapid(map_idx); + if( map[m].clone_id ) { + ShowError("buildin_savepoint: You cannot create a savepoint on this map %s.\n", str); + return SCRIPT_CMD_FAILURE; + } + if (cid_pos == 7) { int dx = script_getnum(st,5), dy = script_getnum(st,6), x1 = x + dx, y1 = y + dy, clonemap.diff
    1 point
  5. shouldn't call the clear() script command if there are no active mes() message. find all those clear() and remove it if there isn't any mes(...) executed before it.
    1 point
  6. // ----------------------------------------------------------- // Quest items -- do NOT use a reward item more than once! // Add(<shop ID>,<reward ID>,<reward amount>,<Zeny cost>,<point cost>,<required item ID>,<required item amount>{,...}); // -----------------------------------------------------------
    1 point
  7. /* CREATE TABLE IF NOT EXISTS `guildpack` ( `id` int(11) NOT NULL auto_increment, `account_id` int(11) NOT NULL default '0', `name` varchar(23) NOT NULL default '', `last_ip` varchar(100) NOT NULL default '', PRIMARY KEY (`account_id`), KEY (`id`) ) ENGINE=MyISAM; */ //====================================================================================================== prontera,130,172,5 script Guild Pack Info 468,{ if ( getcharid(2) == 0 ) { mes "You have no guild!"; close; } if ( @gpack || callsub( L_check ) ) { @gpack = 1; mes "^616D7EYou already given a Guild Package"; close; } mes "[Guild Pack NPC]"; mes "Hello there, it seems you are claiming for a Guild Pack."; next; mes "[Guild Pack NPC]"; mes "Let me gift you a guild pack for joining and"; mes "playing in Lunar RO, we hope you enjoy them."; next; mes "These guild pack is not duplicable and not dropable."; next; switch(select("Yes:No")) { case 1: .@myip$ = getcharip(); if ( callsub( L_check ) ) { mes "^616D7EIt seems you have same IP Address among Guild Mates: ^ff0000" + .@myip$ + "^000000. Sorry, but its not allowed."; close; } query_sql("INSERT INTO `guildpack` VALUES (NULL," + getcharid(3) + ",'" + escape_sql(strcharinfo(0)) + "','" + .@myip$ + "')"); //THIS PART WERE all items they will get getitem 29828,1; getitem 29851,1; getitem 29868,1; getitem 29834,1; getitem 29804,1; getitem 29835,1; getitem2 5170,1,1,7,0,0,0,0,0; getitem2 2319,1,1,7,0,4141,0,0,0; getitem2 2114,1,1,7,0,4058,0,0,0; getitem2 2528,1,1,7,0,4133,0,0,0; getitem2 2424,1,1,7,0,4097,0,0,0; getitem 2607,2; getitem 4035,5; getitem 4064,2; getitem 4079,2; getitem 14175,1; getitem 671,1; getitem 607,300; getitem 12045,100; getitem 12060,100; getitem 12050,100; getitem 12055,100; getitem 12065,100; getitem 12070,100; set @gpack, 1; warp "prontera",156,172; close; case 2: mes "^616D7ENevermind~, You can come back again later!"; close; } end; L_check: return query_sql("SELECT 1 FROM `guildpack` join login on login.`last_ip` = `guildpack`.`last_ip` where login.account_id = "+ getcharid(3), .@tmp ); OnInit: waitingroom "Guild Package",0; end; }
    1 point
×
×
  • Create New...