Jump to content

Leaderboard

Popular Content

Showing content with the highest reputation on 08/06/23 in Posts

  1. 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
    1 point
  2. I just wanted to stop in to say thanks to the Dev team for continuing to support this great game after all these years. RO was a very important game to me in my youth and to see that the community is still active after all this time is amazing. Back in the old days, I always considered running my own server, but I only finally bit the bullet on it recently. I never suspected that the entire server backend would be open-source! As such, I modded the bejeezus out of it. For starters, my server is PRE-RE, however, I backported almost all of the new content from Renewal into it. Here is my Doram character in Malangdo. It's actually pretty easy to pull renewal content into PRE-RE, since they use the same server backend. To pull renewal enemies into pre-re is as simple as grabbing them from db/re's mob-db and mob-skill-db and pulling them into pre-re's mob-db / mob-skill-db. Of course, renewal enemies have slightly different stats, in particular their "max attack" is their "matk" value and their def and mdef values are usually way too high, but that's easily fixed with SDE. Ditto for items and cards, using item-db. As far as the maps are concerned, they're already all in the game, they just don't have warps, so you just need to grab the npc/warps files from renewal and pull them into pre-re. Many renewal dungeons are instances, so you can either pull the instance into pre-re, or do what I did and turn the instance dungeons into normal dungeon floors by adding warps and recreating their mob tables. As for the Doram, it's fairly easy to add them too, I'll probably make a post explaining how to do it at some point. The main thing you have to do is remove your service_korea folder from your prere grf file, which will allow the one from renewal that allows the creation of Doram to be used instead. Then there's a flag in the server settings somewhere that you have to modify so the server won't reject character creation requests for Doram. I'll write up something on this later. The biggest thing I added by far is the ability to rebirth as Super Novice, Star Gladiator, Soul Linker, Ninja, Gunslinger, and Summoner. It always annoyed me that the classes added after the first 12 never got the ability to rebirth, so I did it myself. It's not possible (or at least I can't figure out how to do it) to add new classes to the game since class sprites are hardcoded in the client file, so instead the way I did this is that when you rebirth as one of the new classes, it unlocks a new "quest skill" which is a pre-requisite for their transcendent abilities. The game also checks to see if you have this skill when it determines if you are transcendent (say, for equipping transcendent only armor or getting the 25% max hp / sp bonuses), and it also uses it to force you to the transcendent exp tables. I'd love to share the code for this, but there's so many code changes that it probably can't be done without me just zipping up my entire codebase, which is also somewhat out of date. By I encourage other intrepid coders to experiment! A reborn Ninja's new skill tree. Note the presence of a few Kagerou skills, despite the fact that he is a still a Ninja. The "reborn" skill in the bottom left is the new quest skill that makes this possible. For Ninja / Gunslinger / Star Gladiator / Soul Linker, they get a few skills from their next job as transcendent skills, with many alterations (for example, Soul Linker gains Espa and Eswhoo, but they don't require spirit energy to use, since it's not available. In exchange they have much less power). Summoner gets his post level 100 skills as transcendent skills, since the max level cap is 99. Super Novice gets to become Expanded Super Novice. I also added the ability for Novices to use bows, which required me to make a custom animation for this. The dream of Bow Super Novice is finally real! Beyond this, I also added like a hundred new pets. They all have custom portraits and speech lines. I put up a guide on how to add custom pets elsewhere on the forum if you want to do this. This poor Lunatic is NOT ready for what's about to happen. And then I manually rebalanced the effect of every card in the game and manually tweaked the exp and drop rates of almost every monster in the game. My server is technically 10x, but the beginning feels like 5x or so, while the late game feels more like 20x, because lategame monsters give more exp. I also fixed a ton of bugs and made a number of enhancements, for example if you use the whodrops command, it now shows exact matches first, so if you do "whodrops boots" you actually see slotted boots now! At this point, there's probably some room for debate as to whether or not this game is still Ragnarok Online or something else entirely, but I'm having fun with it. The only problem is that now my regular job seems boring by comparison. Having complete control over the codebase for one of the best games of all time is pretty much impossible to top. Oh well. Everyone reaches the pinnacle of their career sooner or later. I'm sorry if this sounded like a giant advertisement. Actually, my server will probably never be open to the general public. However, where my code is easily distributable I'll probably make some of it available. I've already put up a couple topics sharing some of the files I've written, and I'll probably try to put up a few more once everything is adequately tested (I've also crashed my server about a hundred times already).
    1 point
  3. If they aren't in your data.grf, then your data.grf isn't the latest. You have a few options available. The easiest option is to download one of the "latest" kRO full client on rAthena, this thread appears to be the most active one: Then use Ragnarok.exe to patch your game afterwards. If your "latest" kRO full client above didn't bother to add the official Gravity patcher (Ragnarok.exe), then you can use the one from Ai4rei here: http://nn.ai4rei.net/dev/rsu/#download (use kRO RAG) and patch the data.grf directly with it. By the looks of it though, the thread above provided the rsu patcher directly so might as well use that. The harder option is to go on https://ro.gnjoy.com and download the official RO game (though I think you have to register first, which may be a problem? Not sure, haven't done that in a while).
    1 point
  4. Missing LUB files most likely. Seeing as the error title is "package item", I'm assuming there's something wrong with this file: data\luafiles514\lua files\selectpackage\selectpackageitem.lub That'd be my guess.
    1 point
  5. It's been a while, I've been busy with other projects, but I'm finally back for possibly a last Ragnarok update (granted, I've said that before). For starters, I finally found out how to properly configure BrowEdit to show all the textures properly. This is not really that hard, I was just lazy before. It's all in the config file and making sure it has the right paths. Finally proper textures and objects! This caused me to fall down a rabbit hole of map editing, now that it's actually not a total pain to work on. Something I've always felt is crucial to the identity of Ragnarok Online is the amount of freedom that you have in the game. Unlike many MMORPGs where you basically just follow a linear questline, in Ragnarok you are free to go anywhere and do anything you want, at any time. This is something I've tried to maintain and enhance throughout my work on the game, by working to increase the number of options you have to level at various parts of the game. When it comes to the "present" phase of the game, I think this works pretty well. But the past world map is much smaller, and although it has a fair number of dungeons, for low levels in particular your options are kinda limited. So I figured it might need a few new areas. So the first thing I did was that I completed the Past Geffen map. There is actually a map for Geffen in the Alpha, but it's extremely incomplete, so I polished it up. I think it looks pretty good now. To reach the past version of Geffen, you have to cross a forest map, which is actually a heavily edited version of 1@mjo1. There's a few new enemies here, like Papilla and Verporta, but they are weak, this is a decent low level grinding area. Geffen of course leads to the past version of Geffen Dungeon, which in turn leads to Past Geffenia. Past Geffenia is based on ordeal_a00 and ordeal_a02. ordeal_a00 is a weird map, I assume this is another map that is full of warps or something in the official, but I instead changed it to have bridges. There are new enemies here too, the beta guards and workers. They drop Carnium, which is very useful for something we'll get to in a minute. Adding Bridges through browedit is a huge pain, by the way. You have to raise all the GAT tiles perfectly for the bridge to work. I eventually got good at this but it takes a long time: Carnium Ore is much of the reason to visit Past Geffen. Carnium can be used to forge enchantments! If you bring 10 Carnium, you can add an enchantment to your armor. You can choose the armor piece using a very similar interface to the standard refiner, and you can choose which stat you want to add. Something I think is interesting is that the strength of the enchantment depends on the refine level of the armor. If your armor is +6 or less, you get +1 to the chosen stat. +7 or +8 gives +2 to that stat, and a +9 or +10 armor gets a +3. I think this is an interesting mechanic because to some degree it acts as a counterbalance to the strength of the transcendent armor. Another feature I've always felt is key to the success of Ragnarok Online is that gear doesn't really scale based on level. Even a simple pair of shoes can become a very good piece of armor if it's very heavily upgraded. This is a great mechanic because it means that finding even a common item like Shoes is never worthless, which is important because it ties into the freedom of the game. Even if you're playing a high level character, this means you can still find useful items in areas that are below your level. This is important because it makes it easier to play with your friends. In many games, if you're even 5 levels up, everything in an area will be useless to you, but because of the card and equipment systems this is not the case in RO. It's just one of many small things that makes this game such a masterpiece. But transcendent armor somewhat goes against this idea. Items like the Goibne set, for example, are actually a fair bit more powerful than something like a pair of Boots. On my server, these items are actually a little weaker than they are in the base game, but they're still strong. However, they're also much rarer, so getting a Goibne set to +7 is a heck of an investment. So the enchantment system kind of lets the standard gear catch up to some degree. Of course, if you're super dedicated you could make a Goibne set at +9 and it would be incredibly powerful, but if you're willing to work that hard you probably deserve the 2 extra stat points. I've attached the script for the enchanter to the bottom of this post in case you'd like something similar on your server. Of course, you'd probably have to move it and you'd need to add a source of Carnium to your game, or simply change the item it uses. This isn't all the new stuff, though. Instead of heading south to Past Geffen, you can instead head north from the forest map, which leads to a new area. Even if you're familiar with the Korean version, you probably don't recognize this map. This is actually gw_fild02, but I completely retextured it because I'm a crazy person and I wanted it to fit better visually with the forest. You can find the Pitayas here, which are interesting little goobers. There are 5 colours of Pitayas, and they drop a related set of cards. They're all accessory cards that increase your resistance against a certain status by 50%. For example, Green Pitaya gives 50% resistance against Stone Curse. If you wear 2 different Pitaya cards, you get 100% resistance to those statuses instead. So you could wear, say, Red and Blue Pitaya to be immune to Burning and Freeze, albeit at the cost of both accessory slots. This is interesting on its own, but there's also King Pitaya, an MVP that spawns on this map. King Pitaya drops a dagger and an armor that also get bonuses based on any equipped Pitaya cards. The armor is mediocre, but gains stat bonuses depending on which Pitaya cards are equipped. For example, Green Pitaya gives it Def +4. The weapon has a chance to inflict whichever status your pitaya cards make you resistant too. King Pitaya's own card is an armor card that lets you inflict the statuses of the Pitaya cards that you have equipped on attackers when being hit, though of course it's a boss card so it's hard to get your hands on. It's an interesting set of items that can be pretty powerful if you get a lot of them. You can keep going to reach oz_dun, which is a pretty high level dungeon that contains the Airboat enemies, like Grave Worm and Brain Sucker. By the way, if you're wondering where these enemies are coming from, they're in the latest Korean GRF, which I've been harvesting for more content. At the end of oz_dun you can meet the Dragon Wraith, who is another very difficult MVP. I think it's kind of cool that this boss is sort of similar in concept to the Zombie Dragon, a cancelled MVP from a long time ago. Of course, none of this stuff was in the Alpha, but I think it helps to flesh out the Past area so it feels like there's appropriate variety now, and the enchantment system also gives you another reason to want to get here (as well as something you can pass back to lower-level characters via the storage to make getting this far with future characters somewhat easier. That said, adding new content is starting to take a very long time, as I'm running out of maps and enemies to repurpose from the main game. The new version doesn't tend to add many more field maps, they mostly just add single-map instanced dungeons that don't really fit with my version of the game. I have to pretty heavily edit almost all new maps I add to the game, and there aren't many more that I could feasibly use. Plus, it's reaching the point where coming up with new ideas for cards is getting to be really tough (I'm beginning to sympathize with the dev team now). Still, I think it's reached a pretty good state where I no longer have many issues with any of the content in the game and there's a lot of cool new stuff to play around with. enchanter.txt
    1 point
  6. Atroce hit him with Pulse Strike for about 3500 damage. Poor bunny. A couple other things I forgot to mention before. I also created two completely new enemies. RO has official pet art + accessories for two new pets, Scatleton and Skelion, who don't exist in the mob-db at all (they have sprites, but their entries are just stubs), thus they cannot exist as pets. So I created them myself. Scatleton is a sneaky kitty, his AI is a mix of Frilldora and Matyr, and he stalks people around Niflheim Skelion is a miniboss in Niflheim's first area. His Scatleton mob is cute but deadly. Both of them drop some Doram-related stuff as well as their taming items and accessories. The Bathory pet is a pretty good one, she uses Energy Drain, which I changed so that when a pet uses it, it heals your SP a little. Hunter Fly's Blood Drain also does this, but with HP. I can share the code for this one as this is quite simple. The change is in skill.cpp. Just find and replace the case statements for BLOODRAIN and ENERGYDRAIN with these. You could easily add a similar effect to any skill using the "if src-type == BL_PET" part of the code. case NPC_BLOODDRAIN: { int heal = (int)skill_attack((skill_id == NPC_BLOODDRAIN) ? BF_WEAPON : BF_MAGIC, src, src, bl, skill_id, skill_lv, tick, flag); if (heal > 0) { if (src->type == BL_PET) { // pet heals owner instead of itself clif_skill_nodamage(NULL, (struct block_list*)((TBL_PET*)src)->master, AL_HEAL, heal, 1); status_heal((struct block_list*)((TBL_PET*)src)->master, heal, 0, 0); } else { clif_skill_nodamage(NULL, src, AL_HEAL, heal, 1); status_heal(src, heal, 0, 0); } } } break; case NPC_ENERGYDRAIN: { int heal = (int)skill_attack((skill_id == NPC_BLOODDRAIN) ? BF_WEAPON : BF_MAGIC, src, src, bl, skill_id, skill_lv, tick, flag); if (heal > 0) { if (src->type == BL_PET) { // pet heals owner instead of itself //clif_skill_nodamage(NULL, (struct block_list*)((TBL_PET*)src)->master, AL_HEAL, 0, 1); status_heal((struct block_list*)((TBL_PET*)src)->master, 0, heal / 15, 2); } else { clif_skill_nodamage(NULL, src, AL_HEAL, heal, 1); status_heal(src, heal, 0, 0); } } } The one I like the best though is Moonlight Flower. She attacks with Mammonite, which drains YOUR money! I specifically added a check to this skill to drain your cash if it used by a pet, because I think this is hilarious. She also eats Topaz and constantly praises how wealthy and handsome you are. What a gold-digger! You get what you pay for, though, she's strong. I also reimplemented most of the missing Sograt Desert maps. This is easy as they are still in the game, they just have their warps commented out in npc/pre-re/warps/fields/morroc_fild.txt. I moved the Sograt Exclusion Zone map to where Sograt Desert 17 was (Phreeoni's old map). It also now has proper exits rather than trapping you on that map. Exiting to the bottom right leads to the Satan Morroc Maps. The method to access the new world is also changed on my server, the dimensional gorge on Morroc field 22 now leads to the Bifrost bridge, because I think this makes sense lorewise. After you cross the bifrost bridge you come to bifrost tower, which eventually exits to Splendide. This is relevant because on my server, you cannot teleport to any town or dungeon unless you've already been there, so it's quite a trek to Splendide. Satan Morroc himself is at Flame Basin, which lies past Manuk, probably the farthest point in the game from where you start. Oh, and don't think you'll just warp to Thor Camp via the cats, I disabled that. I also kiboshed the Battlegrounds, as I always thought the battlegrounds equipment was far too strong for PVP. If you want to fight other players, you'll have to farm Hydra and Thara Frog cards like we all had to back in the old days. Similarly, a lot of the new equipment like the Elemental Sword has been nerfed to be more in line with the PRE-RE equipment in terms of power. All of the guild-dungeon exclusive enemies have new spawn locations too.
    1 point
  7. I demand to know what happened to that little Lunatic. Yeah, in a serious note, all devs working on the RO emulator are the real MVP here.
    1 point
  8. disable this line npc/quests/the_sign_quest.txt#L12239 and these npc/quests/the_sign_quest.txt#L12252-L12253
    1 point
×
×
  • Create New...