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!

Lucid

Skilled Illusionist
Joined
Jul 17, 2010
Messages
333
Reaction score
165
Hi, everyone. Today I introduce some packets related to Commander-Lucid-

*Note: I won't release just-copy-pastable codes (I mean, no compatibility to released servers), but a few pieces of code. Besides, since this is not from official-server sniffing, these implementation(used values) are most likely incorrect and missing some functions.

Though, I believe it will trigger you to update your server to up-to-date (v178+). (or, at least so as to attract attention of some people ;P)


Send Opcodes (v178)
Code:
//BEGIN_FIELD_LUCID
LUCID_BUTTERFLY_CREATE(0x4D0),
LUCID_BUTTERFLY_ACTION(0x4D1),
//none? xd
LUCID_DRAGON_CREATE(0x4D3),
LUCID_DO_SKILL(0x4D4),
LUCID2_STAINED_GLASS_ON_OFF(0x4D5),
LUCID2_STAINED_GLASS_BREAK(0x4D6),
LUCID_STATUE_STATE_CHANGE(0x4D7),
LUCID2_SET_FLYING_MODE(0x4D8),
LUCID2_WELCOME_BARRAGE(0x4D9),
//END_FIELD_LUCID
//BEGIN_FIELD_HUNDREDBINGO //just for ref.
Uh, it's bother to find actual values for each versions. So I provide a way to find them easily on IDA.
1. Open the 'string window' and search "BossLucid.img" (press Alt+T on the window).
2. Select something like "___:0249FA58 00000021C Etc/BossLucid.img/Dragon/phase%d").
3. You'll see a tag? "aEtcBosslucid_0", then xref (press X key on the tag) and goto the address found.
4. Press F5 key to see pseudocode, now I assume you're on ("v7 = ZXString<char>::Format(&v134, "Etc/BossLucid.img/Dragon/phase%d", a3);").
5. Press X key on the function name (at the top of the code), it's the main function of LUCID_DRAGON_CREATE.
6. Repeat 5. twice. You can finally find two fuctions, which are CField_Lucid::OnPacket and CField_Lucid2::OnPacket (or what I call so).

Recv Opcodes
Code:
END_BOSS_DEMIAN_FLYINGSWORD,//just for ref.
BEGIN_BOSS_LUCID,
LUCID_FAIRY_DUST_CHECK,
LUCID_ACTIVATE_STATUE_REQUEST,
LUCID_WELCOME_BARRAGE_END,
END_BOSS_LUCID,

Packet
Code:
public static class BossLucid {
    public static byte[] createButterfly(int initId, List<Butterfly> butterflies) {
        MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
        mplew.writeShort(SendOpcode.LUCID_BUTTERFLY_CREATE.getValue());
        mplew.writeInt(initId);//not sure
        mplew.writeInt(butterflies.size());
        for (Butterfly butterfly : butterflies) {
            mplew.writeInt(butterfly.type);
            mplew.writeInt(butterfly.pos.x);
            mplew.writeInt(butterfly.pos.y);
        }
        return mplew.getPacket();
    }

    /**
     *  [USER=2000183830]para[/USER]m mode Butterfly.Mode ADD/MOVE/ATTACK/ERASE
     *  [USER=2000183830]para[/USER]m args <br /> ADD: initId(not sure), typeId, posX, posY<br />
     * MOVE: posX, poxY<br />ATTACK: count, startDelay
     *  [USER=850422]return[/USER] 
     */
    public static byte[] setButterflyAction(Butterfly.Mode mode, int... args) {
        MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
        mplew.writeShort(SendOpcode.LUCID_BUTTERFLY_ACTION.getValue());
        mplew.writeInt(mode.code);
        switch (mode) {
            case ADD:
                mplew.writeInt(args[0]);
                mplew.writeInt(args[1]);
                mplew.writeInt(args[2]);
                mplew.writeInt(args[3]);
                break;
            case MOVE:
                mplew.writeInt(args[0]);
                mplew.writeInt(args[1]);
                break;
            case ATTACK:
                mplew.writeInt(args[0]);
                mplew.writeInt(args[1]);
                break;
        }
        return mplew.getPacket();
    }

