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!

JourneyDEV v83

Elite Diviner
Joined
Mar 24, 2015
Messages
426
Reaction score
416
JourneyDEV v83+

Hello Ragezoners,

Intro and goals
I decided it's time for me to finally post something here. I've been working on a server for over a month using MoopleDev 120 as basis. I don't have much time but I'll try to update frequently.
My goal is to eventually revamp every file in the source and make it more to my liking. I also want to add alot of custom features.

My reason for making this thread is to learn from criticism, and to share my files with anyone who finds them useful.

Files
Github only contains files made by myself. Therefore all files available are originally part of Journey and not redundant. Everything else is not very interesting, other files just contain minor references to the objects I've made.

Critisicm is appreciated, for style too since there's alot of things I'm not sure about.

The files are hosted on github. If you find anything useful, feel free to use it. However be aware that you will be missing all references and edits in other files neccessary for everything to work. Many files are based around WZ edits and will not work without them.
(I'd appreciate if you'd try to remake my files for yourself.)

Custom Features:

Code:
- Custom Potential/Inner Ability
- Boss PQ, with bosses/maps/music from newer versions
- Records system for events like boss pq
- Fishing System
- Main Npc with Achievement System, Guide
- Ardentmill and profession system

Work in progress:
- Crafting professions, custom scroll crafting system
Some features like potentials would require client edits to be properly displayed. I will do this whenever I learn how.
I have a basic idea for it, what I'd want to do is making the client display custom item descriptions (which I can send as packet from the source). I have no idea how hard to do that is tough.

