Jump to content

Tokei

Members
  • Posts

    700
  • Joined

  • Last visited

  • Days Won

    109

Everything posted by Tokei

  1. Hmm, your base is different than rAthena (you do not have the int64 script update applied). There's a couple of mistakes with how you assigned the integers, replace your two functions with this instead: /** * Read Item Random Option Group from db file * @author [Cydh] **/ static bool itemdb_read_randomopt_group(char* str[], int columns, int current) { int id = 0; int randid = 0; unsigned short rate = (unsigned short)strtoul(str[1], NULL, 10); struct s_random_opt_group *g = NULL; if (!script_get_constant(str[0], &id)) { // autogenerate constant, it gets annoying to define it everytime script_set_constant(trim(str[0]), add_str(trim(str[0])), false, false); if (!script_get_constant(trim(str[0]), &id)) { // Should never happen? ShowError("itemdb_read_randomopt_group: Invalid ID for Random Option Group '%s'.\n", str[0]); return false; } } if (!script_get_constant(str[2], &randid) || !itemdb_randomopt_exists(randid)) { ShowError("itemdb_read_randomopt_group: Invalid random group id '%s'!\n", str[2]); return false; } if (!(g = (struct s_random_opt_group *)uidb_get(itemdb_randomopt_group, id))) { CREATE(g, struct s_random_opt_group, 1); g->total = 0; g->entries = NULL; g->total_weight = 0; uidb_put(itemdb_randomopt_group, id, g); } RECREATE(g->entries, struct s_random_opt_group_entry, g->total + 1); memset(&g->entries[g->total], 0, sizeof(g->entries[g->total])); g->entries[g->total].option.id = randid; g->entries[g->total].option.value = (short)strtoul(str[3], NULL, 10); g->entries[g->total].option.param = (char)strtoul(str[4], NULL, 10); g->entries[g->total].weight = rate; if (columns > 5) { g->entries[g->total].max_value = max((short)strtoul(str[5], NULL, 10), g->entries[g->total].option.value); } g->total_weight += rate; g->total++; return true; } /** * Read Item Random Option Group from db file **/ static bool itemdb_read_randomopt_equip(char* str[], int columns, int current) { unsigned short nameid; int group_id = -1; struct item_data *item = NULL; int i; nameid = atoi(str[0]); for (i = 1; i < columns; i++) { if (ISDIGIT(str[i][0])) { group_id = (int)strtoul(str[i], NULL, 10); } else { if (!script_get_constant(trim(str[i]), &group_id)) { ShowError("itemdb_read_randopt_equip: Invalid constant '%s'!\n", str[i]); return false; } } if ((item = itemdb_exists(nameid)) == NULL) { ShowWarning("itemdb_read_randopt_equip: Invalid item ID %hu.\n", nameid); return false; } if (!itemdb_randomopt_group_exists(group_id)) { ShowWarning("itemdb_read_randopt_equip: Invalid random option group ID %hu.\n", group_id); return false; } item->randomopt_groupid[i - 1] = group_id; } return true; }
  2. @mawjustin Hmmm, you'd get this error because the group IDs aren't defined. That... shouldn't be the case, though. The constant for your group ID, "7934", does seem to exist. Can you show me both of your itemdb_read_randomopt_group and itemdb_read_randomopt_equip functions, in itemdb.cpp? Also please show me one item you made in item_randoopt_equips.txt with one of the group from item_randoption_group.txt that is used. The error is somewhat vague.
  3. Heya, If you want to achieve that behavior, you'll have to change a whole bunch of code. There was an earlier version of the system which greatly simplified the randomness of random option enchants. The system would rely on 3 files: db/re/item_randomopt_db.txt (remains the same) db/re/item_randoption_equips.txt (this replaces the db/re/mob_drops.txt file, the random options are instead attached to the weapon itself, rather than the mob the weapon drops from) db/re/item_randoption_group.txt (remains mostly the same, except you add another optional column for the max value of the field) item_randoption_equips.txt would look as below. You first define the random options for the specific weapons as such: // Items Random Option Database // // Structure of Database: // Item_ID,RandomOption_GroupId1{,RandomOption_GroupId2,RandomOption_GroupId3,RandomOption_GroupId4,RandomOption_GroupId5} 28705,RDMOPTG_Crimson_Weapon_1,RDMOPTG_Crimson_Weapon_2,RDMOPTG_Crimson_Weapon_3 13327,RDMOPTG_Crimson_Weapon_1 28604,RDMOPTG_Crimson_Weapon_1 28007,RDMOPTG_Crimson_Weapon_1 1839,RDMOPTG_Crimson_Weapon_1 1498,RDMOPTG_Crimson_Weapon_1 16040,RDMOPTG_Crimson_Weapon_1 13454,RDMOPTG_Crimson_Weapon_1 1443,RDMOPTG_Crimson_Weapon_1 28106,RDMOPTG_Crimson_Weapon_1 21015,RDMOPTG_Crimson_Weapon_1 1939,RDMOPTG_Crimson_Weapon_1 1995,RDMOPTG_Crimson_Weapon_1 The random options for each groups are defined in item_randoption_group.txt. In the sample below, you'll notice a new colum for the 2nd and 3rd random options I chose, which will make the value vary between 30~50 for the earth resistance and 5~10 for... the others. // Items Random Option Database // // Structure of Database: // Group_ID,rate,randopt_id1,randopt_value1,randopt_param1 // Crimson Weapon RDMOPTG_Crimson_Weapon_1,1,RDMOPT_WEAPON_ATTR_NOTHING,0,0 RDMOPTG_Crimson_Weapon_1,1,RDMOPT_WEAPON_ATTR_WATER,0,0 RDMOPTG_Crimson_Weapon_1,1,RDMOPT_WEAPON_ATTR_GROUND,0,0 RDMOPTG_Crimson_Weapon_1,1,RDMOPT_WEAPON_ATTR_FIRE,0,0 RDMOPTG_Crimson_Weapon_1,1,RDMOPT_WEAPON_ATTR_WIND,0,0 RDMOPTG_Crimson_Weapon_1,1,RDMOPT_WEAPON_ATTR_SAINT,0,0 RDMOPTG_Crimson_Weapon_2,1,RDMOPT_ATTR_TOLERACE_GROUND,30,0,50 RDMOPTG_Crimson_Weapon_3,1,RDMOPT_DAMAGE_PROPERTY_GROUND_USER,5,0,10 RDMOPTG_Crimson_Weapon_3,1,RDMOPT_DAMAGE_PROPERTY_NOTHING_TARGET,5,0,10 RDMOPTG_Crimson_Weapon_3,1,RDMOPT_DAMAGE_PROPERTY_WATER_TARGET,5,0,10 RDMOPTG_Crimson_Weapon_3,1,RDMOPT_DAMAGE_PROPERTY_FIRE_USER,5,0,10 As for the source change, you can apply the diff below and do some tests with it (I didn't test it too seriously, it worked well enough for what I believe your request was though). The current weight/ratio system used... doesn't make any sense, so I made my own. diff --git a/db/re/item_randomopt_group.txt b/db/re/item_randomopt_group.txt index 6d9b9929a..05d579f9a 100644 --- a/db/re/item_randomopt_group.txt +++ b/db/re/item_randomopt_group.txt @@ -1,10 +1,16 @@ // <randopt_groupid>,<rate>,<randopt_id1>,<randopt_value1>,<randopt_param1>{,<randopt_id2>,<randopt_value2>,<randopt_param2>,<randopt_id3>,<randopt_value3>,<randopt_param3>,<randopt_id4>,<randopt_value4>,<randopt_param4>,<randopt_id5>,<randopt_value5>,<randopt_param5>} // Crimson Weapon -RDMOPTG_Crimson_Weapon,1,RDMOPT_WEAPON_ATTR_NOTHING,0,0 -RDMOPTG_Crimson_Weapon,1,RDMOPT_WEAPON_ATTR_WATER,0,0 -RDMOPTG_Crimson_Weapon,1,RDMOPT_WEAPON_ATTR_GROUND,0,0 -RDMOPTG_Crimson_Weapon,1,RDMOPT_WEAPON_ATTR_FIRE,0,0 -RDMOPTG_Crimson_Weapon,1,RDMOPT_WEAPON_ATTR_WIND,0,0 -RDMOPTG_Crimson_Weapon,1,RDMOPT_WEAPON_ATTR_SAINT,0,0 -RDMOPTG_Crimson_Weapon,1,RDMOPT_WEAPON_ATTR_DARKNESS,0,0 +RDMOPTG_Crimson_Weapon_1,1,RDMOPT_WEAPON_ATTR_NOTHING,0,0 +RDMOPTG_Crimson_Weapon_1,1,RDMOPT_WEAPON_ATTR_WATER,0,0 +RDMOPTG_Crimson_Weapon_1,1,RDMOPT_WEAPON_ATTR_GROUND,0,0 +RDMOPTG_Crimson_Weapon_1,1,RDMOPT_WEAPON_ATTR_FIRE,0,0 +RDMOPTG_Crimson_Weapon_1,1,RDMOPT_WEAPON_ATTR_WIND,0,0 +RDMOPTG_Crimson_Weapon_1,1,RDMOPT_WEAPON_ATTR_SAINT,0,0 + +RDMOPTG_Crimson_Weapon_2,1,RDMOPT_ATTR_TOLERACE_GROUND,30,0,50 + +RDMOPTG_Crimson_Weapon_3,1,RDMOPT_DAMAGE_PROPERTY_GROUND_USER,5,0,10 +RDMOPTG_Crimson_Weapon_3,1,RDMOPT_DAMAGE_PROPERTY_NOTHING_TARGET,5,0,10 +RDMOPTG_Crimson_Weapon_3,1,RDMOPT_DAMAGE_PROPERTY_WATER_TARGET,5,0,10 +RDMOPTG_Crimson_Weapon_3,1,RDMOPT_DAMAGE_PROPERTY_FIRE_USER,5,0,10 \ No newline at end of file diff --git a/src/map/atcommand.cpp b/src/map/atcommand.cpp index 266f37526..b0c6874e3 100644 --- a/src/map/atcommand.cpp +++ b/src/map/atcommand.cpp @@ -1403,6 +1403,9 @@ ACMD_FUNC(item) item_tmp.nameid = item_id; item_tmp.identify = 1; item_tmp.bound = bound; + + itemdb_add_randomopt(&item_tmp); + if ((flag = pc_additem(sd, &item_tmp, get_count, LOG_TYPE_COMMAND))) clif_additem(sd, 0, 0, flag); } diff --git a/src/map/itemdb.cpp b/src/map/itemdb.cpp index 56ced4d34..f7f606c4e 100644 --- a/src/map/itemdb.cpp +++ b/src/map/itemdb.cpp @@ -1783,53 +1783,138 @@ struct s_random_opt_group *itemdb_randomopt_group_exists(int id) { static bool itemdb_read_randomopt_group(char* str[], int columns, int current) { int64 id_tmp; int id = 0; - int i; + int64 randid_tmp; + int randid = 0; unsigned short rate = (unsigned short)strtoul(str[1], NULL, 10); struct s_random_opt_group *g = NULL; if (!script_get_constant(str[0], &id_tmp)) { - ShowError("itemdb_read_randomopt_group: Invalid ID for Random Option Group '%s'.\n", str[0]); - return false; + // autogenerate constant, it gets annoying to define it everytime + script_set_constant(trim(str[0]), add_str(trim(str[0])), false, false); + + if (!script_get_constant(trim(str[0]), &id_tmp)) { // Should never happen? + ShowError("itemdb_read_randomopt_group: Invalid ID for Random Option Group '%s'.\n", str[0]); + return false; + } } - id = static_cast<int>(id_tmp); - - if ((columns-2)%3 != 0) { - ShowError("itemdb_read_randomopt_group: Invalid column entries '%d'.\n", columns); + if (!script_get_constant(str[2], &randid_tmp) || ((randid = static_cast<int>(randid_tmp)) && !itemdb_randomopt_exists(randid))) { + ShowError("itemdb_read_randomopt_group: Invalid random group id '%s'!\n", str[2]); return false; } + id = static_cast<int>(id_tmp); + if (!(g = (struct s_random_opt_group *)uidb_get(itemdb_randomopt_group, id))) { CREATE(g, struct s_random_opt_group, 1); - g->id = id; g->total = 0; g->entries = NULL; - uidb_put(itemdb_randomopt_group, g->id, g); + g->total_weight = 0; + uidb_put(itemdb_randomopt_group, id, g); } - RECREATE(g->entries, struct s_random_opt_group_entry, g->total + rate); + RECREATE(g->entries, struct s_random_opt_group_entry, g->total + 1); - for (i = g->total; i < (g->total + rate); i++) { - int j, k; - memset(&g->entries[i].option, 0, sizeof(g->entries[i].option)); - for (j = 0, k = 2; k < columns && j < MAX_ITEM_RDM_OPT; k+=3) { - int64 randid_tmp; - int randid = 0; + memset(&g->entries[g->total], 0, sizeof(g->entries[g->total])); + + g->entries[g->total].option.id = randid; + g->entries[g->total].option.value = (short)strtoul(str[3], NULL, 10); + g->entries[g->total].option.param = (char)strtoul(str[4], NULL, 10); + g->entries[g->total].weight = rate; - if (!script_get_constant(str[k], &randid_tmp) || ((randid = static_cast<int>(randid_tmp)) && !itemdb_randomopt_exists(randid))) { - ShowError("itemdb_read_randomopt_group: Invalid random group id '%s' in column %d!\n", str[k], k+1); - continue; + if (columns > 5) { + g->entries[g->total].max_value = max((short)strtoul(str[5], NULL, 10), g->entries[g->total].option.value); + } + + g->total_weight += rate; + g->total++; + return true; +} + +/** +* Read Item Random Option Group from db file +**/ +static bool itemdb_read_randomopt_equip(char* str[], int columns, int current) { + unsigned short nameid; + int64 group_id_tmp; + int group_id = -1; + struct item_data *item = NULL; + int i; + + nameid = atoi(str[0]); + + for (i = 1; i < columns; i++) { + if (ISDIGIT(str[i][0])) { + group_id = (int)strtoul(str[i], NULL, 10); + } + else { + if (!script_get_constant(trim(str[i]), &group_id_tmp)) { + ShowError("itemdb_read_randopt_equip: Invalid constant '%s'!\n", str[i]); + return false; } - g->entries[i].option[j].id = randid; - g->entries[i].option[j].value = (short)strtoul(str[k+1], NULL, 10); - g->entries[i].option[j].param = (char)strtoul(str[k+2], NULL, 10); - j++; + + group_id = static_cast<int>(group_id_tmp); + } + + if ((item = itemdb_exists(nameid)) == NULL) { + ShowWarning("itemdb_read_randopt_equip: Invalid item ID %hu.\n", nameid); + return false; } + + if (!itemdb_randomopt_group_exists(group_id)) { + ShowWarning("itemdb_read_randopt_equip: Invalid random option group ID %hu.\n", group_id); + return false; + } + + item->randomopt_groupid[i - 1] = group_id; } - g->total += rate; + return true; } +/** +* Sets random options to a weapon, if it has any. +**/ +void itemdb_add_randomopt(struct item *it) { + struct item_data *id; + struct s_random_opt_group *randomopt_group; + int i; + + if (!it || !it->nameid || (id = itemdb_exists(it->nameid)) == NULL) { + return; + } + + for (i = 0; i < MAX_ITEM_RDM_OPT; i++) { + if (id->randomopt_groupid[i] && ((randomopt_group = itemdb_randomopt_group_exists(id->randomopt_groupid[i])) != NULL)) { + int rnd_value = rnd() % (randomopt_group->total_weight); + int total = 0; + int j; + + for (j = 0; j < randomopt_group->total; j++) { + total += randomopt_group->entries[j].weight; + + if (rnd_value < total) { + it->option[i].id = randomopt_group->entries[j].option.id; + + if (randomopt_group->entries[j].max_value > 0 && randomopt_group->entries[j].max_value != randomopt_group->entries[j].option.value) { + int max = randomopt_group->entries[j].max_value; + int min = randomopt_group->entries[j].option.value; + + it->option[i].value = rnd() % (max - min + 1) + min; + } + else { + it->option[i].value = randomopt_group->entries[j].option.value; + } + + it->option[i].param = randomopt_group->entries[j].option.param; + break; + } + } + } + } +} + /** * Read all item-related databases */ @@ -1881,7 +1966,8 @@ static void itemdb_read(void) { sv_readdb(dbsubpath2, "item_delay.txt", ',', 2, 3, -1, &itemdb_read_itemdelay, i > 0); sv_readdb(dbsubpath2, "item_buyingstore.txt", ',', 1, 1, -1, &itemdb_read_buyingstore, i > 0); sv_readdb(dbsubpath2, "item_flag.txt", ',', 2, 2, -1, &itemdb_read_flag, i > 0); - sv_readdb(dbsubpath2, "item_randomopt_group.txt", ',', 5, 2+5*MAX_ITEM_RDM_OPT, -1, &itemdb_read_randomopt_group, i > 0); + sv_readdb(dbsubpath2, "item_randomopt_group.txt", ',', 5, 6, -1, &itemdb_read_randomopt_group, i > 0); + sv_readdb(dbsubpath2, "item_randomopt_equips.txt",',', 2, 1 + MAX_ITEM_RDM_OPT, -1, &itemdb_read_randomopt_equip, i > 0); aFree(dbsubpath1); aFree(dbsubpath2); } diff --git a/src/map/itemdb.hpp b/src/map/itemdb.hpp index 546d4ef14..af460a82c 100644 --- a/src/map/itemdb.hpp +++ b/src/map/itemdb.hpp @@ -865,6 +865,7 @@ struct item_data bool isStackable(); int inventorySlotNeeded(int quantity); + unsigned int randomopt_groupid[MAX_ITEM_RDM_OPT]; }; // Struct for item random option [Secret] @@ -882,14 +883,16 @@ enum Random_Option_Group { /// Struct for random option group entry struct s_random_opt_group_entry { - struct s_item_randomoption option[MAX_ITEM_RDM_OPT]; + struct s_item_randomoption option; + short max_value; + int weight; }; /// Struct for Random Option Group struct s_random_opt_group { - uint8 id; struct s_random_opt_group_entry *entries; uint16 total; + int total_weight; }; struct item_data* itemdb_searchname(const char *name); @@ -964,6 +967,7 @@ bool itemdb_parse_roulette_db(void); struct s_random_opt_data *itemdb_randomopt_exists(short id); struct s_random_opt_group *itemdb_randomopt_group_exists(int id); +void itemdb_add_randomopt(struct item *it); void itemdb_reload(void); diff --git a/src/map/mob.cpp b/src/map/mob.cpp index f48c4d942..37e016f65 100644 --- a/src/map/mob.cpp +++ b/src/map/mob.cpp @@ -2119,7 +2119,7 @@ static struct item_drop* mob_setdropitem(struct s_mob_drop *mobdrop, int qty, un drop->item_data.nameid = mobdrop->nameid; drop->item_data.amount = qty; drop->item_data.identify = itemdb_isidentified(mobdrop->nameid); - mob_setdropitem_option(&drop->item_data, mobdrop); + itemdb_add_randomopt(&drop->item_data); drop->mob_id = mob_id; drop->next = NULL; return drop; @@ -2931,7 +2931,7 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type) intif_broadcast(message,strlen(message)+1,BC_DEFAULT); } - mob_setdropitem_option(&item, &mdrop[i]); + itemdb_add_randomopt(&item); if((temp = pc_additem(mvp_sd,&item,1,LOG_TYPE_PICKDROP_PLAYER)) != 0) { clif_additem(mvp_sd,0,0,temp); diff --git a/src/map/pc.cpp b/src/map/pc.cpp index 8f609f505..ce4eb55e3 100755 --- a/src/map/pc.cpp +++ b/src/map/pc.cpp @@ -5632,7 +5632,7 @@ bool pc_steal_item(struct map_session_data *sd,struct block_list *bl, uint16 ski tmp_item.nameid = itemid; tmp_item.amount = 1; tmp_item.identify = itemdb_isidentified(itemid); - mob_setdropitem_option(&tmp_item, &md->db->dropitem[i]); + itemdb_add_randomopt(&tmp_item); flag = pc_additem(sd,&tmp_item,1,LOG_TYPE_PICKDROP_PLAYER); //TODO: Should we disable stealing when the item you stole couldn't be added to your inventory? Perhaps players will figure out a way to exploit this behaviour otherwise? diff --git a/src/map/script.cpp b/src/map/script.cpp index 5af99c5a5..f99bff45e 100644 --- a/src/map/script.cpp +++ b/src/map/script.cpp @@ -7438,6 +7438,8 @@ BUILDIN_FUNC(getitem) // if not pet egg if (!pet_create_egg(sd, nameid)) { + itemdb_add_randomopt(&it); + if ((flag = pc_additem(sd, &it, get_count, LOG_TYPE_SCRIPT))) { clif_additem(sd, 0, 0, flag); Of course, this system isn't compatible with the default one on rAthena, so you'll have to modify your current random option weapons if you have any. Goodluck! option.diff
  4. 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;
  5. 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.
  6. The command you're looking for is -encoding 949
  7. 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.
  8. 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.
  9. 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.
  10. 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.
  11. 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);
  12. 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.
  13. 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},
  14. 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.
  15. Heya, The job names are hard-coded in the client executable. You'll have to open an hex editor and then search for "Gunslinger".
  16. 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.
  17. 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
  18. 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.
  19. Tokei

    Picklog db

    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); } }
  20. 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.
  21. Heya, You can use Scripts > Magnifier. It's a multiplier, so simply use a number below 1 to make it smaller.
  22. 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...!
  23. If it fails to extract, it means the password was incorrect and it didn't properly decrypt the files.
  24. The mob is adorable ;D
  25. 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
×
×
  • Create New...