    public static byte[] createDragon(int phase, int posX, int posY, int createPosX, int createPosY, boolean isLeft) {
        MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
        mplew.writeShort(SendOpcode.LUCID_DRAGON_CREATE.getValue());
        mplew.writeInt(phase);
        mplew.writeInt(posX);
        mplew.writeInt(posY);
        mplew.writeInt(createPosX);
        mplew.writeInt(createPosY);
        mplew.writeBool(isLeft);
        return mplew.getPacket();
    }

    public static byte[] doFlowerTrapSkill(int level, int pattern, int x, int y, boolean flip) {
        MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
        mplew.writeShort(SendOpcode.LUCID_DO_SKILL.getValue());
        mplew.writeInt(238);
        mplew.writeInt(level);//1~3
        mplew.writeInt(pattern);//0~2
        mplew.writeInt(x);
        mplew.writeInt(y);
        mplew.writeBool(flip);//not sure
        return mplew.getPacket();
    }

    public static byte[] doLaserRainSkill(int startDelay, List<Integer> intervals) {
        MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
        mplew.writeShort(SendOpcode.LUCID_DO_SKILL.getValue());
        mplew.writeInt(238);
        mplew.writeInt(5);
        mplew.writeInt(startDelay);
        mplew.writeInt(intervals.size());
        for (int interval : intervals) {
            mplew.writeInt(interval);
        }
        return mplew.getPacket();
    }

    public static byte[] doFairyDustSkill(int level, List<FairyDust> fairyDust) {
        MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
        mplew.writeShort(SendOpcode.LUCID_DO_SKILL.getValue());
        mplew.writeInt(238);
        mplew.writeInt(level);//4 or 10
        mplew.writeInt(fairyDust.size());
        for (FairyDust fd : fairyDust) {
            mplew.writeInt(fd.scale);
            mplew.writeInt(fd.createDelay);
            mplew.writeInt(fd.moveSpeed);
            mplew.writeInt(fd.angle);
        }
        return mplew.getPacket();
    }

    public static byte[] doForcedTeleportSkill(int splitId) {
        MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
        mplew.writeShort(SendOpcode.LUCID_DO_SKILL.getValue());
        mplew.writeInt(238);
        mplew.writeInt(6);
        mplew.writeInt(splitId);//0~7
        return mplew.getPacket();
    }

    public static byte[] doRushSkill() {
        MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
        mplew.writeShort(SendOpcode.LUCID_DO_SKILL.getValue());
        mplew.writeInt(238);
        mplew.writeInt(8);
        mplew.writeInt(0);//only path0 exists o.O
        return mplew.getPacket();
    }

    public static byte[] setStainedGlassOnOff(boolean enable, List<String> tags) {
        MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
        mplew.writeShort(SendOpcode.LUCID2_STAINED_GLASS_ON_OFF.getValue());
        mplew.writeBool(enable);
        mplew.writeInt(tags.size());
        for (String name : tags) {
            mplew.writeMapleString(name);
        }
        return mplew.getPacket();
    }

    public static byte[] breakStainedGlass(List<String> tags) {
        MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
        mplew.writeShort(SendOpcode.LUCID2_STAINED_GLASS_BREAK.getValue());
        mplew.writeInt(tags.size());
        for (String name : tags) {
            mplew.writeMapleString(name);
        }
        return mplew.getPacket();
    }

    public static byte[] setFlyingMode(boolean enable) {
        MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
        mplew.writeShort(SendOpcode.LUCID2_SET_FLYING_MODE.getValue());
        mplew.writeBool(enable);
        return mplew.getPacket();
    }