Changelog: (from 16.05.2015)
Code:
[SPOILER][B]Rev 0: [/B]
- Uploaded source here with all changes so far
[B]Rev 1: [/B]
- Added the basis for a custom scroll system
[B]Rev 2:[/B]
- Added a playerstats object to (hopefully) simplify MapleCharacter.java
- Uploaded equip.java with first version of equip potentials
- Some files had bugs because I didn't have time to test, files should always work from now on
[B]Rev 3:[/B]
- Revised playersats.java to manage stats better
- Simplified equip.java, removed alot of boring get/set functions
[B]Rev 4:[/B] (29.05.2015)
- Added new class RewardsManager to load gachapon and similiar rewards from database
- Added the very raw basis for a profession system similiar to new maplestory
- Revised the way equip potential works
- Revised playerstats again, also some ocd fixes concerning the data type of some stats (for ex., changed gender to enum, stats to short), migrated schedule functions from MapleCharacter.java into ScheduleManager.java
- Uploaded NPCConversationManager.java for gachapon code
[COLOR=#000000][B]Rev 5: [/B][/COLOR](02.06.2015)
- Added magnifying glass to equip potential system
- new feature for supreme world: chaos channels (ik, name sounds like it's coming from a 13 year old)
[B]Rev 6[/B][COLOR=#0000ff][B]: [/B][/COLOR](04.06.2015)
- Added Ardentmill maps/npcs/music
- Implemented a custom formula for damage reflect: -20% hp x skillLevel (1~5) per attack reflected[/SPOILER]
[COLOR=#000000][B]Rev 7: [/B][/COLOR](11.06.2015)
- Added harvesting for Profession System
- Added some new classes in context of harvesting (see post)
- Changed some database saving/loading stuff. Removed everything that won't be in my server (gachaexp, vanquisher dojo stuff for example)
[COLOR=#000000][B]Rev 8: [/B][/COLOR](12.06.2015)
- (Finally) updated github again. most new files should be on there
- made some more changes to how saving chars is approached. the source now checks which information has changed and what queries it can skip. (for maplecharacter.java)
[COLOR=#000000][B]Rev 9: [/B][/COLOR][COLOR=#000000](14.06.2015)[/COLOR][COLOR=#0000cd][B]
- [/B][/COLOR][COLOR=#000000]Revamped Inner Ability System. Stats are now shown on a "inner ability ring" that is permanently in your inventory.[/COLOR]
[COLOR=#0000ff][B]Rev 10: [/B][/COLOR][COLOR=#000000](23.06.2015)
[/COLOR]- Added basics of new AutobanManager
- Revamped map loading system
- Added mining reactors, drops and items
- Changed github to only contain files made by me. Upgraded files with license header.

Now some will probably think: Another v83 thread? Here is my response as to why v83:
It is the version I grew up with so it's nostalgic for me. I'm also allergic to the map/quest changes nexon did after big bang. From browsing through this forum I can tell that some people think working on older versions isn't worth it, but I think the amount of nostalgic players is quite good.
I also have the impression that things like updating packets is quite tedious and mundane. I'd rather have fun and code custom systems similiar to what new versions have.

Screenshots:
BossPQ: (hell)
SYJourney - JourneyDEV v83 - RaGEZONE Forums


Boss PQ: (easy)
SYJourney - JourneyDEV v83 - RaGEZONE Forums


Cubing something:
SYJourney - JourneyDEV v83 - RaGEZONE Forums


Magnifying Glass.
SYJourney - JourneyDEV v83 - RaGEZONE Forums


Item has to be cubed before using mag.
SYJourney - JourneyDEV v83 - RaGEZONE Forums


No potential yet.
SYJourney - JourneyDEV v83 - RaGEZONE Forums


Got +2 avoid! ...
SYJourney - JourneyDEV v83 - RaGEZONE Forums


Maple Coin Shop.
SYJourney - JourneyDEV v83 - RaGEZONE Forums



Ardentmill.
SYJourney - JourneyDEV v83 - RaGEZONE Forums


Harvesting:
SYJourney - JourneyDEV v83 - RaGEZONE Forums


Inner Ability:
SYJourney - JourneyDEV v83 - RaGEZONE Forums


Journey Information:
Code:
Rates: Dynamic Exp / 1x Drop / 2x Meso
Exp Rate: Lv.1-29: 1x,  Lv.30-69: 2x,  Lv.70-119:  3x,  Lv.120-200:   4x
Version: v83+, the '+' stands for all the stuff from newer version
Donation Info: NoPay2Win.
Gameplay Info: Improved v83 gameplay: 
- No freely available sok
- 5 original jobs, no aran or cygnus
- Daily entrance limit to PQs
- Rides between towns, no spoiling of players
- Nostalgic gameplay with custom features to 'spice it up', but which don't get in the way of nostalgia

Github link:
 
Last edited:
Joined
Jan 11, 2013
Messages
589
Reaction score
82
Photo's of items with potential? Looks intriguing

PolarMS(v83) actually had a clever custom potential/item growth function that they publicly released. It can easily be ripped and cleaned up. Not saying this person did that though.
 
Elite Diviner
Joined
Mar 24, 2015
Messages
426
Reaction score
416
Added the code for a new custom upgrade system. (in client.inventory)
Players will be able to fuse scrolls into combined scrolls, but the curse chances will add up and the success rate decrease.
Like 2 10% scrolls -> double the effect with only one slot taken, but only 1% success rate.
Or 1 70% + 1 60% -> 42% success, 29% curse
The rate cannot go under 1%, and the curse chance not above 100%. (Curse chance is calculated as failrate * curserate, so 15% for 70% dark scrolls.)
 
Newbie Spellweaver
Joined
Oct 13, 2013
Messages
53
Reaction score
1
The achievements/records system is nice. Also I believe you left out a getRecordsManager in channel.java (channel is not posted to github). If you forgot to add that to the github :p.
 
Last edited:
Elite Diviner
Joined
Mar 24, 2015
Messages
426
Reaction score
416
The achievements/records system is nice. Also I believe you left out a getRecordsManager in channel.java (channel is not posted to github). If you forgot to add that to the github :p.
The channel's getRecordsManager() literally just returns the RecordsManager for it's world, so it's probably not very interesting. All the other record functions are in EventManager/EventInstanceManager
 
Experienced Elementalist
Joined
Jul 8, 2014
Messages
263
Reaction score
33
I may have been pretty blunt in another post towards you, but I give you a lot of respect, especially in regards to the honestly. I hosted the MoopleDev beta server for rev 121, so I have some intimate knowledge on Kevins source. You ever need a hand, don't hesitate to PM me!
 
Elite Diviner
Joined
Mar 24, 2015
Messages
426
Reaction score
416
I may have been pretty blunt in another post towards you, but I give you a lot of respect, especially in regards to the honestly. I hosted the MoopleDev beta server for rev 121, so I have some intimate knowledge on Kevins source. You ever need a hand, don't hesitate to PM me!
I don't remember you being blunt to me anywhere, I think we're fine. And thanks for your offer.
 
Legendary Battlemage
Joined
Jan 23, 2013
Messages
695
Reaction score
101
PolarMS(v83) actually had a clever custom potential/item growth function that they publicly released. It can easily be ripped and cleaned up. Not saying this person did that though.
Polaris*MS had a 'clever custom potential' function.

And no, it was absolute Ducking garbage. Whoever designed that poop idea was an idiot


Oh wait.
 
Elite Diviner
Joined
Mar 24, 2015
Messages
426
Reaction score
416
Some new updates!

Gachapon and simliar rewards are now stored in the database, simply because I don't want game data to be in the source. The RewardManager.java loads these and picks random items as a reward.
Heres my example of using it (in NPCConversationManager, code for MapleRewardManager on github):
Code:
public void processGachapon(int[] localRewards, boolean remote, int mapid) { //Modified gachapon to use RewardManager.java
        if (getClient().getPlayer().getInventory(MapleInventoryType.USE).isFull() || getClient().getPlayer().getInventory(MapleInventoryType.EQUIP).isFull() || getClient().getPlayer().getInventory(MapleInventoryType.ETC).isFull()) {
            sendOk("Please make some space in your inventory.");
        } else {
            
            if (Randomizer.nextBoolean() == true) { //Local rewards (in npc) or global
                int itemid = localRewards[Randomizer.nextInt(localRewards.length)];
                gainItem(itemid, (short) 1, false);
                if (!remote) {
                    gainItem(5220000, (short) -1);
                } else {
                    gainItem(5451000, (short) -1);
                }
                sendOk("You have obtained:#b\r\n\r\n#fUI/UIWindow.img/QuestIcon/4/0#\r\n#v" + itemid + "#  #z" + itemid + "#");
            } else {
                
                MapleRewardEntry rwe = MapleRewardManager.getInstance().chooseRandomItem(RewardEvent.GACHAPON, getClient().getWorld() == ServerConstants.SUPREME_WORLD);
                int qty = (rwe.max == 1)? 1 : (Randomizer.nextInt((rwe.max - rwe.min)*((rwe.id == 0)?10000:1)) + rwe.min*((rwe.id == 0)?10000:1));
                
                if (qty > 1) {
                    if (rwe.id > 0) {
                        gainItem(rwe.id, (short) qty, false);
                        sendOk("You have obtained:#b\r\n\r\n#fUI/UIWindow.img/QuestIcon/4/0#\r\n#v" + rwe.id + "#  "+qty+" #z" + rwe.id + "#");
                    } else {
                        gainMeso(qty);
                        sendOk("You have obtained #b" + qty + "#k mesos!");
                    }
                    return;
                }
                
                Item gachaItem = addRandomItem(rwe.id);
                if (gachaItem != null) {
                    if (!remote) {
                        gainItem(5220000, (short) -1);
                    } else {
                        gainItem(5451000, (short) -1);
                    }
                    sendOk("You have obtained:#b\r\n\r\n#fUI/UIWindow.img/QuestIcon/4/0#\r\n#v" + rwe.id + "#  #z" + rwe.id + "#");
                    if (rwe.rarity > 2)
                        getClient().getChannelServer().broadcastPacket(MaplePacketCreator.gachaponMessage(gachaItem, c.getChannelServer().getMapFactory().getMap(mapid).getMapName(), getPlayer()));
                } else {
                    sendOk("Please make some space in your inventory.");
                }
            }
        }
    } //End of modifications

I also plan to make a profession system like in new maplestory, this will also be used together with the custom scroll system. I want to import the Ardentmill map and npcs for it too. Code and some ss will be coming when I get time to finsih.
 
Last edited:
Elite Diviner
Joined
Mar 24, 2015
Messages
426
Reaction score
416
Decided to upload some more ss.

Potentialing stuff: (Stats showing up in the normal stats is temporary until I learn client edits)
Equip w/o potential.
SYJourney - JourneyDEV v83 - RaGEZONE Forums


Magnifying Glass.
SYJourney - JourneyDEV v83 - RaGEZONE Forums


Item has to be cubed before using mag.
SYJourney - JourneyDEV v83 - RaGEZONE Forums


No potential yet.
SYJourney - JourneyDEV v83 - RaGEZONE Forums


Got +2 avoid! ...
SYJourney - JourneyDEV v83 - RaGEZONE Forums

If anyone wonders how the system works:
Item potential only gives +stats, with a max of 10 for the highest tier. All items start at 1 line, rare and can get up to 3 lines, godly tier. Weapons can also get %Bossing Damage up to 5. Overall an item can only get stats as potential that it already has. Everything else would be too overpowered for v83.

Cost of miracle cubes compared to other end-game items:
Maple Coin Shop.
SYJourney - JourneyDEV v83 - RaGEZONE Forums


Supreme World:
Chaos Channel (2):
SYJourney - JourneyDEV v83 - RaGEZONE Forums

The supreme world is a super-custom second world with higher exprate and generally my playground for crazy ideas. The idea of the supreme world is that players can try out different classes and also earn points for their achievements here. Those can be traded for goods in the normal world.
The chaos channel is my version of hell channels, basically, mobs are replaced with random mobs of 25 levels higher per channel. Which mobs spawn where resets with server restarts.

Code for chaos channels:
MapleMapFactory.java.
Code:
if (helllevel > 0 && type.equals("m")) {
                        try {
                            if (idcache.containsKey(Integer.valueOf(id))) {
                                id = String.valueOf(idcache.get(Integer.valueOf(id)));
                            } else {
                                int oldLv = MapleLifeFactory.getMonster(Integer.valueOf(id)).getStats().getLevel();
                                oldLv += helllevel;
                                int newid = MapleLifeFactory.getClosestLevelId(oldLv);
                                //id = String.valueOf(newid); fail
                                idcache.put(Integer.valueOf(id), newid);
                                id = String.valueOf(newid);
                            }
                        } catch (NullPointerException npe) {
                            System.out.println("Error for: "+mapid);
                        }
                    }

MapleLifeFactory.java
Code:
public static void loadAllMobLevels() {
        for (MapleData mobs : mobStringData.getChildren()) {
            int id;
            
            try {
                id = Integer.valueOf(mobs.getName());
            } catch (NumberFormatException nfe) {
                System.out.println("Loading error: "+nfe);
                return;
            }
            
            MapleData monsterData = data.getData(StringUtil.getLeftPaddedStr(Integer.toString(id) + ".img", '0', 11));
            if (monsterData == null)
                continue;
            
            MapleData monsterInfo = monsterData.getChildByPath("info");
            
            int level;
            try {
                level = MapleDataTool.getIntConvert("level", monsterInfo);
            } catch (Exception e) {
                System.out.println("Error loading: "+id);
                continue;
            }
            
            if (moblevels.containsKey(level)) {
                List<Integer> moblist = moblevels.get(level);
                moblist.add(id);
                moblevels.put(level, moblist);
            } else {
                List<Integer> moblist = new LinkedList<>();
                moblist.add(id);
                moblevels.put(level, moblist);
            }
        }
    }
    
    public static int getClosestLevelId(int level) {
        boolean contains = false;
        
        do {
            if (moblevels.containsKey(level))
                contains = true;
            else
                level --;
        } while (!contains);
        
        List<Integer> moblist = moblevels.get(level);
        return moblist.get(Randomizer.nextInt(moblist.size()));
    }

Edit:
I think I need some more checks for chaos channels or it will produce funny results o.0:
SYJourney - JourneyDEV v83 - RaGEZONE Forums

I have become one with the pianus.
LhRUHOa - JourneyDEV v83 - RaGEZONE Forums
 

Attachments

You must be registered for see attachments list
Last edited:
Elite Diviner
Joined
Mar 24, 2015
Messages
426
Reaction score
416
Small update!

Added Ardentmill:
SYJourney - JourneyDEV v83 - RaGEZONE Forums


Made a mistake in getting the string :D
SYJourney - JourneyDEV v83 - RaGEZONE Forums


Cole accepts me as his apprentice:
0JWUBJs - JourneyDEV v83 - RaGEZONE Forums

Profession system has yet to be finished, but atleast I have the painful wz edits done.

Rambling about ardentmill:
In case anyone noticed that the streetName for Ardentmill is "Edelstein", I plan to add the whole area since I've always been a fan of it, also like the whole industrialisation vibe of the area. Ardentmill will then only be accessible through Edelstein, like it should be in a before big bang server.

Another small change: I never liked that damage reflect instant kills you. So I changed the formula to -20%hp per skillLevel (1~5):

AbstractDealDamageHandler.java
Code:
if (!attack.isFamiliarAttack()) {
      byte reflect = monster.getReflectLevel();
                        
      if (reflect > 0) {
           if ((!magic && monster.hasWatkReflect()) || (magic && monster.hasMagicReflect()))
                player.decreaseHpMp(MapleStat.HP, (player.getStat(MapleStat.MAXHP)/5)*reflect);
      }
}

One more small thing:
I fixed a bug with the achievement system, achievements where always supposed to be obtainable once per account. So I replaced the charid in load/save with the accountid.
 

Attachments

You must be registered for see attachments list
Last edited:
Legendary Battlemage
Joined
Jan 23, 2013
Messages
695
Reaction score
101
My suggestion here..be care fully with achievements. Keep in mind you're making it 1 per account, so don't make anything that would be an impossibility to do otherwise. Also make sure the rewards are worth it
 
Elite Diviner
Joined
Mar 24, 2015
Messages
426
Reaction score
416
The rewards I currently have can only be obtained by trading them for achievement trophies. I think thats a good place to start with. I've also made sure to explain both in the item description for a trophy and in the admin npc, that trophies can only be obtained once and should only be spend if you sure that you really want an item.

Some rewards:
SYJourney - JourneyDEV v83 - RaGEZONE Forums


Rambling about the Items:
- Premium Gold Key: only way to get a reward from the premium gold chest (super rare gachapon item)
- High five stamp: makes you able to equip stuff 5 levels below the requirement
- Sok: will not obtainable in any other way, so that people have to buy services which is more fun
- Lillins Ring: only ring with watk and all stats in v83
- VIP tele rock: permanent, also only obtainable here
- The cutoff section is nx/chairs/mount covers
 
Last edited:
Elite Diviner
Joined
Mar 24, 2015
Messages
426
Reaction score
416
I still didn't have the time to tackle crafting and stuff, but harvesting is sort of done: (Some stuff is a temporary solution)
My shovel. All items are available as a steel and a gold version (gold has higher drop chances).
SYJourney - JourneyDEV v83 - RaGEZONE Forums


We need to buy a ticket for the herb patch.
SYJourney - JourneyDEV v83 - RaGEZONE Forums


Saffron's Herb patch. Which kind of herbs spawn is randomized when entering. You have 20 mins to harvest. (Entry is once a day)
SYJourney - JourneyDEV v83 - RaGEZONE Forums


Using the shovel on ground or a normal reactor object doesnt work. You can use the shovel from the inventory, or set it to a key (I have it on DEL)
SYJourney - JourneyDEV v83 - RaGEZONE Forums


Harvested something: Quite good drops too. And seems like we can level up our profession.
SYJourney - JourneyDEV v83 - RaGEZONE Forums

I was wondering If I should've made a video for this one, because of sounds/animations etc. Incase you're wondering about sort of what happened here, let me explain: The shovel/pickaxe are USE items so you can use them from the inventory or at a key. You have to use one, while being in range of a reactor (still not perfect, as you can probably tell from the ss, I want the player to stand either right or left of the reactor, but not on top of it...).
Then with a certain chance (Rand.nextInt(5) <= curLevel - reqLevel) the reactor will either just play its shake animation or break and drop stuff. So there's no failing without drops like in gms. Harvesting a higher level reactor just doesnt work as Rand.nextInt() can of course not go below zero.
You will get a certain amount of exp after successfully harvesting. After you reach the exp threshold, you have to level up your profession.

Edit:
I decided that I won't be uploading the code for the profession system. Not because I'm a selfish idiot, but because If I ever make this a server, I'd want some unique features to distinguish from other servers too. And seeing how many servers are created every month, this feature might just end up in another server tomorrow.
At any rate, this wasn't very difficult to code, the most time consuming thing by far were the wz edits.

Edit2:
Is there anyway to figure out which direction the player is facing? I'm kinda struggling with a solution to the position from which to allow harvesting. Nvm, I think I can just use the position updates from packets...

Edit3:
Fixed harvesting range completely. You now have to face the reactor and stand a little in front of it to harvest. I also added a new object to store players last actions (Harvesting, NPC talk...) so that I can disconnect people who put something on their keys to harvest :D.

LastActionManager.java
Code:
/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */

package client;

import java.util.EnumMap;

/**
 * JourneyMS
 * 
 */
public class LastActionManager {
    
    private final EnumMap<MapleAction, Long> lastActionHolder;
    private short observedAction; 
    
    public enum MapleAction {
        NPCTALK(500), HARVEST(1000);
        private final int actionLimit;
        
        MapleAction(int actionLimit) {
            this.actionLimit = actionLimit;
        }
        
        public int getActionLimit() {
            return actionLimit;
        }
    }
    
    public enum ActionResult {
        ALLOW, DISALLOW, DISCONNECT;
    }
    
    public LastActionManager() {
        lastActionHolder = new EnumMap<>(MapleAction.class);
        observedAction = 0;
    }
    
    public ActionResult tryAction(MapleAction ma) {
        if (lastActionHolder.containsKey(ma)) {
            if (System.currentTimeMillis() - lastActionHolder.get(ma) < 200) {
                observedAction ++;
                if (observedAction > 1000)
                    return ActionResult.DISCONNECT;
            } else {
                observedAction = (short) (observedAction/2);
            }
            
            if (System.currentTimeMillis() > lastActionHolder.get(ma) + ma.getActionLimit())
                return ActionResult.ALLOW;
            else
                return ActionResult.DISALLOW;
        } else {
            return ActionResult.ALLOW;
        }
    }
    
    public void setLastAction(MapleAction ma) {
        lastActionHolder.put(ma, System.currentTimeMillis());
    }
}

You'd think 200ms isn't alot but actually, you cannot reach that much without holding the key down.

MapleCharacter.java
Code:
public boolean isAllowed(MapleAction ma) {
        switch (actionmanager.tryAction(ma)) {
            case ALLOW: 
                return true;
            case DISALLOW: 
                return false;
            case DISCONNECT: 
                AutobanFactory.BOTTING.disconnect(this, String.valueOf(ma) + " botting");
            default: 
                return true;
        }
    }

No actually ban here, just logging it.
 
Last edited:
Experienced Elementalist
Joined
Jul 8, 2014
Messages
263
Reaction score
33
I've been keeping up with your GitHub, used some code. I do have to ask, where did you get those BossPQ Maps!?
 
Elite Diviner
Joined
Mar 24, 2015
Messages
426
Reaction score
416
I've been keeping up with your GitHub, used some code. I do have to ask, where did you get those BossPQ Maps!?
Easy Mode is just Haunted House
Normal and Hard are...not done yet. (not even started)
Hell Mode is the "Black Mage's Temple" from new Maplestory. It's part of the adventurer's questline there.
The Lobby is from some event I think.

Edit: Might aswell just use this post for an update instead of double-posting.
I finall updated the github (it got a bit deserted, last update was almost 2 weeks ago...)
I also uploaded some code for the profession system (harvesting), in UseItemHandler.java.
Newest change has been made to the saveToDB() function in MapleCharacter.java. I added some checks to prevent unneccessary queries (like the telerocklocations, skillmacros etc..).
I have no idea if it was worth the effort, but hopefully it improved something.
If I find some more information on SQL stuff and find out that this does infact make sense, I might extend this system to make a more "intelligent" saving than just saving everything after changing channels.
 
Last edited:
Experienced Elementalist
Joined
Nov 21, 2008
Messages
297
Reaction score
38
Easy Mode is just Haunted House
Normal and Hard are...not done yet. (not even started)
Hell Mode is the "Black Mage's Temple" from new Maplestory. It's part of the adventurer's questline there.
The Lobby is from some event I think.

Just met you ingame, thanks for telling me about this thread! JourneyDEV looks like it has some promise to it. Keep up the good work. I really like those WZ edits btw.
 
Back
Top