• Unfortunately, we have experienced significant hard drive damage that requires urgent maintenance and rebuilding. The forum will be a state of read only until we install our new drives and rebuild all the configurations needed. Please follow our Facebook page for updates, we will be back up shortly! (The forum could go offline at any given time due to the nature of the failed drives whilst awaiting the upgrades.) When you see an Incapsula error, you know we are in the process of migration.

Web v83 3rd person Crits, & Damage packet

Newbie Spellweaver
Joined
Dec 30, 2008
Messages
55
Reaction score
15
Hello Hello !

Part 1: Damage Packet


I forced myself to look at this leftover feature that only a few server have on that version.
So here are two simple packet, 199999 dmg, one without crit,the other without.
Code:
        2C 00 00 11 00 00 00 00 00 00 00 00 00 00 00 00 00 7B 80 02 03 DA C2 3B 04 01 CA 9A 3B 06 0D 0B 01 64 00 95 00 64 00 95 00 91 00 3F 0D 03 00 79 37 79 38 C0 00 95 00 // reg
        2C 00 00 11 00 00 00 00 00 00 00 00 00 00 00 00 00 7A 80 02 03 FC 54 3C 04 01 CA 9A 3B 06 0E 16 01 FD FF 95 00 FD FF 95 00 91 00 3F 0D 03 00 79 37 79 38 2E 00 95 00 // crit
        2C 00 00 AA BB BB BB BB CC CC CC CC CC CC CC CC DD EE FF GG HH II II II II JJ JJ JJ JJ KK KK KK KK KK KK KK KK KK KK KK KK KK KK LL LL LL LL MM MM MM MM .. .. .. ..

With the letters, and the code...: The only thing missing is KK's byte. So MoopleDEV has
lea.skip(14); Seriously kevin ? :p

Here's some things for moopleDEV
Code:
            byte b1 = lea.readByte(),
                    b2 = lea.readByte(),
                    b3 = lea.readByte(),
                    b4 = lea.readByte();
            short xPos = lea.readShort(), // Pos, to check for cseax hacks etc?
                    yPos1 = lea.readShort(),
                    yPos2 = lea.readShort(), // same
                    yPos3 = lea.readShort(); // same...
            byte attackSpeed = lea.readByte();  // maybe a way to check attack speed instantely ?
            // aran regular attack 76 - 6 - 64 - 122 - 52
            // brandish 48 118 68 
            byte skip = lea.readByte();

So I'm missing the bytes: b1 b2 b3 b4 and skip.
However, b1>b4, you have to do this on them:

Code:
            int v1 = b1;
            int v2 = b2 & 0x7F;
            int v3 = (b2 >> 7) & 1;
            int v4 = b3;
            int v5 = b4 & 0x7F;
            int v6 = (b4 >> 7) & 1;

Why ? No idea. But that's how its done.
If you have more informations on b1 to b4 & Skip. I'll gadly take it.

Now, to the crit part.
Theres no information in the damage packet about if the damage is crit or not.
However, when logggin in, client receives 3 seeds (cf: urself ;) ) that are clearly used for randomization. So probably for critical randoms aswell.
Does anyone know anything about how to use the randomizer to simulate the maple client with criticals ?

I don't want a solution like:
Code:
double critrate = 0;
if(SE) critrate += 0.15;
if(crit_throw_from_sin) critrate += 0.6;

thanks :p

nico
 
Custom Title Activated
Loyal Member
Joined
Jun 30, 2008
Messages
3,451
Reaction score
1,616
Re: v83 3rd person Crits, & Damage packet

Well sir, I have to disappoint you. In v83 there is no way to know if the client had a critical. That's all done server sided. In higher versions they send a special byte with that info though. In v83 you have to (indeed) calculate it yourself and show the crits by making the damage negative.

Also I am not skipping these bytes anymore, so don't hate me. I never did that, Shoot did.

