Welcome!

Join our community of MMO enthusiasts and game developers! By registering, you'll gain access to discussions on the latest developments in MMO server files and collaborate with like-minded individuals. Join us today and unlock the potential of MMO server development!

Join Today!

[v62] Third Person Crits (Willing to pay)

Newbie Spellweaver
Joined
May 31, 2012
Messages
37
Reaction score
0
I'm trying to work on v62 Third Person Crits. I know its controlled server sided and whatnot but I'm not sure how I could go about doing it because I'm not too familiar with working with packets. Basic to intermediate level Java stuff is fine but I just don't have much understanding with packets. This is something that's been plaguing for years now and I just want to figure it out already so if anyone knows how to do it, I'd be willing to pay someone to get this working with me. Thanks.
 
Last edited:
Junior Spellweaver
Joined
Jan 4, 2013
Messages
162
Reaction score
29
Yea, it could be the version difference, I'll test it on v62 on my end soon. For now try out this just incase:

Code:
public AttackInfo parseDamage(LittleEndianAccessor lea, boolean ranged) {
                // TODO we need information if an attack was a crit or not but it does not seem to be in this packet - find out
        // if it is o.o
        // noncrit strafe
        // 24 00
        // 01
        // 14
        // FE FE 30 00
        // 00
        // 97
        // 04 06 99 2F EE 00 04 00 00 00 41
        // 6B 00 00 00
        // 06 81 00 01 00 00 5F 00 00 00 5F 00 D2 02
        // A3 19 00 00 43 0C 00 00 AD 0B 00 00 DB 12 00 00 64 00 5F 00
        //
        // fullcrit strafe:
        // 24 00
        // 01
        // 14
        // FE FE 30 00
        // 00
        // 97
        // 04 06 F5 C3 EE 00 04 00 00 00 41
        // 6B 00 00 00
        // 06 81 00 01 00 00 5F 00 00 00 5F 00 D2 02
        // 6E 0F 00 00 EA 12 00 00 58 15 00 00 56 11 00 00 64 00 5F 00
        AttackInfo ret = new AttackInfo();


        lea.readByte();
        ret.numAttackedAndDamage = lea.readByte();
        ret.numAttacked = (ret.numAttackedAndDamage >>> 4) & 0xF; // guess why there are no skills damaging more than 15 monsters...
        ret.numDamage = ret.numAttackedAndDamage & 0xF; // how often each single monster was attacked o.o
        ret.allDamage = new ArrayList<Pair<Integer, List<Integer>>>();
        ret.skill = lea.readInt();


        switch (ret.skill) {
            case 2121001:
            case 2221001:
            case 2321001:
            case 5101004:
            case 5201002:
                ret.charge = lea.readInt();
                break;
            default:
                ret.charge = 0;
                break;
        }


        if (ret.skill == 1221011) {
            ret.isHH = true;
        }
        lea.readByte(); // always 0 (?)
        ret.stance = lea.readByte();


        if (ret.skill == 4211006) {
            return parseMesoExplosion(lea, ret);
        }


        if (ranged) {
            lea.readByte();
            ret.speed = lea.readByte();
            lea.readByte();
            ret.direction = lea.readByte(); // contains direction on some 4th job skills
            lea.skip(7);
            // hurricane and pierce have extra 4 bytes :/
            switch (ret.skill) {
                case 3121004:
                case 3221001:
                case 5221004:
                    lea.skip(4);
                    break;
                default:
                    break;
            }
        } else {
            lea.readByte();
            ret.speed = lea.readByte();
            lea.skip(4);
        }


        for (int i = 0; i < ret.numAttacked; i++) {
            int oid = lea.readInt();
            lea.skip(14); // seems to contain some position info o.o


            List<Integer> allDamageNumbers = new ArrayList<Integer>();
            for (int j = 0; j < ret.numDamage; j++) {
                int damage = lea.readInt();
                ByteBuffer b = ByteBuffer.allocate(4);
                b.putInt(damage);


                byte[] result = b.array();
                if (result[1] > 0) {
                    damage += 0x80000000; //Critical
                }
                allDamageNumbers.add(Integer.valueOf(damage));
            }
            if (ret.skill != 5221004) {
                lea.skip(4);
            }
            ret.allDamage.add(new Pair<Integer, List<Integer>>(Integer.valueOf(oid), allDamageNumbers));
        }
        // System.out.println("Unk3: " + HexTool.toString(lea.read(4)));
        return ret;
    }
 