    /**
     *  [USER=2000183830]para[/USER]m placement true:show/hide the statue, false:update the gauge
     *  [USER=2000183830]para[/USER]m gauge 0~3
     *  [USER=2000183830]para[/USER]m enable when the 'placement' is true, a boolean means put/remove, otherwise it means displaying horn effect.
     *  [USER=850422]return[/USER] 
     */
    public static byte[] changeStatueState(boolean placement, int gauge, boolean enable) {
        MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
        mplew.writeShort(SendOpcode.LUCID_STATUE_STATE_CHANGE.getValue());
        mplew.writeInt(placement ? 1 : 0);
        if (placement) {
            mplew.writeBool(enable);
        } else {
            mplew.writeInt(gauge);
            mplew.writeBool(enable);
        }
        return mplew.getPacket();
    }

    public static byte[] doShoot(int angle, int speed) {
        MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
        mplew.writeShort(SendOpcode.LUCID2_WELCOME_BARRAGE.getValue());
        mplew.writeInt(0);
        mplew.writeInt(angle);
        mplew.writeInt(speed);
        return mplew.getPacket();
    }

    public static byte[] doBidirectionShoot(int angleRate, int speed, int interval, int shotCount) {
        MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
        mplew.writeShort(SendOpcode.LUCID2_WELCOME_BARRAGE.getValue());
        mplew.writeInt(3);
        mplew.writeInt(angleRate);
        mplew.writeInt(speed);
        mplew.writeInt(interval);
        mplew.writeInt(shotCount);
        return mplew.getPacket();
    }

    public static byte[] doSpiralShoot(int angle, int angleRate, int angleDiff, int speed, int interval, int shotCount, int bulletAngleRate, int bulletSpeedRate) {
        MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
        mplew.writeShort(SendOpcode.LUCID2_WELCOME_BARRAGE.getValue());
        mplew.writeInt(4);
        mplew.writeInt(angle);
        mplew.writeInt(angleRate);
        mplew.writeInt(angleDiff);
        mplew.writeInt(speed);
        mplew.writeInt(interval);
        mplew.writeInt(shotCount);
        mplew.writeInt(bulletAngleRate);
        mplew.writeInt(bulletSpeedRate);
        return mplew.getPacket();
    }

    /**
     *  [USER=2000183830]para[/USER]m type should be 1/2/5.<br />
     * 1 : ???<br />
     * 2 : Start skill action<br />
     * 5 : Stop skill action (for delaying or... idk)<br />
     * 0/3/4 see below
     *  [USER=287391]See[/USER]  FieldPacket.BossLucid.doShoot
     *  [USER=287391]See[/USER]  FieldPacket.BossLucid.doBidirectionShoot
     *  [USER=287391]See[/USER]  FieldPacket.BossLucid.doSpiralShoot
     */
    public static byte[] doWelcomeBarrageSkill(int type) {
        MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
        mplew.writeShort(SendOpcode.LUCID2_WELCOME_BARRAGE.getValue());
        mplew.writeInt(type);
        return mplew.getPacket();
    }
}

Handler
Implementing handlers is completely depend on how you implement/handle bosses... so honestly I will not answer (or would rather say I can't answer) what you should do.

LucidFairyDustCheck : oh, sorry I don't even know what will happen with this.

LucidActivateStatueRequest.java
Code:
package net.server.channel.handlers;

import client.MapleClient;
import net.AbstractMaplePacketHandler;
import server.field.Field;
import server.field.bosslucid.FieldLucid;
import tools.data.input.SeekableLittleEndianAccessor;

public class LucidActivateStatueRequest extends AbstractMaplePacketHandler {
    @Override
    public void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
        Field field = c.getUser().getField();
        if (field instanceof FieldLucid) {
            ((FieldLucid) field).eraseButterflies(true);
        }
    } 
}
LucidWelcomeBarrageEnd.java
Code:
package net.server.channel.handlers;

import client.MapleClient;
import net.AbstractMaplePacketHandler;
import server.field.Field;
import server.field.bosslucid.FieldLucid;
import tools.data.input.SeekableLittleEndianAccessor;
import tools.packet.FieldPacket;

