Jump to content

Tokei

Members
  • Posts

    700
  • Joined

  • Last visited

  • Days Won

    109

Everything posted by Tokei

  1. 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); }
  2. 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.
  3. I don't understand your question, sorry. Can you phrase it differently?
  4. What part is not working for you? It removes all frames except the first one for me.
  5. 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.
  6. 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.
  7. 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.
  8. 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.
  9. 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.
  10. 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":
  11. 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.
  12. 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
  13. 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 } } },
  14. 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.
  15. 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; }
  16. The lub files are irrelevant, just don't remove/modify/replace them.
  17. 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];
  18. Hmm, well I was able to make it into a flat map without any issues? Make sure you are using the latest version in the description.
  19. What is the map name?
  20. That usually means you're missing a VC++ library, though I don't remember which one it was compiled on. I'm guessing it's most likely VC++ 2010 (maybe 2008 as well). I'm guessing you picked x64 instead of x86 though.
  21. Heya, Unfortunately, that is not really possible. The gif format doesn't support semi-transparency. One pixel color can be transparent (which is commonly the pink color in RO, or 0xff00ff). While... this is possible to support, it would also make any other semi-transparent pixel look horrible with shades of pink for any of your other semi-transparent layers (I'd show you an example, but I'm on phone right now). It's a limitation of the gif format, there's not much I can do there. That's why I didn't really bother with transparency support while saving gif images and instead opted of rendering the str as they are directly shown in the preview window. I would suggest simply changing the background to black to make these gifs as this is when you'll have the best output. Alternatively, you could change the background color to wherever you plan on displaying these gifs, but you'll quickly see white background isn't a great choice for most str. Saving those animations is just really troublesome. The only real "solution" I could come up with is saving the output as a series of PNG images (which I'm not sure is actually possible, but worth looking into). Though, that wouldn't really solve what you're trying to do, at least I don't think...?
  22. Heya, You can create a new script command: static int buildin_killmonsterarea_sub(struct block_list *bl,va_list ap) { int x1 = va_arg(ap, int); int y1 = va_arg(ap, int); int x2 = va_arg(ap, int); int y2 = va_arg(ap, int); if (x1 <= bl->x && bl->x <= x2 && y2 <= bl->y && bl->y <= y1) status_kill(bl); return 0; } BUILDIN_FUNC(killmonsterarea) { const char *mapname; int16 m; int x1, x2, y1, y2; mapname=script_getstr(st,2); if( (m = map_mapname2mapid(mapname))<0 ) return 0; x1=script_getnum(st,3); y1=script_getnum(st,4); x2=script_getnum(st,5); y2=script_getnum(st,6); map_foreachinmap(buildin_killmonsterarea_sub,m,BL_MOB, x1, y1, x2, y2); return SCRIPT_CMD_SUCCESS; } // def BUILDIN_DEF(killmonsterarea,"siiii"),
  23. GRF encryption isn't restricted by client version. It works on any.
  24. I am not able to reproduce this issue. Str files do not have a bias value to begin with though, that's emulated. If the bias value isn't showing up, it could be that it simply failed to guess the value properly. Either way, I would need an example (with a file if possible) on how to reproduce. As for the second part, at 0x10c, the value should indeed be 0x00000000. That is the delay for texture animation. That value, "0x7f800000", means "Infinifty" which is usually the result of a division by 0. That's... a bug with the original str file. I saw it in your EZV file and I fixed the output to say "0" instead as it didn't make any sense to save the value as "Infinity" in a EZV file. As for the str file itself, it has no impact since the animation type is set to normal, and therefore the value isn't read at all. I will make a small change however and make sure this value (infinity) can't propagate anywhere either and fix it when loading the str file instead. I'll wait for more information on the bias issue above though.
  25. Heya, I see what you mean now; it should be fixed in 1.0.7.
×
×
  • Create New...