Have this present:
PHP:
        AttackInfo ret = new AttackInfo();
        lea.readByte();//CField::GetFieldKey(v152)
        ret.damageAndMobCount = lea.readByte();//(tagRECT *)(nDamagePerMob | 16 * nMobCount)
        ret.damagePerMob = ret.damageAndMobCount & 0xF;
        ret.mobCount = ret.damageAndMobCount >> 4;

        ret.skillId = lea.readInt();//nSkillID
        lea.readInt();//nSkillCRC
        lea.readInt();//nSkillLevelCRC
        if (ret.skillId > 0) {
            ret.skilllevel = user.getSkillLevel(GameConstants.getHiddenSkill(ret.skillId));
        }
        if (GameConstants.isKeydownSkill(ret.skillId)) {
            ret.keyDown = lea.readInt();
        } else {
            ret.keyDown = 0;
        }

        ret.option = lea.readByte();//(tagRECT *)((bSpark << 7) | (bSpiritJavelin << 6) | 8 * bShadowPartner | 4 * bMortalBlow | 2 * bSoulArrow)
        ret.stance = lea.readShort();//(tagRECT *)(nAction & 0x7FFF | (bLeft << 15))

        ret.attackType = lea.readByte();

        if (user.getHp() > 0 && user.getField() != null) {
            ret.actionSpeed = lea.readByte();//nActionSpeed
            //start = actionSpeed >> 4;
            //speedDegree = actionSpeed & 0xF;
            lea.readInt();//tAttackTime
            if (type == 1) {
                ret.bulletItemPos = lea.readShort();//nBulletItemPos
                ret.bulletCashItemPos = lea.readShort();//nBulletCashItemPos
                ret.shootRange0a = lea.readByte();//nShootRange0a
                if ((ret.option & 0x40) > 0) {
                    if (ret.skillId != 4111004 && ret.skillId != 4121003 && ret.skillId != 4221003) {
                        ret.bulletItemID = lea.readInt();//nBulletItemID
                    }
                }
            }
            ret.hitInfo = new ArrayList<>();
            for (int i = 0; i < ret.mobCount; i++) {
                HitInfo hitInfo = new HitInfo();
                hitInfo.id = lea.readInt();
                hitInfo.hitAction = lea.readByte();
                byte foreAction = lea.readByte();
                hitInfo.foreAction = foreAction & 0x7F;
                hitInfo.left = ((foreAction >> 7) & 1) > 0;
                hitInfo.frameIdx = lea.readByte();//nFrameIdx
                byte calcDamageStatIndex = lea.readByte();//nCalcDamageStatIndex & 0x7F || doomed >> 7) & 1
                hitInfo.calcDamageStatIndex = calcDamageStatIndex & 0x7F;
                hitInfo.doomed = ((calcDamageStatIndex >> 7) & 1) > 0;
                hitInfo.ptHit = lea.readPos();
                hitInfo.ptPosPrev = lea.readPos();
                if (ret.skillId == ChiefBandit.MESO_EXPLOSION) {
                    hitInfo.attackCount = lea.readByte();
                    for (int j = 0; j < hitInfo.attackCount; j++) {
                        hitInfo.damage.add(lea.readInt());
                    }
                    hitInfo.attackCount = 0;//why?
                } else {
                    ret.delay = lea.readShort();//tDelay
                    for (int j = 0; j < ret.damagePerMob; j++) {
                        hitInfo.damage.add(lea.readInt());
                    }
                }
                lea.readInt();//CMob::GetCrc
                ret.hitInfo.add(hitInfo);
            }
            ret.ptUser = lea.readPos();
            if (ret.skillId == ChiefBandit.MESO_EXPLOSION) {
                int dropCount = lea.readByte();
                if (!user.getField().getDropPool().isEmpty()) {
                    List<Drop> explode = new ArrayList<>();
                    for (int i = 0; i < dropCount; i++) {
                        Drop drop = user.getField().getDropPool().get(lea.readInt());
                        if (drop != null) {
                            if (!drop.isMoney()) {
                                return null;
                            }
                            explode.add(drop);
                            lea.readByte();//mob it hits (index according to mobCount
                        } else {
                            return null;
                        }
                    }
                    int delay = lea.readShort();
                    int i = 0;
                    ret.drops = explode;
                    for (Drop drop : explode) {
                        user.getField().getDropPool().remove(drop.getDropId(), delay + 100 * i++ % 5);
                    }
                }
            }
            if (type == 1) {
                ret.ptStart = lea.readPos();//ptStart
            }
            if (ret.skillId == 15111006) {
                lea.readInt();
            }
        }



PS: You can try if hitInfo.calcDamageStatIndex = calcDamageStatIndex & 0x7F; > 0
Maybe that's the crit.
 
Upvote 0
Newbie Spellweaver
Joined
Dec 30, 2008
Messages
55
Reaction score
15
In the damage packet is nothing hat could tell if the crit is in a damage or not, as far as i know in v83!
The 14 skipped bytes are just speed/positionning stuff ?!

However, Since the client is probably using those 3 seeds to generate a random number that could trigger the critical damage, and since using a same seed on two machines is producing the same random result. We should be able to find the real crit formula right?

Any idea how to use those 3 seeds ?
 
Upvote 0
Back
Top