public class LucidWelcomeBarrageEnd extends AbstractMaplePacketHandler {
    @Override
    public void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
        Field field = c.getUser().getField();
        if (field instanceof FieldLucid) {
            FieldLucid fieldLucid = (FieldLucid) field;
            if (fieldLucid.getLucidState() != FieldLucid.LucidState.END_SKILL) {
                c.sendPacket(FieldPacket.BossLucid.doWelcomeBarrageSkill(5));
                return;
            }
            fieldLucid.setLucidState(FieldLucid.LucidState.NORMAL);
            fieldLucid.broadcastPacket(FieldPacket.BossLucid.setStainedGlassOnOff(true, FieldLucid.STAINED_GLASS));
            fieldLucid.broadcastPacket(FieldPacket.BossLucid.setFlyingMode(false));
        }
    }
}

Some material examples
Butterfly.java
Code:
package server.field.bosslucid;

import java.awt.Point;
import java.io.File;
import java.util.ArrayList;
import java.util.List;

import provider.MapleData;
import provider.MapleDataProviderFactory;
import provider.MapleDataTool;

public class Butterfly {
    private static List<Point> BUTTERFLY_POS1;
    private static List<Point> BUTTERFLY_POS2;
    
    [U]//Load at Server launching[/U]
    public static void load() {
        BUTTERFLY_POS1 = new ArrayList<>();
        BUTTERFLY_POS2 = new ArrayList<>();
        try {
            MapleData butterflyData = MapleDataProviderFactory.getDataProvider(new File(System.getProperty("wzpath")+"/Etc.wz")).getData("BossLucid.img").getChildByPath("Butterfly");
            for (MapleData d : butterflyData.getChildByPath("phase1_pos")) {
                BUTTERFLY_POS1.add(MapleDataTool.getPoint("pos", d));
            }
            for (MapleData d : butterflyData.getChildByPath("phase2_pos")) {
                BUTTERFLY_POS2.add(MapleDataTool.getPoint("pos", d));
            }
        } catch (NullPointerException e) {
            System.err.println("[Butterfly] "+System.getProperty("wzpath")+"/Etc.wz/BossLucid.img/Butterfly is not found.");
        }
    }
    
    public static Point getPosition(boolean isFirstPhase, int index) {
        if (isFirstPhase && index < BUTTERFLY_POS1.size()) {
            return BUTTERFLY_POS1.get(index);
        } else if (index < BUTTERFLY_POS2.size()) {
            return BUTTERFLY_POS2.get(index);
        } else {
            return new Point(0, 0);
        }
    }

    public final int type;//templateId 0~8
    public final Point pos;

    public Butterfly(int type, boolean isFirstPhase, int index) {
        this(type, getPosition(isFirstPhase, index));
    }
    
    public Butterfly(int type, Point pos) {
        this.type = type;
        this.pos = pos;
    }
    
    public static enum Mode {
        ADD(0), MOVE(1), ATTACK(2), ERASE(3);
        
        public final int code;
        
        private Mode(int code) {
            this.code = code;
        }
    }
}
FairyDust
Code:
public class FairyDust {
    public final int scale;
    public final int createDelay;
    public final int moveSpeed;
    public final int angle;

    public FairyDust(int scale, int createDelay, int moveSpeed, int angle) {
        this.scale = scale;
        this.createDelay = createDelay;
        this.moveSpeed = moveSpeed;
        this.angle = angle;
    }
}
STAINED_GLASS
Code:
public static final List<String> STAINED_GLASS = Arrays.asList("Bblue1", "Bblue2", "Bblue3", "Bred1", "Bred2", "Bred3", "Mred2", "Mred3", "Myellow1","Myellow2", "Myellow3");
MobSkill.java (applyEffect)
*Disclaimer: values/formulas are incorrect, [STRIKE]or rather, who knows the right ones?[/STRIKE]
Code:
case 234://CONTAGION
    //A buffstat named CONTAGION (infection)
    break;
