Jump to content

Playtester

Developer
  • Posts

    905
  • Joined

  • Last visited

  • Days Won

    26

Everything posted by Playtester

  1. Is there a pre-re skill that can target frozen enemies and not break frozen?
  2. Attached you can find a patch file that shows how to do it. The patch file contains a few more things and is not up-to-date to latest rAthena (it's from May 2024). What is in the patch: - Replace all unknown drops with Apple and all unknown MVP drops with Elunium - Remove random option feature (doesn't work in pre-re) - Recalculate renewal DEF to pre-renewal DEF if monster ID is 2083 or higher - Recalculate renewal MDEF to pre-renewal MDEF if monster ID is 2083 or higher - Recalculate renewal ATK/ATK2 to pre-renewal ATK/ATK2 - Replace all unknown monster skills with NPC_EMOTION If you are only interested in the DEF/MDEF part, you can only take over those changes: @@ -4561,6 +4570,12 @@ uint64 MobDatabase::parseBodyNode(const ryml::NodeRef& node) { if (!this->asUInt16(node, "Defense", def)) return 0; +#ifndef RENEWAL + // Renewal to pre-re conversion + if (mob_id >= 2083) + def = static_cast<uint16>(100.0 - ((4000.0 + def) / (4000.0 + def * 10.0) * 100.0)); +#endif + if (def < DEFTYPE_MIN || def > DEFTYPE_MAX) { this->invalidWarning(node["Defense"], "Invalid monster defense %d, capping...\n", def); def = cap_value(def, DEFTYPE_MIN, DEFTYPE_MAX); @@ -4575,6 +4590,12 @@ uint64 MobDatabase::parseBodyNode(const ryml::NodeRef& node) { if (!this->asUInt16(node, "MagicDefense", def)) return 0; +#ifndef RENEWAL + // Renewal to pre-re conversion + if (mob_id >= 2083) + def = static_cast<uint16>(100.0 - ((1000.0 + def) / (1000.0 + def * 10.0) * 100.0)); +#endif + if (def < DEFTYPE_MIN || def > DEFTYPE_MAX) { this->invalidWarning(node["MagicDefense"], "Invalid monster magic defense %d, capping...\n", def); def = cap_value(def, DEFTYPE_MIN, DEFTYPE_MAX); Hope this helps! I mainly wrote this patch so I can use all renewal monsters directly in pre-re by copying them over without having to worry about unsupported features and changes of functionality of stats. load_re_mobs_in_prere.patch
  3. What you actually need to do it detect which mobs are renewal mobs by their ID and then when you read in the data, you recalculate their stats from renewal to pre-renewal. I'm not at home right now, but I'll try to remember to post a sample solution later.
  4. You'll have to read through the patch notes and undo them one by one I guess. I usually use this to see what has changed over time: https://www.divine-pride.net/forum/index.php?/topic/4203-kro-skill-adjustment-timeline/
  5. There's no point to give a monster more than 100 DEF in pre-renewal because 100 DEF means 100% damage reduction, so damage is already 0. What are you trying to do?
  6. Renewal or pre-renewal? battle.cpp #ifdef RENEWAL if (sc->getSCE(SC_EDP)) { switch(skill_id) { // Renewal: Venom Splasher, Meteor Assault, Grimtooth and Venom Knife ignore EDP case TF_SPRINKLESAND: case AS_SPLASHER: case ASC_METEORASSAULT: case AS_GRIMTOOTH: case AS_VENOMKNIFE: break; // skills above have no effect with EDP default: // fall through to apply EDP bonuses // Renewal EDP formula [helvetica] // weapon atk * (2.5 + (edp level * .3)) // equip atk * (2.5 + (edp level * .3)) ATK_RATE(wd->weaponAtk, wd->weaponAtk2, 250 + (sc->getSCE(SC_EDP)->val1 * 30)); ATK_RATE(wd->equipAtk, wd->equipAtk2, 250 + (sc->getSCE(SC_EDP)->val1 * 30)); break; } } #endif This is the renewal code in current rAthena. I don't see any check for MVP/boss here, seems to be like it would always multiply the damage. Maybe your code is different? You could debug into it from here and see if it reaches the code and what happens to the damage. For pre-renewal, the code is also in battle.cpp: // EDP bonus damage // This has to be applied after mastery bonuses but still before the elemental extra damage if (sc->getSCE(SC_EDP)) wd->damage += (wd->damage * sc->getSCE(SC_EDP)->val3) / 100;
  7. You didn't put cooldown in your example.
  8. I didn't try it, but maybe the easiest solution would be to give those skills a cooldown. For example let's say you want "Scream/Dazzler" to be castable only every 4000ms, even if you have 4 Kiel Cards, you could add a 4000ms Cooldown like this: Id: 326 Name: DC_SCREAM Description: Dazzler MaxLevel: 5 Type: Misc TargetType: Self DamageFlags: NoDamage: true Splash: true Hit: Single HitCount: 1 SplashArea: -1 AfterCastActDelay: 4000 Cooldown: 4000 Duration1: 5000 Duration2: 5000 Kiel Card would then still reduce the after cast delay to 0ms, so it would allow the player to use other skills immediately, but the player could then still use Scream/Dazzler only once every 4 seconds.
  9. In battle.cpp this is where the multi attack from TF_DOUBLE is triggered: if( rnd()%100 < max_rate ) { wd->div_ = skill_get_num(TF_DOUBLE,skill_lv?skill_lv:1); wd->type = DMG_MULTI_HIT; } But at this point the damage is not calculated yet. So I'm not fully sure how to best go about this. You could remember in a variable that this was applied and then add damage later on based on that. The code for renewal and pre-renewal is pretty different so the solution is also different in both cases. In renewal I think damage just get added on top, so you could actually just put the bonus damage in the damage variable here directly. But in pre-renewal, the calculation is reset when calling "battle_calc_skill_base_damage", so you'd need to add the damage after that.
  10. Look at how Magnum Break is done. Requires: HpCost: - Level: 1 Amount: 20 - Level: 2 Amount: 20 - Level: 3 Amount: 19 - Level: 4 Amount: 19 - Level: 5 Amount: 18 - Level: 6 Amount: 18 - Level: 7 Amount: 17 - Level: 8 Amount: 17 - Level: 9 Amount: 16 - Level: 10 Amount: 16 SpCost: 30 First you define a HP cost. You can also use "HpRateCost" for percentual cost. Then you want to make sure the HP is only required but not consumed. For this go to skill.cpp and find "void skill_consume_hpspap". switch (skill_id) { //Skills that require HP but do not consume them case SM_MAGNUM: case MS_MAGNUM: hp = 0; break; Now you just need to add your skill here, so it doesn't consume the HP that it requires.
  11. I see nothing in the code that would make it not work on boss monsters. I guess just the tooltip in the client is incorrect?
  12. You could try to make Tarot Card of Fate a "magic" skill instead of "misc", but I'm not user what else that would affect. Maybe a cleaner solution would be to adjust the requirements for GTB to work in status.cpp: // Skills (magic type) that are blocked by Golden Thief Bug card or Wand of Hermod if (status_isimmune(bl)) { std::shared_ptr<s_skill_db> skill = skill_db.find(battle_getcurrentskill(src)); if (skill == nullptr) // Check for ground-type skills using the status when a player moves through units skill = skill_db.find(status_db.getSkill(type)); if (skill != nullptr && skill->skill_type == BF_MAGIC && // Basic magic skill !skill->inf2[INF2_IGNOREGTB] && // Specific skill to bypass ((skill->inf == INF_ATTACK_SKILL || skill->inf == INF_GROUND_SKILL || skill->inf == INF_SUPPORT_SKILL) || // Target skills should get blocked even when cast on self (skill->inf == INF_SELF_SKILL && src != bl))) // Self skills should get blocked on all targets except self return 0; } See, these are all the conditions for GTB to block a status. You could add the logic here. For example by checking for the specific skill id of CG_TAROTCARD and then just return 0. Though that would make GTB immune to all status changes from Tarot, so I guess you want to additional check for "type == SC_COMA".
  13. Would need more info. What does it not remove? What buffs did the target have? case 3: // THE HIGH PRIESTESS - all buffs removed { status_change_clear_buffs(target, SCCB_BUFFS | SCCB_CHEM_PROTECT); break; } Easiest to find is probably to debug into this function and see which check fails: /** * Clears buffs/debuffs on an object * @param bl: Object to clear [PC|MOB|HOM|MER|ELEM] * @param type: Type to remove * SCCB_BUFFS: Clear Buffs * SCCB_DEBUFFS: Clear Debuffs * SCCB_REFRESH: Clear specific debuffs through RK_REFRESH * SCCB_CHEM_PROTECT: Clear AM_CP_ARMOR/HELM/SHIELD/WEAPON * SCCB_LUXANIMA: Bonus Script removed through RK_LUXANIMA */ void status_change_clear_buffs(struct block_list* bl, uint8 type) { status_change *sc= status_get_sc(bl); if (!sc || !sc->count) return; //Clears buffs with specified flag and type for (const auto &it : status_db) { sc_type status = static_cast<sc_type>(it.first); const std::bitset<SCF_MAX>& flag = it.second->flag; bool end = false; if (!sc->getSCE(status)) continue; // Skip status with SCF_NOCLEARBUFF, no matter what if (flag[SCF_NOCLEARBUFF]) continue; // &SCCB_LUXANIMA : Cleared by RK_LUXANIMA and has the SCF_REMOVEONLUXANIMA flag if ((type & SCCB_LUXANIMA) && flag[SCF_REMOVEONLUXANIMA]) end = true; // &SCCB_CHEM_PROTECT : Clears AM_CP_ARMOR/HELP/SHIELD/WEAPON else if ((type & SCCB_CHEM_PROTECT) && flag[SCF_REMOVECHEMICALPROTECT]) end = true; // &SCCB_REFRESH : Cleared by RK_REFRESH and has the SCF_REMOVEONREFRESH flag else if ((type & SCCB_REFRESH) && flag[SCF_REMOVEONREFRESH]) end = true; // &SCCB_DEBUFFS : Clears debuffs else if ((type & SCCB_DEBUFFS) && flag[SCF_DEBUFF]) end = true; // &SCCB_BUFFS : Clears buffs - skip if it is a debuff else if ((type & SCCB_BUFFS) && !flag[SCF_DEBUFF]) end = true; // &SCCB_HERMODE : Cleared by CG_HERMODE and has the SCF_REMOVEONHERMODE flag else if ((type & SCCB_HERMODE) && flag[SCF_REMOVEONHERMODE]) end = true; if (status == SC_SATURDAYNIGHTFEVER || status == SC_BERSERK) // Mark to not lose HP sc->getSCE(status)->val2 = 0; if(end) status_change_end(bl, status); } //Removes bonus_script if (bl->type == BL_PC) { uint32 i = 0; if (type&SCCB_BUFFS) i |= BSF_REM_BUFF; if (type&SCCB_DEBUFFS) i |= BSF_REM_DEBUFF; if (type&SCCB_REFRESH) i |= BSF_REM_ON_REFRESH; if (type&SCCB_LUXANIMA) i |= BSF_REM_ON_LUXANIMA; pc_bonus_script_clear(BL_CAST(BL_PC,bl),i); } // Cleaning all extras vars sc->comet_x = 0; sc->comet_y = 0; #ifndef RENEWAL sc->sg_counter = 0; #endif return; }
  14. Why do you think it should be 186 is the question here. The screenshot is clearly from renewal which uses a completely different ASPD formula. If you think ASPD is off, please give an example that's achievable in pre-renewal and then I can verify it.
  15. I thought the point of Hamachi and similar tools was to simulate a local network. Local networks usually have IPs like 192.168.x.x or 10.x.x.x. 26.54.72.174 looks like a global IP to me. So I assume you need to change this IP to your local network IP. Also make sure your server is configured with the local network IPs you got from Hamachi rather than your public one. I never tried this, though, so it's just theoretical.
  16. You'll need to provide more information than that. The item_db doesn't even exist in CSV format anymore. Always 0 ASPD sounds to me like it's a weapon type that hasn't been defined ASPD for for the current job.
  17. https://github.com/rathena/rathena/blob/master/conf/battle/battle.conf // Does HP recover if hit by an attribute that's same as your own? (Note 1) attribute_recover: no The comment is misleading but this is what you are looking for I think.
  18. More like it was just bugged on emulators. Officially Poison always reduced HardDEF of monsters. The original RO team was actually incredibly good at balancing. Sometimes if you feel a skill is useless, you just gotta read up on tricks that you can do with it.
  19. Envenom got quite a bit boosted with my recent fixes: https://github.com/rathena/rathena/commit/861832ec27dd9edabbd337068b8ffccd7b1c1093 https://github.com/rathena/rathena/commit/eb4658f94077055caab8053866a357a3f7804afd Poison reduces HardDEF on monsters now, so it's actually quite useful to boost your damage. And the elemental table is partially applied twice, so Envenom gets more useful on monsters that are weak to Poison.
  20. I used to use OHRRPGCE (kinda like RPG maker, but more niche and less handholding). And I helped out with some Shining Force 1 mods using SF1Edit. I also used C++ Builder for the two coffeebreak roguelikes I made. But mostly I develop text-based games using pure c++.
  21. Currently there is no such status change but you could use the commented status change SC_HPREGEN and SC_SPREGEN. Uncomment them in status.hpp and in script_constants.hpp. Then you need to define it in status.yml. Then in skill_db.yml you link the skill to the status. And then in the source code at the code where the skill is executed in skill.cpp you can just start it with: sc_start(src,bl,type,100,skill_lv,skill_get_time(skill_id,skill_lv)) "type" contains the status that is linked to the skill in skill_db.yml, if you don't define it there you could also hardcode it here. skill_get_time() means it uses Duration1 defined for the skill. And then in the regen code you can just check if the status change is active if(sc && sc->getSCE(SC_HPREGEN)) { [...] }
  22. You need to make the skill give a status change (which I assume you did). Then in the regen code you want to check for the status change instead of the skill being learned.
  23. Just try around a bit. Basically "regen" is the normal regen and "sregen" is the sitting regen.
  24. Just open the rAthena project in Visual Studio and search for the Aegis name e.g. "SM_RECOVERY" and you find everything related to it in the source code.
  25. On a simular request I saw someone suggested to use mapflags and then do % damage adjustments like for GVG/WoE. But I'm not too familiar with that. I'd probably just change the source code to reduce the damage at some point. Probably in battle.cpp "battle_calc_attack" after the type-specific calls but before any no damage checks.
×
×
  • Create New...