Upvote 0
Newbie Spellweaver
Joined
May 31, 2012
Messages
37
Reaction score
0
Yea, it could be the version difference, I'll test it on v62 on my end soon. For now try out this just incase:

Code:
public AttackInfo parseDamage(LittleEndianAccessor lea, boolean ranged) {
                // TODO we need information if an attack was a crit or not but it does not seem to be in this packet - find out
        // if it is o.o
        // noncrit strafe
        // 24 00
        // 01
        // 14
        // FE FE 30 00
        // 00
        // 97
        // 04 06 99 2F EE 00 04 00 00 00 41
        // 6B 00 00 00
        // 06 81 00 01 00 00 5F 00 00 00 5F 00 D2 02
        // A3 19 00 00 43 0C 00 00 AD 0B 00 00 DB 12 00 00 64 00 5F 00
        //
        // fullcrit strafe:
        // 24 00
        // 01
        // 14
        // FE FE 30 00
        // 00
        // 97
        // 04 06 F5 C3 EE 00 04 00 00 00 41
        // 6B 00 00 00
        // 06 81 00 01 00 00 5F 00 00 00 5F 00 D2 02
        // 6E 0F 00 00 EA 12 00 00 58 15 00 00 56 11 00 00 64 00 5F 00
        AttackInfo ret = new AttackInfo();


        lea.readByte();
        ret.numAttackedAndDamage = lea.readByte();
        ret.numAttacked = (ret.numAttackedAndDamage >>> 4) & 0xF; // guess why there are no skills damaging more than 15 monsters...
        ret.numDamage = ret.numAttackedAndDamage & 0xF; // how often each single monster was attacked o.o
        ret.allDamage = new ArrayList<Pair<Integer, List<Integer>>>();
        ret.skill = lea.readInt();


        switch (ret.skill) {
            case 2121001:
            case 2221001:
            case 2321001:
            case 5101004:
            case 5201002:
                ret.charge = lea.readInt();
                break;
            default:
                ret.charge = 0;
                break;
        }


        if (ret.skill == 1221011) {
            ret.isHH = true;
        }
        lea.readByte(); // always 0 (?)
        ret.stance = lea.readByte();


        if (ret.skill == 4211006) {
            return parseMesoExplosion(lea, ret);
        }


        if (ranged) {
            lea.readByte();
            ret.speed = lea.readByte();
            lea.readByte();
            ret.direction = lea.readByte(); // contains direction on some 4th job skills
            lea.skip(7);
            // hurricane and pierce have extra 4 bytes :/
            switch (ret.skill) {
                case 3121004:
                case 3221001:
                case 5221004:
                    lea.skip(4);
                    break;
                default:
                    break;
            }
        } else {
            lea.readByte();
            ret.speed = lea.readByte();
            lea.skip(4);
        }


        for (int i = 0; i < ret.numAttacked; i++) {
            int oid = lea.readInt();
            lea.skip(14); // seems to contain some position info o.o


            List<Integer> allDamageNumbers = new ArrayList<Integer>();
            for (int j = 0; j < ret.numDamage; j++) {
                int damage = lea.readInt();
                ByteBuffer b = ByteBuffer.allocate(4);
                b.putInt(damage);


                byte[] result = b.array();
                if (result[1] > 0) {
                    damage += 0x80000000; //Critical
                }
                allDamageNumbers.add(Integer.valueOf(damage));
            }
            if (ret.skill != 5221004) {
                lea.skip(4);
            }
            ret.allDamage.add(new Pair<Integer, List<Integer>>(Integer.valueOf(oid), allDamageNumbers));
        }
        // System.out.println("Unk3: " + HexTool.toString(lea.read(4)));
        return ret;
    }