case 238://LUCID
    if (!(field instanceof FieldLucid)) {
        return;
    }
    FieldLucid fieldLucid = (FieldLucid) field;
    switch(skillLv) {
        case 1://Flower Trap
        case 2:
        case 3:
            fieldLucid.broadcastPacket(FieldPacket.BossLucid.doFlowerTrapSkill(skillLv, Randomizer.nextInt(3), 1000, 48, Randomizer.nextBoolean()));
            break;
        case 4://Fairy Dust
        case 10:
            //Oh, I'm fairly serious.
            List<FairyDust> fairyDust = new ArrayList<FairyDust>() {
                {
                    int x, s, s2, v, v2, w, w2, u = 2640;
                    if (skillLv == 4) { s = 180; s2 = 240; v = 100; v2 = 5; w = 3; w2 = 1; x = 40;
                    } else { s = 30; s2 = 330; v = 250; v2 = 100; w = 6; w2 = 3; x = 5;}
                    for (int i = 0, max = Randomizer.rand(w, w + w2); i < max; i++) {
                        x += Randomizer.nextInt(x);
                        add(new FairyDust(Randomizer.nextInt(3), u, v + Randomizer.nextInt(v2), x + Randomizer.rand(s, s2)));
                    }
                }
            };
            fieldLucid.broadcastPacket(FieldPacket.BossLucid.doFairyDustSkill(skillLv, fairyDust));
            break;
        case 5://Laser Rain
            List<Integer> laserIntervals =  new ArrayList<Integer>() {{for (int i = 0; i < 15; i++) add(500);}};
            fieldLucid.broadcastPacket(FieldPacket.BossLucid.doLaserRainSkill(4500, laserIntervals));
            break;
        case 6://Forced Teleport
            c.sendPacket(FieldPacket.BossLucid.doForcedTeleportSkill(Randomizer.nextInt(8)));//let's abuse the controller
            break;
        case 7://Dragon
            boolean isLeft= Randomizer.isSuccess(70);
            if (fieldLucid.getId() == FieldLucid.PHASE1_MAP) {//450004150?
                fieldLucid.broadcastPacket(FieldPacket.BossLucid.createDragon(1, 0, 0, 0, 0, isLeft));
            } else {
                int createPosX = isLeft ? -138 : 1498;
                int createPosY = Randomizer.nextBoolean() ? -1312 : 238;
                int posX = createPosX;
                int posY = mob.getPosition().y;
                fieldLucid.broadcastPacket(FieldPacket.BossLucid.createDragon(2, posX, posY, createPosX, createPosY, isLeft));
            }
            break;
        case 8://Rush
            fieldLucid.broadcastPacket(FieldPacket.BossLucid.doRushSkill());
            break;
        case 9://Welcome Barrage
            if (fieldLucid.getButterflyCount() == 0) {
                fieldLucid.setLucidState(FieldLucid.LucidState.NORMAL);
                return;
            }
            fieldLucid.setLucidState(FieldLucid.LucidState.DO_SKILL);
            fieldLucid.broadcastPacket(FieldPacket.BossLucid.setButterflyAction(Butterfly.Mode.MOVE, 700, -600));
            fieldLucid.resetButterflyPositions();
            fieldLucid.getLifePool().removeAllMobsExcept(Collections.singletonList(mob));
            fieldLucid.broadcastPacket(FieldPacket.BossLucid.doWelcomeBarrageSkill(2));
            fieldLucid.broadcastPacket(FieldPacket.BossLucid.setStainedGlassOnOff(false, FieldLucid.STAINED_GLASS));
            fieldLucid.broadcastPacket(FieldPacket.BossLucid.setFlyingMode(true));
            fieldLucid.broadcastPacket(FieldPacket.BossLucid.doBidirectionShoot(50, 120, 500, 3));
            fieldLucid.broadcastPacket(FieldPacket.BossLucid.doSpiralShoot(180, 150, 30, 30, 700, 12, 5, 1));
            fieldLucid.broadcastPacket(FieldPacket.BossLucid.doBidirectionShoot(50, 100, 500, 4));
            fieldLucid.broadcastPacket(FieldPacket.BossLucid.doSpiralShoot(180, 150, 30, 70, 1000, 12, 10, 0));
            fieldLucid.broadcastPacket(FieldPacket.BossLucid.doBidirectionShoot(50, 90, 700, 8));
            fieldLucid.broadcastPacket(FieldPacket.BossLucid.doSpiralShoot(180, 100, 30, 100, 700, 12, 0, 0));
            TimerManager.getInstance().schedule(() -> fieldLucid.setLucidState(FieldLucid.LucidState.END_SKILL), 15700);
            break;
    }
    break;
