Jump to content

Tero

Members
  • Posts

    17
  • Joined

  • Last visited

  • Days Won

    2

Everything posted by Tero

  1. A small update this time, but something I'm quite pleased with. Meet Pere! Players of Renewal might recognize Pere from Jitterbug of Nightmare, which I recently implemented on my server. (Which, as mentioned above, is PRE-RE, I've been porting all of Renewal's content to it). Pere is quite special. Besides being super cute, she can also serve as your ensemble partner! There are two Peres that you can get as pets, one dances and one plays the guitar, and whichever one you are, you need the other one. Someone on my server has been complaining since day 1 about the necessity of being joined at the hip with a Bard and I think this is a good compromise that preserves the intent of the ensemble skills while also making them a little more accessible. If you want to add this functionality to your server, it's actually pretty easy from a coding perspective. You just have to find the method "skill_check_condition_castbegin" in skill.cpp, then find this code: else if(inf2[INF2_ISENSEMBLE]) { if (skill_check_pc_partner(sd, skill_id, &skill_lv, 1, 0) < 1 && !(sc && sc->data[SC_KVASIR_SONATA])) { clif_skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); return false; } } And replace it with this: else if(inf2[INF2_ISENSEMBLE]) { // check to see if we have the ensemble pet bool ensemblepet = false; if (sd && sd->pd) { if ((sd->status.class_ == JOB_BARD || sd->status.class_ == JOB_CLOWN) && sd->pd->pet.class_ == 3069 && sd->pd->pet.intimate > PET_INTIMATE_LOYAL) { ensemblepet = true; } if ((sd->status.class_ == JOB_DANCER || sd->status.class_ == JOB_GYPSY) && sd->pd->pet.class_ == 3070 && sd->pd->pet.intimate > PET_INTIMATE_LOYAL) { ensemblepet = true; } } if (!ensemblepet && skill_check_pc_partner(sd, skill_id, &skill_lv, 1, 0) < 1 && !(sc && sc->data[SC_KVASIR_SONATA])) { clif_skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); return false; } } Of course, you also have to pull everything from Jitterbug of Nightmare into PRE-RE, then implement the Peres as custom pets, but at least the coding part is simple! (alternatively, you could just use a different pet, like maybe a Rocker or something, you can just change the id number it looks for in the pet.class_ part).
  2. You have to recompile the server using visual studio after making changes to the source code. If you have visual studio already, just open up rathena.sln and select to "Build Solution", otherwise you might have to download it (it's free). Make sure to install the files to compile C++. I'm pretty sure there's guides on it somewhere.
  3. I don't think you should need to remove sections 2 and 3, but it looks like it should work. You recompiled your server and restarted after making the change and it still doesn't work? Just tested it myself, with the change I suggested in the first post, it works, I can now steal repeatedly from the same enemy.
  4. You don't actually want it to return at all at that point (regardless of the return status), the actual giving of the item is done near the end of the procedure, so if it returns early, you won't get an item.
  5. This is the line that blocks the steal attempt if(md->state.steal_flag == UCHAR_MAX || ( md->sc.opt1 && md->sc.opt1 != OPT1_BURNING && md->sc.opt1 != OPT1_CRYSTALIZE ) ) //already stolen from / status change check return 0; In particular, md->state.steal_flag is set to UCHAR_MAX after a successful steal. You could simply remove that part of the line to allow stealing from that monster again and again. if(( md->sc.opt1 && md->sc.opt1 != OPT1_BURNING && md->sc.opt1 != OPT1_CRYSTALIZE ) ) //already stolen from / status change check return 0; Or you can just remove that code entirely if you don't want anything to block stealing attempts. Also, leave the configuration for steal_max_tries at 0, that disables it.
  6. I've been fiddling a lot with skills lately. For starters, I've been playing Sage. Sage has always felt like a bit of an underwhelming class to me. A big part of this is that it gets very few new damage spells. So I made a new one. Poison Splash is basically just Poison-element Fire Ball, it does AOE Magic Poison damage and can also inflict the Poison status. On my server, Poison does extra damage against Neutral (I think this makes sense, since Assassins use it and the main targets that are Neutral are players), so this spell is quite useful against Ridewords and the like. I also think it works well for Sage since Sage is intended to be a PVP-focused Mage and this is a pretty decent PVP spell. That said, you have to watch out because a number of enemies can cast this spell against you! I also buffed Professor's Memorize skill, which I've renamed to Lecture. Like the Summoner Buffs, it now also applies this buff to all party members on the screen. I think this makes thematic sense with the class being called "Professor" but doing no actual teaching previously. It was also a move which, in my opinion, didn't have a ton of utility for Professor, as they tend to either use fast-casting spells or autocast, but has a ton of potentially interesting utility for other characters and enhances the "Support Sage" playstyle. Beyond this, something I think is super cool is that I've added some cards that allow you to cast previously enemy-only skills. For example, here my Paladin has the Dark Priest Card, which allows you to cast Soul Strike of Darkness. It even has a proper description in the skill window and everything. This was surprisingly painless to pull off. You need to add entries for the enemy spells (in this case NPC_DARKSTRIKE) to skilldescript.lub and skillinfolist.lub (these are in the GRF file under skillinfoz), and add entries for the spell in skill-cast-db and skill-require-db and that's about it, then just have the card script look something like "skill "NPC_DARKSTRIKE", 5;" and you're good to go. I have cards like this for Grand Darkness, Darkness Jupitel, Blood Drain, and Energy Drain, but none of them are easy to get your hands on. Still, it's cool to have more options for dealing Darkness damage. I also almost completely reworked Endless Tower. For starters, I moved it. It was originally accessed via Alberta, like far too much of the game (like 8 different towns are accessed through there), so it's now where Misty Forest Labyrinth used to be at Bifrost Field 1. The condition where you have to wait a week between attempts is also now gone, you can now play it as much as you like, but creating the instance costs 500k Zeny. The difficulty of the tower has also been rebalanced. Previously, it was kind of ludicrous, forcing you to fight many of the hardest bosses in the game, like Ifrit and Beelzebub. You now generally fight the low to mid tier bosses, with a number of bosses who didn't previously appear in the tower, like Gopinich, Boitata, and Stormy Knight making an appearance. I also tweaked the enemies that spawn on pretty much every floor. There's generally less of them, and they're themed based on various locations in the game. For example, can you identify the map that this floor is based on? I also gave Endless Tower a huge music buff, in that it now plays the previously unused track 168 (well, this is used for Lasanga dungeon in Renewal, but that map isn't in Pre-Re), which I think fits perfectly with this dungeon. If you ever want to edit which songs play where, this is very easily done by editing mp3nametable.txt, which is in root folder of one of your GRF files. (I also restored Track 67, which currently doesn't play anywhere, it now plays on the maps north of Yuno). There are also kafras and shops within Endless Tower (though the Kafras only allow you to use the storage. no saving), to somewhat mitigate how absurdly many items you tend to get here. Additionally, when you clear floors 25, 50, 75, and 99, the warp in the first room is replaced with a new warp that takes you to the appropriate floor (the concept of the Ashes is removed). Overall, I think this makes this dungeon a lot more fun.
  7. My cat is finally rebirthed! I can't believe nothing broke! He even got the correct number of status points and everything. I'm the king of scripting. Back to Toy Factory for me. Now I can learn the cat's (originally) post level-100 skills. Besides all the new content, my server also has a boatload of skill tweaks (this is part of why I don't just share my code directly, there's hundreds of changes most people probably won't want). For example, the first skill in each of the cat skill trees can now level to 10 instead of 5, to give you more options in terms of how you spend your points pre-rebirth. The initial skills for Summoner are also buffed, particularly the nearly-useless Bite and Scratch. These are both worthless 200% damage skills initially, that you would literally never use once you have anything else. I tweaked it so that they now have 100 + <your base level> * 10 % attack, (only *5 for scratch). Bite also has a chance to Stun and does more damage to weakened targets, making them very viable at high levels, with the caveat that Bite is a melee skill with cast time, so unless you have uninterruptable cast, a ton of flee, or tons of cast speed reduction you're going to get hit out of it a lot. At any rate, I think this is interesting because this now means you could go healer cat and have a fairly viable form of offense that requires no further skill point investment, though obviously the loss of the range from Picky Peck is an issue. Soul Attack is also now a 5-level skill which functions similarly to a mastery skill, and enables long range attack at maximum level. This is a fairly substantial nerf, but mastery skills on my server work like they do in the newest version of the game, where they increase your atk rather than final damage, so they're not worthless. Summoner also has, initially, probably the single most broken skill in the game in Silvervine Root Twist. This is a ranged skill with instant cast that completely freezes the enemy's movement with 100% success rate for 10+ seconds. I shouldn't need to tell you how ludicrously busted this is on a character that has powerful ranged attacks. The second you learn this skill, you are essentially completely invincible to almost all normal mobs. I was able to waltz into area 30+ levels above me with no issues by just grabbing anyone who looked at me funny. I have no clue who looked at this skill and thought this was fine. Obviously this had to be adjusted. On my server, Silvervine Root Twist has a 1.5 second cast time and about 1/4 the duration (4 sec at max level). It's still a ludicrously good skill which I think almost any build wants to take, but it no longer completely explodes the game balance. Stop hitting me! I'm supposed to be invincible! (Not pictured: my untimely death) On the flip side, Scar of Tarou is greatly buffed, in that the damage over time effect is greater and can work on bosses (albeit at only 25% of the power) if you have Spirit of Life. With the aid of a powerful tank, Scar of Tarou can handle almost all your DPS needs, so that could be another interesting option for support cat. The only issue is that its power scales with STR instead of DEX, as it does in the base game, so if you have no STR it will be weak. Speaking of, I've even tweaked the way the stats work slightly. For example, every time you get 10 VIT, you now get a point of DEF. I always thought it worked this way initially, but apparently it never did. Well, now that I have absolute power, I can make it work however I want. Actually, every stat gives you some kind of bonus for every 10 points now. The sky's the limit in terms of what you can do with this game. I've tried to generally stick to (my interpretation of) the general balancing of the game prior to the battlegrounds update, since I wanted to make the game what I think it might have become if Renewal had never existed, but you could take it in pretty much any direction you want. This game really is a modder's dream come true.
  8. Additionally, while most headgear items are available as costumes, a few aren't. Should you find a headgear item you want that isn't available, it's easy to add it yourself. The code looks through item IDs 19433 to 20499 for costumes, so add your new items to gaps within this range to put them into the game. Let's take this example of the Monk Hat. It doesn't have a costume entry, so let's create one. If using item-db.txt: First, find another entry to use as a template. Let's use this one here for the Costume Angel Wing. Note that it's important to choose a headgear that uses the same slots as the item you want to create, or use SDE to update the slots for the item afterwards. 19529,C_Angelic_Chain,Costume Angel Wing,4,0,,0,,0,,0,0xFFFFFFFF,63,2,1024,,1,0,38,{},{},{} The costumes are all very similar, so we don't have to do much. The main thing we need to change is the View ID, which determines which sprite will be shown when wearing the costume. This is the last entry before the 3 sets of brackets. The Angel Wing has a view ID of 38. Now, we need to find the original entry for the Monk Hat. Here it is: 2251,Holy_Bonnet,Monk Hat,4,30000,,100,,5,,0,0x00008110,7,2,256,,0,1,35,{ bonus bMdef,3; },{},{} All we care about is the view ID, which is again before the 3 brackets. Its view ID is 35. Now, we just copy paste the Costume Angel Wing line, while making changes to the first number (the id), as well as the following two fields (the item's name) and changing the view ID, like so: 19434,C_Monk_Hat,Costume Monk Hat,4,0,,0,,0,,0,0xFFFFFFFF,63,2,1024,,0,0,35,{},{},{} Now we just paste that into the item-db and the Costume Monk Hat exists. If using item-db.yml The steps are the same if using the yaml version of the item-db, the formatting is just a little different. Again, let's find the Costume Angel wing to use as a template. - Id: 19529 AegisName: C_Angelic_Chain Name: Costume Angel Wing Type: Armor Locations: Costume_Head_Top: true ArmorLevel: 1 EquipLevelMin: 1 View: 38 Script: | bonus bUnbreakableHelm; bonus bVit,1; bonus bAgi,1; I note that apparently by default, this item had stats. I personally removed the stats from all costume items on my server, which is as easy as removing the "script" portion of this definition. Now, let's swap out the values for the Monk Hat, as above. - Id: 19434 AegisName: C_Monk_Hat Name: Costume Monk Hat Type: Armor Locations: Costume_Head_Top: true ArmorLevel: 1 EquipLevelMin: 1 View: 35 Paste this into item-db.yml and we're good to go. Updating the Description file: We're not quite done yet. While we can now trade for this item, it'll show up as "Unknown Item" due to the fact that it doesn't exist in iteminfo.lua. This is present in the System subfolder inside your client folder. There are entries for every item in the game. To start, let's copy the one for the non-costume Monk Hat. This is what my file has. [2251] = { unidentifiedDisplayName = "Hat", unidentifiedResourceName = "ĸ", unidentifiedDescriptionName = { "Unknown Item, can be identified by using a ^6666CCMagnifier^000000." }, identifiedDisplayName = "Monk Hat", identifiedResourceName = "¼ºÁ÷ÀÚÀǸðÀÚ", identifiedDescriptionName = { "A ceremonial hat worn by monks that contains a sacred force which offers protection from evil.", "Mdef +3", "Class:^6666CC Headgear^000000", "Defense:^0000FF 5^000000", "Position:^6666CC Upper^000000", "Weight:^009900 10^000000", "Jobs:^6666CC Acolyte^000000" }, slotCount = 0, ClassNum = 35 }, Now we just make a few small changes, by pulling some related values from another costume entry, to get something like this. [19434] = { unidentifiedDisplayName = "Hat", unidentifiedResourceName = "ĸ", unidentifiedDescriptionName = { "Unknown Item, can be identified by using a ^6666CCMagnifier^000000." }, identifiedDisplayName = "Costume Monk Hat", identifiedResourceName = "¼ºÁ÷ÀÚÀǸðÀÚ", identifiedDescriptionName = { "A ceremonial hat worn by monks that contains a sacred force which offers protection from evil.", "Class:^6666CC Costume^000000", "Position:^6666CC Upper^000000", "Weight:^009900 10^000000", "Jobs:^6666CC All^000000" }, slotCount = 0, ClassNum = 65 And we're done. The Monk Hat is now a fully functional costume item. You can use the same steps to add any other missing costume items that you come across.
  9. This is not tested under renewal. I think it should still work, but test it with a GM character first. The default implementation of Homunculi is kind of obnoxious. When you create one, you get one of the homunculi at random, and in order to get another one, you have to completely delete them from existence. Wouldn't it be nice if you could keep the other homunculi to use later? Well, now you can! What it does: - When you use rest, the Homunculus returns to its Embyro. - You can use Call Homunculus to call it back out, just as it was when you rested it. - You can store the Homunculus for later use, allowing you to raise a different Homunculus, which is not normally possible. - Only you can call the Homunculus back out. If another alchemist tries to call it, it doesn't let them. - You can still delete the Homunculi as normal to remove them from existence completely. How it works from a technical perspective: - When you rest the homunculus, it is technically "removed" from you, similar to deleting it, but it returns an embyro with the Homunculus id set to its card[1] slot. - When you call out a Homunculus from an Embyro, if the embyro has a value in its card[1] slot, it restores that Homunculus instead of creating a new one. Some minor limitations: - It's not possible to distinguish embryos from each other, and call homunculus will always try to call the first one it finds in your inventory. You'll need to store the ones you don't want to raise right now, and it may take some trial and error to hatch the right one if you have a bunch. - The name display of the embryo doesn't work with the client I have (it seems like the client will only display the name if the card[1] slot is 0, which it's not if a homunculus is in there). This makes it hard to tell who owns a homunculus embyro. How to implement: Make the following code changes: In homunculus.cpp: Find the method "hom_vaporize": First, add the following variable declarations to the top, under the existing ones: int itemflag; struct item tmp_item; Next, comment out the following line: hd->homunculus.vaporize = flag ? flag : HOM_ST_REST; Then, insert the following at the end of the method, just before the return statement. if (hd->homunculus.intimacy > 0) { memset(&tmp_item, 0, sizeof(tmp_item)); tmp_item.nameid = 7142; tmp_item.amount = 1; tmp_item.identify = 1; tmp_item.card[0] = CARD0_CREATE; tmp_item.card[1] = hd->homunculus.hom_id; tmp_item.card[2] = GetWord(sd->status.char_id, 0); // CharId tmp_item.card[3] = GetWord(sd->status.char_id, 1); if ((itemflag = pc_additem(sd, &tmp_item, tmp_item.amount, LOG_TYPE_PRODUCE))) { clif_additem(sd, 0, 0, itemflag); if (battle_config.skill_drop_items_full) { map_addflooritem(&tmp_item, tmp_item.amount, sd->bl.m, sd->bl.x, sd->bl.y, 0, 0, 0, 0, 0); } } unit_remove_map(&hd->bl, CLR_OUTSIGHT); sd->status.hom_id = 0; unit_free(&hd->bl, CLR_OUTSIGHT); sd->hd = 0; return 1; } Next, find the method "hom_call": Find this code: if (!sd->status.hom_id) //Create a new homun. return hom_create_request(sd, HM_CLASS_BASE + rnd_value(0, 7)) ; Replace it with this: struct item ed; int n; // find the embryo if (!sd->status.hom_id) { //Create or revive a homun. if ((n = pc_search_inventory(sd, 7142)) >= 0) { ed = sd->inventory.u.items_inventory[n]; } else { return false; // no embryo } if (ed.card[1] != 0) { // is it ours? if (sd->status.char_id == MakeDWord(ed.card[2], ed.card[3])) { // revive the homun // delete the embryo pc_delitem(sd, n, 1, 0, 0, LOG_TYPE_CONSUME); clif_delitem(sd, n, 1, 3); sd->status.hom_id = ed.card[1]; // proceed with rest of function } else { // Cannot revive someone else's homunculus return false; } } else { // create a new homun // delete the embryo pc_delitem(sd, n, 1, 0, 0, LOG_TYPE_CONSUME); clif_delitem(sd, n, 1, 3); return hom_create_request(sd, HM_CLASS_BASE + rnd_value(0, 7)); } } Almost done, just one small change to make in skill.cpp. Find this line: if (sd->status.hom_id) //Don't delete items when hom is already out. And comment it out (we never want this method to delete the embyros, since the call method now handles it). Now just recompile your server and you should have the new homunculus behaviour.
  10. I found a couple things during some further testing that experienced users may want to look at. To perform these changes, you need to be able to make changes to your source code and recompile. These are not mandatory for Doram to work but some skills will not work quite as intended without them. In status.cpp, there are some Doram-specific buffs that affect Matk. These are only applied when in renewal mode, so these buffs have no effect under PRE-RE without a code change. To make these work, you need to add the following to the method "status_calc_matk" in status.cpp. if (sc->data[SC_CATNIPPOWDER]) matk -= matk * sc->data[SC_CATNIPPOWDER]->val2 / 100; if (sc->data[SC_CHATTERING]) matk += sc->data[SC_CHATTERING]->val2; if (sc->data[SC_DORAM_MATK]) matk += sc->data[SC_DORAM_MATK]->val1; They go right before the line: return (unsigned short)cap_value(matk,0,USHRT_MAX); Another Matk Bonus is granted by investing 20 or more points in the plant tree while having Power of Land This too is not applied in PRE-RE. This is also in status.cpp, in the method status_calc_bl_main. Right after this code: if (bl->type&BL_PC && sd->matk_rate != 100) { status->matk_max = status->matk_max * sd->matk_rate/100; status->matk_min = status->matk_min * sd->matk_rate/100; } You need to insert the following to apply the Matk bonus: if (bl->type&BL_PC && pc_checkskill(sd, SU_POWEROFLAND) > 0) { if ((pc_checkskill(sd, SU_SV_STEMSPEAR) + pc_checkskill(sd, SU_CN_POWDERING) + pc_checkskill(sd, SU_CN_METEOR) + pc_checkskill(sd, SU_SV_ROOTTWIST) + pc_checkskill(sd, SU_CHATTERING) + pc_checkskill(sd, SU_MEOWMEOW) + pc_checkskill(sd, SU_NYANGGRASS)) > 19) status->matk_min += status->matk_min * 20 / 100; status->matk_max += status->matk_max * 20 / 100; } By the way, a minor glitch exists here, RO only recalculates your stats, including MAtk, when you learn a passive skill, not an active skill, even though this stat change can be applied by learning an active skill. You could actually fix this if you wanted (it's in pc_skillup in pc.cpp) with the following changes. Find this: if( !skill_get_inf(skill_id) ) status_calc_pc(sd,SCO_NONE); // Only recalculate for passive skills. Change it to this. status_calc_pc(sd, SCO_NONE); // Always recalc because of Power of Land if (!skill_get_inf(skill_id)) ; // Do nothing to avoid breaking the logic You now receive the Matk bonus immediately. There is also a mistake in the skill "Picky Peck" in battle.cpp. Search for this code. if (status_get_hp(target) < status_get_max_hp(target) >> 1) skillratio *= 2; This is actually intended to apply to Bite, not Picky Peck (the description states that Bite is the skill that does extra damage on weakened targets). You can cut these lines and paste them a few lines above under case SU_BITE: skillratio += 100 + sd->status.base_level * 10; In the old version of the code only, there's a mistake in checking the heal bonus granted by power of sea. if (pc_checkskill(sd, SU_TUNABELLY) == 5 && pc_checkskill(sd, SU_TUNAPARTY) == 5 && pc_checkskill(sd, SU_BUNCHOFSHRIMP) == 5 && pc_checkskill(sd, SU_FRESHSHRIMP) == 5) This does not correctly check the entire seafood skill tree to see if the total is 20 or higher. Replace it with this. if ((pc_checkskill(sd, SU_TUNABELLY) + pc_checkskill(sd, SU_TUNAPARTY) + pc_checkskill(sd, SU_BUNCHOFSHRIMP) + pc_checkskill(sd, SU_FRESHSHRIMP) + pc_checkskill(sd, SU_GROOMING) + pc_checkskill(sd, SU_PURRING) + pc_checkskill(sd, SU_SHRIMPARTY)) > 19) This is fixed in the latest version (the skill counting is refactored into its own method and is correct) so if you're on latest you don't have to do this. Additionally, the skill "Fresh Shrimp" skill has some very strange logic, the wiki states it heals half of Heal Level 5 per tick, but in Rathena's code, the value is simply set to 178, regardless of your stats / skill level / whatever. This also causes healing bonuses not to be applied and generally makes the skill nearly worthless. This is also in status.cpp, Search for 178, the only instance will be in the code we need to alter. My fix is simply to insert this before the line "if (sd)" val2 = skill_calc_heal(src, bl, SU_FRESHSHRIMP, val1, true); skill_calc_heal already has a heal formula for fresh_shrimp which otherwise goes unused.
  11. Oh, that's true, my rathena is a little out of date, and I still have the non-yaml item-db. I whipped you up a Yaml version. - Id: 1681 AegisName: Short_Foxtail_Staff Name: Short Foxtail Staff Type: Weapon SubType: Staff Buy: 300 Attack: 40 Range: 1 Slots: 3 Jobs: Summoner: true Spirit_Handler: true Locations: Right_Hand: true WeaponLevel: 1 EquipLevelMin: 1 Refineable: true Script: | bonus bMatkRate,10; - Id: 1683 AegisName: Abundantly_Foxtail Name: Enriched Foxtail Staff Type: Weapon SubType: Staff Buy: 4000 Weight: 200 Attack: 50 Range: 1 Slots: 3 Jobs: Summoner: true Spirit_Handler: true Locations: Right_Hand: true WeaponLevel: 2 EquipLevelMin: 12 Refineable: true Script: | bonus bMaxSP,50; bonus bMatkRate,15; - Id: 1684 AegisName: Long_Foxtail Name: Long Foxtail Staff Type: Weapon SubType: Staff Buy: 4000 Weight: 200 Attack: 70 Range: 2 Slots: 3 Jobs: Summoner: true Spirit_Handler: true Locations: Right_Hand: true WeaponLevel: 2 EquipLevelMin: 12 Refineable: true Script: | bonus bLongAtkRate,5; bonus bMaxHP,200; - Id: 1685 AegisName: DragonFry_Foxtail Name: Dragonfly Sitting Foxtail Staff Type: Weapon SubType: Staff Buy: 8000 Weight: 300 Attack: 60 Range: 1 Slots: 2 Jobs: Summoner: true Spirit_Handler: true Locations: Right_Hand: true WeaponLevel: 3 EquipLevelMin: 30 Refineable: true Script: | bonus bInt,1; bonus bMaxHP,100; bonus bMaxSP,150; bonus bMatkRate,15; - Id: 1686 AegisName: BigSize_Foxtail Name: Large Foxtail Staff Type: Weapon SubType: Staff Buy: 8000 Weight: 300 Attack: 90 Range: 2 Slots: 2 Jobs: Summoner: true Spirit_Handler: true Locations: Right_Hand: true WeaponLevel: 3 EquipLevelMin: 30 Refineable: true Script: | bonus bLongAtkRate,8; bonus bDex,1; bonus bMaxHP,200; bonus bMaxSP,100; - Id: 1687 AegisName: Short_Foxtail_Staff_ Name: Short Foxtail Staff Type: Weapon SubType: Staff Buy: 300 Attack: 40 Range: 1 Slots: 4 Jobs: Summoner: true Spirit_Handler: true Locations: Right_Hand: true WeaponLevel: 1 EquipLevelMin: 1 Refineable: true Script: | bonus bMatkRate,10; - Id: 1690 AegisName: Amazing_Foxtail Name: Mysterious Foxtail Staff Type: Weapon SubType: Staff Buy: 40000 Weight: 400 Attack: 70 Range: 1 Slots: 1 Jobs: Summoner: true Spirit_Handler: true Locations: Right_Hand: true WeaponLevel: 4 EquipLevelMin: 60 Refineable: true Script: | bonus bMaxSP,300; bonus bMatkRate,20; - Id: 1694 AegisName: Model_Foxtail Name: Foxtail Model Type: Weapon SubType: Staff Buy: 40000 Weight: 300 Attack: 130 Range: 2 Slots: 1 Jobs: Summoner: true Spirit_Handler: true Locations: Right_Hand: true WeaponLevel: 4 EquipLevelMin: 60 Refineable: true Script: | bonus bLongAtkRate,10; bonus bMaxHP,500; - Id: 1697 AegisName: Ex_Y_Model_Foxtail Name: Heavenly_Foxtail Type: Weapon SubType: Staff Buy: 60000 Weight: 300 Attack: 150 Range: 2 Jobs: Summoner: true Spirit_Handler: true Locations: Right_Hand: true WeaponLevel: 4 EquipLevelMin: 85 Refineable: true Script: | bonus bLongAtkRate,15; bonus bMatkRate,25; - Id: 15126 AegisName: Doram_Only_Suit Name: Doram Suit Type: Armor Buy: 20 Weight: 700 Defense: 5 Slots: 1 Jobs: Summoner: true Spirit_Handler: true Locations: Armor: true EquipLevelMin: 18 Refineable: true Script: | bonus bMaxHP,500; bonus bMaxSP,100; - Id: 20788 AegisName: Doram_Only_Cape Name: Doram Manteau Type: Armor Buy: 20 Weight: 300 Defense: 3 Slots: 1 Jobs: Summoner: true Spirit_Handler: true Locations: Garment: true EquipLevelMin: 18 Refineable: true Script: | bonus bFlee,5; - Id: 22077 AegisName: Red_Eco_Boots Name: Doram Shoes Type: Armor Buy: 20 Weight: 100 Defense: 2 Slots: 1 Jobs: Summoner: true Spirit_Handler: true Locations: Shoes: true ArmorLevel: 1 EquipLevelMin: 18 Refineable: true Script: | bonus bCritical,5; Hopefully this is all correct, I did the conversion by hand and I haven't tested it since my server doesn't use it, so if there's a small error somewhere you might have to edit it a tiny bit. For skill-tree.yml, that's super easy, you can just copy everything summoner related from the renewal one into the pre-re one. Unlike the one I have, the post-level 100 skills are present here, so you don't need to add anything from scratch. The one thing you have to do is for the post-level 100 skills, their entries look like this - Name: SU_PURRING MaxLevel: 5 BaseLevel: 100 Requires: - Name: SU_GROOMING Level: 5 You need to remove the "BaseLevel: 100" line (just completely delete it), because of course it's not possible for your Doram to be over level 100 in Pre-Re. For skill-cast.yml and skill-require.yml you can similarly just copy from renewal. While reviewing the new version, I also found that job-stats.yml and job-basepoints.yml under pre-re does not have the values for Summoner, you need to copy the summoner values for both of these from the renewal version of the file into the pre-re version. They don't need any changes.
  12. If you've used a relatively recent client for a pre-renewal server, you've probably been greeted by this while creating a character. Coming soon? What a tease! This is a 20-year old game, we've waited long enough. Soon is now. Here's how to add the Doram to PRE-RE. What you'll need: GRF Editor Server Database Editor, or SDE Some basic understanding of how to modify Rathena's configuration files. Getting started: First thing's first, we need to get rid of that Coming Soon message. This requires GRF Editor. The problem lies inside our pre20190427.grf file, or whatever your pre-re grf file is called. We need to navigate to data/lua files/luafiles514/service_korea folder, specifically inside ExternalSettings_kr.lub. There's a line in this file that says: MakeableRace = { Doram = false } We need to change the "false" to "true". You can't directly change .lub files with GRF Editor. You can click on it, select all the text, paste it into notepad, make your changes, save it with the same name, then just drag it into GRF editor and save your GRF to make the update. We can now try to create Doram via the character select screen! The problem is, when you try to create one, you'll get "rejected from server". This is because the server is not configured to accept Doram. This is also easy to fix. We need to go to char.athena.conf within the PRE-RE server folder, under conf. Find this line. //allowed_job_flag: 3 Uncomment this to allow Doram. You can now actually create one! Doram exist! Spawn location for Doram: There's still a lot of problems though. The first is that Doram don't have a proper spawn location. By default, they attempt to spawn in Lasagna, but it doesn't exist in PRE-RE, so the server tosses them into Prontera instead. This is functional, but not very cool. Let's instead send them to the training area, where everyone else goes. Find the "start_point_doram" line, also inside char_athena.conf. Make it this. start_point_doram: new_1-1,53,111:new_2-1,53,111:new_3-1,53,111:new_4-1,53,111:new_5-1,53,111 Now the Doram start inside the training area. However, some of it doesn't work so great for them because it's designed for humans. Never fear, I've created a new version of the training area that handles them. You can download it from the bottom of the post, it's called novice.txt. This goes inside rathena_PRERE\npc\pre-re\jobs\novice Equipment for Doram: Another problem is that Doram use their own weapons, which aren't present in PRE-RE, so right now they can only punch. Let's fix that now. All of the Doram equipment is present in renewal, so we can simply grab it from renewal's item database, at db/re/item-db.txt. However, you have to know what items to grab, so I've made this even easier and done it for you. Copy the following into your pre-re/item-db.txt. Anywhere is fine, you can put them at the end if you want. 1681,Short_Foxtail_Staff,Short Foxtail Staff,5,300,,20,40,,1,3,0x80000000,7,2,2,1,1,1,10,{ bonus bMatkRate,10; },{},{} 1683,Enriched_Foxtail_Staff,Enriched Foxtail Staff,5,4000,,200,50,,1,3,0x80000000,7,2,2,2,12,1,10,{ bonus bMaxSP,50;bonus bMatkRate,15; },{},{} 1684,Long_Foxtail_Staff,Long Foxtail Staff,5,4000,,200,70,,2,3,0x80000000,7,2,2,2,12,1,10,{ bonus bLongAtkRate,5; bonus bMaxHP,200; },{},{} 1685,Dragonfly_Sitting_Foxtail_Staff,Dragonfly Sitting Foxtail Staff,5,8000,,300,60,,1,2,0x80000000,7,2,2,3,30,1,10,{ bonus bInt,1; bonus bMaxHP,100; bonus bMaxSP,150;bonus bMatkRate,15; },{},{} 1686,Large_Foxtail_Staff,Large Foxtail Staff,5,8000,,300,90,,2,2,0x80000000,7,2,2,3,30,1,10,{ bonus bLongAtkRate,8; bonus bDex,1; bonus bMaxHP,200; bonus bMaxSP,100; },{},{} 1687,Short_Foxtail_Staff_,Short Foxtail Staff,5,300,,20,40,,1,4,0x80000000,7,2,2,1,1,1,10,{ bonus bMatkRate,10; },{},{} 1690,Mysterious_Foxtail_Staff,Mysterious Foxtail Staff,5,40000,,400,70,,1,1,0x80000000,7,2,2,4,60,1,10,{ bonus bMaxSP,300; bonus bMatkRate,20; },{},{} 1694,Foxtail_Model,Foxtail Model,5,40000,,300,130,,2,1,0x80000000,7,2,2,4,60,1,10,{ bonus bLongAtkRate,10; bonus bMaxHP,500; },{},{} 1697,Heavenly_Foxtail,Heavenly Foxtail,5,60000,,500,150,,2,0,0x80000000,7,2,2,4,85,1,10,{ bonus bLongAtkRate,15; bonus bMatkRate,25; },{},{} 15126,Female_Poring_Balloon,Doram Suit,4,20,,700,,5,,1,0x80000000,7,2,16,,18,1,,{ bonus bMaxHP,500; bonus bMaxSP,100; },{},{} 20788,Private_Doram_Manteau,Doram Manteau,4,20,,300,,3,,1,0x80000000,7,2,4,,18,1,,{ bonus bFlee,5; },{},{} 22077,Red_Eco-Friendly_Shoes,Doram Shoes,4,20,,100,,2,,1,0x80000000,7,2,64,,18,1,,{ bonus bCritical,5; },{},{} Now the Doram have some weapons and armor. Currently, none of this drops from enemies and none of the shops sell it. If you wish, open up SDE, and add some of these items to the drop tables of various enemies. I added them to various cat and fox-themed enemies like Wild Rose, Nine Tail, Cat O Nine Tail, Leaf Cat, Civil Servant, and Moonlight Flower, but you can add them anywhere you want. I also made the prontera weapon shop sell item 1681, this is inside npc/merchants/shops.txt Add ,1681:-1 To the end of the prontera weapon seller to make him sell 3 slot Short Foxtail Staves. The 4 slot version can drop from an enemy. By the way, these items probably won't have descriptions yet. This is because the descriptions are stored inside System/iteminfo.lua inside your Ragnarok Online client folder. If you want, I've attached a text document containing their descriptions called DoramDescriptions.txt, which you can merge into your iteminfo file by replacing the existing description stubs (use Ctrl-F and look for the item number inside square brackets, like this [1981] ) Point Caps, HP and Skills for Doram: We're making good progress, but there are still more things to fix. For starters, as renewal classes, Doram are allowed to increase their stats past 99. This does not fit with PRE-RE, so let's fix it. This is in conf/battle/player.conf. Find this line: max_summoner_parameter And set the value after the colon to be 99. Now we need to fix their HP. Currently, the Doram are using a stubbed out value for HP and SP that is way too low. This is in job_basehpsp_db.txt. First, search for :4218 (it will appear near the bottom of the file) and remove it, to removed the stubbed values. Next, paste these into the document, at the bottom: //Summoner HP 1,500,4218,0,60,69,80,92,105,119,134,150,167,185,204,224,245,267,291,315,341,368,395,423,453,483,515,548,582,617,653,690,728,767,807,848,890,933,978,1023,1070,1118,1166,1215,1266,1317,1370,1424,1479,1535,1592,1650,1709,1769,1830,1892,1955,2019,2085,2151,2219,2288,2357,2427,2499,2571,2645,2720,2796,2873,2951,3030,3110,3191,3273,3356,3440,3525,3612,3699,3788,3878,3968,4059,4152,4245,4340,4436,4533,4631,4730,4830,4931,5033,5136,5240,5345,5451,5559,5667,5777,5888,5999,6111,6225,6339,6455,6572,6690,6809,6929,7050,7172,7295,7419,7544,7670,7797,7926,8055,8186,8318,8450,8583,8718,8853,8990,9128,9267,9407,9548,9690,9833,9977,10122,10268,10415,10563,10713,10863,11015,11168,11321,11475,11631,11787,11945,12104,12264,12425,12587,12750,12914,13079,13245,13412,13580,13749,13920,14091,14264,14438,14612,14787,14964,15141,15320,15500,15681,15863,16046,16230,16415,16601,16788,16976,17165,17355,17547,17739,17931,18123,18315,18507,18699,18891,19083,19275,19467,19659,19851,20043,20235,20427,20619,20811,21003,21195,21387,21579,21771,21963,22155,22347,22539,22731,22923,23115,23307,23499,23691,23883,24075,24267,24459,24651,24843,25035,25227,25419,25611,25803,25995,26187,26379,26571,26763,26955,27147,27339,27531,27723,27915,28107,28299,28491,28683,28875,29067,29259,29451,29643,29835,30027,30219,30411,30603,30795,30987,31179,31371,31563,31755,31947,32139,32331,32523,32715,32907,33099,33291,33483,33675,33867,34059,34251,34443,34635,34827,35019,35211,35403,35595,35787,35979,36171,36363,36555,36747,36939,37131,37323,37515,37707,37899,38091,38283,38475,38667,38859,39051,39243,39435,39627,39819,40011,40203,40395,40587,40779,40971,41163,41355,41547,41739,41931,42123,42315,42507,42699,42891,43083,43275,43467,43659,43851,44043,44235,44427,44619,44811,45003,45195,45387,45579,45771,45963,46155,46347,46539,46731,46923,47115,47307,47499,47691,47883,48075,48267,48459,48651,48843,49035,49227,49419,49611,49803,49995,50187,50379,50571,50763,50955,51147,51339,51531,51723,51915,52107,52299,52491,52683,52875,53067,53259,53451,53643,53835,54027,54219,54411,54603,54795,54987,55179,55371,55563,55755,55947,56139,56331,56523,56715,56907,57099,57291,57483,57675,57867,58059,58251,58443,58635,58827,59019,59211,59403,59595,59787,59979,60171,60363,60555,60747,60939,61131,61323,61515,61707,61899,62091,62283,62475,62667,62859,63051,63243,63435,63627,63819,64011,64203,64395,64587,64779,64971,65163,65355,65547,65739,65931,66123,66315,66507,66699,66891,67083,67275,67467,67659,67851,68043,68235,68427,68619,68811,69003,69195,69387,69579,69771,69963,70155,70347,70539,70731,70923,71115,71307,71499,71691,71883,72075,72267,72459,72651,72843,73035,73227,73419,73611,73803,73995,74187,74379,74571,74763,74955,75147,75339,75531,75723,75915,76107,76299,76491,76683,76875,77067,77259,77451,77643,77835,78027,78219,78411,78603,78795,78987,79179,79371,79563,79755,79947 //Summoner SP 1,500,4218,1,8,10,13,15,18,20,23,25,28,30,33,35,38,40,43,45,48,50,53,55,58,60,63,65,68,70,73,75,78,80,83,85,88,90,93,95,98,100,103,105,108,110,113,115,118,120,123,125,128,130,133,135,138,140,143,145,148,150,153,155,158,160,163,165,168,170,173,175,178,180,183,185,188,190,193,195,198,200,203,205,208,210,213,215,218,220,223,225,228,230,233,235,238,240,243,245,248,250,253,255,258,260,263,265,268,270,273,275,278,280,283,285,288,290,293,295,298,300,303,305,308,310,313,315,318,320,323,325,328,330,333,335,338,340,343,345,348,350,353,355,358,360,363,365,368,370,373,375,378,380,383,385,388,390,393,395,398,400,403,405,408,410,413,415,418,420,423,425,428,430,433,435,438,440,443,445,448,450,453,455,458,460,463,465,468,470,473,475,478,480,483,485,488,490,493,495,498,500,503,505,508,510,513,515,518,520,523,525,528,530,533,535,538,540,543,545,548,550,553,555,558,560,563,565,568,570,573,575,578,580,583,585,588,590,593,595,598,600,603,605,608,610,613,615,618,620,623,625,628,630,633,635,638,640,643,645,648,650,653,655,658,660,663,665,668,670,673,675,678,680,683,685,688,690,693,695,698,700,703,705,708,710,713,715,718,720,723,725,728,730,733,735,738,740,743,745,748,750,753,755,758,760,763,765,768,770,773,775,778,780,783,785,788,790,793,795,798,800,803,805,808,810,813,815,818,820,823,825,828,830,833,835,838,840,843,845,848,850,853,855,858,860,863,865,868,870,873,875,878,880,883,885,888,890,893,895,898,900,903,905,908,910,913,915,918,920,923,925,928,930,933,935,938,940,943,945,948,950,953,955,958,960,963,965,968,970,973,975,978,980,983,985,988,990,993,995,998,1000,1003,1005,1008,1010,1013,1015,1018,1020,1023,1025,1028,1030,1033,1035,1038,1040,1043,1045,1048,1050,1053,1055,1058,1060,1063,1065,1068,1070,1073,1075,1078,1080,1083,1085,1088,1090,1093,1095,1098,1100,1103,1105,1108,1110,1113,1115,1118,1120,1123,1125,1128,1130,1133,1135,1138,1140,1143,1145,1148,1150,1153,1155,1158,1160,1163,1165,1168,1170,1173,1175,1178,1180,1183,1185,1188,1190,1193,1195,1198,1200,1203,1205,1208,1210,1213,1215,1218,1220,1223,1225,1228,1230,1233,1235,1238,1240,1243,1245,1248,1250,1253,1255 There's another problem. Doram have no skills. Their skills should already exist within db/pre-re/skill-db.txt, but they are not specified within skill-tree.txt, Paste the following at the bottom to give skills to the Doram. //Summoner 4218,5018,1,0,0,0,0,0,0,0,0,0,0 //SU_BASIC_SKILL## 4218,5019,1,5018,1,0,0,0,0,0,0,0,0 //SU_BITE## 4218,5020,1,5019,1,0,0,0,0,0,0,0,0 //SU_HIDE## 4218,5021,3,5020,1,0,0,0,0,0,0,0,0 //SU_SCRATCH## 4218,5022,1,5021,3,0,0,0,0,0,0,0,0 //SU_STOOP## 4218,5023,3,5022,1,0,0,0,0,0,0,0,0 //SU_LOPE## 4218,5024,1,5023,3,0,0,0,0,0,0,0,0 //SU_SPRITEMABLE## 4218,5025,1,5027,3,0,0,0,0,0,0,0,0 //SU_POWEROFLAND## 4218,5026,5,5024,1,0,0,0,0,0,0,0,0 //SU_SV_STEMSPEAR## 4218,5027,5,5028,3,0,0,0,0,0,0,0,0 //SU_CN_POWDERING## 4218,5028,5,5029,3,0,0,0,0,0,0,0,0 //SU_CN_METEOR## 4218,5029,5,5026,3,0,0,0,0,0,0,0,0 //SU_SV_ROOTTWIST## 4218,5031,1,5036,3,0,0,0,0,0,0,0,0 //SU_POWEROFLIFE## 4218,5032,5,5035,3,0,0,0,0,0,0,0,0 //SU_SCAROFTAROU## 4218,5033,5,5024,1,0,0,0,0,0,0,0,0 //SU_PICKYPECK## 4218,5035,5,5033,3,0,0,0,0,0,0,0,0 //SU_ARCLOUSEDASH## 4218,5036,5,5032,3,0,0,0,0,0,0,0,0 //SU_LUNATICCARROTBEAT## 4218,5037,1,5039,3,0,0,0,0,0,0,0,0 //SU_POWEROFSEA## 4218,5038,5,5040,3,0,0,0,0,0,0,0,0 //SU_TUNABELLY## 4218,5039,5,5038,3,0,0,0,0,0,0,0,0 //SU_TUNAPARTY## 4218,5040,5,5041,3,0,0,0,0,0,0,0,0 //SU_BUNCHOFSHRIMP## 4218,5041,5,5024,1,0,0,0,0,0,0,0,0 //SU_FRESHSHRIMP## 4218,5044,1,5024,1,0,0,0,0,0,0,0,0 //SU_SOULATTACK## 4218,5045,5,5047,5,0,0,0,0,0,0,0,0 //SU_POWEROFFLOCK## 4218,5046,5,5045,5,0,0,0,0,0,0,0,0 //SU_SVG_SPIRIT## 4218,5047,5,5031,1,0,0,0,0,0,0,0,0 //SU_HISS## 4218,5048,5,5053,1,0,0,0,0,0,0,0,0 //SU_NYANGGRASS## 4218,5049,5,5037,1,0,0,0,0,0,0,0,0 //SU_GROOMING## 4218,5050,5,5049,1,0,0,0,0,0,0,0,0 //SU_PURRING## 4218,5051,5,5050,1,0,0,0,0,0,0,0,0 //SU_SHRIMPARTY## 4218,5052,1,5046,5,5047,5,5045,5,0,0,0,0 //SU_SPIRITOFLIFE## 4218,5053,5,5025,1,0,0,0,0,0,0,0,0 //SU_MEOWMEOW## 4218,5054,1,5048,5,5053,5,5055,5,0,0,0,0 //SU_SPIRITOFLAND## 4218,5055,5,5025,1,0,0,0,0,0,0,0,0 //SU_CHATTERING## 4218,5056,1,5051,5,5050,5,5049,5,0,0,0,0 //SU_SPIRITOFSEA## 4218,410,1,0,0,0,0,0,0,0,0,0,0 //WE_CALLBABY#Call Baby# //Baby Summoner 4220,5018,1,0,0,0,0,0,0,0,0,0,0 //SU_BASIC_SKILL## 4220,5019,1,5018,1,0,0,0,0,0,0,0,0 //SU_BITE## 4220,5020,1,5019,1,0,0,0,0,0,0,0,0 //SU_HIDE## 4220,5021,3,5020,1,0,0,0,0,0,0,0,0 //SU_SCRATCH## 4220,5022,1,5021,3,0,0,0,0,0,0,0,0 //SU_STOOP## 4220,5023,3,5022,1,0,0,0,0,0,0,0,0 //SU_LOPE## 4220,5024,1,5023,3,0,0,0,0,0,0,0,0 //SU_SPRITEMABLE## 4220,5025,1,5027,3,0,0,0,0,0,0,0,0 //SU_POWEROFLAND## 4220,5026,5,5024,1,0,0,0,0,0,0,0,0 //SU_SV_STEMSPEAR## 4220,5027,5,5028,3,0,0,0,0,0,0,0,0 //SU_CN_POWDERING## 4220,5028,5,5029,3,0,0,0,0,0,0,0,0 //SU_CN_METEOR## 4220,5029,5,5026,3,0,0,0,0,0,0,0,0 //SU_SV_ROOTTWIST## 4220,5031,1,5036,3,0,0,0,0,0,0,0,0 //SU_POWEROFLIFE## 4220,5032,5,5035,3,0,0,0,0,0,0,0,0 //SU_SCAROFTAROU## 4220,5033,5,5024,1,0,0,0,0,0,0,0,0 //SU_PICKYPECK## 4220,5035,5,5033,3,0,0,0,0,0,0,0,0 //SU_ARCLOUSEDASH## 4220,5036,5,5032,3,0,0,0,0,0,0,0,0 //SU_LUNATICCARROTBEAT## 4220,5037,1,5039,3,0,0,0,0,0,0,0,0 //SU_POWEROFSEA## 4220,5038,5,5040,3,0,0,0,0,0,0,0,0 //SU_TUNABELLY## 4220,5039,5,5038,3,0,0,0,0,0,0,0,0 //SU_TUNAPARTY## 4220,5040,5,5041,3,0,0,0,0,0,0,0,0 //SU_BUNCHOFSHRIMP## 4220,5041,5,5024,1,0,0,0,0,0,0,0,0 //SU_FRESHSHRIMP## 4220,408,1,0,0,0,0,0,0,0,0,0,0 //WE_BABY#Baby# 4220,409,1,0,0,0,0,0,0,0,0,0,0 //WE_CALLPARENT#Call Parent# 4220,5065,1,0,0,0,0,0,0,0,0,0,0 //WE_CHEERUP#Cheer Up# It's possible that you might not have the entries for skill-cast-db.txt or skill-require-db.txt either. If you don't see Doram skills here, find the equivalent files in the db/re folder, and copy any summoner skills into these files. I would give you the ones I have, but I changed a bunch of the values. We're almost done! The only problem now is that some of these skills still don't show up properly in-game. This is because the skills need to be added to the client files that display the skill trees. These are skilldescript.lub, skillinfolist.lub, and skilltreeview.lub. First, find these files within your renewal grf file. They are in data/lua files/skillinfoz. As before, we'll need to copy the text from GRF editor to a notepad file to change it. Some of the data for the Doram is already there, but it's incomplete, at least in the version I have. The doram only have their pre-level 99 skills, skills like Chattering are not present. If you want these skills, you'll need to add them. I've attached some txt files to this post that have the entries you need to add. These are not complete files, you'll need to merge these entries into the files that you have, then add them back to the grf and save. And done! If I didn't forget too many steps (I probably forgot a couple, I coded this quite some time ago), you should now have cats! By the way, if you want colours for your cats, as by default they have only one palette available, I made a post that has some colour palettes for the cats elsewhere on the forum. Good luck and happy catting! novice.txt DoramDescriptions.txt skilldescript.txt skillinfolist.txt skilltreeview.txt
  13. 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.
  14. 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).
  15. Nothing fancy here, just a pack of 35 cloth colours for male and female summoners, since in the distribution I had they didn't have any. To add this to your server, download the doram-palettes.grf from the bottom of the post, then find your data.ini (in your client folder) and add a line including this grf file, like so (the last line is the one you would add): [Data] 0=rathena_resources.grf 1=pre20190427.grf 2=renewal20190427.grf 3=palettes.grf 4=data.grf 5=rdata.grf 6=doram-palettes.grf You can also merge this into an existing grf file using GRF Editor if you prefer. If the "max_cloth_color" on your server is not 35, you'll also probably want this, this is a slightly modified version of the stylist npc who manually specifies the maximum number of palettes for Summoners. This should replace your npc/custom/stylist.txt //===== rAthena Script ======================================= //= Stylist //===== By: ================================================== //= Euphy //===== Current Version: ===================================== //= 1.1 //===== Compatible With: ===================================== //= rAthena Project //===== Description: ========================================= //= Changes your hair style, hair color, and cloth color. //===== Additional Comments: ================================= //= 1.0 Initial script. //= 1.1 Switched to 'getbattleflag', credits to Saithis. [Euphy] //= 1.2 Manually specified limits for Summoners [Tero] //============================================================ prontera,170,180,1 script Stylist#custom_stylist 122,{ mes "[Stylist]"; mes "Hey baby!"; mes "I can make you look fabulous!"; mes "Are you ready?"; if (Class == 4218 || Class == 4220) { setarray [email protected][1], 35, 6, 8; setarray [email protected][1], LOOK_CLOTHES_COLOR, LOOK_HAIR, LOOK_HAIR_COLOR; set [email protected], select(" ~ Cloth color: ~ Hairstyle: ~ Hair color"); set [email protected], getlook([email protected][[email protected]]); set [email protected],1; } else { setarray [email protected][1], getbattleflag("max_cloth_color"), getbattleflag("max_hair_style"), getbattleflag("max_hair_color"); setarray [email protected][1], LOOK_CLOTHES_COLOR, LOOK_HAIR, LOOK_HAIR_COLOR; set [email protected], select(" ~ Cloth color: ~ Hairstyle: ~ Hair color"); set [email protected], getlook([email protected][[email protected]]); set [email protected],1; } while(1) { setlook [email protected][[email protected]], [email protected]; message strcharinfo(0),"This is style #"[email protected]+"."; set [email protected]$, " ~ Next (^0055FF"+(([email protected][email protected][[email protected]])[email protected]+1:1)+"^000000): ~ Previous (^0055FF"+(([email protected]!=1)[email protected]:[email protected][[email protected]])+"^000000): ~ Jump to...: ~ Revert to original (^0055FF"[email protected]+"^000000)"; switch(select([email protected]$)) { case 1: set [email protected], (([email protected] != [email protected][[email protected]]) ? [email protected]+1 : 1); break; case 2: set [email protected], (([email protected] != 1) ? [email protected] : [email protected][[email protected]]); break; case 3: message strcharinfo(0),"Choose a style between 1 - "[email protected][[email protected]]+"."; input [email protected],0,[email protected][[email protected]]; if ([email protected]) set [email protected], rand(1,[email protected][[email protected]]); break; case 4: set [email protected], [email protected]; setlook [email protected][[email protected]], [email protected]; break; } } } Enjoy colourful cats! doram-palettes.grf
  16. Someone on my server asked for this, and I saw that many people had been using an old script that doesn't work anymore, so I made a new one. If playing PRE-RE, you need to pull RE's costume headgears into your PRE-RE item database first. Open re's item-db and search for 19500, and copy all the items from there until 20499 into pre-re's item database, under costume system. This script also requires code changes to a few files, but they are purely additions, nothing needs to be changed. In script.cpp Near all of the other defs, you need this line: BUILDIN_DEF(getcostumeid,"i?"), You also need to add this function, anywhere in the class: /*========================================== * Returns the costume id associated with an equip slot, if one exists * return costume id number or -1 * getcostumeid(<equipment slot>{,<char_id>}) *------------------------------------------*/ BUILDIN_FUNC(getcostumeid) { int i, num; TBL_PC* sd; struct item_data* item; unsigned short returnid; if (!script_charid2sd(3, sd)) { script_pushint(st, -1); return SCRIPT_CMD_FAILURE; } num = script_getnum(st, 2); if (!equip_index_check(num)) { script_pushint(st, -1); return SCRIPT_CMD_SUCCESS; } // get inventory position of item i = pc_checkequip(sd, equip_bitmask[num]); if (i < 0) { script_pushint(st, -1); return SCRIPT_CMD_SUCCESS; } item = sd->inventory_data[i]; if (item != 0) { // search item db for an item with the same view id returnid = itemdb_findmatchinglook(item); script_pushint(st, returnid); } else script_pushint(st, -1); return SCRIPT_CMD_SUCCESS; } In itemdb.hpp: Add this near all the other method declarations: int itemdb_findmatchinglook(struct item_data* data); In itemdb.cpp: Add this somewhere in the class. static int itemdb_searchlook(DBKey key, DBData* data, va_list ap) { struct item_data* item = (struct item_data*)db_data2ptr(data), * tomatch, ** dst; tomatch = va_arg(ap, struct item_data*); dst = va_arg(ap, struct item_data**); //We want items that have the same look but not the same id if (dst != NULL && item->look == tomatch->look && item->nameid > 19432 && item->nameid < 20500 && item->nameid != tomatch->nameid) *dst = item; return 0; } int itemdb_findmatchinglook(struct item_data* data) { struct item_data* item = NULL; itemdb->foreach(itemdb, itemdb_searchlook, data, &item, NULL); if (item) { return (int)item->nameid; } else { return -1; } } Then just recompile and add the script to your npc folder and to script_athena.conf or any similar file. //===== rAthena Script ======================================= //= Costume Trader NPC //===== By: ================================================== //= Tero //===== Current Version: ===================================== //= 1.0 //===== Compatible With: ===================================== //= rAthena Project //===== Description: ========================================= //= Can trade headgears for costumes. //===== Additional Comments: ================================= //= //============================================================ prontera,145,211,4 script Costume Trader#prt 612,{ mes "[Costume Trader]"; mes "I'm the costume trader."; mes "I can trade your headgear for costume versions."; mes "These items don't affect your stats, so you can wear other headgear with them."; mes "Do you want to trade for a costume?"; next; switch(select("Trade for a costume:Cancel")) { case 1: setarray [email protected][1], EQI_HEAD_TOP, EQI_HEAD_MID, EQI_HEAD_LOW; for([email protected] = 1; [email protected]<getarraysize([email protected]); [email protected]) { if(getequipisequiped([email protected][[email protected]])) { [email protected]$ = [email protected]$ + F_getpositionname([email protected][[email protected]]) + "-[" + getequipname([email protected][[email protected]]) + "]"; [email protected] = 1; } [email protected]$ = [email protected]$ + ":"; } if ([email protected] == 0) { mes "[Costume Trader]"; mes "It doesn't seem you have anything you can trade."; close; } mes "[Costume Trader]"; mes "Here's what you're wearing right now."; next; [email protected] = [email protected][select([email protected]$)]; [email protected] = getequipid([email protected]); [email protected] = getcostumeid([email protected]); if ([email protected] < 19433 || [email protected] > 20499 ) { mes "[Costume Trader]"; mes "Unfortunately, it doesn't seem like a costume exists for this item."; mes "I guess you'll just have to keep wearing it."; mes "I think it looks good on you at least."; close; } mes "[Costume Trader]"; mes "A costume is available for that item."; mes "If you trade, the costume will have no stats,"; mes "and any cards in it will be lost"; mes "Are you sure you want to trade?"; next; switch(select("Do the trade!:Cancel")) { case 1: // anti-hack if (callfunc("F_IsEquipIDHack", [email protected], [email protected])) { mes "[Costume Trader]"; emotion ET_FRET; mes "Wait a second..."; mes "Do you think I'm stupid?!"; mes "You switched the item while I wasn't looking! Get out of here!"; close; } delequip [email protected]; getitem [email protected], 1; mes "[Costume Trader]"; mes "Tada!"; mes "It's a shiny new costume item!"; mes "Aren't I amazing?"; mes "Come back again!"; close; case 2: mes "[Costume Trader]"; mes "That's too bad."; mes "But I understand you might be attached to it."; mes "Come back again."; close; } case 2: mes "[Costume Trader]"; mes "That's too bad."; mes "Collect more cute headgear and come back."; close; } } Enjoy costumes!
  17. I saw a lot of posts about this over the years, but none seemed updated for the most recent version. I recently spent a lot of time on pets, so here's a quick guide. I did everything for pre-renewal, but I would imagine most of this would work for renewal too, you might just need to add some stuff about evolution. What you'll need: GRF Editor SDE (Server Database Editor) Both of these can be found elsewhere on this forum and are used for most things involving editing your server. Understanding GRF files: When the client needs a file, it searches through the GRF files in a certain order to find it. The order it uses is specified in data.ini in the client's root folder. Mine looks like this. [Data] 0=rathena_resources.grf 1=pre20190427.grf 2=renewal20190427.grf 3=palettes.grf 4=data.grf 5=rdata.grf It looks in files that are higher in the list first. This means rathena_resources.grf is checked first, and rdata.grf is checked last. This means that if I need to override a file which is normally in data,grf, I can simply add it to any grf file that is higher in the list, and it will be used instead of the one in data.grf, without having to modify that file. Since rathena_resources.grf is first in the list, it's easiest to add your files to that. Getting started with your custom pet: The first two things your pet needs are an egg and a taming item. For eggs, I simply chose to replace an existing pet egg that was unused. In Pre-Re, there aren't any unused eggs, but we can fix that. In a text editor, open up the item_db.txt file for renewal, which is under your db/re folder. Search for 9001, which will get you to the beginning of the pet eggs. Renewal has tons of them! Copy and paste all the eggs that renewal's item_db has into pre-re's item db, and now they'll be available for pre-re to use. Now open up SDE. To add an egg for your new pet, all we have to do is rename it. Use the item search and find an egg you don't care about. Change its Aegis Name and Name to be the one of the pet you want. For example, I made Garm Baby, so the Aegis name is Garm_Baby_Egg and the Name is Garm Baby Egg. This part is done. Now we need a taming item. It's easiest to make a taming item by using a miscellaneous item. For Garm Baby, I used Nursing Bottle. To turn this item into a taming item, first we have to change it from a Misc Item to a Usable item, which is done using the dropdown in the upper right. We then need to set the Applicable Job to FFFFFFFF, upper to 7, and Gender to Both. Now we need to set the script. The script must look like this: pet 1515; Except that the number must match the id number of the enemy you want to be able to capture. Look this up in the mob database. You might want to modify the drop rates on your item through the mob database too, particularly if it's an item that no one in the game drops. Most pet items also have a sell price of 2500 and a weight of 50, if you want to be consistent. Use "save database (quick)" to save your changes. We're done with SDE for now. Adding your pet to the game: The next thing to do is to add your pet to pet_db.yml so it can spawn into the game. The installation I have actually breaks pet_db.yml into two parts. There's one file inside pre-re that contains the pet's basic information, and one inside import that contains its skill information. You could merge these files if you wanted, but if not you'll need to update both. There are already a bunch of entries in this file, so you can probably just copy one. Note that when it comes to yaml files, the spacing of the file is important, so make sure you copy it exactly including the spacing. Here's the one I used for Garm Baby. - Mob: GARM_BABY TameItem: Milk_Bottle EggItem: Garm_Baby_Egg FoodItem: Ice_Piece Fullness: 4 IntimacyFed: 10 CaptureRate: 500 Script: > [email protected] = getpetinfo(PETINFO_INTIMATE); if( [email protected] >= PET_INTIMATE_LOYAL ){ bonus2 bResEff,Eff_Freeze,5000; } The entries for MOB, TameItem, EggItem, and FoodItem are all Aegis_Names, you can look these up through SDE. For example, the Nursing Bottle's Aegis Name is actually Milk_Bottle. The script is something you'll have to come up with on your own. There's a bunch of examples in the file already you can draw on. My script makes the pet give you 50% resistance to the freeze status. If you want the pet to use skills, you'll need to update the other yml file inside import. Garm Baby has this inside that file: - Mob: GARM_BABY AttackRate: 8000 RetaliateRate: 8000 ChangeTargetRate: 800 SupportScript: > petskillattack "MG_FROSTDIVER",5,10,30; The main thing we care about is the SupportScript. This is what attack your pet will use. Here, this pet uses Frost Driver level 5, between 10-30% of the time depending on how happy it is. For a support skill, you use petskillsupport instead, with values like this one: petskillsupport "HP_ASSUMPTIO",1,80,100,100; This pet would cast Assumptio level 1 with an 80 second delay, when your hp and sp are 100% or less. There's also stat bonuses available: petskillbonus bLuk,5,20,40; This pet gives a bonus of 5 luck for 20 seconds, with a 40 second delay between uses. For more detail, look in script_commands.txt within Rathena's doc folder. With this, you can now restart your server and your pet will exist in the game! There will still be a bit of jank, for example its egg won't show the right name on the client, it won't have a picture, and it won't talk, we'll discuss how to fix that next. Fixing your pet's egg entry: This one is fairly easy. Navigate to your client folder and open up System/iteminfo.lua This is where the game stores all the item translations. Find the egg that you used by searching for its item id inside square brackets, like this [9001]. The description will be listed here. If you added a completely new egg, it won't be in this file and you'll need to add an entry for it. Update the name so it shows the right name. You can also add a description if you want. Mine looks like this, but it doesn't need to be this fancy. [9108] = { unidentifiedDisplayName = "Garm Baby Egg", unidentifiedResourceName = "¾ðµ¥µå¾Ë", unidentifiedDescriptionName = { "..." }, identifiedDisplayName = "Garm Baby Egg", identifiedResourceName = "¾ðµ¥µå¾Ë", identifiedDescriptionName = { "An egg in which a Garm Baby Cute Pet rests.", "Can be hatched by using a ^33CC33Pet Incubator^000000.", "^33CC33Special Power ^000000:", "Casts level 5 Frost Driver against the enemy", "^33CC33Loyal Bonus^000000", "Increases resistance to the Freeze status by 50%", "Class:^6666CC Monster Egg^000000" }, slotCount = 0, ClassNum = 0 }, Adding a picture for your pet: Every pet has a little picture that is displayed in their pet window. If you don't do this step, it'll just display NO IMAGE. This is not cool, so let's add an image. This requires GRF editor. To start with, you should probably open up data.grf, just to know how it's structured. Images for pets are stored in data/texture/userinterface/illust . If you search this folder for "pet", you'll see the existing images. They are all 90x134 pixels, your image will need to be this size too. Name it something like pet_garm_baby.bmp. You could just upload your file into data.grf, but data.grf is huge and thus it's slow to send update to this file to your players. Instead, it's easier to put it into rathena_resources.grf. It does not have this folder, but you can create it using GRF editor. Remember, any files you put inside something higher in the list of GRF files will override the earlier files. After adding your file, you'll notice that it won't actually display in game. This is because there is also a table of pets in the application that maintains the paths to the images that you need to update. This file is called petinfo.lub, and it is stored inside data.grf in the folder data/luafiles514/lua files/datainfo. We'll need to make a copy of this file, so extract it using right click extract with GRF editor. This file has specific encoding, so make sure to open it in an editor that is more powerful than notepad, like notepad++ or even wordpad. There are many tables in this file that you'll need to add your pet to. Generally, you can follow the format they use. You'll notice that most of the entries use an identifier that looks like this: [jobtbl.JT_GARM_BABY] = "GARM_BABY", This is an entry into the file jobidentity.lub, which is in the same folder. You should not need to modify that file, pretty much every enemy in the game is already in there, just enter your pet's Aegis name here, in all caps. When you come to this table: PetEggItemID_PetJobID You'll need to give your pet a new JobID, you can just assign a new one at the end. When you're finished updating this file, add it into your rathena_resources.grf, making the same folder path for it as above, so it will overwrite the one in the base game. Make sure to save your GRF afterwards. If you find that the pet accessories on your server no longer work after doing this, you broke the file's encoding. I fixed this by switching all the pet accessory files to the english names and adding them all to my GRF files, but the smart way is probably just to make sure you leave the encoding alone. Making your pet talk: To make your pet talk, it needs entries in pettalktable.xml. For me, this file was in my renewal.grf file, in the data folder. This is fairly straightforward, you can just copy and then modify Poring's entry. You just need to know what to put for the enclosing tags. The name must match the entry you made in the PetNameTable inside petinfo.lub. I put the name "GARM_BABY" for my pet, so the tag must say <GARM_BABY>. For some reason, my pets only talked when I put their entries near the beginning of the file. I suspect one of the entries inside the default file has an error in it, but I haven't found it. Either way, adding them to the top of the file is safe. With all of this stuff done, just save your GRF edits and restart the game (it's not necessary to restart the server for GRF changes) and hopefully your pet should talk and have a picture! Once you confirm everything works, you'll need to distribute the changed grf files and iteminfo.lua to your players. It's probably worth adding all your custom pets to the server first before you open in to the public! I'm sorry that this was long, no one said custom pets were going to be easy. Hopefully it all works for you.
×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use and Privacy Policy.