Leaderboard
Popular Content
Showing content with the highest reputation on 03/09/24 in all areas
-
Froggo Rö Folder This is a simple RO folder that contains everything you need to run a 2022-04-06 client, the latest publicly available. I have cleaned and compressed the data.grf file to reduce its size from 3.87GB to 2.14GB. official_data.grf took the same treatment and the file size went down to 426MB. Additionally, I have added a mini-map to all those maps that were lacking one, approximately 275 mini-maps were added, I only ignored some indoor (_in) and guild castles maps. Before BGM, the Rö folder has a total size of 2.62GB, after BGM it reaches 2.96GB Screenshots Requirements Server Up & Running with PACKETVER=20220406 Visual C++ Redistributables DirectX Runtime Features Includes latest RoEnglishRE - 16/mar/2024 Custom Lua Support jRO Enchantment Display Includes rsu-kro-rag-lite (kRO updater) - v4.2.2.1316 Includes opensetup - v3.1.0.627 Includes iRO's Setup.exe, thanks to relzz! Includes AzzyAI 1.55 Includes Packet Viewer Download click here to download a .zip file of this ro-folder ~fast mirror (●'◡'●)~ Extra Warp Profile for 2022-04-06 used for FroggoClient.exe (mirror) 2022-04-06 Vanilla Ragexe Client Login Screen Creator Official Ragnarok Complete Zipped Folder(10/June/2024) Official Ragnarok Complete EXE Installer (08/Jan/2024)(mirror) Froggö Ro Folder Gitlab's Repo FAQ Why am I getting CHARACTER_INFO size error when trying to log in? Possible reasons: You are using outdated rAthena which doesn't work with 2022-04-06 client. You haven't set correct PACKETVER or done it with mistakes (skill issue ). You haven't recompiled rAthena. You haven't restarted server after recompilation. Why am I getting errors about MSVCP140.dll, VCRUNTIME140.dll when executing FroggoClient.exe? You haven't installed Visual C++ Redist, check requirements section, if problem persists, try installing this too Visual C++ Redist for VS 2012u4 What is official_data.grf ? official_data.grf is from the ROResourceCollection project, which brings many items, mobs and npc files from other RO Regions and merges it into one convenient grf. Why does the Setup.exe opens instead of the FroggoClient.exe? In your Windows registry there is no data about your selected graphic card, to fix it, just set up your settings in Setup.exe and click on OK, be aware to don't select DirectX9, stay on DirectX7 What was removed from the data.grf? Several unnecessary files were removed from the data.grf . These included residual files such as thumbs.db and stray BMP Screenshots. However, the majority of the cleanup was performed in the mob and npc sprite folders. In these folders, some .spr files contained sprites (images) that were not utilized in their corresponding .act files. For example, the monster katrinn's .spr file contained approximately 140 images, but only 6 of them were actually used. In total, out of nearly 90,000 collective images, around 9,400 were removed alv.2 points
-
Hello, I'm sharing this project, since this might help someone who need to generate this easily. Right now, this project support custom file generator for : 1. Custom headgear. 2. Custom robe/garment. 3. Custom weapon. 4. Custom NPC. 5. Custom Mob. 6. Commands. 7. Attendance. 8. Login Screen. 9. Statpoint.yml 10. Job_stats.yml 11. item_cash.yml The required file generated depends on which generator that you used. The scenario on how to generate for custom headgear file : 1. Maybe extract data\texture\유저인터페이스\item\ folder and u will have the listed one .BMP that u want to add. 2. Select all the item u want to add, right click mouse and right click, copy as path. Then open notepad, paste it. 3. Get the only .BMP in list, so replace your directory path and replace all with blank/nothing . And lastly the " with blank/nothing. So the result is as below. Copy all of it, insert in https://x-files.amirazman.my/customfilegenerator and change your : - Starting ItemID you want it to start with. Make sure the itemID is supported by your client. - Starting AccessoryID that you didnt use yet. Also make sure the final accessoryID didnt reach the maximum of your client can support/set. - Defense, so you can set all the defense in bulk. - Weight. - Slots. - Script. Insert any scripts or anything that you can replace all easily later on in itemdb and also custom_iteminfo.lua (yes, its generated inside the description). - Item Type for now only support headgears and costume headgears, I will add another item types soon if possible (yes, its generated inside the description). And click Generate. Download, extract, add it in your System folder and server file or create a patch or anything. You can access to this simple project here : https://x-files.amirazman.my/customfilegenerator. Let me know if you having issues and I'll update it if possible & have some leisure time to play with.1 point
-
Thank you, guys, I really hope this helps the newbies struggling with setting up the client. At least for a renewal environment...1 point
-
1 point
-
Well, I'm not quite done yet. Whenever I'm away from Ragnarok for a while, I tend to come up with new ideas for skills, so I figured I'd do one last round of custom skills for classes that were a bit low in terms of total skill count. Pretty much every one of these skills required some kind of unique nuance to get it working, so it was a good test of all I've learned coding this game so far. Assassin: Assassin is one of the most changed classes on my server, as I feel it is a problematic class in a number of ways. It is simultaneously super strong and extremely basic to play, with among the fewest skills in the game and a large portion of its skill tree that no one ever uses. It also has the second-highest base HP of any class in the game for some reason, despite being extremely hard to hit. As such, I've endeavored to flesh out their skill tree to encourage build diversity while simultaneously scaling back their tankiness (they now have the lowest max health of any non-mage class). I think this has mostly worked, but it's had the side effect of making it a significantly harder class to play, and in particular it feels much harder to level at endgame because it's far less self-sufficient now. I wanted to restore a little bit of that feeling of being a one man army without turning them back into a one man army in guild war, so I came up with this. Soul Absorption is a fairly simple passive that restores some HP and SP when you kill things, significantly increasing the levelling efficiency of the class, though it's also now a prerequisite for Soul Breaker, which also scales back the strength of that build to some extent (it was somewhat outperforming the other Assassin builds, especially at low levels). If you think the idea behind this sounds very similar to the Wizard skill Soul Drain, you're not wrong, and mechanically it's implemented very similarly, though unlike Soul Drain it works with any type of attack, not just single target skills. This skill does also work in PVP, though I doubt it would be worth the skill points in guild war. It is fun to grimtooth down a bunch of enemies and get a full heal, though. Rogue: Besides build diversity, something else I want to encourage within the game is class diversity. In vanilla Ragnarok Online, there's quite a lot of classes to choose from to construct your party. Most of the classes can do just fine for DPS. For tanking, you'll usually use a Swordsman class or an Assassin, or maybe a Blacksmith. Then for healing, you bring a Priest. See the problem here? Pretty much no matter how you construct your party, the Priest is kind of essential. As such, one of the main things I've tried to address is to give various classes more options in terms of healing and support to make non-Priest parties more viable. For example, Summoner, Bard, and Alchemist all have better healing options, Monk is better for support, and Star Gladiator and Blacksmith are better at tanking. However, I wanted one more healing option available, but I didn't just want to give another class a standard heal spell. So I came up with a fairly unique healing option for everyone's favourite jack of all trades, the Rogue. Herbology is a unique skill in a bunch of different ways. For starters, it's a heal spell that has cast time and is interruptible, so it's not super great to spam during combat. It also requires an item to use, specifically a Hinalle Leaflet for Levels 1-5, and an Aloe Leaflet for Levels 6-10. The power of the heal actually resets at level 6, but the level 6+ version is an area heal that can heal multiple people close together, while the former version is single target. It also removes certain statuses at certain levels, level 3+ removes Bleeding, level 7+ removes Paralysis, and level 9+ removes Infection (which is a new status that Assassin has access to). Notably, these are all statuses that are hard to get rid of since many status heals don't affect them. It's intended to be used as a kind of backline heal spell, so it's part of the Bow Rogue skill tree, giving them a bit more support power to compliment their backline DPS, though you can certainly also use it as an out-of-combat heal for standard Rogue if you're willing to spend a few points for it. It's probably not a particularly class-defining skill but I feel like the idea behind it fits well with the class. From an implementation standpoint, this is actually kind of complicated due to the fact that it requires different items at different levels, which is not a concept that rathena supports natively (the only other skill that works this way is Potion Pitcher). Also, you might remember from before that the list of skills that target allies is defined client-side, so I had to cannibalize an existing skill for this. There was actually only one ally-targeting skill left in the game that wasn't already used, which was GC_Antidote, which was kind of a funny coincidence since this skill actually also heals Assassin's special poison status (infection is actually a modified version of SC_Toxin). Wizard: Of all the classes in the game, Wizard was probably one of the ones I touched the least. It was always a pretty good class, but with all the other classes getting new skills, it had kind of fallen behind in terms of the number of skills (I was actually a bit shocked by just how small its skill tree was). For some time now, I've sort of wanted to give Wizard some kind of utility spell, but I hadn't come up with any idea I really liked. However, the new Assassin ability gave me an idea. Soul Drain has always been kind of mediocre ability for Wizard, the class doesn't tend to have problems with SP and it doesn't use a ton of single-target spells either, and that ability just felt like it made way more sense for Assassin, so I completely reworked the ability into something totally different. Power Drain is now a regular spell with a totally new effect. It's basically Marionette Control but backwards, when you cast this on an enemy you steal some of their stats for a little while, with the level of the spell determining which stat is stolen. Like Marionette Control, there's both a status for the caster and the victim, and the caster's stats are increased by 1/10th of the victim's value for the chosen stat, while the victim's stats are decreased instead. Casting this on an enemy with high stats is very powerful, for example you could steal 12 Dex from an enemy who had 118 Dex, which is a ton, though the effect doesn't last especially long. I think it's still fun to play around with though. High Wizard also gets another attack spell in Explosion. This is just a reworked version of Warlock's Soul Expansion, where it's a slow-casting single target fire spell that hits really hard. Not too much to say about this, I just always felt that Wizard's fire spells seemed kind of weak. If you stone curse someone and then do magical amplification before this spell it does bonkers damage, so I guess this increases Wizard's dueling potential in PVP. That's not all for Wizard, though, they also get another new attacking spell in Static Field. This is kind of like a wind-element version of the Ninja's Blaze Shield spell, in that it creates a zone of damaging magic that can also inflict a status, in this case Paralyse. It doesn't hit as frequently, but it's still a decent way to slow down attackers. This skill is actually a reworked version of Shadow Chaser's Chaos Panic skill. It looks much more like an electric attack to me. Speaking of Shadow Chaser skills there's also this. This is actually what I always expected Shadow Chaser's Dimension Door would do, as similarly-named spells in other games usually have this effect, but instead what it does is it creates a zone on the floor that simply teleports you to a random location if you step on it, which is kind of a troll spell that you can't even use in GVG. Instead, my version of the spell creates an exit portal wherever you cast the spell, and an entrance portal wherever you were standing. This results in you warping to the new location immediately, but your allies can use it too. This is a fun way to take shortcuts or bypass traps in War of Emperium, though Dex does not reduce the spell's casting time and the portal doesn't stay open for very long, so it's not super abusable. Actually, Wizard also gets Teleport and Warp Portal as well, which are both prerequisites to get this spell, so even if this doesn't have a lot of use outside of WoE they still gain some extra utility. I think this is enough new tools to play with that Wizard doesn't feel neglected anymore. This was probably the hardest one to program. The entrance portal is actually Manhole, which didn't otherwise exist on my server, but obviously its functionality is totally changed. The exit portal is the actual Dimension Door spell, but it no longer does anything at all since the trip is one-way (save for the fact that it can be removed by spells like Ganbantein, which also eliminates the entry portal as they are linked to each other). Anyway, that's probably it for new stuff for a bit. The classes are looking pretty good now, there's probably mainly just going to be relatively small balance adjustments to skill power and enemy skill lists and such for the next little while.1 point
-
Remove everything on this Label https://github.com/rathena/rathena/blob/f34a47ae24b6e96e2d68d03cb0bdc7dc3dbee74c/npc/custom/woe_controller.txt#L32 Rynbef~1 point
-
int counter = static_cast<int>(pc_readreg2( sd, ATTENDANCE_COUNT_VAR )); // Check if we have a remaining counter from a previous period if( counter >= 25 && !pc_attendance_rewarded_today(sd) ){ pc_setreg2( sd, ATTENDANCE_COUNT_VAR, 0 ); return 0; }1 point
-
1 point
-
1 point
-
Hi how do I add the Geffenia map? when I warp to Geffenia01 I get an error message1 point
-
1 point
-
Now Before we delve into the details, lets consider a few things - this is meant for newbies. If you have made patches before skip ahead. Introduction to patching When we say we patch a client what it means is we change few bytes with a different set of bytes. (essentially we change a few opcodes or assembly instructions for e.g. a JNE to JMP so that the client behaves differently) Now these codes will be different for each client date and/or their location will change. So how do we make it generic? For this you need a sort of flow-chart to follow to get to the locations where modification needs to be made and for getting the replace logic. If you know how the original bytes were found , try to make note of the procedure you followed and you can usually make a patch following same logic. For e.g. like find a string -> find where its pushed -> 8 bytes later there is a JNE -> change to JMP Another step that helps out is finding a common pattern in a set of clients around where your modification is to be done. For e.g. Lets say i find '75 C0 E8 09 22 04 00 68 44 65 97 00' in 20130612 and '75 C0 E8 10 23 04 00 68 54 44 98 00' in 20130626 common pattern => '75 C0 E8 ?? ?? ?? 00 68 ?? ?? ?? 00' where ?? can be anything so you can use this common pattern instead of the individual ones. Not sure whether I made it clearer or confused you with that Intro. To summarize - making a patch is a combination of finding byte patterns, finding referenced addresses, changing instructions, finding vacant spaces and adding new codes, updating calls etc. If you know assembly language then it should be easy for you. If you don't know already try to read up on it at-least a little before going forward Now then back to topic Patches in NEMO The patches for NEMO are written in QtScript which follows ECMAScript format guidelines same as ... Javascript Therefore almost all of the functions & behaviors offered by Javascript you will find is also there in QtScript (well except for the actual web development part ) So I am not going to concentrate on the language itself. But rather I would be focussing on What all aspects are there specific to NEMO. NEMO Patch Instructions For NEMO to recognize a patch it needs to be registered. This is done in _patchlist.qs file in the patches folder. FORMAT for registering patch : registerPatch(patch id, functionName, patch Name, category, group id, author, description, recommended [true/false] ); patch id - a unique number used for referring to the patch internally in NEMO. functionName - the name of the function which will be called when a patch is enabled in NEMO. This function will contain your logic for making modifications into the client. patch Name - Name of the patch (displayed in the table) category - Category of the patch (like UI , Data, etc. displayed in the table) group id - id of the registered group to which this patch will belong. (details below) author - Patch Maker's Name (displayed in the table) description - Description of what the patch does (displayed in the table) recommended - boolean value showing whether this belongs to the recommended list of patches. Each Patch will belong to a Patch Group (if its not supposed to be part of any specific group use group id 0). All Patch Groups must be registered before they are used (except for 0 which is the Generic Patch Group registered by default) FORMAT for registering group : registerGroup(group id, group Name, mutualexclude [true/false]); group id - a unique number used internally in NEMO as well as when registering a patch. group Name - Name of the group (displayed in the table for all member Patches) mutualexclude - boolean value determining whether member patches are mutually exclusive i.e. Only 1 can be selected at a time or not. Once a patch is registered you need to make the function (name specified while registering). You can make it in any .qs file and save it in patches folder. It will be read automatically. Now to facilitate writing patches there are some ready-made variables & functions available to you. Now to facilitate writing patches there are some ready-made variables & functions available to you. 1) Reserved Keywords (well in a sense) i) Section Types - The following four can be used for referring to a section instead of using the section name itself as an alternative. CODE = 0, DATA = 1, IMPORT = 2, DIFF = 3 ii) User Input Types - These are the available input types in NEMO that you need to specify while getting an input value from user with the getUserInput() Function. Based on the types a different prompt appears for the user to select the value. You will understand more once you see function later on. XTYPE_NONE = 0, XTYPE_BYTE = 1, XTYPE_WORD = 2, XTYPE_DWORD = 3, XTYPE_STRING = 4, XTYPE_COLOR = 5, XTYPE_HEXSTRING = 6, XTYPE_FONT = 7, XTYPE_FILE = 8 iii) Pattern Types - You can specify a string in two forms : PTYPE_STRING => 0) Regular C Style string with Null termination - i.e. anything after '\0' or "\x00" will be ignored. E.g. "Ragnarok" PTYPE_HEX => 1) Hex String with spacing - You specify each byte with a space prefixed before it. E.g. " 68 90 00 95 00" As you might have guessed already if you have a null byte in your hex string always use PTYPE_HEX. iv) Address Types - Currently it is only used in findString() function to specify the type of value you want returned RAW = 0, RVA = 1 i.e. RAW/real address or Relative Virtual Address 2) Global Variables APP_PATH = path where NEMO is run from. CLIENT_FILE = path of the currently loaded client exe. Whenever your client exe gets loaded the object gets updated to refer to the loaded client. To access the bytes inside the exe we make use of the various methods of this object (Client Access functions detailed below). 3) Client Access Functions 3.1) - Fetching data i) exe.fetchByte(offset) - Extract 1 Byte and return it as a signed number. ii) exe.fetchWord(offset) - Extract 2 Bytes and return it as a signed number (little endian) iii)exe.fetchDWord(offset) - Extract 4 Bytes and return it as a signed number (little endian) iv) exe.fetchQWord(offset) - Extract 8 Bytes and return it as a signed number (little endian) v) exe.fetch(offset, num) - Extract <num> Bytes and return it as a string ( PTYPE_STRING ). vi) exe.fetchHex(offset, num) - Extract <num> Bytes and return it as a hex string ( PTYPE_HEX ). Do note that the returned hex string will already have space prefixed. 3.2) - Searching for data i) exe.find(pattern, type, useWildCard = false, wildCard = "\xAB", start = -1, finish = -1) This is the core searching function available in NEMO. All the others are just extended versions of this function. This function searches for the <pattern> you provide in the client between the <start> and <finish> offsets. You need to specify the pattern <type> (PTYPE_STRING or PTYPE_HEX) for the client to use it accordingly. if start is -1 then it will automatically shift to beginning of the file i.e. 0, similarly if finish is kept at -1 it automatically shifts to the end of the file. Sometimes you wish to search for a pattern like " 68 ?? ?? ?? 00 74 ?? 83" where ?? actually means you dont care what is there in those areas. So how to search in those scenarios? First replace the ?? with a byte you dont have in your original pattern. For e.g. " 68 AA AA AA 00 74 AA 83" and call exe.find() with useWildCard as true and wildCard as "\xAA" like shown below. var offset = exe.find(" 68 AA AA AA 00 74 AA 83", PTYPE_HEX, true, "\xAA") - i didnt set the start and finish since i want the full client searched. If a match is not found then this function returns -1. ii) exe.findAll(pattern, type, useWildCard = false, wildCard = "\xAB", start = -1, finish = -1) Same functionality as exe.find except that exe.find() stops at the first matched location but this one returns array of all matched locations. If no matches are found returned array is empty. iii)exe.findCode( pattern, type = PTYPE_HEX, useWildCard = false, wildCard = "\xAB") - Extended version of exe.find() function with searching limited to CODE section iv) exe.findCodes(pattern, type = PTYPE_HEX, useWildCard = false, wildCard = "\xAB") Extended version of exe.findAll() function with searching limited to CODE section v) exe.findString(pattern, rtype = RVA, prefixZero = true) - Extended version of find function with searching limited to DATA section. pattern can only be a PTYPE_STRING. rtype argument here refers to what type of address should be returned when found (RAW or RVA). If you want to search for isolated strings (i.e. NULL on both sides) set prefixZero to true vi) exe.findFunction(pattern, type = PTYPE_STRING, isString = true) - Extended version of find function for getting the address of an imported function. You can either specify the function's original name or the address of the function name in IMPORT section. vii)exe.findZeros(zsize) - Extended version of find function used for locating empty space in DIFF section for inserting new code. The function always looks for zsize+2 null bytes to make sure each inserted code is seperated by atleast 1 null byte. 3.3) - Modifying data i) exe.replace(offset, code, type = PTYPE_STRING) The core function used for replacing bytes in the client file. code is the pattern which will replace the original - don't forget to mention the pattern type. There is no return value for replace functions. You can also provide the variable name you used in exe.getUserInput() function earlier as the code (NEMO will pick up the value inside). ii) exe.replaceWord(offset, code) - Extended version of exe.replace(). Here code is expected to be a 16 bit signed number. iii)exe.replaceDWord(offset, code) - Extended version of exe.replace(). Here code is expected to be a 32 bit signed number. iv) exe.insert(offset, allocSize, code, type = PTYPE_STRING) - Extended version of exe.replace() used for Inserting code into Null areas. offset should be the value you got from exe.findZeros(allocSize). 3.4) - User Interaction i) exe.getUserInput(varname, valtype, title, prompt, value, min=0, max=2147483647) - Prompts the user for a value. Based on the valtype you get different windows for value entry and the value selected by the user is also returned by the function. varname used should be unique across patches and can be used in replace & insert functions to refer to the user entered value. title is the text displayed on the input window title bar prompt is the text displayed as prompt next to the input box. in case there is no input box. for e.g. like in XTYPE_COLOR , the prompt is suffixed to the title bar itself. value is the initial value to use for the input. If the variable was set previously or reloaded from a profile/from a previous applied patch, this value is ignored. 3.5) Section information All the four functions mentioned below gets 1 information of a section specified by key. key can be either the section name or section type (mentioned at top) i) exe.getROffset(key) - Real Offset ii) exe.getRSize(key) - Real Size iii)exe.getVOffset(key) - Virtual Offset iv) exe.getVSize(key) - Virtual Size 3.6) Miscellaneous i) exe.getClientDate() - Need i say more? ii) exe.isThemida() - return true if its a 2013 unpacked client. iii)exe.Raw2Rva(rawaddr) - Converts a RAW/real address to Relative Virtual Address. iv) exe.Rva2Raw(rvaaddr) - inverse of above. In case you are still wondering: RAW address is the physical offset of a code (bytes) from beginning of the client which you see in a Hex Editor such as HxD. Relative Virtual Address or RVA is the address you see for the same code when you open the client in a debugger such as Ollydbg. RVA is relative to a value called imagebase hence the name Relative Virtual Address. RVA - imagebase = VA. 4) Utility Functions There are a few utility functions written in QtScript (you will find them in the core folder) to facilitate some commonly done routines. i) "string".replaceAt(i, newstring) - by default strings have a replace command but no command to replace at a specific offset this one does that. For e.g. "abracadabra".replaceAt(4,"k") will return "abrakadabra" ii) "string".repeat(i) - returns new string with the "string" repeated i times e.g. "na".repeat(4) will return "nananana" .... ... batman? iii)"hexstring".hexlength() - returns the number of bytes in the hex string (PTYPE_HEX). For e.g. " 90 49 54".hexlength() returns 3 iv) "string".toHex() - converts string to hex string (from PTYPE_STRING to PTYPE_HEX) e.g. "AM".toHex() returns " v) "string".toHexUC() - converts string to hex string (similar to above but extra null byte padding is provided - like ASCII in Unicode) vi) "hexstring".toAscii() - reverse of iv) vii) (Number).packToHex(size) - packs a number to its little endian hex string with the size number of bytes used up size can be maximum 4. the number or expression needs to be in a bracket or a variable. e.g. (123456).packToHex(4) => " 40 E2 01 00" viii) getInputFile(f, varname, title, prompt, fpath) - repeatedly loops until a valid file is specified as input or the form is cancelled => patch should be disabled. 5) TextFile class Since I found no suitable types in QtScript for accessing files. I have added a new class called TextFile for accessing textfiles.To use the class first we need to make an object of the class (yes i mean in the patch file itself) var fp = new TextFile(); Methods i) fp.open(<absolute file path>, <mode>) - once fp is assigned we need to use the open method to use it to access a file. mode can be "r" or "w" ii) fp.readline() - currently only reading full line is available, since i needed full lines at a time. iii)fp.write(data) - writes the specified data onto file. iv) fp.writeline(data) - same as above but also adds a carriage return + form feed (goes to new line) v) fp.eof() - true when end of the file has been reached. vi) fp.close() - closes the file opened by fp.open() You can check the TranslateClient.qs file in patches folder for an example of its use. --------------------------------------------------------------------------------------------------------------------------------------------------------- Hmm what else .... so now that you have gone through this guide, hopefully you can better understand what is written in the patches already there. and maybe bring in your own ideas? Let me know if any part of this guide didn't make sense, needs elaborations, clarifications etc. FYI: I know it doesn't look pretty right now. But this was done in a hurry since I will be gone for a week . I will clean things up later on.1 point