SpineAnimation
Code:
public static byte[] showSpineScreen(boolean isBinary, boolean isLoop, boolean isPostRender, String path, String animationName, int endDelay) {
    MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
    mplew.writeShort(SendOpcode.FIELD_EFFECT.getValue());
    mplew.write(FieldEffectType.SPINE_SCREEN.type);
    mplew.writeBool(isBinary);//not .json file
    mplew.writeBool(isLoop);
    mplew.writeBool(isPostRender);
    mplew.writeInt(endDelay);
    mplew.writeMapleString(path);//e.g. "Map/Effect3.img/BossLucid/Lucid/lusi"
    mplew.writeMapleString(animationName);//e.g. "animation"
    mplew.writeBool(false);//use key
    //mplew.writeMapleString("");//the key to stop animation?
    return mplew.getPacket();
}

Video



Thanks for reading :)
 
Last edited:
Newbie Spellweaver
Joined
May 14, 2015
Messages
26
Reaction score
1
Nice, why are you using a KMS base and not GMS?
 
Joined
Nov 9, 2012
Messages
608
Reaction score
164
Nice, why are you using a KMS base and not GMS?

Yuuroido - Lucid - RaGEZONE Forums
 
Newbie Spellweaver
Joined
Aug 28, 2015
Messages
95
Reaction score
47
Good release, thanks you :)

here is v182 opcodes if someone need them..
Code:
LUCID_BUTTERFLY_CREATE(0x4D2),
LUCID_BUTTERFLY_ACTION(0x4D3),
//none xd
LUCID_DRAGON_CREATE(0x4D5),
LUCID_DO_SKILL(0x4D6),
LUCID2_STAINED_GLASS_ON_OFF(0x4D7),
LUCID2_STAINED_GLASS_BREAK(0x4D8),
LUCID_STATUE_STATE_CHANGE(0x4D9),
LUCID2_SET_FLYING_MODE(0x4DA),
LUCID2_WELCOME_BARRAGE(0x4DB),
 
Newbie Spellweaver
Joined
May 14, 2015
Messages
26
Reaction score
1
Lmao sorry guys, I didn't pay close enough attention to the characters. Also I guess I wrongly assumed everyone here has English as their native language. My bad :sleep:
 
Skilled Illusionist
Joined
Jul 17, 2010
Messages
333
Reaction score
165
Nice release. But shouldn't there be more checks in the handlers? Easy to abuse now.. looks like Nexon code lol
Thank you. Hmm... then I would add a player's position check for statue-activation handler and a controller check for barrage-end handler. (I don't think that's what you meant, though.)
 
Newbie Spellweaver
Joined
Jan 9, 2015
Messages
18
Reaction score
1
can you explain createButterfly triggering conditions?
butterfly refers to the butterfly in the background, not mob

thank
 
Last edited:
Skilled Illusionist
Joined
Jul 17, 2010
Messages
333
Reaction score
165
can you explain createButterfly triggering conditions?
butterfly refers to the butterfly in the background, not mob

thank
triggering conditions?

I just create a butterfly by the field updater (it's just a timer though) and then check the butterfly count and explode them if it's over 40.
 
Back
Top