Jump to content

twostars

Administrators
  • Content Count

    1558
  • Joined

  • Last visited


Reputation Activity

  1. Like
    twostars got a reaction from Built4CZ in OTP Disable??   
    Please send me a PM with as many of your known account details as possible. Thankyou.
  2. Like
    twostars got a reaction from Built4CZ in OTP Disable??   
    Please send me a PM with as many of your known account details as possible. Thankyou.
  3. Like
    twostars got a reaction from Built4CZ in OTP Disable??   
    Please send me a PM with as many of your known account details as possible. Thankyou.
  4. Thanks
    twostars got a reaction from Built4CZ in inbox is full problem.   
    I think it should start to fix itself now. Thanks for letting me know
  5. Thanks
    twostars got a reaction from Built4CZ in inbox is full problem.   
    I think it should start to fix itself now. Thanks for letting me know
  6. Like
    twostars reacted to david4244 in Hello Everyone!   
    Well imo it's indeed a really light farm server. You are basicly ready to rape in cz with the starting gear (especially as a warrior), since the starting stuffs  are high class weapon +11s, rosetta set +8 (which gives only 50 def less than a krowaz set +8), +2 accs and +1 iron set.    Sure a krowaz set 11 (which aint that much ppl have) and a +11 krowaz weapon (AP wise it isn't rly better) with +3 uniques is better but the gap is kinda small pk wise, if you are good enough you can easily rape ppl with the starter stuffs.
     
    Anyway, to answer the questions:
     
    1.: As i said at shoutbox too, mostly go to events. (BDW , and Chaos event winners getting tears of karivdis which worth around 160m)  Juraid drops gems / krowaz chests / monster stone. [Monster stone fodder mobs can be ignored, only go for the boss at the end of the map if you do Monster stones, it drops Old Rocs, rols, etc].  FT isn't as good as BDW / chaos / juraid but still get ya dragon scale (upgrade item that allows you to make +0 regular unique from 3x old unique with 100% chance) and 1-2 other stuffs too.
    Other than this, you can farm Hepa Weapon +7s from Booro at CZ, they drop really well. (a +11 hepa raptor has 212 AP, 7 more than the regular rappy 11)
    There is also a daily quests at CZ, which gives you 1 hour DC premium // 1 hour auto loot everyday. Takes like 6 mins to do both quest together, if you do it with all the 4 chars on your acc everyday, you can have 4 hours DC prem for free daily (and 1-1-1-1 hour auto loot. Sadly the auto loot isn't storeable).
    With DC prem + flashes you can farm blood seekers at CZ for BUS / bes etc. Can get ya some decent money. (You can do it with genie, which is free to use)
    Or make an archer (can do it with warrior or other class too but easiest with archer imo) go to bowl and kill cardinals / dark eyes / harungas. (Cardinal - dark eyes drops 1x gold coin [=1.000.000 coin] with 100% chance, harungas drops 2x gold coin each with 100% chance].  Can get you like 150-300m per hour depends on how much guy from the enemy nation wanna kill ya.  [Also Atrosses and Riotes drops silver bar with 100% chance so if you see them, kill them for free 10m coin too]
    (100 KC worth ~300m now  so you can buy KC ingame too and then buy Pathos, wings etc for yourself with it)
     
    2.: As mentioned above, easily. You are good to go with the starting gear + pathos / wing.   Ah and also as i mentioned before too get a Draki SSC / SSB   (SSS is the best, but those aren't that cheap yet) those are the top tier necklaces and you can get those for like 200-500m.
    3.:  Mentioned in "1".   Mostly bowl mobs, or blood seekers.
    4.:  See it above aswell, but if you win 1-2 events a day that's a good money source already.  Plus there are daily quests at CZ for apex / krowaz chests which can get you gg money too.    
    5.: Nope, nothing. They can have full cospre items (pathos + valkyrie + wings) for some ap / def (or hp) boost, but you can get those too if you farm some money, and buy KC ingame.
    6.:  Idk, not much else comes to my mind right now.  Go to events, farm some coin if you can at bowl or blood seekers, do some daily quests and you are good to go but if you have any other question feel free to ask.
     
     
     
     
     
     
  7. Like
    twostars got a reaction from Holland in Suggestion: /roll   
    Random bump, but maybe.
    In WoW it actually works like: /roll [[min-]max]
    e.g. /roll 500-1000
    or /roll 1000 (1-1000)
    Default /roll (with no args) is just 1-100.
    I'd prefer it to preserve context, i.e. if you used the command in clan chat it'd only be sent to clan members, etc. This rules out making it a "/" command. "!roll" would be nice, but "!" is also used for shouting, so that doesn't work either.
    So it'd probably just have to act like a GM command (+roll). That can easily work. The command would then just be something like:
    +roll [[min] max]
    Since context is preserved, it can be sent to the relevant players (party/clan/alliance/general chat/etc).
    Seems trivial enough.
  8. Like
    twostars got a reaction from Holland in Can't launch the game - Application Error   
    This has been dealt with.
  9. Like
    twostars got a reaction from Badran in lost 2k kc to NPC   
    Your KC was restored. Thanks for your patience.
  10. Like
    twostars got a reaction from Badran in lost 2k kc to NPC   
    Your KC was restored. Thanks for your patience.
  11. Like
    twostars got a reaction from Holland in Maestro pots   
    Sorry, but this isn't going to change.
    Closing this thread.
  12. Like
    twostars reacted to Razordagawd in Boat map.   
    This map is kinda fun but needs work imo.
    First off, the abusable spawns. It needs some sort of hard-limit coded on how far you can climb or move into enemy spawn at all. Instant dc or one of the perma rubberband rollbacks that apex is known to have when dropping downhill would suffice to limit access into spawns. Or perhaps an actual safe-zone implemented so that you're immune above the hill by your spawn (nobody would abuse if they couldn't kill anyone).
    Next, the monument phase. It's quite fun and competitive to organize and capture monuments with a strategy of sorts going on. The problem is that it starts at the 15 min mark! I don't remember this from official, but even if I'm wrong, can it be dropped to the 5 or 10 minute mark?
    Third, the monument phase is supposed to have some sort of scoring system that depends on overall capture progress (this war is not defined by kills). Example: Each monument (there are 7 total) you hold gives you 0.1 points per second as long as you have it captured, and when the score tally comes up, each nation has a total come up as a "#### Notice:". By the end that nation that has more points, win (or if a nation captured all 7 monuments at one point, it ends immediately and said nation wins, regardless of score, kills or warders).
    das all.
  13. Like
    twostars got a reaction from Sierra in draki's pendant problem   
    For anyone coming across this thread now, this bug was fixed so you cannot bug bound items in order to trade them (which is what happened here, and also what the proposed solution was).
     
    In order to trade bound items you must first unbind them via "Bind item / Unbind item" option at an Inn Hostess.
    For that you'll need [unbind Items] which you can buy from Sundries or the Power-Up Store.
  14. Like
    twostars got a reaction from Drunken in Help Me   
    Looked into your case, and account sharing's forbidden for this reason. I won't be restoring these items, sorry.
     
    I suggest changing your password, enabling OTP, and not telling anyone your account details.
     
    Edit:
    There's no way for anyone to gain access to your account unless they know your details.
    Be safe with your details.
     
    We have never once had a case where a player's account was 'hacked' (i.e. by someone they didn't know).
    We've done all we can to ensure your account security. It's up to you to protect your own account with the tools provided, coupled with a sprinkling of common sense.
  15. Like
    twostars got a reaction from SkyHunter in List of bugs 2017   
    RNG. Each skill has an individual rate of cancellation. This is why it's harder to interrupt healers.
    int SuccessValue = rand()%100; if(SuccessValue >= pSkill->iPercentSuccess) // cancel the skill at a rate defined per the skill we're casting That's this. 
    I'm not sure what you mean by that. I know arrows can interrupt, as can lightning-based magic skills because there's logic there for it. 
    So with that in mind, going back to your original post:
    Taking away from the whole "at the right time" thing (unless we translate that mean "we got lucky with RNG"), it all makes complete sense with what I'm seeing. 
    The difference between here and other servers is purely that we shifted this logic to the server, since doing it on the client's end is very abusable ("hey, I can't ever be cancelled!").
    So with that in mind, we need to determine what actually is the problem here. Are we implementing it for things that shouldn't trip it, etc.
     
    Why priests in particular feel like they're getting cancelled more than they should be, and we've ruled out the window thing.
    So I'll look into that.
  16. Like
    twostars got a reaction from SkyHunter in List of bugs 2017   
    Since this "window logic" apparently applies to skills too, let's look at skills. It's essentially the same, but no awkward Action() call -- it's handled directly, so there's less to... interpret, I guess.
    So, let's look at type 3 stuff (generally mage skills) in particular, since it's the easiest to interpret (they're all handled the same way, just different triggers).
     
    The client source is really underwhelming for this, since it's lacking a lot, but the gist of it's here:

    void CMagicSkillMng::EffectingType3(DWORD dwMagicID) { __TABLE_UPC_SKILL_TYPE_3* pType3 = m_pTbl_Type_3->Lookup(dwMagicID); __ASSERT(pType3, "NULL type3 Pointer!!"); if(!pType3) return; StunMySelf(pType3); int key = 0; if(pType3->iStartDamage>0 || (pType3->iStartDamage==0 && pType3->iDuraDamage>0) ) key = DDTYPE_TYPE3_DUR_OUR; else key = DDTYPE_TYPE3_DUR_ENEMY; if(key==DDTYPE_TYPE3_DUR_ENEMY && pType3->iAttribute==3) StopCastingByRatio(); The important part that cancels our casts is StopCastingByRatio(). According to this, this applies for lightning based skills from enemies. 
    StopCastingByRatio() looks like this:

    void CMagicSkillMng::StopCastingByRatio() { m_pGameProcMain->CommandSitDown(false, false); // ÀÏÀ¸ÄÑ ¼¼¿î´Ù. if(IsCasting()) { __TABLE_UPC_SKILL* pSkill = s_pTbl_Skill->Lookup(s_pPlayer->m_dwMagicID); if(pSkill) { int SuccessValue = rand()%100; if(SuccessValue >= pSkill->iPercentSuccess) // ½ºÅ³ Å×ÀÌºí¿¡ ÀÖ´Â È®·ü´ë·Î ½ÇÆÐÇÑ´Ù.. { FailCast(pSkill); //if( s_pPlayer->Action(PSA_BASIC, false, NULL, true); // ij½ºÆà Ãë¼Ò, ±âº»µ¿ÀÛÀ¸·Î °­Á¦ ¼¼ÆÃ.. } } }So same deal as with regular attacks, but this calls FailCast() instead to immediately fail the cast. Simple. 
    For reference, FailCast() looks like this:

    void CMagicSkillMng::FailCast(__TABLE_UPC_SKILL* pSkill) { s_pPlayer->m_dwMagicID = 0xffffffff; s_pPlayer->m_fCastingTime = 0.0f; s_pPlayer->m_iSkillStep = 0; int16_t data[SkillDataFields] = {0}; data[3] = SKILLMAGIC_FAIL_CASTING; BuildAndSendSkillPacket(s_pPlayer->IDNumber(), s_pPlayer->IDNumber(), MAGIC_FAIL, pSkill->dwID, data); } All it does is resets the cast (immediately) and tells the server. 
    In 1.298:

    v4 = *(_DWORD *)(this + 36); v19 = a2; sub_58D550(&v21, &v19); result = *(_DWORD *)(v4 + 24); if ( v21 != result ) { v6 = v21 + 16; if ( v21 != -16 ) { CMagicSkillMng::StunMySelf((_DWORD *)v3, v6); v7 = *(_DWORD *)(v6 + 12); if ( v7 <= 0 && (v7 || *(_DWORD *)(v6 + 16) <= 0) ) { v8 = 200; if ( *(_DWORD *)(v6 + 24) == 3 ) // pType3->iAttribute == 3 CMagicSkillMng::StopCastingByRatio(v3); } else { v8 = 100; }There's no changes there, it's just merged in the lightning-type check into the existing check, instead of checking a second time. 

    void __thiscall CMagicSkillMng::StopCastingByRatio(int this) { int v1; // [email protected] int v2; // [email protected] int v3; // [email protected] int chance; // [email protected] signed int v5; // [email protected] int v6; // [email protected] int v7; // [email protected] __int16 v8; // [email protected] int v9; // [email protected] char v10; // [email protected] char v11; // [sp+Fh] [bp-31h]@0 int v12; // [sp+10h] [bp-30h]@4 int v13; // [sp+14h] [bp-2Ch]@4 int v14; // [sp+18h] [bp-28h]@9 int v15; // [sp+1Ch] [bp-24h]@9 int v16; // [sp+20h] [bp-20h]@9 char v17; // [sp+24h] [bp-1Ch]@9 int v18; // [sp+28h] [bp-18h]@9 int v19; // [sp+2Ch] [bp-14h]@9 int v20; // [sp+30h] [bp-10h]@9 int v21; // [sp+3Ch] [bp-4h]@9 v1 = this; sub_5D91F0(*(_DWORD **)(this + 24), 0, 0, 0); // CommandSitDown(false, false, false) if ( *(_DWORD *)(dword_818794 + 0x2FC) == 6 // These are the IsCasting() checks, just inlined because the compiler felt like it I guess. || *(_DWORD *)(dword_818794 + 0xB04) != -1 || *(_BYTE *)(dword_818794 + 0xAF4) == 1 ) { v2 = dword_818760; // __TABLE_UPC_SKILL* pSkill = s_pTbl_Skill->Lookup(s_pPlayer->m_dwMagicID); v12 = *(_DWORD *)(dword_818794 + 2820); sub_46D7E0(dword_818760 + 20, &v13, &v12); if ( v13 != *(_DWORD *)(v2 + 24) ) { v3 = v13 - 0xFFFFFFF0; if ( v13 != -0x10u ) // if (pSkill) { chance = rand() % 100; v5 = 100; if ( !*(_BYTE *)(dword_818794 + 0x470) ) // same check as in the previous example, to allow the specific transformations to have a rate of 100%. v5 = *(_DWORD *)(v3 + 0x88); if ( chance >= v5 ) { v18 = 0; // FailCast() is inlined here as well, so this is what FailCast() looks like. v17 = v11; v19 = 0; v20 = 0; v21 = 0; //4002 Casting failed sub_615080(4002, &v17); // show the fail message (client source doesn't do this) v6 = *(_DWORD *)(v1 + 24); sub_5D7250(&v17, -50373); *(_DWORD *)(dword_818794 + 2820) = -1; // s_pPlayer->m_dwMagicID = 0xffffffff; v14 = 0; *(_DWORD *)(dword_818794 + 2828) = 0; // not sure what this flag is v7 = *(_DWORD *)(dword_818794 + 1140); // prepare the packet to send v8 = *(_DWORD *)(dword_818794 + 1140); v9 = *(_DWORD *)v3; v15 = 0; v16 = 0; sub_583540(4, v9, v8, v7, &v14, -100, 0, 0); // send the packet v21 = -1; } } } } }So it's more or less the same, no window logic there either...
  17. Like
    twostars got a reaction from SkyHunter in List of bugs 2017   
    Okay. Well, it is affected by resistances. It uses the same logic as stuns, with the addition of a reduction to rates for staff skills.  

    The DoTs themselves are doing this? Or is it the initial skill that applies the DoT? I'm assuming it's the latter?  

    Which skills *should* be cancelling then?  

    I've looked over all the logic involving cancellations in the client (that's where they're normally handled). Not gonna lie, I've never seen anything remotely like this. I think this is just a coincidental thing that's been assumed to be the case, to be honest...
  18. Like
    twostars got a reaction from SkyHunter in List of bugs 2017   
    Does this happen anywhere in particular? The reason it still exists (despite being reported in beta) is because we've never been unable to reproduce it and it's never been clarified when asked. Even testing just now in the Moradon arena & CZ, it works just fine for me.
     
    Is there something in the mix like transformations? Is it in a specific area? I highly doubt it, but are you dead when you relog? (and respawn after relogging)
     
    Edit:
    Alright. As suspected, transformations can cause this. At least, when they're fixed (right now, they can't because they're broken, so the bug report *now* is rather confusing).
     
    Edit 2:
    This behaviour is the same officially. You cannot blink while transformed. It's impossible.
     
    So unless this occurs when not using a transformation...
  19. Like
    twostars got a reaction from SkyHunter in List of bugs 2017   
    RNG. Each skill has an individual rate of cancellation. This is why it's harder to interrupt healers.
    int SuccessValue = rand()%100; if(SuccessValue >= pSkill->iPercentSuccess) // cancel the skill at a rate defined per the skill we're casting That's this. 
    I'm not sure what you mean by that. I know arrows can interrupt, as can lightning-based magic skills because there's logic there for it. 
    So with that in mind, going back to your original post:
    Taking away from the whole "at the right time" thing (unless we translate that mean "we got lucky with RNG"), it all makes complete sense with what I'm seeing. 
    The difference between here and other servers is purely that we shifted this logic to the server, since doing it on the client's end is very abusable ("hey, I can't ever be cancelled!").
    So with that in mind, we need to determine what actually is the problem here. Are we implementing it for things that shouldn't trip it, etc.
     
    Why priests in particular feel like they're getting cancelled more than they should be, and we've ruled out the window thing.
    So I'll look into that.
  20. Like
    twostars got a reaction from SkyHunter in List of bugs 2017   
    Since this "window logic" apparently applies to skills too, let's look at skills. It's essentially the same, but no awkward Action() call -- it's handled directly, so there's less to... interpret, I guess.
    So, let's look at type 3 stuff (generally mage skills) in particular, since it's the easiest to interpret (they're all handled the same way, just different triggers).
     
    The client source is really underwhelming for this, since it's lacking a lot, but the gist of it's here:

    void CMagicSkillMng::EffectingType3(DWORD dwMagicID) { __TABLE_UPC_SKILL_TYPE_3* pType3 = m_pTbl_Type_3->Lookup(dwMagicID); __ASSERT(pType3, "NULL type3 Pointer!!"); if(!pType3) return; StunMySelf(pType3); int key = 0; if(pType3->iStartDamage>0 || (pType3->iStartDamage==0 && pType3->iDuraDamage>0) ) key = DDTYPE_TYPE3_DUR_OUR; else key = DDTYPE_TYPE3_DUR_ENEMY; if(key==DDTYPE_TYPE3_DUR_ENEMY && pType3->iAttribute==3) StopCastingByRatio(); The important part that cancels our casts is StopCastingByRatio(). According to this, this applies for lightning based skills from enemies. 
    StopCastingByRatio() looks like this:

    void CMagicSkillMng::StopCastingByRatio() { m_pGameProcMain->CommandSitDown(false, false); // ÀÏÀ¸ÄÑ ¼¼¿î´Ù. if(IsCasting()) { __TABLE_UPC_SKILL* pSkill = s_pTbl_Skill->Lookup(s_pPlayer->m_dwMagicID); if(pSkill) { int SuccessValue = rand()%100; if(SuccessValue >= pSkill->iPercentSuccess) // ½ºÅ³ Å×ÀÌºí¿¡ ÀÖ´Â È®·ü´ë·Î ½ÇÆÐÇÑ´Ù.. { FailCast(pSkill); //if( s_pPlayer->Action(PSA_BASIC, false, NULL, true); // ij½ºÆà Ãë¼Ò, ±âº»µ¿ÀÛÀ¸·Î °­Á¦ ¼¼ÆÃ.. } } }So same deal as with regular attacks, but this calls FailCast() instead to immediately fail the cast. Simple. 
    For reference, FailCast() looks like this:

    void CMagicSkillMng::FailCast(__TABLE_UPC_SKILL* pSkill) { s_pPlayer->m_dwMagicID = 0xffffffff; s_pPlayer->m_fCastingTime = 0.0f; s_pPlayer->m_iSkillStep = 0; int16_t data[SkillDataFields] = {0}; data[3] = SKILLMAGIC_FAIL_CASTING; BuildAndSendSkillPacket(s_pPlayer->IDNumber(), s_pPlayer->IDNumber(), MAGIC_FAIL, pSkill->dwID, data); } All it does is resets the cast (immediately) and tells the server. 
    In 1.298:

    v4 = *(_DWORD *)(this + 36); v19 = a2; sub_58D550(&v21, &v19); result = *(_DWORD *)(v4 + 24); if ( v21 != result ) { v6 = v21 + 16; if ( v21 != -16 ) { CMagicSkillMng::StunMySelf((_DWORD *)v3, v6); v7 = *(_DWORD *)(v6 + 12); if ( v7 <= 0 && (v7 || *(_DWORD *)(v6 + 16) <= 0) ) { v8 = 200; if ( *(_DWORD *)(v6 + 24) == 3 ) // pType3->iAttribute == 3 CMagicSkillMng::StopCastingByRatio(v3); } else { v8 = 100; }There's no changes there, it's just merged in the lightning-type check into the existing check, instead of checking a second time. 

    void __thiscall CMagicSkillMng::StopCastingByRatio(int this) { int v1; // [email protected] int v2; // [email protected] int v3; // [email protected] int chance; // [email protected] signed int v5; // [email protected] int v6; // [email protected] int v7; // [email protected] __int16 v8; // [email protected] int v9; // [email protected] char v10; // [email protected] char v11; // [sp+Fh] [bp-31h]@0 int v12; // [sp+10h] [bp-30h]@4 int v13; // [sp+14h] [bp-2Ch]@4 int v14; // [sp+18h] [bp-28h]@9 int v15; // [sp+1Ch] [bp-24h]@9 int v16; // [sp+20h] [bp-20h]@9 char v17; // [sp+24h] [bp-1Ch]@9 int v18; // [sp+28h] [bp-18h]@9 int v19; // [sp+2Ch] [bp-14h]@9 int v20; // [sp+30h] [bp-10h]@9 int v21; // [sp+3Ch] [bp-4h]@9 v1 = this; sub_5D91F0(*(_DWORD **)(this + 24), 0, 0, 0); // CommandSitDown(false, false, false) if ( *(_DWORD *)(dword_818794 + 0x2FC) == 6 // These are the IsCasting() checks, just inlined because the compiler felt like it I guess. || *(_DWORD *)(dword_818794 + 0xB04) != -1 || *(_BYTE *)(dword_818794 + 0xAF4) == 1 ) { v2 = dword_818760; // __TABLE_UPC_SKILL* pSkill = s_pTbl_Skill->Lookup(s_pPlayer->m_dwMagicID); v12 = *(_DWORD *)(dword_818794 + 2820); sub_46D7E0(dword_818760 + 20, &v13, &v12); if ( v13 != *(_DWORD *)(v2 + 24) ) { v3 = v13 - 0xFFFFFFF0; if ( v13 != -0x10u ) // if (pSkill) { chance = rand() % 100; v5 = 100; if ( !*(_BYTE *)(dword_818794 + 0x470) ) // same check as in the previous example, to allow the specific transformations to have a rate of 100%. v5 = *(_DWORD *)(v3 + 0x88); if ( chance >= v5 ) { v18 = 0; // FailCast() is inlined here as well, so this is what FailCast() looks like. v17 = v11; v19 = 0; v20 = 0; v21 = 0; //4002 Casting failed sub_615080(4002, &v17); // show the fail message (client source doesn't do this) v6 = *(_DWORD *)(v1 + 24); sub_5D7250(&v17, -50373); *(_DWORD *)(dword_818794 + 2820) = -1; // s_pPlayer->m_dwMagicID = 0xffffffff; v14 = 0; *(_DWORD *)(dword_818794 + 2828) = 0; // not sure what this flag is v7 = *(_DWORD *)(dword_818794 + 1140); // prepare the packet to send v8 = *(_DWORD *)(dword_818794 + 1140); v9 = *(_DWORD *)v3; v15 = 0; v16 = 0; sub_583540(4, v9, v8, v7, &v14, -100, 0, 0); // send the packet v21 = -1; } } } } }So it's more or less the same, no window logic there either...
  21. Like
    twostars got a reaction from SkyHunter in List of bugs 2017   
    Look, I spent way more time than I should have trying to prove its existence. I'm not saying there's nothing wrong, but what I am saying is: this "window" logic doesn't appear to exist in any step of the process. I went through it, in the old client source, in 1.298 and in 2.128. I'm not just waving my arms around being all "I don't want to fix this, it doesn't exist" -- I spent my time trying to prove it exists to understand how it worked so we could make sure it worked the same here. I just happened to end up proving it didn't.
     
    You could at least attempt to prove its existence by demonstrating you can only successfully cancel during those windows? Or something?
  22. Like
    twostars got a reaction from SkyHunter in List of bugs 2017   
    This "window" thing doesn't exist. If you're saying it applies to R attacks, I can tell you with absolute certainty that it doesn't exist.
     
    The client handles cancellation rates (or, did).
     
    In the client source (I know, not a great place to check because it's very dated and is lacking a lot -- but it'll help understand the next bit):

    if(bIAmTarget) // if we're the player being attacked { this->CommandSitDown(false, false); // force us to stand if we're not already if(m_pMagicSkillMng->IsCasting()) // if we're currently using the cast animation (which gets set the second we start casting something and lasts until the cast animation finishes) { __TABLE_UPC_SKILL* pSkill = s_pTbl_Skill->Lookup(s_pPlayer->m_dwMagicID); // lookup the skill we're casting if(pSkill) { int SuccessValue = rand()%100; if(SuccessValue >= pSkill->iPercentSuccess) // cancel the skill at a rate defined per the skill we're casting s_pPlayer->Action(PSA_BASIC, false, NULL, true); // reset the animation to what it would otherwise be (e.g. stand animation). cast will fail on the next tick because the state's reset. } } pTarget = s_pPlayer; } For reference, CMagicSkillMng::IsCasting() does this:
    bool CMagicSkillMng::IsCasting() { if(s_pPlayer->State() == PSA_SPELLMAGIC || // if we're currently in the cast animation s_pPlayer->m_dwMagicID != 0xffffffff || // if we have a skill ID set s_pPlayer->m_bStun == true) // also apply when they're stunned, so I guess this is why peoples' animations reset when stunned and interrupted return true; return false; } In 1.298:
    bool CMagicSkillMng::IsCasting() { return *(_DWORD *)(dword_818794 + 0x2FC) == 6 // s_pPlayer->State() == PSA_SPELLMAGIC || *(_DWORD *)(dword_818794 + 2820) != -1 // s_pPlayer->m_dwMagicID != 0xffffffff || *(_BYTE *)(dword_818794 + 0xAF4) == 1; // s_pPlayer->m_bStun == true }Attack logic in 1.298 (because it's slightly easier to read, but it's the same in 2.128):
    v12 = *(_DWORD *)(dword_818794 + 1140); v13 = v9 == v12; .. if ( v13 ) // if the player being attacked is us { sub_648EB0(4); v16 = v69; sub_5D91F0(v69, 0, 0, 0); // CommandSitDown(false, false, false); // force us to stand if we're not already v17 = v69[99]; if ( CMagicSkillMng::IsCasting() ) // if we're casting { // lookup the skill we're casting v18 = dword_818760; v67 = *(_DWORD *)(dword_818794 + 2820); sub_46D7E0(dword_818760 + 20, &v79, &v67); if ( v79 != *(_DWORD *)(v18 + 24) ) { v19 = v79 + 16; // logic is super obscure because internal lookup stuff, but if we're here it means the skill was found and we can proceed // if (pSkill) if ( v79 != -16 ) { v20 = rand() % 100; v21 = 100; // set default rate if ( !*(_BYTE *)(dword_818794 + 1136) ) // except for very few, very specific transformations (opening/closing ladders, kaul, mama magpie, "valentina"), use the skill's specified cancel rate v21 = *(_DWORD *)(v19 + 136); if ( v20 >= v21 ) { LOBYTE(v75) = v66; std::basic_string<char,std::char_traits<char>,std::allocator<char>>::_Tidy(0); v88 = 0; sub_615080(4002, &v75); if ( v16[18] ) sub_52ACD0(&v75, 0xFFFF3B3B); (*(void (__stdcall **)(_DWORD, _DWORD, _DWORD, signed int, signed int))(*(_DWORD *)dword_818794 + 24))( // Action()... 0, 0, 0, 1, -1); v88 = -1; std::basic_string<char,std::char_traits<char>,std::allocator<char>>::_Tidy(1);Logic there is the same. Only difference is:
    if ( !*(_BYTE *)(dword_818794 + 1136) ) // except for very few, very specific transformations (opening/closing ladders, kaul, mama magpie, "valentina"), use the skill's specified cancel rate v21 = *(_DWORD *)(v19 + 136); Where we're allowing for specific transformations that have a cancellation rate of 100% (apparently that's a thing, didn't realise until now). 
    Point being, the logic's the same. There's no "window" here. It applies from the moment the player starts casting their skill to the time the cast finishes (i.e. the cast animation).
     
    Just to prove that it also isn't a thing in 2.1xx:
     

    bool CMagicSkillMng::IsCasting() { return *(_DWORD *)(dword_DF0714 + 996) == 6 || *(_DWORD *)(dword_DF0714 + 3964) != -1 || *(_BYTE *)(dword_DF0714 + 3920) == 1; } // skipping into it a little because 2.1xx disassembly is a lot messier, but the above checks are the same if ( CMagicSkillMng::IsCasting() ) // same deal as before, if we're casting... { // lookup the skill we're casting v15 = sub_4EE700((char *)dword_DF060C, *(_DWORD *)(dword_DF0714 + 3964)); pSkill = v15; // if the skill exists if ( v15 ) { v3 = (int *)(rand() % 100); v15 = 100; // default the rate to 100% if ( !*(_BYTE *)(dword_DF0714 + 0x678) ) // if we're not using a specific transformation skill that overrides cancellation rate to 100%... specify the rate intead v15 = *(_DWORD *)(pSkill + 180); if ( (signed int)v3 >= v15 ) // time to cancel { v24 = *(_DWORD *)(s_pProcMain + 1268); if ( v24 ) // lookup genie ui { if ( dword_DF0714 ) // genie stuff --v { v25 = *(_DWORD *)(v24 + 844); if ( v25 ) { if ( *(_BYTE *)(dword_DF0714 + 1864) ) { switch ( *(_DWORD *)(dword_DF0714 + 1712) ) { case 103: case 109: case 110: case 203: case 209: case 210: *(_BYTE *)(v25 + 294) = 0; break; default: break; } } } } } // back to cancelling stuff... v81 = 15; v80 = 0; LOBYTE(v79) = 0; v89 = 0; sub_916270(4002, (int)&v78); // show the fail message v26 = *((_DWORD *)v68 + 113); if ( v26 ) sub_69A460(v26, (int)&v78, (int)&v78, 0xFFFF3B3B); // use Action() to override the animation. next tick will fail the cast since we're no longer casting. (*(void (__stdcall **)(_DWORD, _DWORD, _DWORD, signed int, signed int, signed int))(*(_DWORD *)dword_DF0714 + 24))( 0, 0, 0, 1, -1, -1); So that's R attacks. But you might say, but what if it for some reason succeeds with the cast anyway since R attacks wait until the next tick to fail casts, whereas if you're cancelling via a skill, it interrupts it immediately.So let's check that logic out:
     
    In the client source:

    void CMagicSkillMng::ProcessCasting() { //ij½ºÆà ó¸®.. if(s_pPlayer->m_dwMagicID != 0xffffffff) { __TABLE_UPC_SKILL* pSkill = s_pTbl_Skill->Lookup(s_pPlayer->m_dwMagicID); CPlayerBase* pTarget = m_pGameProcMain->CharacterGetByID(m_iTarget, true); if(pTarget) s_pPlayer->RotateTo(pTarget); // ÀÏ´Ü Å¸°ÙÀ» ÇâÇØ ¹æÇâÀ» µ¹¸°´Ù.. //ij½ºÆà ¼º°øÀûÀ¸·Î ¿Ï·á... float fCastingTime = ((float)pSkill->iCastTime) / 10.0f * s_pPlayer->m_fAttackDelta; if(pSkill) { bool bSuccess = false; if( s_pPlayer->m_fCastingTime >= fCastingTime && s_pPlayer->State()==PSA_SPELLMAGIC && s_pPlayer->StateMove()==PSM_STOP) { SuccessCast(pSkill, pTarget); bSuccess = true; } //ij½ºÆà ½ÇÆÐ... if(bSuccess == false && (s_pPlayer->State()!=PSA_SPELLMAGIC || s_pPlayer->StateMove()!=PSM_STOP)) { FailCast(pSkill); } } else s_pPlayer->m_dwMagicID = 0xffffffff; } } So, relevant logic is here:
    if( s_pPlayer->m_fCastingTime >= fCastingTime && s_pPlayer->State()==PSA_SPELLMAGIC && s_pPlayer->StateMove()==PSM_STOP) { SuccessCast(pSkill, pTarget); bSuccess = true; } //ij½ºÆà ½ÇÆÐ... if(bSuccess == false && (s_pPlayer->State()!=PSA_SPELLMAGIC || s_pPlayer->StateMove()!=PSM_STOP)) { FailCast(pSkill); } If we've finished our cast, and we're in a cast animation and the player's movement state is stopped, then the cast should succeed.It will fail here though, since their animation is no longer the cast animation -- thus "s_pPlayer->State()==PSA_SPELLMAGIC" will fail and so will the skill, in the next check.
     
    Let's see what this looks like in 2.1xx:

    v10 = 0.0; if ( sub_53E380(v6, (int)&v10) ) { result = CMagicSkillMng::SucceedCast((int)v2, v9, (int)v5, v7, v10); } else { result = dword_DF0714; if ( *(_DWORD *)(dword_DF0714 + 996) != 6 || *(_DWORD *)(dword_DF0714 + 1008) ) result = CMagicSkillMng::FailCast(v5); }So, they moved the check into a method:
    bool __thiscall sub_53E380(int this, int a2) { return *(_DWORD *)(this + 996) == 6 && !*(_DWORD *)(this + 1008) && sub_53CE10(this + 92, (float *)a2); }Which is essentially the same, reads something like:
    if (s_pPlayer->State()==PSA_SPELLMAGIC && s_pPlayer->StateMove()==PSM_STOP && CastTimeFinished())CastTimeFinished() is a little more complex than it used to be (a simple time check), but that's not important because s_pPlayer->State()==PSA_SPELLMAGIC is still false so it immediately fails because of that. 
    I think all that you've experienced is just RNG. I'm pretty sure that this "window" logic doesn't exist.
  23. Like
    twostars got a reaction from SkyHunter in List of bugs 2017   
    Okay. Well, it is affected by resistances. It uses the same logic as stuns, with the addition of a reduction to rates for staff skills.  

    The DoTs themselves are doing this? Or is it the initial skill that applies the DoT? I'm assuming it's the latter?  

    Which skills *should* be cancelling then?  

    I've looked over all the logic involving cancellations in the client (that's where they're normally handled). Not gonna lie, I've never seen anything remotely like this. I think this is just a coincidental thing that's been assumed to be the case, to be honest...
  24. Like
    twostars got a reaction from SkyHunter in List of bugs 2017   
    Are these things it's doing now and shouldn't? Or things it's not doing now and should? Your wording is confusing.
  25. Like
    twostars got a reaction from SkyHunter in List of bugs 2017   
    Does this happen anywhere in particular? The reason it still exists (despite being reported in beta) is because we've never been unable to reproduce it and it's never been clarified when asked. Even testing just now in the Moradon arena & CZ, it works just fine for me.
     
    Is there something in the mix like transformations? Is it in a specific area? I highly doubt it, but are you dead when you relog? (and respawn after relogging)
     
    Edit:
    Alright. As suspected, transformations can cause this. At least, when they're fixed (right now, they can't because they're broken, so the bug report *now* is rather confusing).
     
    Edit 2:
    This behaviour is the same officially. You cannot blink while transformed. It's impossible.
     
    So unless this occurs when not using a transformation...
×