Yeah it was a no go when I did it. :\
 
Upvote 0
Junior Spellweaver
Joined
Jan 4, 2013
Messages
162
Reaction score
29
Give this a shot and see if it works.

Code:
                int newDamage = 0;
                if (damage < 1000000) {
                    newDamage = damage + 1000000;
                } else {
                    newDamage = damage;
                }


                ByteBuffer b = ByteBuffer.allocate(4);
                b.putInt(newDamage);


                byte[] result = b.array();


                if (result[1] > 15) {
                    damage += 0x80000000; //Critical
                }

If it still doesn't work, then its likely you character is doing low damage. I'll will post an update once I find a another way to fix that since if you do 1 damage it won't work at all.
 
Last edited:
Upvote 0
Newbie Spellweaver
Joined
May 31, 2012
Messages
37
Reaction score
0
Give this a shot and see if it works.

Code:
                int newDamage = 0;
                if (damage < 1000000) {
                    newDamage = damage + 1000000;
                } else {
                    newDamage = damage;
                }


                ByteBuffer b = ByteBuffer.allocate(4);
                b.putInt(newDamage);


                byte[] result = b.array();


                if (result[1] > 15) {
                    damage += 0x80000000; //Critical
                }

If it still doesn't work, then its likely you character is doing low damage. I'll will post an update once I find a another way to fix that since if you do 1 damage it won't work at all.

What exactly is the ByteBuffering and putting the damage into the array for exactly? If I just remove the if statment to snipe, the crit text will show in the third party but for some reason normal attacks don't register damage, although they stil show damage, and attacks such as mortal blow stop working. Attack skills sometimes work, but sometimes also don't register. With all that, all attacks still show a critical text damage.
 
Upvote 0
Junior Spellweaver
Joined
Jan 4, 2013
Messages
162
Reaction score
29
I found a pattern with in the damage int, it matches up when ever a crit happens. ByteBuffering is what I used to find that pattern. This isn't the correct way to do it, but I want to see what happens if I play with it.
 
Upvote 0
Joined
Aug 10, 2008
Messages
858
Reaction score
516
I found a pattern with in the damage int, it matches up when ever a crit happens. ByteBuffering is what I used to find that pattern. This isn't the correct way to do it, but I want to see what happens if I play with it.

If you want the 2nd highest byte from that integer (assumption big endian order) you can use this instead of creating a ByteBuffer:
Code:
int result = 0xFF & (damage >>> 16); // moves the value in damage 16 bits (1 short) and removes the front byte

Also will have to look into this myself. I imagine you can probably simulate a critical strike event based on critical rate via a random and try to figure out which hits were critical based upon the aggregate damage the player deals.
 
Last edited:
Upvote 0
Junior Spellweaver
Joined
Jan 4, 2013
Messages
162
Reaction score
29
I give up, this is taking way too long. I haven't touched this in the last 2-3 weeks, but I did figure out why is didn't work.

- Damage value of 1 or 0 will not give you what you need to see the pattern and who does crit with 0 damage :L
- Needed to create a table for the pattern, since it follows a certain amount of damage for each stage. Ex. byte = 16, 16 takes 125????? damage.
- Not the right way to do it, since I don't know the right way to do it.
- Only meant to experiment with an idea, and a pattern.

It does indeed works for my character since my character does damage in a certain range that is flux between 16 or 17. 17 being normal damage and 16 being crit. If anyone wants proof I can record a video of it, since I've been trying to set a stand way for all damage range.

v62 = Past Life
v75 = Skipped
v83 = My Whole Life :D
 
Last edited:
Upvote 0
Back
Top