-
Posts
696 -
Joined
-
Last visited
-
Days Won
102
Content Type
Profiles
Forums
Downloads
Jobs Available
Server Database
Third-Party Services
Top Guides
Store
Crowdfunding
Everything posted by Tokei
-
Heya, Don't use timers that run scripts on players (you should avoid using the addtimer command entirely). The reason for that is you're attempting to run two scripts at once, and the script engine doesn't support that very well. Set the timer as a local variable instead: mes "type anything in 5 seconds"; .@limit = gettimetick(0) + 5000; input(.@text); clear(); if (gettimetick(0) >= .@limit) { mes "time over"; close; } mes "you did it"; close;
-
Hmm, well the following command worked fine on Windows: GrfCL.exe -encoding 949 -open "C:\Program Files (x86)\GRF Editor\test.grf" -extractFiles "" "" Perhaps you do not have the 949 codepage on your machine. You could test by opening GrfCL and typing the encoding command directly: .\GrfCL.exe Commands> encoding 949 #Log : Extraction and files added will now use this encoding : ks_c_5601-1987 If you get an error with the above, you'll have to use a different encoding or keep it as the default one.
-
The command you're looking for is -encoding 949
-
The "cps.dll" string is there twice in the client executable, the tool only expects one. So you need to change one of them manually before using the tool, or you can just keep cps.dll as the name of the file.
-
You are trying to open the file as a GRF, that will cause you errors. You have to open an already existing GRF or make a new one, then add the iteminfo and click on it to decompile it. It's a GRF tool, it's able to read and decompile lub files as a preview feature, but it's not its main purpose.
-
Updated GRF Editor to version 1.8.3.4: Added support for RSM2 files and the new RSW format. You are missing .net 3.5 and 4.0, most likely.
-
Heya, As of 1.8.3.3, GRF Editor now has a Dark Theme available. You can choose the theme from Tools > Settings > General > Theme.
-
Well, this adds a flat 80 hit to all players and enemies. While yes, it does help with your initial issue, it also makes flee builds a lot less worthwhile (it gives a free Phreeoni card to everyone). If that works out for you, then that's up to you...! Although it seems to me your biggest concern is the flee bonus that the higher level monsters get. Why not simply remove that instead? // Flee stat = status->flee; stat += level + status->agi + (bl->type == BL_MER ? 0 : bl->type == BL_PC ? status->luk / 5 : 0) + 100; //base level + ( every 1 agi = +1 flee ) + (every 5 luk = +1 flee) + 100 status->flee = cap_value(stat, 1, SHRT_MAX); to // Flee stat = status->flee; stat += (bl->type == BL_MOB ? 0 : level) + status->agi + (bl->type == BL_MER ? 0 : bl->type == BL_PC ? status->luk / 5 : 0) + 100; //base level + ( every 1 agi = +1 flee ) + (every 5 luk = +1 flee) + 100 status->flee = cap_value(stat, 1, SHRT_MAX);
-
Heya, Well, the function that determines whether you hit or miss the target is is_attack_hitting in battle.cpp. This is purely based on the hit vs flee between you and the target though. Mobs with higher levels have more flee because of the formula they use (in status.cpp): // Flee stat = status->flee; stat += level + status->agi + (bl->type == BL_MER ? 0 : bl->type == BL_PC ? status->luk / 5 : 0) + 100; //base level + ( every 1 agi = +1 flee ) + (every 5 luk = +1 flee) + 100 status->flee = cap_value(stat, 1, SHRT_MAX); What you're asking for doesn't really fit well with the current system though.
-
How can i duplicate a NPC inside of my script?
Tokei replied to luizragna's question in Source Requests
Heya, This is possible, but it usually means the solution/algoritm you're trying to use is the wrong one to start with. That aside, you can use something similar to: duplicate "prontera", 154, 182, 4, "SourceNPC", "DuplicatedNPC", 77; And you'll have to do the changes below: diff --git a/src/map/npc.hpp b/src/map/npc.hpp index 0ce0c96a0..ffde62587 100644 --- a/src/map/npc.hpp +++ b/src/map/npc.hpp @@ -1219,6 +1219,7 @@ void do_clear_npc(void); void do_final_npc(void); void do_init_npc(void); void npc_event_do_oninit(void); +const char* npc_parse_duplicate(char* w1, char* w2, char* w3, char* w4, const char* start, const char* buffer, const char* filepath); int npc_event_do(const char* name); int npc_event_do_id(const char* name, int rid); diff --git a/src/map/script.cpp b/src/map/script.cpp index 604274ecd..9da5d4690 100644 --- a/src/map/script.cpp +++ b/src/map/script.cpp @@ -24548,6 +24548,38 @@ BUILDIN_FUNC(preg_match) { #endif } +BUILDIN_FUNC(duplicate) +{ + const char *map = script_getstr(st,2); + int x = script_getnum(st,3); + int y = script_getnum(st,4); + int dir = script_getnum(st,5); + const char *duplicate_name = script_getstr(st,6); + const char *npc_name = script_getstr(st,7); + char w1[2048], w2[2048], w3[2048], w4[2048], p[2048]; + int view_id = script_getnum(st,8); + struct npc_data* nd = map_id2nd(st->oid); + + if (!nd) { + return SCRIPT_CMD_FAILURE; + } + + sprintf(w1, "%s,%d,%d,%d", map, x, y, dir); + sprintf(w2, "duplicate(%s)", duplicate_name); + sprintf(w3, "%s", npc_name); + + if (script_hasdata(st,9) && script_hasdata(st,10)) { + sprintf(w4, "%d,%d,%d", view_id, script_getnum(st,9), script_getnum(st,10)); + } + else { + sprintf(w4, "%d", view_id); + } + + sprintf(p, "%s\t%s\t%s\t%s", w1, w2, w3, w4); + npc_parse_duplicate(w1,w2,w3,w4, p, p, nd->path); + return SCRIPT_CMD_SUCCESS; +} + /// script command definitions /// for an explanation on args, see add_buildin_func struct script_function buildin_func[] = { @@ -25170,6 +25202,8 @@ struct script_function buildin_func[] = { BUILDIN_DEF(achievement_condition,"i"), BUILDIN_DEF(getvariableofinstance,"ri"), BUILDIN_DEF(convertpcinfo,"vi"), + + BUILDIN_DEF(duplicate,"siiissi??"), #include "../custom/script_def.inc" {NULL,NULL,NULL}, -
That means you tried to use the close command when there was no text being displayed (from the mes command). I... don't know what NPC this is, but you'll want to change that "close" for "end" instead.
-
I want to change the letters in the red line
Tokei replied to lleldigm's question in Client-side Support
Heya, The job names are hard-coded in the client executable. You'll have to open an hex editor and then search for "Gunslinger". -
What file is responsible for 'Wear Costume' button?
Tokei replied to Mistique's question in Client-side Support
Yes, when you "receive" the item in your inventory, the button will display properly because it uses the clif_additem packet. I meant how you receive the item information packet-wise, not the source of where it came from (though that's related of course). As for why 20285 shows up and 20286 doesn't, that is because 20285 has a hat effect and these are not displayed on the client with the feature. You can remove the item from the list by opening hateffectinfo.lub and then removing the ids from effectHatItemTable. It's probably best to keep the button disabled for that one though. -
Heya, These are ground unit skills. You'll want to skip the BL_PC check and then adjust the skill ratios to battle.cpp: diff --git a/src/map/battle.cpp b/src/map/battle.cpp index de8167f4a..904a672d8 100644 --- a/src/map/battle.cpp +++ b/src/map/battle.cpp @@ -4354,6 +4354,13 @@ static int battle_calc_attack_skill_ratio(struct Damage* wd, struct block_list * if (sd && pc_checkskill(sd, SU_SPIRITOFLIFE)) skillratio += skillratio * status_get_hp(src) / status_get_max_hp(src); break; + case SG_SUN_WARM: + case SG_MOON_WARM: + case SG_STAR_WARM: + if (tsd) { + skillratio += -50; + } + break; } return skillratio; } diff --git a/src/map/skill.cpp b/src/map/skill.cpp index 3b7b4ba86..7656a247f 100755 --- a/src/map/skill.cpp +++ b/src/map/skill.cpp @@ -13795,7 +13795,7 @@ int skill_unit_onplace_timer(struct skill_unit *unit, struct block_list *bl, t_t do { if( bl->type == BL_PC ) status_zap(bl, 0, 15); // sp damage to players - else // mobs + if( status_charge(ss, 0, 2) ) { // costs 2 SP per hit if( !skill_attack(BF_WEAPON,ss,&unit->bl,bl,sg->skill_id,sg->skill_lv,tick+(t_tick)count*sg->interval,0) ) status_charge(ss, 0, 8); //costs additional 8 SP if miss
-
What file is responsible for 'Wear Costume' button?
Tokei replied to Mistique's question in Client-side Support
Heya, I presume you're talking about the "Preview" button from the item descriptions? If so, then it's not a file, this is decided server-side. How you receive the item makes the button appear or not. If you look in the clif_vendinglist function, you'll see some item packets sent to the client have 6 extra bytes. This part in particular: WFIFOL(fd,offset+47+i*item_length) = pc_equippoint_sub(sd,data); WFIFOW(fd,offset+51+i*item_length) = data->look; The data->look is the actual view ID that will be shown on the client for the item after clicking the button. The pc_equippoint_sub decides whether the client should display the button or not. The problem with that system is that many packets don't have that feature. If you try to preview the item from a shop NPC, it won't give you the option either. If you put the item in your cart, the button will disappear as well, etc. It's just very unreliable overall. kRO added more "locations" where this feature is available, though. -
Heya, You'll need to edit log_pick in log.cpp: void log_pick(int id, int16 m, e_log_pick_type type, int amount, struct item* itm) Something along those lines: /// logs item transactions (generic) void log_pick(int id, int16 m, e_log_pick_type type, int amount, struct item* itm) { nullpo_retv(itm); if( ( log_config.enable_logs&type ) == 0 ) {// disabled return; } if( !should_log_item(itm->nameid, amount, itm->refine) ) return; //we skip logging this item set - it doesn't meet our logging conditions [Lupus] if( log_config.sql_logs ) { int i; struct map_session_data *sd = map_charid2sd(id); SqlStmt* stmt = SqlStmt_Malloc(logmysql_handle); char esc_sname[NAME_LENGTH*2+1]; StringBuf buf; StringBuf_Init(&buf); if (sd) { Sql_EscapeStringLen(logmysql_handle, esc_sname, sd->status.name, strnlen(sd->status.name, NAME_LENGTH)); } StringBuf_Printf(&buf, "%s INTO `%s` (`time`, `char_id`, `account_id`, `name`, `type`, `nameid`, `amount`, `refine`, `map`, `unique_id`, `bound`", LOG_QUERY, log_config.log_pick); for (i = 0; i < MAX_SLOTS; ++i) StringBuf_Printf(&buf, ", `card%d`", i); for (i = 0; i < MAX_ITEM_RDM_OPT; ++i) { StringBuf_Printf(&buf, ", `option_id%d`", i); StringBuf_Printf(&buf, ", `option_val%d`", i); StringBuf_Printf(&buf, ", `option_parm%d`", i); } StringBuf_Printf(&buf, ") VALUES(NOW(),'%u','%u','%s','%c','%d','%d','%d','%s','%" PRIu64 "','%d'", id, sd ? sd->status.account_id : 0, sd ? esc_sname : "", log_picktype2char(type), itm->nameid, amount, itm->refine, map_getmapdata(m)->name[0] ? map_getmapdata(m)->name : "", itm->unique_id, itm->bound); for (i = 0; i < MAX_SLOTS; i++) StringBuf_Printf(&buf, ",'%d'", itm->card[i]); for (i = 0; i < MAX_ITEM_RDM_OPT; i++) StringBuf_Printf(&buf, ",'%d','%d','%d'", itm->option[i].id, itm->option[i].value, itm->option[i].param); StringBuf_Printf(&buf, ")"); if (SQL_SUCCESS != SqlStmt_PrepareStr(stmt, StringBuf_Value(&buf)) || SQL_SUCCESS != SqlStmt_Execute(stmt)) SqlStmt_ShowDebug(stmt); SqlStmt_Free(stmt); StringBuf_Destroy(&buf); } else { char timestring[255]; time_t curtime; FILE* logfp; if( ( logfp = fopen(log_config.log_pick, "a") ) == NULL ) return; time(&curtime); strftime(timestring, sizeof(timestring), log_timestamp_format, localtime(&curtime)); fprintf(logfp,"%s - %d\t%c\t%hu,%d,%d,%hu,%hu,%hu,%hu,%s,'%" PRIu64 "',%d\n", timestring, id, log_picktype2char(type), itm->nameid, amount, itm->refine, itm->card[0], itm->card[1], itm->card[2], itm->card[3], map_getmapdata(m)->name[0]?map_getmapdata(m)->name:"", itm->unique_id, itm->bound); fclose(logfp); } }
-
Heya, You can't do that (not without major changes anyway). I presume the goal here is to run a script in the source (which is a bad idea), but the easy solution here would simply be to set your variables as temporary global variables and then run an event label: In the source, you would use something like: #include "mapreg.h" #include "npc.h" [...] mapreg_setreg(reference_uid(add_str("$@param1"), 0), MG_SAFETYWALL); mapreg_setreg(reference_uid(add_str("$@param2"), 0), skill_id); mapreg_setregstr(reference_uid(add_str("$@param3$"), 0), "a string"); npc_event_do_id("MyScript::OnCalled", sd->bl.id); And in the script: function script myfunction { announce "arg1: " + getarg(0) + ", arg2: " + getarg(1) + ", arg3: " + getarg(2); return; } - script MyScript -1,{ end; OnCalled: callfunc("myfunction", $@param1, $@param2, $@param3$); end; } It would be much easier to do the code in the source directly instead though.
-
Act editor if it has magnifer why it doesnt have shrink script?
Tokei replied to sonatta09's question in Third Party Support
Heya, You can use Scripts > Magnifier. It's a multiplier, so simply use a number below 1 to make it smaller. -
Heya, Your files are encrypted and they cannot be read/extracted from the GRF. That is the purpose of an encryption tool. Your GRF is not locked in any way. It can be merged, it can be patched, it can be modified, etc. It's meant to protect your work, sprites, custom maps, etc. What you're looking for is an anti-cheat software and this is not one...!
-
If it fails to extract, it means the password was incorrect and it didn't properly decrypt the files.
-
The mob is adorable ;D
-
The latest version is always provided with the latest mediafire link. Updated to 1.8.2.7: Fixed a bug when adding a large number of files that ended up ignoring some of the added files. Updated GRF Editor Decompiler to fix some annoying issues with the LUB files. The "Use GRF Editor Decompiler" can no longer be unchecked. Removed the third-party luadec decompilers. Esc now works in the Text encoding window. The Image converter tool now works in batches and automatically set purple (and its variants) as transparent. Added more default paths when making thor files. Extracting broken directory links will no longer stop the file extraction. Brought back the software's sources for those interested: Sources
-
This option was removed quite a while ago, sorry!
-
Version 1.0.2
5268 downloads
Heya, This is a tool to edit mapcache files for rAthena (db/(pre-)re/map_cache.dat). It is already part of Server Database Editor as a sub tool, but I've made it a tool on its own instead. It was made to fix the issue with WeeMapCache not assigning the water tiles properly. Otherwise, it's pretty much the same interface, but easier to use. The most recent version will always be found from the mediafire link below: http://www.mediafire.com/file/tjlnooebx6am673 Source files: https://github.com/Tokeiburu/Mapcache-EditorFree -
Heya, The following script commands replace addrid and they were initially implemented by Luxuri. The main advantage of these is that they do not attach the players on the current script, allowing an easier code flow. The commands: foreachinserver "<npc_label>" foreachinmap "<npc_label>", "<map_name>" foreachinparty "<npc_label>", <party_id> foreachinarea "<npc_label>", "<map_name>", <x1>, <y1>, <x2>, <y2> foreachinshootablerange "<npc_label>", "<map_name>", <x>, <y>, <range> foreachinguild "<npc_label>", <guild_id> prontera,155,185,3 script Test 77,{ foreachinserver("Test::OnEvent"); foreachinmap("Test::OnEvent", "prontera"); foreachinparty("Test::OnEvent", getcharid(1)); foreachinarea("Test::OnEvent", "this", 153, 182, 159, 177); foreachinshootablerange("Test::OnEvent", "this", 153, 182, 2); foreachinguild("Test::OnEvent", getcharid(2)); end; OnEvent: announce "Attached script to " + strcharinfo(0), 0; end; } For example, for making a script that kicks dead players without using OnPCDieEvent, you could use: prontera,155,185,3 script Test 77,{ initnpctimer; dispbottom "Kicking dead players."; end; OnTimer1000: .kicked = 0; foreachinmap("Test::OnKick", "prontera"); if (.kicked > 0) { announce .kicked + " player(s) have died!", 0; } initnpctimer; end; OnKick: if (HP <= 0) { .kicked++; getitem 501, 1; warp "alberta", 192, 147; percentheal 100, 100; } end; } You can easily make your own foreach methods (for BG, clans, etc). Diff file: diff --git a/src/map/npc.cpp b/src/map/npc.cpp index 647a765..c60a5d7 100644 --- a/src/map/npc.cpp +++ b/src/map/npc.cpp @@ -2224,6 +2224,20 @@ int npc_unload(struct npc_data* nd, bool single) { return 0; } +/// Returns the NPC associated with the specified event label. +struct npc_data* npc_event_label_nd(const char* labelname) +{ + struct event_data* ev = (struct event_data*)strdb_get(ev_db, labelname); + return (ev != NULL ? ev->nd : NULL); +} + +/// Returns the bytecode position that the specified event label refers to. +int npc_event_label_pos(const char* labelname) +{ + struct event_data* ev = (struct event_data*)strdb_get(ev_db, labelname); + return (ev != NULL ? ev->pos : -1); +} + // // NPC Source Files // diff --git a/src/map/npc.hpp b/src/map/npc.hpp index d6a9b97..3049651 100644 --- a/src/map/npc.hpp +++ b/src/map/npc.hpp @@ -1162,6 +1162,9 @@ bool npc_isnear(struct block_list * bl); int npc_get_new_npc_id(void); +struct npc_data* npc_event_label_nd(const char* labelname); +int npc_event_label_pos(const char* labelname); + int npc_addsrcfile(const char* name, bool loadscript); void npc_delsrcfile(const char* name); int npc_parsesrcfile(const char* filepath, bool runOnInit); diff --git a/src/map/script.cpp b/src/map/script.cpp index 180f9ba..5535094 100644 --- a/src/map/script.cpp +++ b/src/map/script.cpp @@ -12230,6 +12230,150 @@ BUILDIN_FUNC(isloggedin) return SCRIPT_CMD_SUCCESS; } +static int script_foreach_sub(TBL_PC* sd, const char* event) +{ + struct npc_data* nd; + int pos; + + if ((nd = npc_event_label_nd(event)) == NULL || (pos = npc_event_label_pos(event)) == -1) + return 0; + + run_script(nd->u.scr.script, pos, sd->bl.id, nd->bl.id); + return 1; +} + +static int script_foreach_sub_va_bl(struct block_list* bl, va_list args) { + const char* event = va_arg(args, const char*); + return script_foreach_sub((TBL_PC*)bl, event); +} + +static int script_foreach_sub_va_sd(TBL_PC* sd, va_list args) { + const char* event = va_arg(args, const char*); + return script_foreach_sub(sd, event); +} + +/// foreachinserver "<npc_label>" +BUILDIN_FUNC(foreachinserver) +{ + const char* event = script_getstr(st, 2); + map_foreachpc(script_foreach_sub_va_sd, event); + return SCRIPT_CMD_SUCCESS; +} + +/// foreachinmap "<npc_label>", "<map_name>" +BUILDIN_FUNC(foreachinmap) +{ + const char* event = script_getstr(st, 2); + const char* mapname = script_getstr(st, 3); + TBL_NPC* nd = map_id2nd(st->oid); + int16 m = (nd && strcmp(mapname, "this") == 0) ? nd->bl.m : map_mapname2mapid(mapname); + + if (m < 0) { + ShowWarning("buildin_foreachinmap: Invalid map name '%s'.\n", mapname); + return SCRIPT_CMD_SUCCESS; + } + + map_foreachinmap(script_foreach_sub_va_bl, m, BL_PC, event); + return SCRIPT_CMD_SUCCESS; +} + +/// foreachinparty "<npc_label>", <party_id> +BUILDIN_FUNC(foreachinparty) +{ + const char* event = script_getstr(st, 2); + int party_id = script_getnum(st, 3); + struct party_data* p; + int i; + + if ((p = party_search(party_id)) == NULL) { + ShowWarning("buildin_foreachinparty: Party id '%d' doesn't exist or is not loaded yet.\n", party_id); + return SCRIPT_CMD_SUCCESS; + } + + for (i = 0; i < MAX_PARTY; ++i) { + TBL_PC* sd; + int char_id = p->party.member[i].char_id; + + if (char_id == 0 || (sd = map_charid2sd(char_id)) == NULL) + continue; + + script_foreach_sub(sd, event); + } + + return SCRIPT_CMD_SUCCESS; +} + +/// foreachinarea "<npc_label>", "<map_name>", <x1>, <y1>, <x2>, <y2> +BUILDIN_FUNC(foreachinarea) +{ + const char* event = script_getstr(st, 2); + const char* mapname = script_getstr(st, 3); + int x1 = script_getnum(st, 4); + int y1 = script_getnum(st, 5); + int x2 = script_getnum(st, 6); + int y2 = script_getnum(st, 7); + TBL_NPC* nd = map_id2nd(st->oid); + int16 m = (nd && strcmp(mapname, "this") == 0) ? nd->bl.m : map_mapname2mapid(mapname); + + if (m < 0) { + ShowWarning("buildin_foreachinarea: Invalid map name '%s'.\n", mapname); + return SCRIPT_CMD_SUCCESS; + } + + map_foreachinarea(script_foreach_sub_va_bl, m, x1, y1, x2, y2, BL_PC, event); + return SCRIPT_CMD_SUCCESS; +} + +/// foreachinshootablerange "<npc_label>", "<map_name>", <x>, <y>, <range> +BUILDIN_FUNC(foreachinshootablerange) +{ + const char* event = script_getstr(st, 2); + const char* mapname = script_getstr(st, 3); + struct block_list bl; + int x1 = script_getnum(st, 4); + int y1 = script_getnum(st, 5); + int range = script_getnum(st, 6); + TBL_NPC* nd = map_id2nd(st->oid); + int16 m = (nd && strcmp(mapname, "this") == 0) ? nd->bl.m : map_mapname2mapid(mapname); + + if (m < 0) { + ShowWarning("buildin_foreachinarea: Invalid map name '%s'.\n", mapname); + return SCRIPT_CMD_SUCCESS; + } + + memset(&bl, 0, sizeof(struct block_list)); + bl.m = m; + bl.x = x1; + bl.y = y1; + + map_foreachinshootrange(script_foreach_sub_va_bl, &bl, range, BL_PC, event); + return SCRIPT_CMD_SUCCESS; +} + +/// foreachinguild "<npc_label>", <guild_id> +BUILDIN_FUNC(foreachinguild) +{ + const char* event = script_getstr(st, 2); + int guild_id = script_getnum(st, 3); + struct guild* g; + int i; + + if ((g = guild_search(guild_id)) == NULL) { + ShowWarning("buildin_foreachinguild: Guild id '%d' doesn't exist or is not loaded yet.\n", guild_id); + return SCRIPT_CMD_SUCCESS; + } + + for (i = 0; i < MAX_GUILD; ++i) { + TBL_PC* sd; + + if (!(sd = g->member[i].sd)) + continue; + + script_foreach_sub(sd, event); + } + + return SCRIPT_CMD_SUCCESS; +} /*========================================== * @@ -24642,6 +24786,13 @@ struct script_function buildin_func[] = { BUILDIN_DEF2(round, "floor", "i"), BUILDIN_DEF(getequiptradability, "i?"), BUILDIN_DEF(mail, "isss*"), + + BUILDIN_DEF(foreachinserver, "s"), + BUILDIN_DEF(foreachinmap, "ss"), + BUILDIN_DEF(foreachinparty, "si"), + BUILDIN_DEF(foreachinarea, "ssiiii"), + BUILDIN_DEF(foreachinshootablerange, "ssiii"), + BUILDIN_DEF(foreachinguild, "si"), #include "../custom/script_def.inc" {NULL,NULL,NULL}, foreach.diff