Jump to content

Tokei

Members
  • Posts

    657
  • Joined

  • Last visited

  • Days Won

    89

Everything posted by Tokei

  1. Well, auras are str files to begin with, no? You could open an existing aura, change the textures to your files, and save it again for a quick custom aura.
  2. The quadtree isn't meant for something like that; it's a bandaid for BrowEdit 1 that didn't build the quadtree properly (related to black square issues). Though that's long been fixed by now. There's no such feature to convert to Blender or other common 3D formats from GRF Editor. Your best bet would be to look at BrowEdit 3 (https://github.com/Borf/BrowEdit3/releases), though... I don't think such a feature is available there either? Either way, GRF Editor is quite bare-bone and unoptimized as far as managing 3D assets goes. You may want to look into these projects:
  3. Heya, I've removed the GRF Editor sources from public view a long time ago, but I don't mind adding them back now. You'll have to set the startup project to GrfCL, you can find the project here: https://github.com/Tokeiburu/GRFEditor
  4. Hmm, which software was used to create these? The integer for the frame count is written in plain text with "Fram". That looks like a bug when saving the file. I can't really retrieve that value perfectly, but I can guess it while loading the file and make an estimate. __ Updated to 1.0.8: Fixed the issue above. Added Flip Horizontal/Vertical transformations. Added a new button "Group Edit" to modify multiple frames at the same time. The available transformations for Group Edit are translation, rotation and flip.
  5. Well, it looks like there are more than one error there...? Your output is very confusing. I'd probably recommend you make sure .net 3.5 and .net 4.0 are installed for starter.
  6. Well, you'd have to check which palette it actually uses in your case. If it's cardinal, then it's most likely using cardinal_³²_2.pal. The default kRO palettes for 4th classes are not compatible with the fixed sprites that private servers use (and not compatible with older sprites either, such as a GM sprite). So to make the 4th class palette compatible with your GM sprite, you'll have to use custom palettes instead. I'm not sure how's the progress on those; I made mine myself but I'm sure someone out there made them available to everyone by now. If you use custom palettes, then you'll obviously also have to use one of the "4th Jobs Corrected Sprites" pack available on rAthena.
  7. Unfortunately, that's not possible at all right now for various compatibility reasons. For saving it as a gif, the output would also have to be rendered with OpenGL, on an actual window, which a console application doesn't have.
  8. I mean, read the error message and it will tell you what the problem is/how to fix it.
  9. var path = @"C:\test\"; foreach (var actFile in Directory.GetFiles(path, "*.act")) { var sprFile = actFile.ReplaceExtension(".spr"); var act2 = new Act(actFile, sprFile); foreach (var action in act2) { action.Frames = action.Frames.Take(1).ToList(); } act2.SaveWithSprite(actFile, sprFile); }
  10. The palette used depends of your class, so it's somewhat unrealistic to give palettes for the GM sprite as it can be any class. Plus, each server has different palettes, so only your related server can create those.
  11. I don't understand your question, sorry. Can you phrase it differently?
  12. What part is not working for you? It removes all frames except the first one for me.
  13. That's problematic because the mobs are loaded from script files. If you reload a script without removing the mobs prior, you'll end up with twice as many mobs on the map (and it will keep increasing if you reload the file again). Also, you might want to get away from using @reloadscript as a whole. That command is only really useful to reload mobs... Instead, I'd recommend looking into "@reloadnpcfile npc/custom/test.txt". It will unload and reload only a specific file without having to reload your whole server scripts. It's much faster and efficient.
  14. Well, do you have maps in your input folder? If you aren't using the input folder, you have to check the "Use this GRF" box.
  15. Well, there's some information missing on what you're trying to achieve there. Do you actually need this particular file? A translated one would probably be better for you. So as Winter above said, using the file from a translated git repository might be a better. Though if you do want to extract this particular file (which I assume is from data.grf; from kRO), then use "Save as..." and save the file wherever you want (make sure to save it as skillinfolist.lub, not lua). You should also change the view by clicking on "Raw view" as well. If you're going to copy the file from kRO, you'll probably run into missing defined skills from skillid.lub, but again it depends what you're trying to achieve. Mixing lub files isn't a good idea if you don't know what you're doing.
  16. Well, something's most likely wrong somewhere with your _battle_data value(s). The error's too vague to be more precise though, but... You could simply check for the changes you've made in battle.cpp using your git logs to see what was pushed to it.
  17. Well, the file air_evt is probably encrypted, so you can't make it into a flat map. As for the cities, well, the files may be in another GRF which takes priority over your data.grf. I would presume they are in whateverRO.grf. Either way, it'd be easier to make yourself a new grf, like maps.grf and then put it as the highest priority possible in your data.ini.
  18. Well, same way you're patching your iteminfo. If you're using GRF Editor to make your thor files, then drop the files in "root":
  19. Heya, Did you check if the char-server has loaded properly first? The map-server will not connect to the char-server unless the char-server is loaded, so you might want to check that. It should be saying "Awaiting maps from map-server." For inter-server connections, you should also use the localhost IP (127.0.0.1). This goes for map-server to char-server and char-server to login-server. Regardless of your server being public or not, inter-server connections should remain in a "closed" system. But ultimately, since you're using your private IP to connect right now, it would seem to indicate there is also a problem with your port configuration. So make sure port 6121 is forwarded to 192.168.1.14 in your router configuration. Note that this step is only required if you plan to make your server public. You should make sure that the server can run locally first using the localhost IP.
  20. Heya, These script commands are an alternative for those who do not want to use yaml for making barter shops. The shops can be reloaded by reloading the script, using the barter_clear command. The NPC location is defined just like a regular NPC and then using callshop <npc barter name>, just like regular shop types (which is already possible without this diff, but I thought I'd mention it anyway). Removes all items from a barter shop barter_clear <npc name>; Add item, not extended barter_add <npc name>,<item id>,<amount>,<req item id>,<req amount>; Add item, extended barter_add_ex <npc name>,<item id>,<amount>,<zeny>{,<req item id>,<req amount>,<req refine>}*; Here's a script example: prontera,150,188,0 script Barter NPC 77,{ mes "[Barter NPC]"; next; switch(select("Normal barter shop.:Extended barter shop.:")) { case 1: mes "[Barter NPC]"; mes "..."; close2; callshop "barter_test_npc"; end; case 2: mes "[Barter NPC]"; mes "..."; close2; callshop "barter_test_npc_ex"; end; } end; OnInit: barter_clear "barter_test_npc"; barter_add "barter_test_npc", 504, 10, 501, 20; barter_add "barter_test_npc", 504, 10, 502, 10; barter_add "barter_test_npc", "White_Potion", 10, "Yellow_Potion", 3; barter_clear "barter_test_npc_ex"; barter_add_ex "barter_test_npc_ex", "Zeny_Knife", 5, 5000, "Knife", 1, 9; barter_add_ex "barter_test_npc_ex", "Zeny_Knife", 5, 5000, "Knife", 1, 9, "White_Potion", 10, 0; barter_add_ex "barter_test_npc_ex", "Zeny_Knife", 5, 5000, "Knife", 1, 9, "White_Potion", 10, 0, "White_Potion", 10, 0; end; } prontera,152,188,0 script Barter NPC2 77,{ callshop "barter_test_npc"; end; } And here's the diff file: diff --git a/src/map/npc.cpp b/src/map/npc.cpp index d227467ed..37f50d94d 100644 --- a/src/map/npc.cpp +++ b/src/map/npc.cpp @@ -842,6 +842,26 @@ void BarterDatabase::loadingFinished(){ BarterDatabase barter_db; +struct npc_data* npc_create_dummy_barter_npc(const char *npcname) { + struct npc_data* nd = npc_create_npc(-1, 0, 0); + + npc_parsename(nd, npcname, nullptr, nullptr, __FILE__ ":" QUOTE(__LINE__)); + + nd->class_ = -1; + nd->speed = 200; + + nd->bl.type = BL_NPC; + nd->subtype = NPCTYPE_BARTER; + + nd->u.barter.extended = false; + + map_addiddb(&nd->bl); + + strdb_put(npcname_db, npcname, nd); + + return nd; +} + /** * Returns the viewdata for normal NPC classes. * @param class_: NPC class ID diff --git a/src/map/npc.hpp b/src/map/npc.hpp index 0a0c104e6..82ad2cf3d 100644 --- a/src/map/npc.hpp +++ b/src/map/npc.hpp @@ -1479,6 +1479,8 @@ enum e_npcv_status : uint8 { NPCVIEW_INVISIBLE = 0x29, NPCVIEW_CLOAK = 0x30, }; + +struct npc_data* npc_create_dummy_barter_npc(const char* npcname); struct view_data* npc_get_viewdata(int class_); int npc_chat_sub(struct block_list* bl, va_list ap); int npc_event_dequeue(map_session_data* sd,bool free_script_stack=true); diff --git a/src/map/script.cpp b/src/map/script.cpp index 5aeebe228..6742ab8c4 100644 --- a/src/map/script.cpp +++ b/src/map/script.cpp @@ -26916,6 +26916,154 @@ BUILDIN_FUNC(preg_match) { #endif } +/*========================================== + * Removes all items from a barter shop + * barter_clear <npc name>; + *------------------------------------------*/ +BUILDIN_FUNC(barter_clear) +{ + const char* npcname = script_getstr(st, 2); + std::shared_ptr<s_npc_barter> barter = barter_db.find(npcname); + + if (barter != nullptr) { + barter->items.clear(); + } + + return SCRIPT_CMD_SUCCESS; +} + +/*========================================== + * Add an item to the barter shop + * Not extended: + * barter_add <npc name>,<item id>,<amount>,<req item id>,<req amount>; + * + * Extended: + * barter_add_ex <npc name>,<item id>,<amount>,<zeny>{,<req item id>,<req amount>,<req refine>}*; + *------------------------------------------*/ +BUILDIN_FUNC(barter_add) +{ + const char* npcname = script_getstr(st, 2); + std::shared_ptr<s_npc_barter> barter = barter_db.find(npcname); + struct npc_data* nd = npc_name2id(npcname); + const char* command = script_getfuncname(st); + + if (barter == nullptr) { + barter = std::make_shared<s_npc_barter>(); + barter->name = npcname; + barter_db.put(npcname, barter); + } + + if (nd == nullptr) { + nd = npc_create_dummy_barter_npc(npcname); + } + + int index = barter->items.size(); + + std::shared_ptr<s_npc_barter_item> item = std::make_shared<s_npc_barter_item>(); + item->index = index; + barter->items[index] = item; + + if (strcmpi(command, "barter_add_ex") == 0) { + nd->u.barter.extended = true; + + if (script_isstring(st, 3)) { + const char* name = script_getstr(st, 3); + + std::shared_ptr<item_data> id = item_db.searchname(name); + + if (id == nullptr) { + ShowError("buildin_barter_add: Nonexistant item %s\n", name); + return SCRIPT_CMD_FAILURE; + } + + item->nameid = id->nameid; + } + else { + item->nameid = script_getnum(st, 3); + } + + item->stock = script_getnum(st, 4); + item->stockLimited = false; + item->price = script_getnum(st, 5); + + int offset = 6; + + while (script_hasdata(st, offset) && script_hasdata(st, offset + 1) && script_hasdata(st, offset + 2)) { + std::shared_ptr<s_npc_barter_requirement> requirement = std::make_shared<s_npc_barter_requirement>(); + + requirement->index = (uint16)item->requirements.size(); + + if (script_isstring(st, offset)) { + const char* name = script_getstr(st, offset); + + std::shared_ptr<item_data> id = item_db.searchname(name); + + if (id == nullptr) { + ShowError("buildin_barter_add: Nonexistant item %s\n", name); + return SCRIPT_CMD_FAILURE; + } + + requirement->nameid = id->nameid; + } + else { + requirement->nameid = script_getnum(st, offset); + } + + requirement->amount = script_getnum(st, offset + 1); + requirement->refine = script_getnum(st, offset + 2); + item->requirements[requirement->index] = requirement; + offset += 3; + } + } + else { + nd->u.barter.extended = false; + + if (script_isstring(st, 3)) { + const char* name = script_getstr(st, 3); + + std::shared_ptr<item_data> id = item_db.searchname(name); + + if (id == nullptr) { + ShowError("buildin_barter_add: Nonexistant item %s\n", name); + return SCRIPT_CMD_FAILURE; + } + + item->nameid = id->nameid; + } + else { + item->nameid = script_getnum(st, 3); + } + + item->stock = script_getnum(st, 4); + item->stockLimited = false; + + std::shared_ptr<s_npc_barter_requirement> requirement = std::make_shared<s_npc_barter_requirement>(); + + requirement->index = 0; + + if (script_isstring(st, 5)) { + const char* name = script_getstr(st, 5); + + std::shared_ptr<item_data> id = item_db.searchname(name); + + if (id == nullptr) { + ShowError("buildin_barter_add: Nonexistant item %s\n", name); + return SCRIPT_CMD_FAILURE; + } + + requirement->nameid = id->nameid; + } + else { + requirement->nameid = script_getnum(st, 5); + } + + requirement->amount = script_getnum(st, 6); + item->requirements[0] = requirement; + } + + return SCRIPT_CMD_SUCCESS; +} + /// script command definitions /// for an explanation on args, see add_buildin_func struct script_function buildin_func[] = { @@ -27623,6 +27771,10 @@ struct script_function buildin_func[] = { BUILDIN_DEF(isdead, "?"), BUILDIN_DEF(macro_detector, "?"), + BUILDIN_DEF(barter_clear, "s"), + BUILDIN_DEF(barter_add, "svi*"), + BUILDIN_DEF2(barter_add, "barter_add_ex", "svii*"), + #include "../custom/script_def.inc" {NULL,NULL,NULL}, Quick notes: There isn't a whole lot of error handling. Do... not use an existing NPC name for the barter name if you don't want to crash, but otherwise, should be fine! There is no handling for stocks. You can add parameters to it in the script command if you feel like it, but I've personally never used this option so I just didn't add it. barter.diff
  21. Take a look at System\OngoingQuestInfoList_True.lub (or Sakray.lub, depending of your client version), for example: [7858] = { Title = "불온한 소리의 정체 조사", IconName = "ico_ep.bmp", Description = { "리벨리온 대원 일부는 격벽 너머에서 들려오는 소리의 정체를 밝히기 위해 이미 움직였다. 루키는 소리의 근원이 괴물이라면 멋지게 해치워 달라고 했다." }, Summary = "괴물 사냥", RewardEXP = "800000", RewardJEXP = "800000", RewardItemList = { { ItemID = 25723, ItemNum = 15 } } },
  22. Make sure you are at the latest version: 1.8.4.6 (link in the download description page). Well, that means it found no *.gat files in your currently opened GRF. You're not showing what's in there, so I don't know.
  23. This script is... way more complicated than it has to be. The rand function is misused in two different places, which I'm guessing is the main problem you're having. First thing first: .@r > rand( 1, 1000 ) ^ that's a big no-no. Randomized numbers for chances are always from [0-999], not [1-1000]. You then use rand(1000); or rand(0, 999), but the former is preferred for various reasons. Also, normally you put the rand first for clarity's sake, but that one is preference: if (rand(1000) < .@r) Declaring functions at the beginning is fine, but it's also unecessary and not used that much anymore. Use callsub instead, though... using local scope functions for this script is overkill. rAthena scripts prefer the no-space syntax for function arguments, but that one is up to you. As for the main problem you're having, that is because .@in is returning negative values because of rand( 1, getd( ".size_tot_"+ getarg(0) ) ) has invalid bounds and... well, because this is overly complicated so it's not really worth spending time deciphering what it does. I suggest a simpler approach: prontera,155,177,5 script random 615,{ if (countitem(.rare_ticket)) { mes "Rare Ticket"; .@r = .rate_chance_rare; // chance .@ticket = .rare_ticket; } else if (countitem(.normal_ticket)) { mes "Normal Ticket"; .@r = .rate_chance_normal; // chance .@ticket = .normal_ticket; } else { mes "random"; close; } switch(select("Go.:No.:")) { case 2: close; } delitem .@ticket, 1; if (rand(1000) < .@r) { mes "random"; getitem .rare[rand(.rare_size)], 1; close; } else { mes "random"; getitem .normal[rand(.normal_size)], 1; close; } end; OnInit: .normal_ticket = 501; .rare_ticket = 502; .rate_chance_rare = 500; // chance to get a rare costume with rare ticket (500 = 50%) .rate_chance_normal = 100; // chance to get a rare costume with normal ticket (100 = 10%) // rare items setarray .rare,5909,5912,5914,5915,5977,5979,5980,15280,15841,15843,15858; .rare_size = getarraysize(.rare); // normal items setarray .normal,50001; .normal_size = getarraysize(.normal); end; }
  24. The lub files are irrelevant, just don't remove/modify/replace them.
  25. The separator used for menus is the colon, ":". So just change "%" to "%:". Though, this line: .@part = .@count[select(.@menu$)]; doesn't make a whole lot of sense. Keep in mind that select returns the first value as 1 instead of 0, so you have to remove 1. What you probably wanted to write was the following. .@selected = select(.@menu$) - 1; .@itemid = .@item[.@selected]; Also, not... an issue, but you'd probably want to change your variable names a bit by adding an 's' to your arrays otherwise it becomes very messy (and addding [0] is redundant). copyarray .@items, $@MobDrop_item, .@count; Also, might as well use sprintf for your drop rates, it makes your life easier. So something like this: mes "Monster ID: "+getmonsterinfo(.@mob_id,MOB_NAME)+"'"; if (getmobdrops(.@mob_id)) { // 'getmobdrops' returns 1 on success // immediately copy global temporary variables into scope variables, // since we don't know when 'getmobdrops' will get called again for // another mob, overwriting your global temporary variables .@count = $@MobDrop_count; copyarray .@items, $@MobDrop_item, .@count; copyarray .@rates, $@MobDrop_rate, .@count; mes getmonsterinfo(.@mob_id,MOB_NAME) + " - " + .@count + " drops found:"; for (.@i = 0; .@i < .@count; .@i++) { .@menu$ = .@menu$ + sprintf("%d (%s) %d.%02d%%", .@items[.@i], getitemname(.@items[.@i]), .@rates[.@i] / 100, .@rates[.@i] % 100) + ":"; } .@menu$ = .@menu$ + ":"; } else { mes "Unknown monster ID."; } .@selected = select(.@menu$) - 1; .@item = .@items[.@selected]; .@rate = .@rates[.@selected];
×
×
  • Create New...