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!

[Release] Clone system

Status
Not open for further replies.
Mythic Archon
Loyal Member
Joined
May 11, 2008
Messages
722
Reaction score
50
Code:
  public void setID(int id) {
        this.id = id;
    }
:)
Ya really xBlackCat
 
Junior Spellweaver
Joined
Aug 9, 2008
Messages
111
Reaction score
0
add import static net.sf.odinms.client.messages.CommandProcessor.getOptionalIntArg; to command file
 
Newbie Spellweaver
Joined
Oct 3, 2008
Messages
77
Reaction score
1
ok i fixed the closrange thingy forgot the import silly me.. but i got those problems when i go to compile with my fakecharcter.. everything else works but the fakecharcter... so if anybody could be help be greatful thanks :D


Code:
init:
deps-jar:
Compiling 5 source files to C:\Documents and Settings\Patrick\Desktop\OdinMS\build\classes
C:\Documents and Settings\Patrick\Desktop\fmsource\trunk\src\net\sf\odinms\server\maps\FakeCharacter.java:16: MapleCharacter() has private access in net.sf.odinms.client.MapleCharacter
        MapleCharacter fakechr = new MapleCharacter();
C:\Documents and Settings\Patrick\Desktop\fmsource\trunk\src\net\sf\odinms\server\maps\FakeCharacter.java:21: cannot find symbol
symbol  : method setID(int)
location: class net.sf.odinms.client.MapleCharacter
        fakechr.setID(id + 100000);
C:\Documents and Settings\Patrick\Desktop\fmsource\trunk\src\net\sf\odinms\server\maps\FakeCharacter.java:23: cannot find symbol
symbol  : method setJob(int)
location: class net.sf.odinms.client.MapleCharacter
        fakechr.setJob(player.getJob().getId());
3 errors
BUILD FAILED (total time: 4 seconds)
 
Newbie Spellweaver
Joined
Aug 26, 2008
Messages
28
Reaction score
0
Add

Code:
public void setID(int id){
     this.id = id;
    }
    
    public void setJob(int job){
        this.job = MapleJob.getById(job);
    }
    
    public void setInventory(MapleInventoryType type, MapleInventory inv) {
        inventory[type.ordinal()] = inv;
    }

In MapleCharacter.java

That should fix 2 errors, I am getting the first error too.
 
Last edited:
Newbie Spellweaver
Joined
Apr 23, 2008
Messages
11
Reaction score
0
Code:
          public boolean hasFakeChar()
    {
        for (FakeCharacter ch : fakes) {
            if(ch != null)
                return true;
        }
        return false;
    }

"fakes" is an incompatible type.
 
Newbie Spellweaver
Joined
Aug 26, 2008
Messages
28
Reaction score
0
I fixed everything but

Code:
C:\Users\Johann\Desktop\Repack\Repack\src\net\sf\odinms\server\maps\FakeCharacter.java:19: MapleCharacter() has private access in net.sf.odinms.client.MapleCharacter
        MapleCharacter fakechr = new MapleCharacter();
 
Newbie Spellweaver
Joined
Apr 23, 2008
Messages
11
Reaction score
0
I fixed everything but

Code:
C:\Users\Johann\Desktop\Repack\Repack\src\net\sf\odinms\server\maps\FakeCharacter.java:19: MapleCharacter() has private access in net.sf.odinms.client.MapleCharacter
        MapleCharacter fakechr = new MapleCharacter();

All I did was this to fix it:
change:
Code:
    private MapleCharacter() {
        setStance(0);
        // pet = new MaplePet(5000005, (byte) 10);
        // pet.setName("Hase");
        inventory = new MapleInventory[MapleInventoryType.values().length];
        for (MapleInventoryType type : MapleInventoryType.values()) {
            inventory[type.ordinal()] = new MapleInventory(type, (byte) 100);
        }

        savedLocations = new int[SavedLocationType.values().length];
        for (int i = 0; i < SavedLocationType.values().length; i++) {
            savedLocations[i] = -1;
        }

        quests = new LinkedHashMap<MapleQuest, MapleQuestStatus>();
        anticheat = new CheatTracker(this);
        setPosition(new Point(0, 0));
    }

to:
Code:
    public MapleCharacter() {
        setStance(0);
        // pet = new MaplePet(5000005, (byte) 10);
        // pet.setName("Hase");
        inventory = new MapleInventory[MapleInventoryType.values().length];
        for (MapleInventoryType type : MapleInventoryType.values()) {
            inventory[type.ordinal()] = new MapleInventory(type, (byte) 100);
        }

        savedLocations = new int[SavedLocationType.values().length];
        for (int i = 0; i < SavedLocationType.values().length; i++) {
            savedLocations[i] = -1;
        }

        quests = new LinkedHashMap<MapleQuest, MapleQuestStatus>();
        anticheat = new CheatTracker(this);
        setPosition(new Point(0, 0));
    }

(I'm not sure if this will make the code stable or not)

Btw, how did you fix the "fakes" thing? Can you help me by seeing the code above or do I need to post more information?
 
Newbie Spellweaver
Joined
Apr 4, 2008
Messages
96
Reaction score
0
anyone help me?=)

Quote:
C:\Documents and Settings\T ' ce\My Documents\RenzMs Pack\Ems Repack\Ems Repack\src\net\sf\odinms\net\channel\handler\Close RangeDamageHandler.java:148: cannot find symbol
symbol : variable speed
location: class net.sf.odinms.net.channel.handler.AbstractDealDama geHandler.AttackInfo
attack.numAttackedAndDamage, attack.allDamage, attack.speed);
C:\Documents and Settings\T ' ce\My Documents\RenzMs Pack\Ems Repack\Ems Repack\src\net\sf\odinms\net\channel\handler\MoveP layerHandler.java:73: cannot find symbol
symbol : class ScheduledFuture
location: class net.sf.odinms.net.channel.handler.MovePlayerHandle r
ScheduledFuture<?> scheduleRemove = TimerManager.getInstance().schedule(new Runnable() {
C:\Documents and Settings\T ' ce\My Documents\RenzMs Pack\Ems Repack\Ems Repack\src\net\sf\odinms\server\maps\FakeCharacter .java:16: MapleCharacter() has private access in net.sf.odinms.client.MapleCharacter
MapleCharacter fakechr = new MapleCharacter();
C:\Documents and Settings\T ' ce\My Documents\RenzMs Pack\Ems Repack\Ems Repack\src\net\sf\odinms\server\maps\FakeCharacter .java:21: cannot find symbol
symbol : method setID(int)
location: class net.sf.odinms.client.MapleCharacter
fakechr.setID(id + 100000);
C:\Documents and Settings\T ' ce\My Documents\RenzMs Pack\Ems Repack\Ems Repack\src\net\sf\odinms\server\maps\FakeCharacter .java:23: cannot find symbol
symbol : method setJob(int)
location: class net.sf.odinms.client.MapleCharacter
fakechr.setJob(player.getJob().getId());
C:\Documents and Settings\T ' ce\My Documents\RenzMs Pack\Ems Repack\Ems Repack\src\net\sf\odinms\server\maps\FakeCharacter .java:26: cannot find symbol
symbol : method getAllBuffs()
location: class net.sf.odinms.client.MapleCharacter
fakechr.silentGiveBuffs(player.getAllBuffs());
6 errors
BUILD FAILED (total time: 1 second)
 
Newbie Spellweaver
Joined
May 12, 2008
Messages
13
Reaction score
0
Thanks dude.

wtf man all your posts has ''thanks dude''

Omg duck off and stop spamming.

@Author : So this script basically lets you make a clone of your character standing there?

Or does it move around and talk? I think i saw a thread about a ''sexbot'' :blink:
 
You've got my respect!
Joined
Apr 8, 2008
Messages
508
Reaction score
147
wtf man all your posts has ''thanks dude''

Omg duck off and stop spamming.

@Author : So this script basically lets you make a clone of your character standing there?

Or does it move around and talk? I think i saw a thread about a ''sexbot'' :blink:
It's basically a clone of yourself.
If you attack, the clone attacks. If you move, the clone moves.
 
The almighty chicken
Loyal Member
Joined
Apr 7, 2008
Messages
570
Reaction score
31
if you spawn clones in a map with monsters, you will get extremely bugged
(or i modded this too much and it's my own fault.. dunno?)
 
Experienced Elementalist
Joined
May 19, 2008
Messages
281
Reaction score
0
traitor, does your damage count for the clone?
 
Newbie Spellweaver
Joined
Apr 23, 2008
Messages
11
Reaction score
0
Did you add this:
Code:
private List<FakeCharacter> fakes = new ArrayList<FakeCharacter>();
Try re-doing the guide

I just did that and it did fixed the "fakes" error, but now it causes 5 other errors, all of them are saying that "getFakeChars" is an incompatible type.
 
Junior Spellweaver
Joined
Oct 15, 2008
Messages
188
Reaction score
0
I just did that and it did fixed the "fakes" error, but now it causes 5 other errors, all of them are saying that "getFakeChars" is an incompatible type.
Your parameters are set wrong. Adjust the one where the error shows. Post it here.
 
Newbie Spellweaver
Joined
Apr 23, 2008
Messages
11
Reaction score
0
MapleCharacter:
Code:
/*
This file is part of the OdinMS Maple Story Server
Copyright (C) 2008 Patrick Huy <patrick.huy@frz.cc> 
Matthias Butz <matze@odinms.de>
Jan Christian Meyer <vimes@odinms.de>

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License version 3
as published by the Free Software Foundation. You may not use, modify
or distribute this program under any other version of the
GNU Affero General Public License.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Affero General Public License for more details.

You should have received a copy of the GNU Affero General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package net.sf.odinms.client;

import java.awt.Point;
import java.lang.ref.WeakReference;
import java.rmi.RemoteException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.atomic.AtomicInteger;
import java.text.NumberFormat;
import java.text.DecimalFormat;

import java.util.HashSet;
import net.sf.odinms.client.anticheat.CheatTracker;
import net.sf.odinms.database.DatabaseConnection;
import net.sf.odinms.database.DatabaseException;
import net.sf.odinms.server.maps.FakeCharacter;
import net.sf.odinms.net.MaplePacket;
import net.sf.odinms.net.PacketProcessor;
import net.sf.odinms.net.channel.ChannelServer;
import net.sf.odinms.net.channel.handler.SpawnPetHandler;
import net.sf.odinms.net.world.MapleMessenger;
import net.sf.odinms.net.world.MapleMessengerCharacter;
import net.sf.odinms.net.world.MapleParty;
import net.sf.odinms.net.world.MaplePartyCharacter;
import net.sf.odinms.net.world.PartyOperation;
import net.sf.odinms.net.world.PlayerBuffValueHolder;
import net.sf.odinms.net.world.PlayerCoolDownValueHolder;
import net.sf.odinms.net.world.remote.WorldChannelInterface;
import net.sf.odinms.scripting.event.EventInstanceManager;
import net.sf.odinms.server.MapleItemInformationProvider;
import net.sf.odinms.server.MaplePlayerShop;
import net.sf.odinms.server.MaplePortal;
import net.sf.odinms.server.MapleShop;
import net.sf.odinms.server.MapleStatEffect;
import net.sf.odinms.server.MapleStorage;
import net.sf.odinms.server.MapleTrade;
import net.sf.odinms.server.TimerManager;
import net.sf.odinms.server.life.MapleMonster;
import net.sf.odinms.server.maps.AbstractAnimatedMapleMapObject;
import net.sf.odinms.server.maps.MapleDoor;
import net.sf.odinms.server.maps.MapleMap;
import net.sf.odinms.server.maps.MapleMapFactory;
import net.sf.odinms.server.maps.MapleMapObject;
import net.sf.odinms.server.maps.MapleMapObjectType;
import net.sf.odinms.server.maps.MapleSummon;
import net.sf.odinms.server.maps.SavedLocationType;
import net.sf.odinms.server.quest.MapleCustomQuest;
import net.sf.odinms.server.quest.MapleQuest;
import net.sf.odinms.tools.MaplePacketCreator;
import net.sf.odinms.tools.Pair;
import net.sf.odinms.net.world.guild.*;

import net.sf.odinms.server.life.MobSkill;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class MapleCharacter extends AbstractAnimatedMapleMapObject implements InventoryContainer {

    private static Logger log = LoggerFactory.getLogger(PacketProcessor.class);
    public static final double MAX_VIEW_RANGE_SQ = 850 * 850;
    private int world;
    private int accountid;
    private int rank;
    private int rankMove;
    private int jobRank;
    private int jobRankMove;
    private String name;
    private int level;
        //pvp
        private int pvpkills;
        private int pvpdeaths;

    private int str,  dex,  luk,  int_;
    private AtomicInteger exp = new AtomicInteger();
    private int hp,  maxhp;
    private int mp,  maxmp;
    private int mpApUsed,  hpApUsed;
    private int hair,  face;
    private AtomicInteger meso = new AtomicInteger();
    private int remainingAp,  remainingSp;
    private int savedLocations[];
    private int fame;
    private long lastfametime;
    private List<Integer> lastmonthfameids;    // local stats represent current stats of the player to avoid expensive operations
    private transient int localmaxhp,  localmaxmp;
    private transient int localstr,  localdex,  localluk,  localint_;
    private transient int magic,  watk;
private transient int wdef, mdef;
    private transient double speedMod,  jumpMod;
    private transient int localmaxbasedamage;
    private int id;
    private MapleClient client;
    private MapleMap map;
    private int initialSpawnPoint;
    // mapid is only used when calling getMapId() with map == null, it is not updated when running in channelserver mode
    private int mapid;
    private MapleShop shop = null;
    private MaplePlayerShop playerShop = null;
    private MapleStorage storage = null;
    private MaplePet[] pets = new MaplePet[3];
    private SkillMacro[] skillMacros = new SkillMacro[5];
    private MapleTrade trade = null;
    private MapleSkinColor skinColor = MapleSkinColor.NORMAL;
    private MapleJob job = MapleJob.BEGINNER;
    private int gender;
    private int gmLevel;
    private boolean hidden;
    private boolean canDoor = true;
    private int chair;
    private int itemEffect;
    private MapleParty party;
    private EventInstanceManager eventInstance = null;
    private MapleInventory[] inventory;
    private Map<MapleQuest, MapleQuestStatus> quests;
    private Set<MapleMonster> controlled = new LinkedHashSet<MapleMonster>();
    private Set<MapleMapObject> visibleMapObjects = new LinkedHashSet<MapleMapObject>();
    private Map<ISkill, SkillEntry> skills = new LinkedHashMap<ISkill, SkillEntry>();
    private Map<MapleBuffStat, MapleBuffStatValueHolder> effects = new LinkedHashMap<MapleBuffStat, MapleBuffStatValueHolder>();
    private Map<Integer, MapleKeyBinding> keymap = new LinkedHashMap<Integer, MapleKeyBinding>();
    private List<MapleDoor> doors = new ArrayList<MapleDoor>();
    private Map<Integer, MapleSummon> summons = new LinkedHashMap<Integer, MapleSummon>();
    private BuddyList buddylist;
    private Map<Integer, MapleCoolDownValueHolder> coolDowns = new LinkedHashMap<Integer, MapleCoolDownValueHolder>();    // anticheat related information
    private CheatTracker anticheat;
    private ScheduledFuture<?> dragonBloodSchedule;    //guild related information
	private ScheduledFuture<?> mapTimeLimitTask = null;
    private int guildid;
    private int guildrank;
    private MapleGuildCharacter mgc = null;    // cash shop related information
    private int nxcash;
    private int maplepoints;
    private int gifttokens;
    private boolean incs;
        private double sword;
        private double blunt;
        private double axe;
        private double spear;
        private double polearm;
        private double claw;
        private double dagger;
        private double staffwand = 0.1;
        private double crossbow;
        private double bow;
        private int skill = 0;
        private ISkill skil;
        private int maxDis;
        
        private int pvpDeaths = 1;
        private int pvpKills = 0;

    private MapleMessenger messenger = null;
    int messengerposition = 4;
    private ScheduledFuture<?>[] fullnessSchedule = new ScheduledFuture<?>[3];
    private ScheduledFuture<?> hpDecreaseTask;
    private List<MapleDisease> diseases = new ArrayList<MapleDisease>();

private List<FakeCharacter> fakes = new ArrayList<FakeCharacter>();
    public boolean isfake = false;

public void setID(int id){
     this.id = id;
    }
    
    public void setJob(int job){
        this.job = MapleJob.getById(job);
    }
    
    public void setInventory(MapleInventoryType type, MapleInventory inv) {
        inventory[type.ordinal()] = inv;
    }

    public boolean hasFakeChar()
    {
        for (FakeCharacter ch : fakes) {
            if(ch != null)
                return true;
        }
        return false;
    }
    
    public List getFakeChars()
    {
        return fakes;
    }
    
    public void addFakeChar(FakeCharacter f)
    {
       fakes.add(f);
    }



    public MapleCharacter() {
        setStance(0);
        // pet = new MaplePet(5000005, (byte) 10);
        // pet.setName("Hase");
        inventory = new MapleInventory[MapleInventoryType.values().length];
        for (MapleInventoryType type : MapleInventoryType.values()) {
            inventory[type.ordinal()] = new MapleInventory(type, (byte) 100);
        }

        savedLocations = new int[SavedLocationType.values().length];
        for (int i = 0; i < SavedLocationType.values().length; i++) {
            savedLocations[i] = -1;
        }

        quests = new LinkedHashMap<MapleQuest, MapleQuestStatus>();
        anticheat = new CheatTracker(this);
        setPosition(new Point(0, 0));
    }

    public MapleCharacter getThis() {
        return this;
    }

    public static MapleCharacter loadCharFromDB(int charid, MapleClient client, boolean channelserver)
            throws SQLException {
        MapleCharacter ret = new MapleCharacter();
        ret.client = client;
        ret.id = charid;

        Connection con = DatabaseConnection.getConnection();
        PreparedStatement ps = con.prepareStatement("SELECT * FROM characters WHERE id = ?");
        ps.setInt(1, charid);
        ResultSet rs = ps.executeQuery();
        if (!rs.next()) {
            throw new RuntimeException("Loading the Char Failed (char not found)");
        }
        ret.name = rs.getString("name");
        ret.level = rs.getInt("level");
                //pvp
                ret.pvpdeaths = rs.getInt("pvpdeaths");
                ret.pvpkills = rs.getInt("pvpkills");

        ret.fame = rs.getInt("fame");
        ret.str = rs.getInt("str");
        ret.dex = rs.getInt("dex");
        ret.int_ = rs.getInt("int");
        ret.luk = rs.getInt("luk");
        ret.exp.set(rs.getInt("exp"));

        ret.hp = rs.getInt("hp");
        ret.maxhp = rs.getInt("maxhp");
        ret.mp = rs.getInt("mp");
        ret.maxmp = rs.getInt("maxmp");

        ret.hpApUsed = rs.getInt("hpApUsed");
        ret.mpApUsed = rs.getInt("mpApUsed");
        ret.remainingSp = rs.getInt("sp");
        ret.remainingAp = rs.getInt("ap");

        ret.meso.set(rs.getInt("meso"));

        ret.gmLevel = rs.getInt("gm") == 0 ? 0 : 1000;

        ret.skinColor = MapleSkinColor.getById(rs.getInt("skincolor"));
        ret.gender = rs.getInt("gender");
        ret.job = MapleJob.getById(rs.getInt("job"));

        ret.hair = rs.getInt("hair");
        ret.face = rs.getInt("face");

        ret.accountid = rs.getInt("accountid");

        ret.mapid = rs.getInt("map");
        ret.initialSpawnPoint = rs.getInt("spawnpoint");
        ret.world = rs.getInt("world");

        ret.rank = rs.getInt("rank");
        ret.rankMove = rs.getInt("rankMove");
        ret.jobRank = rs.getInt("jobRank");
        ret.jobRankMove = rs.getInt("jobRankMove");


        ret.guildid = rs.getInt("guildid");
        ret.guildrank = rs.getInt("guildrank");
        if (ret.guildid > 0) {
            ret.mgc = new MapleGuildCharacter(ret);
        }
        int buddyCapacity = rs.getInt("buddyCapacity");
        ret.buddylist = new BuddyList(buddyCapacity);
        if (channelserver) {
            MapleMapFactory mapFactory = ChannelServer.getInstance(client.getChannel()).getMapFactory();
            ret.map = mapFactory.getMap(ret.mapid);
            if (ret.map == null) { //char is on a map that doesn't exist warp it to henesys
                ret.map = mapFactory.getMap(100000000);
            }
            MaplePortal portal = ret.map.getPortal(ret.initialSpawnPoint);
            if (portal == null) {
                portal = ret.map.getPortal(0); // char is on a spawnpoint that doesn't exist - select the first spawnpoint instead
                ret.initialSpawnPoint = 0;
            }
            ret.setPosition(portal.getPosition());

            int partyid = rs.getInt("party");
            if (partyid >= 0) {
                try {
                    MapleParty party = client.getChannelServer().getWorldInterface().getParty(partyid);
                    if (party != null && party.getMemberById(ret.id) != null) {
                        ret.party = party;
                    }
                } catch (RemoteException e) {
                    client.getChannelServer().reconnectWorld();
                }
            }

            int messengerid = rs.getInt("messengerid");
            int position = rs.getInt("messengerposition");
            if (messengerid > 0 && position < 4 && position > -1) {
                try {
                    WorldChannelInterface wci = ChannelServer.getInstance(client.getChannel()).getWorldInterface();
                    MapleMessenger messenger = wci.getMessenger(messengerid);
                    if (messenger != null) {
                        ret.messenger = messenger;
                        ret.messengerposition = position;
                    }
                } catch (RemoteException e) {
                    client.getChannelServer().reconnectWorld();
                }
            }
        }

        rs.close();
        ps.close();

        ps = con.prepareStatement("SELECT * FROM accounts WHERE id = ?");
        ps.setInt(1, ret.accountid);
        rs = ps.executeQuery();
        while (rs.next()) {
            ret.getClient().setAccountName(rs.getString("name"));
            ret.nxcash = rs.getInt("nxCash");
            ret.maplepoints = rs.getInt("mPoints");
            ret.gifttokens = rs.getInt("gTokens");
        }
        rs.close();
        ps.close();

        String sql = "SELECT * FROM inventoryitems " + "LEFT JOIN inventoryequipment USING (inventoryitemid) " + "WHERE characterid = ?";
        if (!channelserver) {
            sql += " AND inventorytype = " + MapleInventoryType.EQUIPPED.getType();
        }
        ps = con.prepareStatement(sql);
        ps.setInt(1, charid);
        // PreparedStatement itemLog = con.prepareStatement("SELECT msg FROM inventorylog WHERE inventoryitemid = ?");
        rs = ps.executeQuery();
        while (rs.next()) {
            MapleInventoryType type = MapleInventoryType.getByType((byte) rs.getInt("inventorytype"));
            // itemLog.setInt(1, rs.getInt("inventoryitemid"));
            // ResultSet rsItemLog = itemLog.executeQuery();
            // IItem logItem;
            if (type.equals(MapleInventoryType.EQUIP) || type.equals(MapleInventoryType.EQUIPPED)) {
                int itemid = rs.getInt("itemid");
                Equip equip = new Equip(itemid, (byte) rs.getInt("position"), rs.getInt("ringid"));
                equip.setOwner(rs.getString("owner"));
                equip.setQuantity((short) rs.getInt("quantity"));
                equip.setAcc((short) rs.getInt("acc"));
                equip.setAvoid((short) rs.getInt("avoid"));
                equip.setDex((short) rs.getInt("dex"));
                equip.setHands((short) rs.getInt("hands"));
                equip.setHp((short) rs.getInt("hp"));
                equip.setInt((short) rs.getInt("int"));
                equip.setJump((short) rs.getInt("jump"));
                equip.setLuk((short) rs.getInt("luk"));
                equip.setMatk((short) rs.getInt("matk"));
                equip.setMdef((short) rs.getInt("mdef"));
                equip.setMp((short) rs.getInt("mp"));
                equip.setSpeed((short) rs.getInt("speed"));
                equip.setStr((short) rs.getInt("str"));
                equip.setWatk((short) rs.getInt("watk"));
                equip.setWdef((short) rs.getInt("wdef"));
                equip.setUpgradeSlots((byte) rs.getInt("upgradeslots"));
                equip.setLevel((byte) rs.getInt("level"));
                ret.getInventory(type).addFromDB(equip);
            // logItem = equip;
            } else {
                Item item = new Item(rs.getInt("itemid"), (byte) rs.getInt("position"), (short) rs.getInt("quantity"), rs.getInt("petid"));
                item.setOwner(rs.getString("owner"));
                ret.getInventory(type).addFromDB(item);
            // logItem = item;
            }
        // while (rsItemLog.next()) {
        // logItem.log(rsItemLog.getString("msg"), true);
        // }
        // rsItemLog.close();
        }
        rs.close();
        ps.close();
        // itemLog.close();

        if (channelserver) {
            ps = con.prepareStatement("SELECT * FROM queststatus WHERE characterid = ?");
            ps.setInt(1, charid);
            rs = ps.executeQuery();
            PreparedStatement pse = con.prepareStatement("SELECT * FROM queststatusmobs WHERE queststatusid = ?");
            while (rs.next()) {
                MapleQuest q = MapleQuest.getInstance(rs.getInt("quest"));
                MapleQuestStatus status = new MapleQuestStatus(q, MapleQuestStatus.Status.getById(rs.getInt("status")));
                long cTime = rs.getLong("time");
                if (cTime > -1) {
                    status.setCompletionTime(cTime * 1000);
                }
                status.setForfeited(rs.getInt("forfeited"));
                ret.quests.put(q, status);
                pse.setInt(1, rs.getInt("queststatusid"));
                ResultSet rsMobs = pse.executeQuery();
                while (rsMobs.next()) {
                    status.setMobKills(rsMobs.getInt("mob"), rsMobs.getInt("count"));
                }
                rsMobs.close();
            }
            rs.close();
            ps.close();
            pse.close();

            ps = con.prepareStatement("SELECT skillid,skilllevel, masterlevel FROM skills WHERE characterid = ?");
            ps.setInt(1, charid);
            rs = ps.executeQuery();
            while (rs.next()) {
                ret.skills.put(SkillFactory.getSkill(rs.getInt("skillid")), new SkillEntry(rs.getInt("skilllevel"), rs.getInt("masterlevel")));
            }
            rs.close();
            ps.close();

            ps = con.prepareStatement("SELECT * FROM skillmacros WHERE characterid = ?");
            ps.setInt(1, charid);
            rs = ps.executeQuery();

            while (rs.next()) {
                int skill1 = rs.getInt("skill1");
                int skill2 = rs.getInt("skill2");
                int skill3 = rs.getInt("skill3");
                String name = rs.getString("name");
                int shout = rs.getInt("shout");
                int position = rs.getInt("position");
                SkillMacro macro = new SkillMacro(skill1, skill2, skill3, name, shout, position);
                ret.skillMacros[position] = macro;
            }
            rs.close();
            ps.close();

            ps = con.prepareStatement("SELECT `key`,`type`,`action` FROM keymap WHERE characterid = ?");
            ps.setInt(1, charid);
            rs = ps.executeQuery();
            while (rs.next()) {
                int key = rs.getInt("key");
                int type = rs.getInt("type");
                int action = rs.getInt("action");
                ret.keymap.put(Integer.valueOf(key), new MapleKeyBinding(type, action));
            }
            rs.close();
            ps.close();

            ps = con.prepareStatement("SELECT `locationtype`,`map` FROM savedlocations WHERE characterid = ?");
            ps.setInt(1, charid);
            rs = ps.executeQuery();
            while (rs.next()) {
                String locationType = rs.getString("locationtype");
                int mapid = rs.getInt("map");
                ret.savedLocations[SavedLocationType.valueOf(locationType).ordinal()] = mapid;
            }
            rs.close();
            ps.close();

            ps = con.prepareStatement("SELECT `characterid_to`,`when` FROM famelog WHERE characterid = ? AND DATEDIFF(NOW(),`when`) < 30");
            ps.setInt(1, charid);
            rs = ps.executeQuery();
            ret.lastfametime = 0;
            ret.lastmonthfameids = new ArrayList<Integer>(31);
            while (rs.next()) {
                ret.lastfametime = Math.max(ret.lastfametime, rs.getTimestamp("when").getTime());
                ret.lastmonthfameids.add(Integer.valueOf(rs.getInt("characterid_to")));
            }
            rs.close();
            ps.close();

            ret.buddylist.loadFromDb(charid);
            ret.storage = MapleStorage.loadOrCreateFromDB(ret.accountid);
        }

        // if (charid == 30000) {
        // ret.playerShop = new MaplePlayerShop(ret, "For the lulztest");
        // ret.playerShop.addItem(new MaplePlayerShopItem(ret.playerShop, new Item(4000000, (byte) 0, (short) 1),
        // (short) 80, 400));
        // }

        ret.recalcLocalStats();
        ret.silentEnforceMaxHpMp();
        return ret;
    }

    public static MapleCharacter getDefault(MapleClient client, int chrid) {
        MapleCharacter ret = getDefault(client);
        ret.id = chrid;
        return ret;
    }

    public static MapleCharacter getDefault(MapleClient client) {
        MapleCharacter ret = new MapleCharacter();
        ret.client = client;
        ret.hp = 500;
        ret.maxhp = 500;
        ret.mp = 500;
        ret.maxmp = 500;
        ret.map = null;
        // ret.map = ChannelServer.getInstance(client.getChannel()).getMapFactory().getMap(0);
        ret.exp.set(0);
        ret.gmLevel = 0;
        ret.job = MapleJob.BEGINNER;
        ret.meso.set(1000000);
        ret.level = 1;
                ret.pvpdeaths = 0;
                ret.pvpkills = 0;

        ret.accountid = client.getAccID();
        ret.buddylist = new BuddyList(25);
        ret.nxcash = 500000;
        ret.maplepoints = 500000;
        ret.gifttokens = 5000;
        ret.incs = false;

        ret.keymap.put(Integer.valueOf(18), new MapleKeyBinding(4, 0));
        ret.keymap.put(Integer.valueOf(65), new MapleKeyBinding(6, 106));
        ret.keymap.put(Integer.valueOf(2), new MapleKeyBinding(4, 10));
        ret.keymap.put(Integer.valueOf(23), new MapleKeyBinding(4, 1));
        ret.keymap.put(Integer.valueOf(3), new MapleKeyBinding(4, 12));
        ret.keymap.put(Integer.valueOf(4), new MapleKeyBinding(4, 13));
        ret.keymap.put(Integer.valueOf(5), new MapleKeyBinding(4, 18));
        ret.keymap.put(Integer.valueOf(6), new MapleKeyBinding(4, 21));
        ret.keymap.put(Integer.valueOf(16), new MapleKeyBinding(4, 8));
        ret.keymap.put(Integer.valueOf(17), new MapleKeyBinding(4, 5));
        ret.keymap.put(Integer.valueOf(19), new MapleKeyBinding(4, 4));
        ret.keymap.put(Integer.valueOf(25), new MapleKeyBinding(4, 19));
        ret.keymap.put(Integer.valueOf(26), new MapleKeyBinding(4, 14));
        ret.keymap.put(Integer.valueOf(27), new MapleKeyBinding(4, 15));
        ret.keymap.put(Integer.valueOf(29), new MapleKeyBinding(5, 52));
        ret.keymap.put(Integer.valueOf(31), new MapleKeyBinding(4, 2));
        ret.keymap.put(Integer.valueOf(34), new MapleKeyBinding(4, 17));
        ret.keymap.put(Integer.valueOf(35), new MapleKeyBinding(4, 11));
        ret.keymap.put(Integer.valueOf(37), new MapleKeyBinding(4, 3));
        ret.keymap.put(Integer.valueOf(38), new MapleKeyBinding(4, 20));
        ret.keymap.put(Integer.valueOf(40), new MapleKeyBinding(4, 16));
        ret.keymap.put(Integer.valueOf(43), new MapleKeyBinding(4, 9));
        ret.keymap.put(Integer.valueOf(44), new MapleKeyBinding(5, 50));
        ret.keymap.put(Integer.valueOf(45), new MapleKeyBinding(5, 51));
        ret.keymap.put(Integer.valueOf(46), new MapleKeyBinding(4, 6));
        ret.keymap.put(Integer.valueOf(50), new MapleKeyBinding(4, 7));
        ret.keymap.put(Integer.valueOf(56), new MapleKeyBinding(5, 53));
        ret.keymap.put(Integer.valueOf(59), new MapleKeyBinding(6, 100));
        ret.keymap.put(Integer.valueOf(60), new MapleKeyBinding(6, 101));
        ret.keymap.put(Integer.valueOf(61), new MapleKeyBinding(6, 102));
        ret.keymap.put(Integer.valueOf(62), new MapleKeyBinding(6, 103));
        ret.keymap.put(Integer.valueOf(63), new MapleKeyBinding(6, 104));
        ret.keymap.put(Integer.valueOf(64), new MapleKeyBinding(6, 105));

        ret.recalcLocalStats();

        return ret;
    }

    public void saveToDB(boolean update) {
        saveToDB(update, -1, false);
    }

    public void saveToDB(boolean update, int forcedReturnID) {
        saveToDB(update, forcedReturnID, true);
    }

    private void saveToDB(boolean update, int forcedReturnID, boolean forcedReturn) {
        Connection con = DatabaseConnection.getConnection();
        try {
            // clients should not be able to log back before their old state is saved (see MapleClient#getLoginState) so we are save to switch to a very low isolation level here
            con.setTransactionIsolation(Connection.TRANSACTION_READ_UNCOMMITTED);
            // connections are thread local now, no need to
            // synchronize anymore =)
            con.setAutoCommit(false);
            PreparedStatement ps;
			if (update) {
				ps = con.prepareStatement("UPDATE characters "
					+ "SET level = ?, fame = ?, str = ?, dex = ?, luk = ?, `int` = ?, "
					+ "exp = ?, hp = ?, mp = ?, maxhp = ?, maxmp = ?, sp = ?, ap = ?, "
					+ "gm = ?, skincolor = ?, gender = ?, job = ?, hair = ?, face = ?, map = ?, "
					+ "meso = ?, hpApUsed = ?, mpApUsed = ?, spawnpoint = ?, party = ?, buddyCapacity = ?, messengerid = ?, messengerposition = ?, pvpkills = ?, pvpdeaths = ? WHERE id = ?");
			} else {
                            //31 inserts
				ps = con
					.prepareStatement("INSERT INTO characters ("
						+ "level, fame, str, dex, luk, `int`, exp, hp, mp, "
						+ "maxhp, maxmp, sp, ap, gm, skincolor, gender, job, hair, face, map, meso, hpApUsed, mpApUsed, spawnpoint, party, buddyCapacity, messengerid, messengerposition, pvpkills, pvpdeaths, accountid, name, world"
						+ ") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
			}

            ps.setInt(1, level);
            ps.setInt(2, fame);
            ps.setInt(3, str);
            ps.setInt(4, dex);
            ps.setInt(5, luk);
            ps.setInt(6, int_);
            ps.setInt(7, exp.get());
            ps.setInt(8, hp);
            ps.setInt(9, mp);
            ps.setInt(10, maxhp);
            ps.setInt(11, maxmp);
            ps.setInt(12, remainingSp);
            ps.setInt(13, remainingAp);
            ps.setInt(14, (gmLevel > 0 ? 1 : 0));
            ps.setInt(15, skinColor.getId());
            ps.setInt(16, gender);
            ps.setInt(17, job.getId());
            ps.setInt(18, hair);
            ps.setInt(19, face);
            if (map == null) {
                ps.setInt(20, 0);
            } else {
                if (forcedReturn) {
                    ps.setInt(20, forcedReturnID);
                } else {
                    ps.setInt(20, map.getId());
                }
            }
            ps.setInt(21, meso.get());
            ps.setInt(22, hpApUsed);
            ps.setInt(23, mpApUsed);
            if (map == null) {
                ps.setInt(24, 0);
            } else {
                MaplePortal closest = map.findClosestSpawnpoint(getPosition());
                if (closest != null) {
                    ps.setInt(24, closest.getId());
                } else {
                    ps.setInt(24, 0);
                }
            }
            if (party != null) {
                ps.setInt(25, party.getId());
            } else {
                ps.setInt(25, -1);
            }
            ps.setInt(26, buddylist.getCapacity());

            if (messenger != null) {
                ps.setInt(27, messenger.getId());
                ps.setInt(28, messengerposition);
            } else {
                ps.setInt(27, 0);
                ps.setInt(28, 4);
            }

                        ps.setInt(29, pvpkills);
                        ps.setInt(30, pvpdeaths);

			if (update) {
				ps.setInt(31, id);
			} else {
				ps.setInt(31, accountid);
                                ps.setString(32, name);
				ps.setInt(33, world); // TODO store world somewhere ;)
			}

            int updateRows = ps.executeUpdate();
            if (!update) {
                ResultSet rs = ps.getGeneratedKeys();
                if (rs.next()) {
                    this.id = rs.getInt(1);
                } else {
                    throw new DatabaseException("Inserting char failed.");
                }
            } else if (updateRows < 1) {
                throw new DatabaseException("Character not in database (" + id + ")");
            }
            ps.close();

            for (int i = 0; i < 3; i++) {
                if (pets[i] != null) {
                    pets[i].saveToDb();
                }
            }

            ps = con.prepareStatement("DELETE FROM skillmacros WHERE characterid = ?");
            ps.setInt(1, id);
            ps.executeUpdate();
            ps.close();

            for (int i = 0; i < 5; i++) {
                SkillMacro macro = skillMacros[i];
                if (macro != null) {
                    ps = con.prepareStatement("INSERT INTO skillmacros" + " (characterid, skill1, skill2, skill3, name, shout, position) " + "VALUES (?, ?, ?, ?, ?, ?, ?)");

                    ps.setInt(1, id);
                    ps.setInt(2, macro.getSkill1());
                    ps.setInt(3, macro.getSkill2());
                    ps.setInt(4, macro.getSkill3());
                    ps.setString(5, macro.getName());
                    ps.setInt(6, macro.getShout());
                    ps.setInt(7, i);

                    ps.executeUpdate();
                    ps.close();
                }
            }

            ps = con.prepareStatement("DELETE FROM inventoryitems WHERE characterid = ?");
            ps.setInt(1, id);
            ps.executeUpdate();
            ps.close();

            ps = con.prepareStatement("INSERT INTO inventoryitems" + "(characterid, itemid, inventorytype, position, quantity, owner, petid) " + "VALUES (?, ?, ?, ?, ?, ?, ?)");
            PreparedStatement pse = con.prepareStatement("INSERT INTO inventoryequipment " + "VALUES (DEFAULT, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
            // PreparedStatement psl = con.prepareStatement("INSERT INTO inventorylog " +
            // "VALUES (DEFAULT, ?, ?)");
            for (MapleInventory iv : inventory) {
                ps.setInt(3, iv.getType().getType());
                for (IItem item : iv.list()) {
                    // ps.setInt(1, item.getId());
                    ps.setInt(1, id);
                    ps.setInt(2, item.getItemId());
                    ps.setInt(4, item.getPosition());
                    ps.setInt(5, item.getQuantity());
                    ps.setString(6, item.getOwner());
                    ps.setInt(7, item.getPetId());
                    ps.executeUpdate();
                    ResultSet rs = ps.getGeneratedKeys();
                    int itemid;
                    if (rs.next()) {
                        itemid = rs.getInt(1);
                    } else {
                        throw new DatabaseException("Inserting char failed.");
                    }
                    // for (String msg : item.getLog()) {
                    // psl.setInt(1, itemid);
                    // psl.setString(2, msg);
                    // psl.executeUpdate();
                    // }

                    if (iv.getType().equals(MapleInventoryType.EQUIP) ||
                            iv.getType().equals(MapleInventoryType.EQUIPPED)) {
                        pse.setInt(1, itemid);
                        IEquip equip = (IEquip) item;
                        pse.setInt(2, equip.getUpgradeSlots());
                        pse.setInt(3, equip.getLevel());
                        pse.setInt(4, equip.getStr());
                        pse.setInt(5, equip.getDex());
                        pse.setInt(6, equip.getInt());
                        pse.setInt(7, equip.getLuk());
                        pse.setInt(8, equip.getHp());
                        pse.setInt(9, equip.getMp());
                        pse.setInt(10, equip.getWatk());
                        pse.setInt(11, equip.getMatk());
                        pse.setInt(12, equip.getWdef());
                        pse.setInt(13, equip.getMdef());
                        pse.setInt(14, equip.getAcc());
                        pse.setInt(15, equip.getAvoid());
                        pse.setInt(16, equip.getHands());
                        pse.setInt(17, equip.getSpeed());
                        pse.setInt(18, equip.getJump());
                        pse.setInt(19, equip.getRingId());
                        pse.executeUpdate();
                    }
                }
            }
            ps.close();
            pse.close();
            // psl.close();

            deleteWhereCharacterId(con, "DELETE FROM queststatus WHERE characterid = ?");
            ps = con.prepareStatement("INSERT INTO queststatus (`queststatusid`, `characterid`, `quest`, `status`, `time`, `forfeited`) " +
                    " VALUES (DEFAULT, ?, ?, ?, ?, ?)",
                    Statement.RETURN_GENERATED_KEYS);
            pse = con.prepareStatement("INSERT INTO queststatusmobs VALUES (DEFAULT, ?, ?, ?)");
            ps.setInt(1, id);
            for (MapleQuestStatus q : quests.values()) {
                ps.setInt(2, q.getQuest().getId());
                ps.setInt(3, q.getStatus().getId());
                ps.setInt(4, (int) (q.getCompletionTime() / 1000));
                ps.setInt(5, q.getForfeited());
                ps.executeUpdate();
                ResultSet rs = ps.getGeneratedKeys();
                rs.next();
                for (int mob : q.getMobKills().keySet()) {
                    pse.setInt(1, rs.getInt(1));
                    pse.setInt(2, mob);
                    pse.setInt(3, q.getMobKills(mob));
                    pse.executeUpdate();
                }
                rs.close();
            }
            ps.close();
            pse.close();


            deleteWhereCharacterId(con, "DELETE FROM skills WHERE characterid = ?");
            ps = con.prepareStatement("INSERT INTO skills (characterid, skillid, skilllevel, masterlevel) VALUES (?, ?, ?, ?)");
            ps.setInt(1, id);
            for (Entry<ISkill, SkillEntry> skill : skills.entrySet()) {
                ps.setInt(2, skill.getKey().getId());
                ps.setInt(3, skill.getValue().skillevel);
                ps.setInt(4, skill.getValue().masterlevel);
                ps.executeUpdate();
            }
            ps.close();

            deleteWhereCharacterId(con, "DELETE FROM keymap WHERE characterid = ?");
            ps = con.prepareStatement("INSERT INTO keymap (characterid, `key`, `type`, `action`) VALUES (?, ?, ?, ?)");
            ps.setInt(1, id);
            for (Entry<Integer, MapleKeyBinding> keybinding : keymap.entrySet()) {
                ps.setInt(2, keybinding.getKey().intValue());
                ps.setInt(3, keybinding.getValue().getType());
                ps.setInt(4, keybinding.getValue().getAction());
                ps.executeUpdate();
            }
            ps.close();

            deleteWhereCharacterId(con, "DELETE FROM savedlocations WHERE characterid = ?");
            ps = con.prepareStatement("INSERT INTO savedlocations (characterid, `locationtype`, `map`) VALUES (?, ?, ?)");
            ps.setInt(1, id);
            for (SavedLocationType savedLocationType : SavedLocationType.values()) {
                if (savedLocations[savedLocationType.ordinal()] != -1) {
                    ps.setString(2, savedLocationType.name());
                    ps.setInt(3, savedLocations[savedLocationType.ordinal()]);
                    ps.executeUpdate();
                }
            }
            ps.close();

            deleteWhereCharacterId(con, "DELETE FROM buddies WHERE characterid = ? AND pending = 0");
            ps = con.prepareStatement("INSERT INTO buddies (characterid, `buddyid`, `pending`) VALUES (?, ?, 0)");
            ps.setInt(1, id);
            for (BuddylistEntry entry : buddylist.getBuddies()) {
                if (entry.isVisible()) {
                    ps.setInt(2, entry.getCharacterId());
                    ps.executeUpdate();
                }
            }
            ps.close();

            ps = con.prepareStatement("UPDATE accounts SET `nxCash` = ?, `mPoints` = ?, `gTokens` = ? WHERE id = ?");
            ps.setInt(1, nxcash);
            ps.setInt(2, maplepoints);
            ps.setInt(3, gifttokens);
            ps.setInt(4, client.getAccID());
            ps.executeUpdate();
            ps.close();

            if (storage != null) {
                storage.saveToDB();
            }

            con.commit();
        } catch (Exception e) {
            log.error(MapleClient.getLogMessage(this, "[charsave] Error saving character data"), e);
            try {
                con.rollback();
            } catch (SQLException e1) {
                log.error(MapleClient.getLogMessage(this, "[charsave] Error Rolling Back"), e);
            }
        } finally {
            try {
                con.setAutoCommit(true);
                con.setTransactionIsolation(Connection.TRANSACTION_REPEATABLE_READ);
            } catch (SQLException e) {
                log.error(MapleClient.getLogMessage(this, "[charsave] Error going back to autocommit mode"), e);
            }
        }
    }

    private void deleteWhereCharacterId(Connection con, String sql) throws SQLException {
        PreparedStatement ps = con.prepareStatement(sql);
        ps.setInt(1, id);
        ps.executeUpdate();
        ps.close();
    }

    public MapleQuestStatus getQuest(MapleQuest quest) {
        if (!quests.containsKey(quest)) {
            return new MapleQuestStatus(quest, MapleQuestStatus.Status.NOT_STARTED);
        }
        return quests.get(quest);
    }

    public void updateQuest(MapleQuestStatus quest) {
        quests.put(quest.getQuest(), quest);
        if (!(quest.getQuest() instanceof MapleCustomQuest)) {
            if (quest.getStatus().equals(MapleQuestStatus.Status.STARTED)) {
                client.getSession().write(MaplePacketCreator.startQuest(this, (short) quest.getQuest().getId()));
                client.getSession().write(MaplePacketCreator.updateQuestInfo(this, (short) quest.getQuest().getId(), quest.getNpc(), (byte) 8));
            } else if (quest.getStatus().equals(MapleQuestStatus.Status.COMPLETED)) {
                client.getSession().write(MaplePacketCreator.completeQuest(this, (short) quest.getQuest().getId()));
            } else if (quest.getStatus().equals(MapleQuestStatus.Status.NOT_STARTED)) {
                client.getSession().write(MaplePacketCreator.forfeitQuest(this, (short) quest.getQuest().getId()));
            }
        }
    }

    public static int getIdByName(String name, int world) {
        Connection con = DatabaseConnection.getConnection();
        PreparedStatement ps;
        try {
            ps = con.prepareStatement("SELECT id FROM characters WHERE name = ? AND world = ?");
            ps.setString(1, name);
            ps.setInt(2, world);
            ResultSet rs = ps.executeQuery();
            if (!rs.next()) {
                ps.close();
                return -1;
            }
            int id = rs.getInt("id");
            ps.close();
            return id;
        } catch (SQLException e) {
            log.error("ERROR", e);
        }
        return -1;
    }

    public Integer getBuffedValue(MapleBuffStat effect) {
        MapleBuffStatValueHolder mbsvh = effects.get(effect);
        if (mbsvh == null) {
            return null;
        }
        return Integer.valueOf(mbsvh.value);
    }

    public boolean isBuffFrom(MapleBuffStat stat, ISkill skill) {
        MapleBuffStatValueHolder mbsvh = effects.get(stat);
        if (mbsvh == null) {
            return false;
        }
        return mbsvh.effect.isSkill() && mbsvh.effect.getSourceId() == skill.getId();
    }

    public int getBuffSource(MapleBuffStat stat) {
        MapleBuffStatValueHolder mbsvh = effects.get(stat);
        if (mbsvh == null) {
            return -1;
        }
        return mbsvh.effect.getSourceId();
    }

    public void setBuffedValue(MapleBuffStat effect, int value) {
        MapleBuffStatValueHolder mbsvh = effects.get(effect);
        if (mbsvh == null) {
            return;
        }
        mbsvh.value = value;
    }

    public Long getBuffedStarttime(MapleBuffStat effect) {
        MapleBuffStatValueHolder mbsvh = effects.get(effect);
        if (mbsvh == null) {
            return null;
        }
        return Long.valueOf(mbsvh.startTime);
    }

    public MapleStatEffect getStatForBuff(MapleBuffStat effect) {
        MapleBuffStatValueHolder mbsvh = effects.get(effect);
        if (mbsvh == null) {
            return null;
        }
        return mbsvh.effect;
    }

    private void prepareDragonBlood(final MapleStatEffect bloodEffect) {
        if (dragonBloodSchedule != null) {
            dragonBloodSchedule.cancel(false);
        }
        dragonBloodSchedule = TimerManager.getInstance().register(new Runnable() {

            @Override
            public void run() {
                addHP(-bloodEffect.getX());
        {
        }
                getClient().getSession().write(MaplePacketCreator.showOwnBuffEffect(bloodEffect.getSourceId(), 5));
                getMap().broadcastMessage(MapleCharacter.this, MaplePacketCreator.showBuffeffect(getId(), bloodEffect.getSourceId(), 5), false);
            }
        }, 4000, 4000);
    }

    public void startFullnessSchedule(final int decrease, final MaplePet pet, int petSlot) {
        ScheduledFuture<?> schedule = TimerManager.getInstance().register(new Runnable() {

            @Override
            public void run() {
                int newFullness = pet.getFullness() - decrease;
                if (newFullness <= 5) {
                    pet.setFullness(15);
                    unequipPet(pet, true, true);
                } else {
                    pet.setFullness(newFullness);
                    getClient().getSession().write(MaplePacketCreator.updatePet(pet, true));
                }
            }
        }, 60000, 60000);
		fullnessSchedule[petSlot] = schedule;
	}
	
	public void cancelFullnessSchedule(int petSlot) {
		fullnessSchedule[petSlot].cancel(false);
	}
	
	public void startMapTimeLimitTask(final MapleMap from, final MapleMap to) {
		if (to.getTimeLimit() > 0 && from != null) {
	    	final MapleCharacter chr = this;
	    	mapTimeLimitTask = TimerManager.getInstance().register(new Runnable() {

				@Override
				public void run() {
		    		MaplePortal pfrom = null;
		    		if (MapleItemInformationProvider.getInstance().isMiniDungeonMap(from.getId())) {
						pfrom = from.getPortal("MD00");
		    		} else {
						pfrom = from.getPortal(0);
		    		}
		    		if (pfrom != null) {
						chr.changeMap(from, pfrom);
		    		}
				}
	    	}, from.getTimeLimit() * 1000, from.getTimeLimit() * 1000);
        }
    }


	public void cancelMapTimeLimitTask() {
	    if (mapTimeLimitTask != null) {
		mapTimeLimitTask.cancel(false);
	}
        }

    public void registerEffect(MapleStatEffect effect, long starttime, ScheduledFuture<?> schedule) {
        if (effect.isHide()) {
            this.hidden = true;
            getMap().broadcastMessage(this, MaplePacketCreator.removePlayerFromMap(getId()), false);
        } else if (effect.isDragonBlood()) {
            prepareDragonBlood(effect);
        }
        for (Pair<MapleBuffStat, Integer> statup : effect.getStatups()) {
            effects.put(statup.getLeft(), new MapleBuffStatValueHolder(effect, starttime, schedule, statup.getRight().intValue()));
        }

        recalcLocalStats();
    }

    private List<MapleBuffStat> getBuffStats(MapleStatEffect effect, long startTime) {
        List<MapleBuffStat> stats = new ArrayList<MapleBuffStat>();
        for (Entry<MapleBuffStat, MapleBuffStatValueHolder> stateffect : effects.entrySet()) {
            MapleBuffStatValueHolder mbsvh = stateffect.getValue();
            if (mbsvh.effect.sameSource(effect) && (startTime == -1 || startTime == mbsvh.startTime)) {
                stats.add(stateffect.getKey());
            }
        }
        return stats;
    }

    private void deregisterBuffStats(List<MapleBuffStat> stats) {
        List<MapleBuffStatValueHolder> effectsToCancel = new ArrayList<MapleBuffStatValueHolder>(stats.size());
        for (MapleBuffStat stat : stats) {
            MapleBuffStatValueHolder mbsvh = effects.get(stat);
            if (mbsvh != null) {
                effects.remove(stat);
                boolean addMbsvh = true;
                for (MapleBuffStatValueHolder contained : effectsToCancel) {
                    if (mbsvh.startTime == contained.startTime && contained.effect == mbsvh.effect) {
                        addMbsvh = false;
                    }
                }
                if (addMbsvh) {
                    effectsToCancel.add(mbsvh);
                }
                if (stat == MapleBuffStat.SUMMON || stat == MapleBuffStat.PUPPET) {
                    int summonId = mbsvh.effect.getSourceId();
                    MapleSummon summon = summons.get(summonId);
                    if (summon != null) {
                        getMap().broadcastMessage(MaplePacketCreator.removeSpecialMapObject(summon, true), summon.getPosition());
                        getMap().removeMapObject(summon);
                        removeVisibleMapObject(summon);
                        summons.remove(summonId);
                    }
                } else if (stat == MapleBuffStat.DRAGONBLOOD) {
                    dragonBloodSchedule.cancel(false);
                    dragonBloodSchedule = null;
                }
            }
        }
        for (MapleBuffStatValueHolder cancelEffectCancelTasks : effectsToCancel) {
            if (getBuffStats(cancelEffectCancelTasks.effect, cancelEffectCancelTasks.startTime).size() == 0) {
                cancelEffectCancelTasks.schedule.cancel(false);
            }
        }
    }

    /**
     * @param effect
     * @param overwrite when overwrite is set no data is sent and all the Buffstats in the StatEffect are deregistered
     * @param startTime
     */
    public void cancelEffect(MapleStatEffect effect, boolean overwrite, long startTime) {
        List<MapleBuffStat> buffstats;
        if (!overwrite) {
            buffstats = getBuffStats(effect, startTime);
        } else {
            List<Pair<MapleBuffStat, Integer>> statups = effect.getStatups();
            buffstats = new ArrayList<MapleBuffStat>(statups.size());
            for (Pair<MapleBuffStat, Integer> statup : statups) {
                buffstats.add(statup.getLeft());
            }
        }
        deregisterBuffStats(buffstats);
        if (effect.isMagicDoor()) {
            // remove for all on maps
            if (!getDoors().isEmpty()) {
                MapleDoor door = getDoors().iterator().next();
                for (MapleCharacter chr : door.getTarget().getCharacters()) {
                    door.sendDestroyData(chr.getClient());
                }
                for (MapleCharacter chr : door.getTown().getCharacters()) {
                    door.sendDestroyData(chr.getClient());
                }
                for (MapleDoor destroyDoor : getDoors()) {
                    door.getTarget().removeMapObject(destroyDoor);
                    door.getTown().removeMapObject(destroyDoor);
                }
                clearDoors();
                silentPartyUpdate();
            }
        }

        // check if we are still logged in o.o
        if (!overwrite) {
            cancelPlayerBuffs(buffstats);
            if (effect.isHide() && (MapleCharacter) getMap().getMapObject(getObjectId()) != null) {
                this.hidden = false;
                getMap().broadcastMessage(this, MaplePacketCreator.spawnPlayerMapobject(this), false);
                for (int i = 0; i < 3; i++) {
                    if (pets[i] != null) {
                        getMap().broadcastMessage(this, MaplePacketCreator.showPet(this, pets[i], false, false), false);
                    }
                }
            }
        }
    }

    public void cancelBuffStats(MapleBuffStat... stat) {
        List<MapleBuffStat> buffStatList = Arrays.asList(stat);
        deregisterBuffStats(buffStatList);
        cancelPlayerBuffs(buffStatList);
    }

    public void cancelEffectFromBuffStat(MapleBuffStat stat) {
        cancelEffect(effects.get(stat).effect, false, -1);
    }

    private void cancelPlayerBuffs(List<MapleBuffStat> buffstats) {
        if (getClient().getChannelServer().getPlayerStorage().getCharacterById(getId()) != null) { // are we still connected ?
            recalcLocalStats();
            enforceMaxHpMp();
            getClient().getSession().write(MaplePacketCreator.cancelBuff(buffstats));
            getMap().broadcastMessage(this, MaplePacketCreator.cancelForeignBuff(getId(), buffstats), false);
        }
    }

    public void dispel() {
        LinkedList<MapleBuffStatValueHolder> allBuffs = new LinkedList<MapleBuffStatValueHolder>(effects.values());
        for (MapleBuffStatValueHolder mbsvh : allBuffs) {
            if (mbsvh.effect.isSkill() && !isGM()) {
                cancelEffect(mbsvh.effect, false, mbsvh.startTime);
            }
        }
    }

    public void cancelAllBuffs() {
        LinkedList<MapleBuffStatValueHolder> allBuffs = new LinkedList<MapleBuffStatValueHolder>(effects.values());
        for (MapleBuffStatValueHolder mbsvh : allBuffs) {
            cancelEffect(mbsvh.effect, false, mbsvh.startTime);
        }
    }

    public void silentGiveBuffs(List<PlayerBuffValueHolder> buffs) {
        for (PlayerBuffValueHolder mbsvh : buffs) {
            mbsvh.effect.silentApplyBuff(this, mbsvh.startTime);
        }
    }

    public List<PlayerBuffValueHolder> getAllBuffs() {
        List<PlayerBuffValueHolder> ret = new ArrayList<PlayerBuffValueHolder>();
        for (MapleBuffStatValueHolder mbsvh : effects.values()) {
            ret.add(new PlayerBuffValueHolder(mbsvh.startTime, mbsvh.effect));
        }
        return ret;
    }

    public void cancelMagicDoor() {
        LinkedList<MapleBuffStatValueHolder> allBuffs = new LinkedList<MapleBuffStatValueHolder>(effects.values());
        for (MapleBuffStatValueHolder mbsvh : allBuffs) {
            if (mbsvh.effect.isMagicDoor()) {
                cancelEffect(mbsvh.effect, false, mbsvh.startTime);
            }
        }
    }

    public void handleOrbgain() {
        int orbcount = getBuffedValue(MapleBuffStat.COMBO);
        ISkill combo = SkillFactory.getSkill(1111002);
        ISkill advcombo = SkillFactory.getSkill(1120003);

        MapleStatEffect ceffect = null;
        int advComboSkillLevel = getSkillLevel(advcombo);
        if (advComboSkillLevel > 0) {
            ceffect = advcombo.getEffect(advComboSkillLevel);
        } else {
            ceffect = combo.getEffect(getSkillLevel(combo));
        }

        if (orbcount < ceffect.getX() + 1) {
            int neworbcount = orbcount + 1;
            if (advComboSkillLevel > 0 && ceffect.makeChanceResult()) {
                if (neworbcount < ceffect.getX() + 1) {
                    neworbcount++;
                }
            }

            List<Pair<MapleBuffStat, Integer>> stat = Collections.singletonList(new Pair<MapleBuffStat, Integer>(MapleBuffStat.COMBO, neworbcount));
            setBuffedValue(MapleBuffStat.COMBO, neworbcount);
            int duration = ceffect.getDuration();
            duration += (int) ((getBuffedStarttime(MapleBuffStat.COMBO) - System.currentTimeMillis()));

            getClient().getSession().write(MaplePacketCreator.giveBuff(1111002, duration, stat, false));
            getMap().broadcastMessage(this, MaplePacketCreator.giveForeignBuff(getId(), stat, false), false);
        }
    }

    public void handleOrbconsume() {
        ISkill combo = SkillFactory.getSkill(1111002);
        MapleStatEffect ceffect = combo.getEffect(getSkillLevel(combo));
        List<Pair<MapleBuffStat, Integer>> stat = Collections.singletonList(new Pair<MapleBuffStat, Integer>(MapleBuffStat.COMBO, 1));
        setBuffedValue(MapleBuffStat.COMBO, 1);
        int duration = ceffect.getDuration();
        duration += (int) ((getBuffedStarttime(MapleBuffStat.COMBO) - System.currentTimeMillis()));

        getClient().getSession().write(MaplePacketCreator.giveBuff(1111002, duration, stat, false));
        getMap().broadcastMessage(this, MaplePacketCreator.giveForeignBuff(getId(), stat, false), false);
    }

    private void silentEnforceMaxHpMp() {
        setMp(getMp());
        setHp(getHp(), true);
    }

    private void enforceMaxHpMp() {
        List<Pair<MapleStat, Integer>> stats = new ArrayList<Pair<MapleStat, Integer>>(2);
        if (getMp() > getCurrentMaxMp()) {
            setMp(getMp());
            stats.add(new Pair<MapleStat, Integer>(MapleStat.MP, Integer.valueOf(getMp())));
        }
        if (getHp() > getCurrentMaxHp()) {
            setHp(getHp());
            stats.add(new Pair<MapleStat, Integer>(MapleStat.HP, Integer.valueOf(getHp())));
        }
        if (stats.size() > 0) {
            getClient().getSession().write(MaplePacketCreator.updatePlayerStats(stats));
        }
    }

    public MapleMap getMap() {
        return map;
    }

    /**
     * only for tests
     * 
     * @param newmap
     */
    public void setMap(MapleMap newmap) {
        this.map = newmap;
    }

    public int getMapId() {
        if (map != null) {
            return map.getId();
        }
        return mapid;
    }

    public int getInitialSpawnpoint() {
        return initialSpawnPoint;
    }

    public int getId() {
        return id;
    }

    public String getName() {
        return name;
    }

    public int getLevel() {
        return level;
    }

    public int getRank() {
        return rank;
    }

    public int getRankMove() {
        return rankMove;
    }

    public int getJobRank() {
        return jobRank;
    }

    public int getJobRankMove() {
        return jobRankMove;
    }

    public int getFame() {
        return fame;
    }

    public int getStr() {
        return str;
    }

    public int getDex() {
        return dex;
    }

    public int getLuk() {
        return luk;
    }

    public int getInt() {
        return int_;
    }

    public MapleClient getClient() {
        return client;
    }

    public int getExp() {
        return exp.get();
    }
        public int getPvpKills() {
                return pvpkills;
        }
        
        public int getPvpDeaths() {
                return pvpdeaths;
        }


    public int getHp() {
        return hp;
    }

    public int getMaxHp() {
        return maxhp;
    }

    public int getMp() {
        return mp;
    }

    public int getMaxMp() {
        return maxmp;
    }

    public int getRemainingAp() {
        return remainingAp;
    }

    public int getRemainingSp() {
        return remainingSp;
    }

    public int getMpApUsed() {
        return mpApUsed;
    }

    public void setMpApUsed(int mpApUsed) {
        this.mpApUsed = mpApUsed;
    }

    public int getHpApUsed() {
        return hpApUsed;
    }

    public boolean isHidden() {
        return hidden;
    }

    public void setHpApUsed(int hpApUsed) {
        this.hpApUsed = hpApUsed;
    }

    public MapleSkinColor getSkinColor() {
        return skinColor;
    }

    public MapleJob getJob() {
        return job;
    }

    public int getGender() {
        return gender;
    }

    public int getHair() {
        return hair;
    }

    public int getFace() {
        return face;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void setStr(int str) {
        this.str = str;
        recalcLocalStats();
    }

    public void setDex(int dex) {
        this.dex = dex;
        recalcLocalStats();
    }

    public void setLuk(int luk) {
        this.luk = luk;
        recalcLocalStats();
    }

    public void setInt(int int_) {
        this.int_ = int_;
        recalcLocalStats();
    }

    public void setMaxHp(int hp) {
        this.maxhp = hp;
        recalcLocalStats();
    }

    public void setMaxMp(int mp) {
        this.maxmp = mp;
        recalcLocalStats();
    }

    public void setHair(int hair) {
        this.hair = hair;
    }

    public void setFace(int face) {
        this.face = face;
    }

    public void setRemainingAp(int remainingAp) {
        this.remainingAp = remainingAp;
    }

    public void setRemainingSp(int remainingSp) {
        this.remainingSp = remainingSp;
    }
        public void setPvpDeaths(int amount) {
                this.pvpdeaths = amount;
        }

        public void setPvpKills(int amount) {
                this.pvpkills = amount;
        }
        public void gainPvpDeath() {
                this.pvpdeaths += 1;
        }

        public void gainPvpKill() {
                this.pvpkills += 1;
        }

    public void setSkinColor(MapleSkinColor skinColor) {
        this.skinColor = skinColor;
    }

    public void setGender(int gender) {
        this.gender = gender;
    }

    public void setGM(int gmlevel) {
        this.gmLevel = gmlevel;
    }
    
    public void setFame(int fame) {
        this.fame = fame;
    }

    public CheatTracker getCheatTracker() {
        return anticheat;
    }

    public BuddyList getBuddylist() {
        return buddylist;
    }

    public void addFame(int famechange) {
        this.fame += famechange;
    }

    public void changeMap(final MapleMap to, final Point pos) {
        /*getClient().getSession().write(MaplePacketCreator.spawnPortal(map.getId(), to.getId(), pos));
        if (getParty() != null) {
        getClient().getSession().write(MaplePacketCreator.partyPortal(map.getId(), to.getId(), pos));
        }*/
        MaplePacket warpPacket = MaplePacketCreator.getWarpToMap(to, 0x80, this);
        changeMapInternal(to, pos, warpPacket);
    }

    public void changeMap(final MapleMap to, final MaplePortal pto) {
        MaplePacket warpPacket = MaplePacketCreator.getWarpToMap(to, pto.getId(), this);
        changeMapInternal(to, pto.getPosition(), warpPacket);
    }

    private void changeMapInternal(final MapleMap to, final Point pos, MaplePacket warpPacket) {
        warpPacket.setOnSend(new Runnable() {

            @Override
            public void run() {
                map.removePlayer(MapleCharacter.this);
                if (getClient().getChannelServer().getPlayerStorage().getCharacterById(getId()) != null) {
                    map = to;
                    setPosition(pos);
                    to.addPlayer(MapleCharacter.this);
                    if (party != null) {
                        silentPartyUpdate();
                        getClient().getSession().write(MaplePacketCreator.updateParty(getClient().getChannel(), party, PartyOperation.SILENT_UPDATE, null));
                        updatePartyMemberHP();
                    }
                    if (getMap().getHPDec() > 0) {
                        hpDecreaseTask = TimerManager.getInstance().schedule(new Runnable() {

                            @Override
                            public void run() {
                                doHurtHp();
                            }
                        }, 10000);


                    }
                }
            }
        });
        if(hasFakeChar())
        {
            for (FakeCharacter ch : getFakeChars()) {
                ch.getFakeChar().getMap().removePlayer(ch.getFakeChar());
            }
        }
        getClient().getSession().write(warpPacket);
    }

    public void leaveMap() {
        controlled.clear();
        visibleMapObjects.clear();
        if (chair != 0) {
            chair = 0;
        }
        if (hpDecreaseTask != null) {
            hpDecreaseTask.cancel(false);
        }
    }

    public void doHurtHp() {
        if (this.getInventory(MapleInventoryType.EQUIPPED).findById(getMap().getHPDecProtect()) != null) {
            return;
        }
        addHP(-getMap().getHPDec());
        hpDecreaseTask = TimerManager.getInstance().schedule(new Runnable() {

            @Override
            public void run() {
                doHurtHp();
            }
        }, 10000);
    }

    public void changeJob(MapleJob newJob) {
        this.job = newJob;
        this.remainingSp++;
        if (newJob.getId() % 10 == 2) {
            this.remainingSp += 2;
        }
        this.setMaxHp(Math.min(30000, getMaxHp() + getJobChangeHp(newJob.getId())));
        this.setMaxMp(Math.min(30000, getMaxMp() + getJobChangeMp(newJob.getId())));
        updateSingleStat(MapleStat.AVAILABLESP, this.remainingSp);
        updateSingleStat(MapleStat.JOB, newJob.getId());
        getMap().broadcastMessage(this, MaplePacketCreator.showJobChange(getId()), false);
        silentPartyUpdate();
        guildUpdate();
    }

    public void gainAp(int ap) {
        this.remainingAp += ap;
        updateSingleStat(MapleStat.AVAILABLEAP, this.remainingAp);
    }

    public void changeSkillLevel(ISkill skill, int newLevel, int newMasterlevel) {
        skills.put(skill, new SkillEntry(newLevel, newMasterlevel));
        this.getClient().getSession().write(MaplePacketCreator.updateSkill(skill.getId(), newLevel, newMasterlevel));
    }

    public void setHp(int newhp) {
        setHp(newhp, false);
    }

    public void setHp(int newhp, boolean silent) {
        int oldHp = hp;
        int thp = newhp;
        if (thp < 0) {
            thp = 0;
        }
        if (thp > localmaxhp) {
            thp = localmaxhp;
        }
        this.hp = thp;

        if (!silent) {
            updatePartyMemberHP();
        }
        if (oldHp > hp && !isAlive()) {
            playerDead();
        }
    }

    private int getJobChangeHp(int id) {
        switch (id) {
            case 100:
                return 230; //Warrior
            case 110:
                return 335; //Fighter
            case 120:
                return 0; //Page
            case 130:
                return 0; //Spearman
            case 200:
                return 0; //Magician
            case 210:
                return 0; //FP Wizard
            case 220:
                return 0; //IL Wizard
            case 230:
                return 0; //Cleric
            case 300:
                return 125; //Bowman
            case 310:
                return 325; //Hunter
            case 320:
                return 325; //Crossbowman
            case 400:
                return 130; //Rogue
            case 410:
                return 325; //Assassin
            case 420:
                return 325; //Bandit
            default:
                return 0;

        }
    }

    private int getJobChangeMp(int id) {
        switch (id) {
            case 100:
                return 0; //Warrior
            case 110:
                return 0; //Fighter
            case 120:
                return 140; //Page
            case 130:
                return 135; //Spearman
            case 200:
                return 120; //Magician
            case 210:
                return 475; //FP Wizard
            case 220:
                return 475; //IL Wizard
            case 230:
                return 475; //Cleric
            case 300:
                return 50; //Bowman
            case 310:
                return 100; //Hunter
            case 320:
                return 100; //Crossbowman
            case 400:
                return 50; //Rogue
            case 410:
                return 175; //Assassin
            case 420:
                return 155; //Bandit
            default:
                return 0;

        }
    }

    private void playerDead() {
        if (getEventInstance() != null) {
            getEventInstance().playerKilled(this);
        }
        getClient().getSession().write(MaplePacketCreator.enableActions());
    }

    public void updatePartyMemberHP() {
        if (party != null) {
            int channel = client.getChannel();
            for (MaplePartyCharacter partychar : party.getMembers()) {
                if (partychar.getMapid() == getMapId() && partychar.getChannel() == channel) {
                    MapleCharacter other = ChannelServer.getInstance(channel).getPlayerStorage().getCharacterByName(partychar.getName());
                    if (other != null) {
                        other.getClient().getSession().write(
                                MaplePacketCreator.updatePartyMemberHP(getId(), this.hp, localmaxhp));
                    }
                }
            }
        }
    }

    public void receivePartyMemberHP() {
        if (party != null) {
            int channel = client.getChannel();
            for (MaplePartyCharacter partychar : party.getMembers()) {
                if (partychar.getMapid() == getMapId() && partychar.getChannel() == channel) {
                    MapleCharacter other = ChannelServer.getInstance(channel).getPlayerStorage().getCharacterByName(partychar.getName());
                    if (other != null) {
                        getClient().getSession().write(
                                MaplePacketCreator.updatePartyMemberHP(other.getId(), other.getHp(), other.getCurrentMaxHp()));
                    }
                }
            }
        }
    }

    public void setMp(int newmp) {
        int tmp = newmp;
        if (tmp < 0) {
            tmp = 0;
        }
        if (tmp > localmaxmp) {
            tmp = localmaxmp;
        }
        this.mp = tmp;
    }

    /**
     * Convenience function which adds the supplied parameter to the current hp then directly does a updateSingleStat.
     * 
     * @see MapleCharacter#setHp(int)
     * @param delta
     */
    public void addHP(int delta) {
        setHp(hp + delta);
        updateSingleStat(MapleStat.HP, hp);
    }

    /**
     * Convenience function which adds the supplied parameter to the current mp then directly does a updateSingleStat.
     * 
     * @see MapleCharacter#setMp(int)
     * @param delta
     */
    public void addMP(int delta) {
        setMp(mp + delta);
        updateSingleStat(MapleStat.MP, mp);
    }

    public void addMPHP(int hpDiff, int mpDiff) {
        setHp(hp + hpDiff);
        setMp(mp + mpDiff);
        List<Pair<MapleStat, Integer>> stats = new ArrayList<Pair<MapleStat, Integer>>();
        stats.add(new Pair<MapleStat, Integer>(MapleStat.HP, Integer.valueOf(hp)));
        stats.add(new Pair<MapleStat, Integer>(MapleStat.MP, Integer.valueOf(mp)));
        MaplePacket updatePacket = MaplePacketCreator.updatePlayerStats(stats);
        client.getSession().write(updatePacket);
    }

    /**
     * Updates a single stat of this MapleCharacter for the client. This method only creates and sends an update packet,
     * it does not update the stat stored in this MapleCharacter instance.
     * 
     * @param stat
     * @param newval
     * @param itemReaction
     */
    public void updateSingleStat(MapleStat stat, int newval, boolean itemReaction) {
        Pair<MapleStat, Integer> statpair = new Pair<MapleStat, Integer>(stat, Integer.valueOf(newval));
        MaplePacket updatePacket = MaplePacketCreator.updatePlayerStats(Collections.singletonList(statpair),
                itemReaction);
        client.getSession().write(updatePacket);
    }

    public void updateSingleStat(MapleStat stat, int newval) {
        updateSingleStat(stat, newval, false);
    }

    public void gainExp(int gain, boolean show, boolean inChat, boolean white) {
        int gainShow = gain;
	if (getLevel() >= 200) {
	    this.exp.set(0);
            updateSingleStat(MapleStat.EXP, 0);
	    return;
	}
        if (getLevel() < 200) { // lv200 is max and has 0 exp required to level
            int newexp = this.exp.addAndGet(gain);
            updateSingleStat(MapleStat.EXP, newexp);
        }
        if ((long)this.exp.get() + (long)gain > (long)Integer.MAX_VALUE) {
		int gainFirst = ExpTable.getExpNeededForLevel(level + 1) - this.exp.get();
		gain -= gainFirst + 1;
		this.gainExp(gainFirst + 1, false, inChat, white);
	    }
        if (show) { // still show the expgain even if it's not there
            client.getSession().write(MaplePacketCreator.getShowExpGain(gainShow, inChat, white));
        }
        while (level < 200 && exp.get() >= ExpTable.getExpNeededForLevel(level + 1)) {
            levelUp();
        }
    }

    public void silentPartyUpdate() {
        if (party != null) {
            try {
                getClient().getChannelServer().getWorldInterface().updateParty(party.getId(),
                        PartyOperation.SILENT_UPDATE, new MaplePartyCharacter(MapleCharacter.this));
            } catch (RemoteException e) {
                log.error("REMOTE THROW", e);
                getClient().getChannelServer().reconnectWorld();
            }
        }
    }

    public void gainExp(int gain, boolean show, boolean inChat) {
        gainExp(gain, show, inChat, true);
    }

    public boolean isGM() {
        return gmLevel > 0;
    }

    public int getGMLevel() {
        return gmLevel;
    }

    public boolean hasGmLevel(int level) {
        return gmLevel >= level;
    }

    public MapleInventory getInventory(MapleInventoryType type) {
        return inventory[type.ordinal()];
    }

    public MapleShop getShop() {
        return shop;
    }

    public void setShop(MapleShop shop) {
        this.shop = shop;
    }

    public int getMeso() {
        return meso.get();
    }

    public int getSavedLocation(SavedLocationType type) {
        return savedLocations[type.ordinal()];
    }

    public void saveLocation(SavedLocationType type) {
        savedLocations[type.ordinal()] = getMapId();
    }

    public void clearSavedLocation(SavedLocationType type) {
        savedLocations[type.ordinal()] = -1;
    }

    public void gainMeso(int gain, boolean show) {
        gainMeso(gain, show, false, false);
    }

    public void gainMeso(int gain, boolean show, boolean enableActions) {
        gainMeso(gain, show, enableActions, false);
    }

    public void gainMeso(int gain, boolean show, boolean enableActions, boolean inChat) {
        if (meso.get() + gain < 0) {
            client.getSession().write(MaplePacketCreator.enableActions());
            return;
        }
        int newVal = meso.addAndGet(gain);
        updateSingleStat(MapleStat.MESO, newVal, enableActions);
        if (show) {
            client.getSession().write(MaplePacketCreator.getShowMesoGain(gain, inChat));
        }
    }

    /**
     * Adds this monster to the controlled list. The monster must exist on the Map.
     * 
     * @param monster
     */
    public void controlMonster(MapleMonster monster, boolean aggro) {
        monster.setController(this);
        controlled.add(monster);
        client.getSession().write(MaplePacketCreator.controlMonster(monster, false, aggro));
    }

    public void stopControllingMonster(MapleMonster monster) {
        controlled.remove(monster);
    }

    public Collection<MapleMonster> getControlledMonsters() {
        return Collections.unmodifiableCollection(controlled);
    }

    public int getNumControlledMonsters() {
        return controlled.size();
    }

    @Override
    public String toString() {
        return "Character: " + this.name;
    }

    public int getAccountID() {
        return accountid;
    }

    public void mobKilled(int id) {
        for (MapleQuestStatus q : quests.values()) {
            if (q.getStatus() == MapleQuestStatus.Status.COMPLETED || q.getQuest().canComplete(this, null)) {
                continue;
            }
            if (q.mobKilled(id) && !(q.getQuest() instanceof MapleCustomQuest)) {
                client.getSession().write(MaplePacketCreator.updateQuestMobKills(q));
                if (q.getQuest().canComplete(this, null)) {
                    client.getSession().write(MaplePacketCreator.getShowQuestCompletion(q.getQuest().getId()));
                }
            }
        }
    }

    public final List<MapleQuestStatus> getStartedQuests() {
        List<MapleQuestStatus> ret = new LinkedList<MapleQuestStatus>();
        for (MapleQuestStatus q : quests.values()) {
            if (q.getStatus().equals(MapleQuestStatus.Status.STARTED) && !(q.getQuest() instanceof MapleCustomQuest)) {
                ret.add(q);
            }
        }
        return Collections.unmodifiableList(ret);
    }

    public final List<MapleQuestStatus> getCompletedQuests() {
        List<MapleQuestStatus> ret = new LinkedList<MapleQuestStatus>();
        for (MapleQuestStatus q : quests.values()) {
            if (q.getStatus().equals(MapleQuestStatus.Status.COMPLETED) && !(q.getQuest() instanceof MapleCustomQuest)) {
                ret.add(q);
            }
        }
        return Collections.unmodifiableList(ret);
    }

    public MaplePlayerShop getPlayerShop() {
        return playerShop;
    }

    public void setPlayerShop(MaplePlayerShop playerShop) {
        this.playerShop = playerShop;
    }

    public Map<ISkill, SkillEntry> getSkills() {
        return Collections.unmodifiableMap(skills);
    }

    public int getSkillLevel(ISkill skill) {
        SkillEntry ret = skills.get(skill);
        if (ret == null) {
            return 0;
        }
        return ret.skillevel;
    }

    public int getMasterLevel(ISkill skill) {
        SkillEntry ret = skills.get(skill);
        if (ret == null) {
            return 0;
        }
        return ret.masterlevel;
    }

    // the equipped inventory only contains equip... I hope
    public int getTotalDex() {
        return localdex;
    }

    public int getTotalInt() {
        return localint_;
    }

    public int getTotalStr() {
        return localstr;
    }

    public int getTotalLuk() {
        return localluk;
    }

    public int getTotalMagic() {
        return magic;
    }
        public int getTotalMdef() {
                return mdef;
        }

    public double getSpeedMod() {
        return speedMod;
    }

    public double getJumpMod() {
        return jumpMod;
    }

    public int getTotalWatk() {
        return watk;
    }
        public int getTotalWdef() {
            return wdef;
        }
        
       /* public int getPvpKills() {
                return pvpKills;
        }
        
        public int getPvpDeaths() {
                return pvpDeaths;
        }
        
        public void gainPvpDeath() {
                this.pvpDeaths += 1;
        }

        public void gainPvpKill() {
                this.pvpKills += 1;
        }*/


    public static int rand(int lbound, int ubound) {
        return (int) ((Math.random() * (ubound - lbound + 1)) + lbound);
    }

    public void levelUp() {
        ISkill improvingMaxHP = SkillFactory.getSkill(1000001);
        ISkill improvingMaxMP = SkillFactory.getSkill(2000001);

        int improvingMaxHPLevel = getSkillLevel(improvingMaxHP);
        int improvingMaxMPLevel = getSkillLevel(improvingMaxMP);
        remainingAp += 5;
        if (job == MapleJob.BEGINNER) {
            // info from the odin what's working thread, thanks
            maxhp += rand(14, 16);
            maxmp += rand(10, 12);
        } else if (job.isA(MapleJob.BOWMAN) || job.isA(MapleJob.THIEF) || job.isA(MapleJob.GM)) {
            // info from bowman forum at sleepywood, thanks guys
            maxhp += rand(20, 24);
            maxmp += rand(14, 16);
        } else if (job.isA(MapleJob.MAGICIAN)) {
            // made up
            maxhp += rand(10, 14);
            maxmp += rand(20, 24);
        } else if (job.isA(MapleJob.WARRIOR)) {
            // made up
            maxhp += rand(22, 26);
            maxmp += rand(4, 7);
        } else if (job.isA(MapleJob.PIRATE)) { 
            // info from David (Davidkun) on his KMS pirate. 
            maxhp += rand(22, 25); 
            maxmp += rand(17, 22); 
        }  

        if (improvingMaxHPLevel > 0) {
            maxhp += improvingMaxHP.getEffect(improvingMaxHPLevel).getX();
        }
        if (improvingMaxMPLevel > 0) {
            maxmp += improvingMaxMP.getEffect(improvingMaxMPLevel).getX();
        }
        maxmp += getTotalInt() / 10;
        exp.addAndGet(-ExpTable.getExpNeededForLevel(level + 1));
        level += 1;
        if (level == 200 && !isGM()) {
            exp.set(0);
            MaplePacket packet = MaplePacketCreator.serverNotice(0, "Congratulations to " + getName() + " for reaching level 200!");
            try {
                getClient().getChannelServer().getWorldInterface().broadcastMessage(getName(), packet.getBytes());
            } catch (RemoteException e) {
                getClient().getChannelServer().reconnectWorld();
            }
        }

        maxhp = Math.min(30000, maxhp);
        maxmp = Math.min(30000, maxmp);

        List<Pair<MapleStat, Integer>> statup = new ArrayList<Pair<MapleStat, Integer>>(8);
        statup.add(new Pair<MapleStat, Integer>(MapleStat.AVAILABLEAP, Integer.valueOf(remainingAp)));
        statup.add(new Pair<MapleStat, Integer>(MapleStat.MAXHP, Integer.valueOf(maxhp)));
        statup.add(new Pair<MapleStat, Integer>(MapleStat.MAXMP, Integer.valueOf(maxmp)));
        statup.add(new Pair<MapleStat, Integer>(MapleStat.HP, Integer.valueOf(maxhp)));
        statup.add(new Pair<MapleStat, Integer>(MapleStat.MP, Integer.valueOf(maxmp)));
        statup.add(new Pair<MapleStat, Integer>(MapleStat.EXP, Integer.valueOf(exp.get())));
        statup.add(new Pair<MapleStat, Integer>(MapleStat.LEVEL, Integer.valueOf(level)));

        if (job != MapleJob.BEGINNER) {
            remainingSp += 3;
            statup.add(new Pair<MapleStat, Integer>(MapleStat.AVAILABLESP, Integer.valueOf(remainingSp)));
        }

        setHp(maxhp);
        setMp(maxmp);
        getClient().getSession().write(MaplePacketCreator.updatePlayerStats(statup));
        getMap().broadcastMessage(this, MaplePacketCreator.showLevelup(getId()), false);
        recalcLocalStats();
        silentPartyUpdate();
        guildUpdate();
    }

    public void changeKeybinding(int key, MapleKeyBinding keybinding) {
        if (keybinding.getType() != 0) {
            keymap.put(Integer.valueOf(key), keybinding);
        } else {
            keymap.remove(Integer.valueOf(key));
        }
    }

    public void sendKeymap() {
        getClient().getSession().write(MaplePacketCreator.getKeymap(keymap));
    }

    public void sendMacros() {
        boolean macros = false;
        for (int i = 0; i < 5; i++) {
            if (skillMacros[i] != null) {
                macros = true;
            }
        }
        if (macros) {
            getClient().getSession().write(MaplePacketCreator.getMacros(skillMacros));
        }
    }

    public void updateMacros(int position, SkillMacro updateMacro) {
        skillMacros[position] = updateMacro;
    }

    public void tempban(String reason, Calendar duration, int greason) {
        if (lastmonthfameids == null) {
            throw new RuntimeException("Trying to ban a non-loaded character (testhack)");
        }
        tempban(reason, duration, greason, client.getAccID());
        client.getSession().close();
    }

    public static boolean tempban(String reason, Calendar duration, int greason, int accountid) {
        try {
            Connection con = DatabaseConnection.getConnection();
            PreparedStatement ps = con.prepareStatement("UPDATE accounts SET tempban = ?, banreason = ?, greason = ? WHERE id = ?");
            Timestamp TS = new Timestamp(duration.getTimeInMillis());
            ps.setTimestamp(1, TS);
            ps.setString(2, reason);
            ps.setInt(3, greason);
            ps.setInt(4, accountid);
            ps.executeUpdate();
            ps.close();
            return true;
        } catch (SQLException ex) {
            log.error("Error while tempbanning", ex);
        }
        return false;
    }

    public void ban(String reason) {
        if (lastmonthfameids == null) {
            throw new RuntimeException("Trying to ban a non-loaded character (testhack)");
        }
        try {
            getClient().banMacs();
            Connection con = DatabaseConnection.getConnection();
            PreparedStatement ps = con.prepareStatement("UPDATE accounts SET banned = ?, banreason = ? WHERE id = ?");
            ps.setInt(1, 1);
            ps.setString(2, reason);
            ps.setInt(3, accountid);
            ps.executeUpdate();
            ps.close();
            ps = con.prepareStatement("INSERT INTO ipbans VALUES (DEFAULT, ?)");
            String[] ipSplit = client.getSession().getRemoteAddress().toString().split(":");
            ps.setString(1, ipSplit[0]);
            ps.executeUpdate();
            ps.close();
        } catch (SQLException ex) {
            log.error("Error while banning", ex);
        }
        client.getSession().close();
    }

    public static boolean ban(String id, String reason, boolean accountId) {
        try {
            Connection con = DatabaseConnection.getConnection();
            PreparedStatement ps;
            if (id.matches("/[0-9]{1,3}\\..*")) {
                ps = con.prepareStatement("INSERT INTO ipbans VALUES (DEFAULT, ?)");
                ps.setString(1, id);
                ps.executeUpdate();
                ps.close();
                return true;
            }
            if (accountId) {
                ps = con.prepareStatement("SELECT id FROM accounts WHERE name = ?");
            } else {
                ps = con.prepareStatement("SELECT accountid FROM characters WHERE name = ?");
            }
            boolean ret = false;
            ps.setString(1, id);
            ResultSet rs = ps.executeQuery();
            if (rs.next()) {
                PreparedStatement psb = con.prepareStatement("UPDATE accounts SET banned = 1, banreason = ? WHERE id = ?");
                psb.setString(1, reason);
                psb.setInt(2, rs.getInt(1));
                psb.executeUpdate();
                psb.close();
                ret = true;
            }
            rs.close();
            ps.close();
            return ret;
        } catch (SQLException ex) {
            log.error("Error while banning", ex);
        }
        return false;
    }

    /**
     * Oid of players is always = the cid
     */
    @Override
    public int getObjectId() {
        return getId();
    }

    /**
     * Throws unsupported operation exception, oid of players is read only
     */
    @Override
    public void setObjectId(int id) {
        throw new UnsupportedOperationException();
    }

    public MapleStorage getStorage() {
        return storage;
    }

    public int getCurrentMaxHp() {
        return localmaxhp;
    }

    public int getCurrentMaxMp() {
        return localmaxmp;
    }

    public int getCurrentMaxBaseDamage() {
        return localmaxbasedamage;
    }
 public int getMaxDis(MapleCharacter player) {
        IItem weapon_item = player.getInventory(MapleInventoryType.EQUIPPED).getItem((byte) -11);
        if(weapon_item != null) {
            MapleWeaponType weapon = MapleItemInformationProvider.getInstance().getWeaponType(weapon_item.getItemId());
            if(weapon == MapleWeaponType.SPEAR || weapon == MapleWeaponType.POLE_ARM) {
                maxDis = 106;
            }
            if(weapon == MapleWeaponType.DAGGER || weapon == MapleWeaponType.SWORD1H || weapon == MapleWeaponType.AXE1H || weapon == MapleWeaponType.BLUNT1H) {
                maxDis = 63;
            }
            if(weapon == MapleWeaponType.SWORD2H || weapon == MapleWeaponType.AXE1H || weapon == MapleWeaponType.BLUNT1H) {
                maxDis = 73;
            }
            if(weapon == MapleWeaponType.STAFF || weapon == MapleWeaponType.WAND) {
                maxDis = 51;
            }
            if(weapon == MapleWeaponType.CLAW) {
                skil = SkillFactory.getSkill(4000001);
                skill = player.getSkillLevel(skil);
                if(skill > 0){
                maxDis = (skil.getEffect(player.getSkillLevel(skil)).getRange()) + 205;
                }
                else {
                    maxDis = 205;
                }
            }
            if(weapon == MapleWeaponType.BOW || weapon == MapleWeaponType.CROSSBOW) {
                skil = SkillFactory.getSkill(3000002);
                skill = player.getSkillLevel(skil);
                if(skill > 0){
                maxDis = (skil.getEffect(player.getSkillLevel(skil)).getRange()) + 270;
                }
                else {
                    maxDis = 270;
                }
            }
        }
        return maxDis;
        }

    public int calculateMaxBaseDamage(int watk) {
        int maxbasedamage;
        if (watk == 0) {
            maxbasedamage = 1;
        } else {
            IItem weapon_item = getInventory(MapleInventoryType.EQUIPPED).getItem((byte) -11);
            if (weapon_item != null) {
                MapleWeaponType weapon = MapleItemInformationProvider.getInstance().getWeaponType(weapon_item.getItemId());
                int mainstat;
                int secondarystat;
                if (weapon == MapleWeaponType.BOW || weapon == MapleWeaponType.CROSSBOW) {
                    mainstat = localdex;
                    secondarystat = localstr;
                } else if (getJob().isA(MapleJob.THIEF) && (weapon == MapleWeaponType.CLAW || weapon == MapleWeaponType.DAGGER)) {
                    mainstat = localluk;
                    secondarystat = localdex + localstr;
                } else {
                    mainstat = localstr;
                    secondarystat = localdex;
                }
                maxbasedamage = (int) (((weapon.getMaxDamageMultiplier() * mainstat + secondarystat) / 100.0) * watk);
                //just some saveguard against rounding errors, we want to a/b for this
                maxbasedamage += 10;
            } else {
                maxbasedamage = 0;
            }
        }
        return maxbasedamage;
    }
         public int calculateMinBaseDamage (MapleCharacter player) {
                int minbasedamage = 0;
                int atk = player.getTotalWatk();
                if (atk == 0) {
                        minbasedamage = 1;
                } else {
                    IItem weapon_item = getInventory(MapleInventoryType.EQUIPPED).getItem((byte) - 11);
                    if( weapon_item != null) {
                        MapleWeaponType weapon = MapleItemInformationProvider.getInstance().getWeaponType(weapon_item.getItemId());
                        //mastery start
                        if (player.getJob().isA(MapleJob.FIGHTER)) {
                        skil = SkillFactory.getSkill(1100000);
                        skill = player.getSkillLevel(skil);
                        if(skill > 0){
                        sword = ((skil.getEffect(player.getSkillLevel(skil)).getMastery() * 5 + 10) / 100);
                        }
                        else {
                            sword = 0.1;
                        }
                        }
                        else {
                        skil = SkillFactory.getSkill(1200000);
                        skill = player.getSkillLevel(skil);
                        if(skill > 0){
                        sword = ((skil.getEffect(player.getSkillLevel(skil)).getMastery() * 5 + 10) / 100);
                        }
                        else {
                            sword = 0.1;
                        }
                        }
                        skil = SkillFactory.getSkill(1100001);
                        skill = player.getSkillLevel(skil);
                        if(skill > 0){
                        axe = ((skil.getEffect(player.getSkillLevel(skil)).getMastery() * 5 + 10) / 100);
                        }
                        else {
                            axe = 0.1;
                        }
                        skil = SkillFactory.getSkill(1200001);
                        skill = player.getSkillLevel(skil);
                        if(skill > 0){
                        blunt = ((skil.getEffect(player.getSkillLevel(skil)).getMastery() * 5 + 10) / 100);
                        }
                        else {
                            blunt = 0.1;
                        }
                        skil = SkillFactory.getSkill(1300000);
                        skill = player.getSkillLevel(skil);
                        if(skill > 0){
                        spear = ((skil.getEffect(player.getSkillLevel(skil)).getMastery() * 5 + 10) / 100);
                        }
                        else {
                            spear = 0.1;
                        }
                        skil = SkillFactory.getSkill(1300001);
                        skill = player.getSkillLevel(skil);
                        if(skill > 0){
                        polearm = ((skil.getEffect(player.getSkillLevel(skil)).getMastery() * 5 + 10) / 100);
                        }
                        else {
                            polearm = 0.1;
                        }
                        skil = SkillFactory.getSkill(3200000);
                        skill = player.getSkillLevel(skil);
                        if(skill > 0){
                        crossbow = ((skil.getEffect(player.getSkillLevel(skil)).getMastery() * 5 + 10) / 100);
                        }
                        else {
                            crossbow = 0.1;
                        }
                        skil = SkillFactory.getSkill(3100000);
                        skill = player.getSkillLevel(skil);
                        if(skill > 0){
                        bow = ((skil.getEffect(player.getSkillLevel(skil)).getMastery() * 5 + 10) / 100);
                        }
                        else {
                            bow = 0.1;
                        }
                        //end mastery
                        if (weapon == MapleWeaponType.CROSSBOW) {
                            minbasedamage = (int) (localdex * 0.9 * 3.6 * crossbow + localstr) / 100 * (atk + 15);
                        }
                        if (weapon == MapleWeaponType.BOW) {
                            minbasedamage = (int) (localdex * 0.9 * 3.4 * bow + localstr) / 100 * (atk + 15);
                        }
                        if (getJob().isA(MapleJob.THIEF) && (weapon == MapleWeaponType.DAGGER)) {
                            minbasedamage = (int) (localluk * 0.9 * 3.6 * dagger + localstr + localdex) / 100 * atk;
                        }
                        if (!getJob().isA(MapleJob.THIEF) && (weapon == MapleWeaponType.DAGGER)) {
                            minbasedamage = (int) (localstr * 0.9 * 4.0 * dagger + localdex) / 100 * atk;
                        }
                        if (getJob().isA(MapleJob.THIEF) && (weapon == MapleWeaponType.CLAW)) {
                            minbasedamage = (int) (localluk * 0.9 * 3.6 * claw + localstr + localdex) / 100 * (atk + 15);
                        }
                        if (weapon == MapleWeaponType.SPEAR) {
                            minbasedamage = (int) (localstr * 0.9 * 3.0 * spear + localdex) / 100 * atk;
                        }
                        if (weapon == MapleWeaponType.POLE_ARM) {
                            minbasedamage = (int) (localstr * 0.9 * 3.0 * polearm + localdex) / 100 * atk;
                        }
                        if (weapon == MapleWeaponType.SWORD1H) {
                            minbasedamage = (int) (localstr * 0.9 * 4.0 * sword + localdex) / 100 * atk;
                        }
                        if (weapon == MapleWeaponType.SWORD2H) {
                            minbasedamage = (int) (localstr * 0.9 * 4.6 * sword + localdex) / 100 * atk;
                        }
                        if (weapon == MapleWeaponType.AXE1H) {
                            minbasedamage = (int) (localstr * 0.9 * 3.2 * axe + localdex) / 100 * atk;
                        }
                        if (weapon == MapleWeaponType.BLUNT1H) {
                            minbasedamage = (int) (localstr * 0.9 * 3.2 * blunt + localdex) / 100 * atk;
                        }
                        if (weapon == MapleWeaponType.AXE2H) {
                            minbasedamage = (int) (localstr * 0.9 * 3.4 * axe + localdex) / 100 * atk;
                        }
                        if (weapon == MapleWeaponType.BLUNT2H) {
                            minbasedamage = (int) (localstr * 0.9 * 3.4 * blunt + localdex) / 100 * atk;
                        }
                        if (weapon == MapleWeaponType.STAFF || weapon == MapleWeaponType.WAND) {
                            minbasedamage = (int) (localstr * 0.9 * 3.0 * staffwand + localdex) / 100 * atk;
                        }
                    }
                }
                return minbasedamage;
        }
public int getRandomage(MapleCharacter player) {
            int maxdamage = player.getCurrentMaxBaseDamage();
            int mindamage = player.calculateMinBaseDamage(player);
            return player.rand(mindamage, maxdamage);
        }
        public MaplePacket makeHPBarPacket(MapleCharacter player) {
                byte tagcolor = 01;
                byte tagbgcolor = 05;
		return MaplePacketCreator.showBossHP(9400711, player.getHp(), player.getMaxHp(), tagcolor, tagbgcolor);
        }


    public void addVisibleMapObject(MapleMapObject mo) {
        visibleMapObjects.add(mo);
    }

    public void removeVisibleMapObject(MapleMapObject mo) {
        visibleMapObjects.remove(mo);
    }

    public boolean isMapObjectVisible(MapleMapObject mo) {
        return visibleMapObjects.contains(mo);
    }

    public Collection<MapleMapObject> getVisibleMapObjects() {
        return Collections.unmodifiableCollection(visibleMapObjects);
    }

    public boolean isAlive() {
        return this.hp > 0;
    }

    @Override
    public void sendDestroyData(MapleClient client) {
        client.getSession().write(MaplePacketCreator.removePlayerFromMap(this.getObjectId()));
    }

    @Override
    public void sendSpawnData(MapleClient client) {
        if (!this.isHidden()) {
            client.getSession().write(MaplePacketCreator.spawnPlayerMapobject(this));
            for (int i = 0; i < 3; i++) {
                if (pets[i] != null) {
                    client.getSession().write(MaplePacketCreator.showPet(this, pets[i], false, false));
                }
            }
        }
    }

    private void recalcLocalStats() {
        int oldmaxhp = localmaxhp;
        localmaxhp = getMaxHp();
        localmaxmp = getMaxMp();
        localdex = getDex();
        localint_ = getInt();
        localstr = getStr();
        localluk = getLuk();
        int speed = 100;
        int jump = 100;
        magic = localint_;
        watk = 0;
wdef = 0;
mdef = 0;

        for (IItem item : getInventory(MapleInventoryType.EQUIPPED)) {
            IEquip equip = (IEquip) item;
            localmaxhp += equip.getHp();
            localmaxmp += equip.getMp();
            localdex += equip.getDex();
            localint_ += equip.getInt();
            localstr += equip.getStr();
            localluk += equip.getLuk();
            magic += equip.getMatk() + equip.getInt();
            watk += equip.getWatk();
            speed += equip.getSpeed();
            jump += equip.getJump();
wdef += equip.getWdef();
mdef += equip.getMdef();

        }
        magic = Math.min(magic, 2000);
        Integer hbhp = getBuffedValue(MapleBuffStat.HYPERBODYHP);
        if (hbhp != null) {
            localmaxhp += (hbhp.doubleValue() / 100) * localmaxhp;
        }
        Integer hbmp = getBuffedValue(MapleBuffStat.HYPERBODYMP);
        if (hbmp != null) {
            localmaxmp += (hbmp.doubleValue() / 100) * localmaxmp;
        }
        localmaxhp = Math.min(30000, localmaxhp);
        localmaxmp = Math.min(30000, localmaxmp);
        Integer watkbuff = getBuffedValue(MapleBuffStat.WATK);
        if (watkbuff != null) {
            watk += watkbuff.intValue();
        }
        if (job.isA(MapleJob.BOWMAN)) {
            ISkill expert = null;
            if (job.isA(MapleJob.CROSSBOWMASTER)) {
                expert = SkillFactory.getSkill(3220004);
            } else if (job.isA(MapleJob.BOWMASTER)) {
                expert = SkillFactory.getSkill(3120005);
            }
            if (expert != null) {
                int boostLevel = getSkillLevel(expert);
                if (boostLevel > 0) {
                    watk += expert.getEffect(boostLevel).getX();
                }
            }
        }
        Integer matkbuff = getBuffedValue(MapleBuffStat.MATK);
        if (matkbuff != null) {
            magic += matkbuff.intValue();
        }
        Integer speedbuff = getBuffedValue(MapleBuffStat.SPEED);
        if (speedbuff != null) {
            speed += speedbuff.intValue();
        }
        Integer jumpbuff = getBuffedValue(MapleBuffStat.JUMP);
        if (jumpbuff != null) {
            jump += jumpbuff.intValue();
        }
        if (speed > 140) {
            speed = 140;
        }
        if (jump > 123) {
            jump = 123;
        }
        speedMod = speed / 100.0;
        jumpMod = jump / 100.0;
        Integer mount = getBuffedValue(MapleBuffStat.MONSTER_RIDING);
        if (mount != null) {
            jumpMod = 1.23;
            switch (mount.intValue()) {
                case 1:
                    speedMod = 1.5;
                    break;
                case 2:
                    speedMod = 1.7;
                    break;
                case 3:
                    speedMod = 1.8;
                    break;
                default:
                    log.warn("Unhandeled monster riding level");
            }
        }
        localmaxbasedamage = calculateMaxBaseDamage(watk);
        if (oldmaxhp != 0 && oldmaxhp != localmaxhp) {
            updatePartyMemberHP();
        }
    }

    public void equipChanged() {
        getMap().broadcastMessage(this, MaplePacketCreator.updateCharLook(this), false);
        recalcLocalStats();
        enforceMaxHpMp();
        if (getClient().getPlayer().getMessenger() != null) {
            WorldChannelInterface wci = ChannelServer.getInstance(getClient().getChannel()).getWorldInterface();
            try {
                wci.updateMessenger(getClient().getPlayer().getMessenger().getId(), getClient().getPlayer().getName(), getClient().getChannel());
            } catch (RemoteException e) {
                getClient().getChannelServer().reconnectWorld();
            }
        }
    }

    public MaplePet getPet(int index) {
        return pets[index];
    }

    public void addPet(MaplePet pet) {
        for (int i = 0; i < 3; i++) {
            if (pets[i] == null) {
                pets[i] = pet;
                return;
            }
        }
    }

    public void removePet(MaplePet pet, boolean shift_left) {
        int slot = -1;
        for (int i = 0; i < 3; i++) {
            if (pets[i] != null) {
                if (pets[i].getUniqueId() == pet.getUniqueId()) {
                    pets[i] = null;
                    slot = i;
                    break;
                }
            }
        }
        if (shift_left) {
			if (slot > -1) {

            	for (int i = slot; i < 3; i++) {
                	if (i != 2) {
                    	pets[i] = pets[i + 1];
                	} else {
                    	pets[i] = null;
                	}
            	}
        	}
    	}
	}

    public int getNoPets() {
        int ret = 0;
        for (int i = 0; i < 3; i++) {
            if (pets[i] != null) {
                ret++;
            }
        }
        return ret;
    }

    public int getPetIndex(MaplePet pet) {
        for (int i = 0; i < 3; i++) {
            if (pets[i] != null) {
                if (pets[i].getUniqueId() == pet.getUniqueId()) {
                    return i;
                }
            }
        }
        return -1;
    }

    public int getPetIndex(int petId) {
        for (int i = 0; i < 3; i++) {
            if (pets[i] != null) {
                if (pets[i].getUniqueId() == petId) {
                    return i;
                }
            }
        }
        return -1;
    }

    public int getNextEmptyPetIndex() {
        if (pets[0] == null) {
            return 0;
        }
        if (pets[1] == null) {
            return 1;
        }
        if (pets[2] == null) {
            return 2;
        }
        return 3;
    }

    public MaplePet[] getPets() {
        return pets;
    }

    public void unequipAllPets() {
        for (int i = 0; i < 3; i++) {
            if (pets[i] != null) {
                unequipPet(pets[i], true);
            }
        }
    }

    public void unequipPet(MaplePet pet, boolean shift_left) {
        unequipPet(pet, shift_left, false);
    }

    public void unequipPet(MaplePet pet, boolean shift_left, boolean hunger) {
        cancelFullnessSchedule(getPetIndex(pet));

        pet.saveToDb();

        // Broadcast the packet to the map - with null instead of MaplePet
        getMap().broadcastMessage(this, MaplePacketCreator.showPet(this, pet, true, hunger), true);

        // Make a new list for the stat updates
        List<Pair<MapleStat, Integer>> stats = new ArrayList<Pair<MapleStat, Integer>>();
        stats.add(new Pair<MapleStat, Integer>(MapleStat.PET, Integer.valueOf(0)));

        // Write the stat update to the player...
        getClient().getSession().write(MaplePacketCreator.petStatUpdate(this));
        getClient().getSession().write(MaplePacketCreator.enableActions());

        // Un-assign the pet set to the player
        removePet(pet, shift_left);
    }

    public void shiftPetsRight() {
        if (pets[2] == null) {
            pets[2] = pets[1];
            pets[1] = pets[0];
            pets[0] = null;
        }
    }

    public FameStatus canGiveFame(MapleCharacter from) {
        if (lastfametime >= System.currentTimeMillis() - 60 * 60 * 24 * 1000) {
            return FameStatus.NOT_TODAY;
        } else if (lastmonthfameids.contains(Integer.valueOf(from.getId()))) {
            return FameStatus.NOT_THIS_MONTH;
        } else {
            return FameStatus.OK;
        }
    }

    public void hasGivenFame(MapleCharacter to) {
        lastfametime = System.currentTimeMillis();
        lastmonthfameids.add(Integer.valueOf(to.getId()));
        Connection con = DatabaseConnection.getConnection();
        try {
            PreparedStatement ps = con.prepareStatement("INSERT INTO famelog (characterid, characterid_to) VALUES (?, ?)");
            ps.setInt(1, getId());
            ps.setInt(2, to.getId());
            ps.executeUpdate();
            ps.close();
        } catch (SQLException e) {
            log.error("ERROR writing famelog for char " + getName() + " to " + to.getName(), e);
        }
    }

    public MapleParty getParty() {
        return party;
    }

	public int getPartyId() {
	    return (party != null ? party.getId() : -1);
	}
    public int getWorld() {
        return world;
    }

    public void setWorld(int world) {
        this.world = world;
    }

    public void setParty(MapleParty party) {
        this.party = party;
    }

    public MapleTrade getTrade() {
        return trade;
    }

    public void setTrade(MapleTrade trade) {
        this.trade = trade;
    }

    public EventInstanceManager getEventInstance() {
        return eventInstance;
    }

    public void setEventInstance(EventInstanceManager eventInstance) {
        this.eventInstance = eventInstance;
    }

    public void addDoor(MapleDoor door) {
        doors.add(door);
    }

    public void clearDoors() {
        doors.clear();
    }

    public List<MapleDoor> getDoors() {
        return new ArrayList<MapleDoor>(doors);
    }

    public boolean canDoor() {
        return canDoor;
    }

    public void disableDoor() {
        canDoor = false;
        TimerManager tMan = TimerManager.getInstance();
        tMan.schedule(new Runnable() {

            @Override
            public void run() {
                canDoor = true;
            }
        }, 5000);
    }

    public Map<Integer, MapleSummon> getSummons() {
        return summons;
    }

    public int getChair() {
        return chair;
    }

    public int getItemEffect() {
        return itemEffect;
    }

    public void setChair(int chair) {
        this.chair = chair;
    }

    public void setItemEffect(int itemEffect) {
        this.itemEffect = itemEffect;
    }

    @Override
    public Collection<MapleInventory> allInventories() {
        return Arrays.asList(inventory);
    }

    @Override
    public MapleMapObjectType getType() {
        return MapleMapObjectType.PLAYER;
    }

    public int getGuildId() {
        return guildid;
    }

    public int getGuildRank() {
        return guildrank;
    }

    public void setGuildId(int _id) {
        guildid = _id;
        if (guildid > 0) {
            if (mgc == null) {
                mgc = new MapleGuildCharacter(this);
            } else {
                mgc.setGuildId(guildid);
            }
        } else {
            mgc = null;
        }
    }

    public void setGuildRank(int _rank) {
        guildrank = _rank;
        if (mgc != null) {
            mgc.setGuildRank(_rank);
        }
    }

    public MapleGuildCharacter getMGC() {
        return mgc;
    }

    public void guildUpdate() {
        if (this.guildid <= 0) {
            return;
        }
        mgc.setLevel(this.level);
        mgc.setJobId(this.job.getId());

        try {
            this.client.getChannelServer().getWorldInterface().memberLevelJobUpdate(this.mgc);
        } catch (RemoteException re) {
            log.error("RemoteExcept while trying to update level/job in guild.", re);
        }
    }
    private NumberFormat nf = new DecimalFormat("#,###,###,###");

    public String guildCost() {
        return nf.format(MapleGuild.CREATE_GUILD_COST);
    }

    public String emblemCost() {
        return nf.format(MapleGuild.CHANGE_EMBLEM_COST);
    }

    public String capacityCost() {
        return nf.format(MapleGuild.INCREASE_CAPACITY_COST);
    }

    public void genericGuildMessage(int code) {
        this.client.getSession().write(MaplePacketCreator.genericGuildMessage((byte) code));
    }

    public void disbandGuild() {
        if (guildid <= 0 || guildrank != 1) {
            log.warn(this.name + " tried to disband and s/he is either not in a guild or not leader.");
            return;
        }

        try {
            client.getChannelServer().getWorldInterface().disbandGuild(this.guildid);
        } catch (Exception e) {
            log.error("Error while disbanding guild.", e);
        }
    }

    public void increaseGuildCapacity() {
        if (this.getMeso() < MapleGuild.INCREASE_CAPACITY_COST) {
            client.getSession().write(MaplePacketCreator.serverNotice(1, "You do not have enough mesos."));
            return;
        }

        if (this.guildid <= 0) {
            log.info(this.name + " is trying to increase guild capacity without being in the guild.");
            return;
        }

        try {
            client.getChannelServer().getWorldInterface().increaseGuildCapacity(this.guildid);
        } catch (Exception e) {
            log.error("Error while increasing capacity.", e);
            return;
        }

        this.gainMeso(-MapleGuild.INCREASE_CAPACITY_COST, true, false, true);
    }

    public void saveGuildStatus() {
        Connection con = DatabaseConnection.getConnection();
        try {
            PreparedStatement ps = con.prepareStatement("UPDATE characters SET guildid = ?, guildrank = ? WHERE id = ?");
            ps.setInt(1, this.guildid);
            ps.setInt(2, this.guildrank);
            ps.setInt(3, this.id);
            ps.execute();
            ps.close();
        } catch (SQLException se) {
            log.error("SQL error: " + se.getLocalizedMessage(), se);
        }
    }

    /**
     * Allows you to change someone's NXCash, Maple Points, and Gift Tokens!
     * 
     * Created by Acrylic/Penguins
     * 
     * @param type: 0 = NX, 1 = MP, 2 = GT, quantity: how much to modify it by. Negatives subtract points, Positives add points. 
     */
    public void modifyCSPoints(int type, int quantity) {
        if (type == 0) {
            this.nxcash += quantity;
        } else if (type == 1) {
            this.maplepoints += quantity;
        } else if (type == 2) {
            this.gifttokens += quantity;
        }
    }

    public int getCSPoints(int type) {
        if (type == 0) {
            return this.nxcash;
        } else if (type == 1) {
            return this.maplepoints;
        } else if (type == 2) {
            return this.gifttokens;
        } else {
            return 0;
        }
    }

    public boolean haveItem(int itemid, int quantity, boolean checkEquipped, boolean greaterOrEquals) {
        MapleInventoryType type = MapleItemInformationProvider.getInstance().getInventoryType(itemid);
        MapleInventory iv = inventory[type.ordinal()];
        int possesed = iv.countById(itemid);
        if (checkEquipped) {
            possesed += inventory[MapleInventoryType.EQUIPPED.ordinal()].countById(itemid);
        }
        if (greaterOrEquals) {
            return possesed >= quantity;
        } else {
            return possesed == quantity;
        }
    }

    private static class MapleBuffStatValueHolder {

        public MapleStatEffect effect;
        public long startTime;
        public int value;
        public ScheduledFuture<?> schedule;

        public MapleBuffStatValueHolder(MapleStatEffect effect, long startTime, ScheduledFuture<?> schedule, int value) {
            super();
            this.effect = effect;
            this.startTime = startTime;
            this.schedule = schedule;
            this.value = value;
        }
    }

    public static class MapleCoolDownValueHolder {

        public int skillId;
        public long startTime;
        public long length;
        public ScheduledFuture<?> timer;

        public MapleCoolDownValueHolder(int skillId, long startTime, long length, ScheduledFuture<?> timer) {
            super();
            this.skillId = skillId;
            this.startTime = startTime;
            this.length = length;
            this.timer = timer;
        }
    }

    public static class SkillEntry {

        public int skillevel;
        public int masterlevel;

        public SkillEntry(int skillevel, int masterlevel) {
            this.skillevel = skillevel;
            this.masterlevel = masterlevel;
        }

        @Override
        public String toString() {
            return skillevel + ":" + masterlevel;
        }
    }

    public enum FameStatus {

        OK, NOT_TODAY, NOT_THIS_MONTH
    }

    public int getBuddyCapacity() {
        return buddylist.getCapacity();
    }

    public void setBuddyCapacity(int capacity) {
        buddylist.setCapacity(capacity);
        client.getSession().write(MaplePacketCreator.updateBuddyCapacity(capacity));
    }

    public MapleMessenger getMessenger() {
        return messenger;
    }

    public void setMessenger(MapleMessenger messenger) {
        this.messenger = messenger;
    }

    public void checkMessenger() {
        if (messenger != null && messengerposition < 4 && messengerposition > -1) {
            try {
                WorldChannelInterface wci = ChannelServer.getInstance(client.getChannel()).getWorldInterface();
                MapleMessengerCharacter messengerplayer = new MapleMessengerCharacter(client.getPlayer(), messengerposition);
                wci.silentJoinMessenger(messenger.getId(), messengerplayer, messengerposition);
                wci.updateMessenger(getClient().getPlayer().getMessenger().getId(), getClient().getPlayer().getName(), getClient().getChannel());
            } catch (RemoteException e) {
                client.getChannelServer().reconnectWorld();
            }
        }
    }

    public int getMessengerPosition() {
        return messengerposition;
    }

    public void setMessengerPosition(int position) {
        this.messengerposition = position;
    }

    public int hasEXPCard() {
        return 1;
    }

    public boolean getNXCodeValid(String code, boolean validcode) throws SQLException {

        Connection con = DatabaseConnection.getConnection();
        PreparedStatement ps = con.prepareStatement("SELECT `valid` FROM nxcode WHERE code = ?");
        ps.setString(1, code);
        ResultSet rs = ps.executeQuery();
        while (rs.next()) {
            validcode = rs.getInt("valid") == 0 ? false : true;
        }

        rs.close();
        ps.close();

        return validcode;
    }

    public int getNXCodeType(String code) throws SQLException {

        int type = -1;
        Connection con = DatabaseConnection.getConnection();
        PreparedStatement ps = con.prepareStatement("SELECT `type` FROM nxcode WHERE code = ?");
        ps.setString(1, code);
        ResultSet rs = ps.executeQuery();
        while (rs.next()) {
            type = rs.getInt("type");
        }

        rs.close();
        ps.close();

        return type;
    }

    public int getNXCodeItem(String code) throws SQLException {

        int item = -1;
        Connection con = DatabaseConnection.getConnection();
        PreparedStatement ps = con.prepareStatement("SELECT `item` FROM nxcode WHERE code = ?");
        ps.setString(1, code);
        ResultSet rs = ps.executeQuery();
        while (rs.next()) {
            item = rs.getInt("item");
        }

        rs.close();
        ps.close();

        return item;
    }

    public void setNXCodeUsed(String code) throws SQLException {
        Connection con = DatabaseConnection.getConnection();
        PreparedStatement ps = con.prepareStatement("UPDATE nxcode SET `valid` = 0 WHERE code = ?");
        ps.setString(1, code);
        ps.executeUpdate();
        ps = con.prepareStatement("UPDATE nxcode SET `user` = ? WHERE code = ?");
        ps.setString(1, this.getName());
        ps.setString(2, code);
        ps.executeUpdate();
        ps.close();
    }

    public void setInCS(boolean yesno) {
        this.incs = yesno;
    }

    public boolean inCS() {
        return this.incs;
    }

    public void addCooldown(int skillId, long startTime, long length, ScheduledFuture<?> timer) {
        if (this.coolDowns.containsKey(Integer.valueOf(skillId))) {
            this.coolDowns.remove(skillId);
        }
        this.coolDowns.put(Integer.valueOf(skillId), new MapleCoolDownValueHolder(skillId, startTime, length, timer));
    }

    public void removeCooldown(int skillId) {
        if (this.coolDowns.containsKey(Integer.valueOf(skillId))) {
            this.coolDowns.remove(Integer.valueOf(skillId));
        }
    }

    public void giveCoolDowns(final List<PlayerCoolDownValueHolder> cooldowns) {
        for (PlayerCoolDownValueHolder cooldown : cooldowns) {
            int time = (int) ((cooldown.length + cooldown.startTime) - System.currentTimeMillis());
            ScheduledFuture<?> timer = TimerManager.getInstance().schedule(new CancelCooldownAction(this, cooldown.skillId), time);
            addCooldown(cooldown.skillId, System.currentTimeMillis(), time, timer);
        }

    }

    public List<PlayerCoolDownValueHolder> getAllCooldowns() {
        List<PlayerCoolDownValueHolder> ret = new ArrayList<PlayerCoolDownValueHolder>();
        for (MapleCoolDownValueHolder mcdvh : coolDowns.values()) {
            ret.add(new PlayerCoolDownValueHolder(mcdvh.skillId, mcdvh.startTime, mcdvh.length));
        }
        return ret;
    }

    public static class CancelCooldownAction implements Runnable {

        private int skillId;
        private WeakReference<MapleCharacter> target;

        public CancelCooldownAction(MapleCharacter target, int skillId) {
            this.target = new WeakReference<MapleCharacter>(target);
            this.skillId = skillId;
        }

        @Override
        public void run() {
            MapleCharacter realTarget = target.get();
            if (realTarget != null) {
                realTarget.removeCooldown(skillId);
                realTarget.getClient().getSession().write(MaplePacketCreator.skillCooldown(skillId, 0));
            }
        }
    }

    public void addDisease(MapleDisease disease) {
        this.diseases.add(disease);
    }

    public List<MapleDisease> getDiseases() {
        synchronized (diseases) {
            return Collections.unmodifiableList(diseases);
        }
    }

    public void removeDisease(MapleDisease disease) {
        synchronized (diseases) {
            if (diseases.contains(disease)) {
                diseases.remove(disease);
            }
        }
    }

    public void giveDebuff(MapleDisease disease, MobSkill skill) {
        List<Pair<MapleDisease, Integer>> disease_ = new ArrayList<Pair<MapleDisease, Integer>>();
        disease_.add(new Pair<MapleDisease, Integer>(disease, Integer.valueOf(skill.getX())));
        this.diseases.add(disease);
        getClient().getSession().write(MaplePacketCreator.giveDebuff(disease_, skill));
        getMap().broadcastMessage(this, MaplePacketCreator.giveForeignDebuff(this.id, disease_, skill), false);
    }

    public void dispelDebuffs() {
        List<MapleDisease> disease_ = new ArrayList<MapleDisease>();
        for (MapleDisease disease : diseases) {
            if (disease != MapleDisease.SEDUCE && disease != MapleDisease.SLOW) {
                disease_.add(disease);
                getClient().getSession().write(MaplePacketCreator.cancelDebuff(disease_));
                getMap().broadcastMessage(this, MaplePacketCreator.cancelForeignDebuff(this.id, disease_), false);
                disease_.clear();
            }
        }
        this.diseases.clear();
    }

    public void setLevel(int level) {
        this.level = level - 1;
    }
    //public boolean canWear(IEquip equip) {
    //	if (equip.)
    //}
    public void setMap(int PmapId) {
        this.mapid = PmapId;
    }

    public List<Integer> getQuestItemsToShow() {
        Set<Integer> delta = new HashSet<Integer>();
        for (Map.Entry<MapleQuest, MapleQuestStatus> questEntry : this.quests.entrySet()) {
            if (questEntry.getValue().getStatus() != MapleQuestStatus.Status.STARTED) {
                delta.addAll(questEntry.getKey().getQuestItemsToShowOnlyIfQuestIsActivated());
            }
        }
        List<Integer> returnThis = new ArrayList<Integer>();
        returnThis.addAll(delta);
        return Collections.unmodifiableList(returnThis);
    }

    public void sendNote(String to, String msg) throws SQLException {
        Connection con = DatabaseConnection.getConnection();
        PreparedStatement ps = con.prepareStatement("INSERT INTO notes (`to`, `from`, `message`, `timestamp`) VALUES (?, ?, ?, ?)");
        ps.setString(1, to);
        ps.setString(2, this.getName());
        ps.setString(3, msg);
        ps.setLong(4, System.currentTimeMillis());
        ps.executeUpdate();
        ps.close();
    }

    public void showNote() throws SQLException {
        Connection con = DatabaseConnection.getConnection();

        PreparedStatement ps = con.prepareStatement("SELECT * FROM notes WHERE `to`=?", ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE);
        ps.setString(1, this.getName());
        ResultSet rs = ps.executeQuery();

        rs.last();
        int count = rs.getRow();
        rs.first();

        client.getSession().write(MaplePacketCreator.showNotes(rs, count));
        ps.close();
    }

    public void deleteNote(int id) throws SQLException {
        Connection con = DatabaseConnection.getConnection();
        PreparedStatement ps = con.prepareStatement("DELETE FROM notes WHERE `id`=?");
        ps.setInt(1, id);
        ps.executeUpdate();
        ps.close();
    }
}

MapleClient:
Code:
/*
	This file is part of the OdinMS Maple Story Server
    Copyright (C) 2008 Patrick Huy <patrick.huy@frz.cc> 
                       Matthias Butz <matze@odinms.de>
                       Jan Christian Meyer <vimes@odinms.de>

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License version 3
    as published by the Free Software Foundation. You may not use, modify
    or distribute this program under any other version of the
    GNU Affero General Public License.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Affero General Public License for more details.

    You should have received a copy of the GNU Affero General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

package net.sf.odinms.client;

import java.rmi.RemoteException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.Calendar;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.concurrent.ScheduledFuture;

import javax.script.ScriptEngine;

import net.sf.odinms.client.messages.MessageCallback;
import net.sf.odinms.database.DatabaseConnection;
import net.sf.odinms.database.DatabaseException;
import net.sf.odinms.net.channel.ChannelServer;
import net.sf.odinms.server.maps.FakeCharacter;
import net.sf.odinms.net.channel.handler.SpawnPetHandler;
import net.sf.odinms.net.login.LoginServer;
import net.sf.odinms.net.world.MapleMessengerCharacter;
import net.sf.odinms.net.world.MaplePartyCharacter;
import net.sf.odinms.net.world.PartyOperation;
import net.sf.odinms.net.world.guild.MapleGuildCharacter;
import net.sf.odinms.net.world.remote.WorldChannelInterface;
import net.sf.odinms.scripting.npc.NPCScriptManager;
import net.sf.odinms.server.MapleTrade;
import net.sf.odinms.server.TimerManager;
import net.sf.odinms.tools.IPAddressTool;
import net.sf.odinms.tools.MapleAESOFB;
import net.sf.odinms.tools.MaplePacketCreator;

import org.apache.mina.common.IoSession;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class MapleClient {
	public static final int LOGIN_NOTLOGGEDIN = 0;
	public static final int LOGIN_SERVER_TRANSITION = 1;
	public static final int LOGIN_LOGGEDIN = 2;
	public static final int LOGIN_WAITING = 3;

	public static final String CLIENT_KEY = "CLIENT";
	private static final Logger log = LoggerFactory.getLogger(MapleClient.class);

	private MapleAESOFB send;
	private MapleAESOFB receive;
	private IoSession session;

	private MapleCharacter player;
	private int channel = 1;
	private int accId = 1;
	private boolean loggedIn = false;
	private boolean serverTransition = false;
	private boolean waiting = false;
	private Calendar birthday = null;
	private Calendar tempban = null;
	private String accountName;
	private int world;
	private long lastPong;
	private boolean gm;
	private byte greason = 1;

	private Set<String> macs = new HashSet<String>();
	private Map<String, ScriptEngine> engines = new HashMap<String, ScriptEngine>();
	private ScheduledFuture<?> idleTask = null;

	public MapleClient(MapleAESOFB send, MapleAESOFB receive, IoSession session) {
		this.send = send;
		this.receive = receive;
		this.session = session;
	}

	public MapleAESOFB getReceiveCrypto() {
		return receive;
	}

	public MapleAESOFB getSendCrypto() {
		return send;
	}

	public synchronized IoSession getSession() {
		return session;
	}

	public MapleCharacter getPlayer() {
		return player;
	}

	public void setPlayer(MapleCharacter player) {
		this.player = player;
	}

	public void sendCharList(int server) {
		this.session.write(MaplePacketCreator.getCharList(this, server));
	}

	public List<MapleCharacter> loadCharacters(int serverId) { // TODO make
																// this less
																// costly zZz
		List<MapleCharacter> chars = new LinkedList<MapleCharacter>();
		for (CharNameAndId cni : loadCharactersInternal(serverId)) {
			try {
				chars.add(MapleCharacter.loadCharFromDB(cni.id, this, false));
			} catch (SQLException e) {
				log.error("Loading characters failed", e);
			}
		}
		return chars;
	}

	public List<String> loadCharacterNames(int serverId) {
		List<String> chars = new LinkedList<String>();
		for (CharNameAndId cni : loadCharactersInternal(serverId)) {
			chars.add(cni.name);
		}
		return chars;
	}

	private List<CharNameAndId> loadCharactersInternal(int serverId) {
		Connection con = DatabaseConnection.getConnection();
		PreparedStatement ps;
		List<CharNameAndId> chars = new LinkedList<CharNameAndId>();
		try {
			ps = con.prepareStatement("SELECT id, name FROM characters WHERE accountid = ? AND world = ?");
			ps.setInt(1, this.accId);
			ps.setInt(2, serverId);

			ResultSet rs = ps.executeQuery();
			while (rs.next()) {
				chars.add(new CharNameAndId(rs.getString("name"), rs.getInt("id")));
			}
			rs.close();
			ps.close();
		} catch (SQLException e) {
			log.error("THROW", e);
		}
		return chars;
	}

	public boolean isLoggedIn() {
		return loggedIn;
	}

	private Calendar getTempBanCalendar(ResultSet rs) throws SQLException {
		Calendar lTempban = Calendar.getInstance();
		long blubb = rs.getLong("tempban");
		if (blubb == 0) { // basically if timestamp in db is 0000-00-00
			lTempban.setTimeInMillis(0);
			return lTempban;
		}
		Calendar today = Calendar.getInstance();
		lTempban.setTimeInMillis(rs.getTimestamp("tempban").getTime());
		if (today.getTimeInMillis() < lTempban.getTimeInMillis()) {
			return lTempban;
		}

		lTempban.setTimeInMillis(0);
		return lTempban;
	}
	
	public Calendar getTempBanCalendar() {
		return tempban;
	}

	public byte getBanReason() {
		return greason;
	}

	public boolean hasBannedIP() {
		boolean ret = false;
		try {
			Connection con = DatabaseConnection.getConnection();
			PreparedStatement ps = con.prepareStatement("SELECT COUNT(*) FROM ipbans WHERE ? LIKE CONCAT(ip, '%')");
			ps.setString(1, session.getRemoteAddress().toString());
			ResultSet rs = ps.executeQuery();
			rs.next();
			if (rs.getInt(1) > 0) {
				ret = true;
			}
			rs.close();
			ps.close();
		} catch (SQLException ex) {
			log.error("Error checking ip bans", ex);
		}
		return ret;
	}

	public boolean hasBannedMac() {
		if (macs.isEmpty())
			return false;
		boolean ret = false;
		int i = 0;
		try {
			Connection con = DatabaseConnection.getConnection();
			StringBuilder sql = new StringBuilder("SELECT COUNT(*) FROM macbans WHERE mac IN (");
			for (i = 0; i < macs.size(); i++) {
				sql.append("?");
				if (i != macs.size() - 1)
					sql.append(", ");
			}
			sql.append(")");
			PreparedStatement ps = con.prepareStatement(sql.toString());
			i = 0;
			for (String mac : macs) {
				i++;
				ps.setString(i, mac);
			}
			ResultSet rs = ps.executeQuery();
			rs.next();
			if (rs.getInt(1) > 0) {
				ret = true;
			}
			rs.close();
			ps.close();
		} catch (SQLException ex) {
			log.error("Error checking mac bans", ex);
		}
		return ret;
	}

	private void loadMacsIfNescessary() throws SQLException {
		if (macs.isEmpty()) {
			Connection con = DatabaseConnection.getConnection();
			PreparedStatement ps = con.prepareStatement("SELECT macs FROM accounts WHERE id = ?");
			ps.setInt(1, accId);
			ResultSet rs = ps.executeQuery();
			if (rs.next()) {
				String[] macData = rs.getString("macs").split(", ");
				for (String mac : macData) {
					if (!mac.equals("")) {
						macs.add(mac);
					}
				}
			} else {
				throw new RuntimeException("No valid account associated with this client.");
			}
			rs.close();
			ps.close();
		}
	}

	public void banMacs() {
		Connection con = DatabaseConnection.getConnection();
		try {
			loadMacsIfNescessary();
			List<String> filtered = new LinkedList<String>();
			PreparedStatement ps = con.prepareStatement("SELECT filter FROM macfilters");
			ResultSet rs = ps.executeQuery();
			while (rs.next()) {
				filtered.add(rs.getString("filter"));
			}
			rs.close();
			ps.close();
			ps = con.prepareStatement("INSERT INTO macbans (mac) VALUES (?)");
			for (String mac : macs) {
				boolean matched = false;
				for (String filter : filtered) {
					if (mac.matches(filter)) {
						matched = true;
						break;
					}
				}
				if (!matched) {
					ps.setString(1, mac);
					try {
						ps.executeUpdate();
					} catch (SQLException e) {
						// can fail because of UNIQUE key, we dont care
					}
				}
			}
			ps.close();
		} catch (SQLException e) {
			log.error("Error banning MACs", e);
		}
	}

	/**
	 * Returns 0 on success, a state to be used for
	 * {@link MaplePacketCreator#getLoginFailed(int)} otherwise.
	 * 
	 * @param success
	 * @return The state of the login.
	 */
	public int finishLogin(boolean success) {
		if (success) {
			synchronized (MapleClient.class) {
				if (getLoginState() > MapleClient.LOGIN_NOTLOGGEDIN && getLoginState() != MapleClient.LOGIN_WAITING) { // already
																		// loggedin
					loggedIn = false;
					return 7;
				}
				updateLoginState(MapleClient.LOGIN_LOGGEDIN);
			}
			return 0;
		} else {
			return 10;
		}
	}

	public int login(String login, String pwd, boolean ipMacBanned) {
		int loginok = 5;
		Connection con = DatabaseConnection.getConnection();
		try {
			PreparedStatement ps = con
				.prepareStatement("SELECT id,password,salt,tempban,banned,gm,macs,greason FROM accounts WHERE name = ?");
			ps.setString(1, login);
			ResultSet rs = ps.executeQuery();
			if (rs.next()) {
				int banned = rs.getInt("banned");
				accId = rs.getInt("id");
				int igm = rs.getInt("gm");
				String passhash = rs.getString("password");
				String salt = rs.getString("salt");
				gm = igm > 0;
				greason = rs.getByte("greason");
				tempban = getTempBanCalendar(rs);
				if ((banned == 0 && !ipMacBanned) || banned == -1) {
					PreparedStatement ips = con.prepareStatement("INSERT INTO iplog (accountid, ip) VALUES (?, ?)");
					ips.setInt(1, accId);
					String sockAddr = session.getRemoteAddress().toString();
					ips.setString(2, sockAddr.substring(1, sockAddr.lastIndexOf(':')));
					ips.executeUpdate();
					ips.close();
				}

				// do NOT track ALL mac addresses ever used
				/*String[] macData = rs.getString("macs").split(", ");
				for (String mac : macData) {
					if (!mac.equals(""))
						macs.add(mac);
				}*/
				ps.close();
				// if (gm > 0) {
				// session.write(MaplePacketCreator.getAuthSuccessRequestPin(getAccountName()));
				// return finishLogin(true);
				// }
				if (banned == 1) {
					loginok = 3;
				} else {
					// this is to simplify unbanning
					// all known ip and mac bans associated with the current
					// client
					// will be deleted
					if (banned == -1)
						unban();
					if (getLoginState() > MapleClient.LOGIN_NOTLOGGEDIN) { // already
																			// loggedin
						loggedIn = false;
						loginok = 7;
					} else {
						boolean updatePasswordHash = false;
						// Check if the passwords are correct here. :B
						if (LoginCryptoLegacy.isLegacyPassword(passhash) && LoginCryptoLegacy.checkPassword(pwd, passhash)) {
							// Check if a password upgrade is needed.
							loginok = 0;
							updatePasswordHash = true;
						} else if (salt == null && LoginCrypto.checkSha1Hash(passhash, pwd)) {
							loginok = 0;
							updatePasswordHash = true;
						} else if (LoginCrypto.checkSaltedSha512Hash(passhash, pwd, salt)) {
							loginok = 0;
						} else {
							loggedIn = false;
							loginok = 4;
						}
						if (updatePasswordHash) {
							PreparedStatement pss = con.prepareStatement("UPDATE `accounts` SET `password` = ?, `salt` = ? WHERE id = ?");
							try {
								String newSalt = LoginCrypto.makeSalt();
								pss.setString(1, LoginCrypto.makeSaltedSha512Hash(pwd, newSalt));
								pss.setString(2, newSalt);
								pss.setInt(3, accId);
								pss.executeUpdate();
							} finally {
								pss.close();
							}
						}
					}
				}
			}
			rs.close();
			ps.close();
		} catch (SQLException e) {
			log.error("ERROR", e);
		}
		return loginok;
	}
	
	/**
	 * Gets the special server IP if the client matches a certain subnet.
	 * 
	 * @param subnetInfo A <code>Properties</code> instance containing all the subnet info.
	 * @param clientIPAddress The IP address of the client as a dotted quad.
	 * @param channel The requested channel to match with the subnet.
	 * @return <code>0.0.0.0</code> if no subnet matched, or the IP if the subnet matched.
	 */
	public static String getChannelServerIPFromSubnet(String clientIPAddress, int channel) {
		long ipAddress = IPAddressTool.dottedQuadToLong(clientIPAddress);
		Properties subnetInfo = LoginServer.getInstance().getSubnetInfo();
		
		if(subnetInfo.contains("net.sf.odinms.net.login.subnetcount")) {
			int subnetCount = Integer.parseInt(subnetInfo.getProperty("net.sf.odinms.net.login.subnetcount"));
			for(int i = 0; i < subnetCount; i++) {
				String[] connectionInfo = subnetInfo.getProperty("net.sf.odinms.net.login.subnet." + i).split(":");
				long subnet = IPAddressTool.dottedQuadToLong(connectionInfo[0]);
				long channelIP = IPAddressTool.dottedQuadToLong(connectionInfo[1]);
				int channelNumber = Integer.parseInt(connectionInfo[2]);
	
				if(((ipAddress & subnet) == (channelIP & subnet)) && (channel == channelNumber)) {
					return connectionInfo[1];
				}
			}
		}
		
		return "0.0.0.0";
	}

	private void unban() {
		int i;
		try {
			Connection con = DatabaseConnection.getConnection();
			loadMacsIfNescessary();
			StringBuilder sql = new StringBuilder("DELETE FROM macbans WHERE mac IN (");
			for (i = 0; i < macs.size(); i++) {
				sql.append("?");
				if (i != macs.size() - 1)
					sql.append(", ");
			}
			sql.append(")");
			PreparedStatement ps = con.prepareStatement(sql.toString());
			i = 0;
			for (String mac : macs) {
				i++;
				ps.setString(i, mac);
			}
			ps.executeUpdate();
			ps.close();
			ps = con.prepareStatement("DELETE FROM ipbans WHERE ip LIKE CONCAT(?, '%')");
			ps.setString(1, getSession().getRemoteAddress().toString().split(":")[0]);
			ps.executeUpdate();
			ps.close();
			ps = con.prepareStatement("UPDATE accounts SET banned = 0 WHERE id = ?");
			ps.setInt(1, accId);
			ps.executeUpdate();
			ps.close();
		} catch (SQLException e) {
			log.error("Error while unbanning", e);
		}
	}

	public void updateMacs(String macData) {
		for (String mac : macData.split(", ")) {
			macs.add(mac);
		}
		StringBuilder newMacData = new StringBuilder();
		Iterator<String> iter = macs.iterator();
		while (iter.hasNext()) {
			String cur = iter.next();
			newMacData.append(cur);
			if (iter.hasNext())
				newMacData.append(", ");
		}
		Connection con = DatabaseConnection.getConnection();
		try {
			PreparedStatement ps = con.prepareStatement("UPDATE accounts SET macs = ? WHERE id = ?");
			ps.setString(1, newMacData.toString());
			ps.setInt(2, accId);
			ps.executeUpdate();
			ps.close();
		} catch (SQLException e) {
			log.error("Error saving MACs", e);
		}
	}

	public void setAccID(int id) {
		this.accId = id;
	}

	public int getAccID() {
		return this.accId;
	}

	public void updateLoginState(int newstate) { // TODO hide?
		Connection con = DatabaseConnection.getConnection();
		try {
			PreparedStatement ps = con
				.prepareStatement("UPDATE accounts SET loggedin = ?, lastlogin = CURRENT_TIMESTAMP() WHERE id = ?");
			ps.setInt(1, newstate);
			ps.setInt(2, getAccID());
			ps.executeUpdate();
			ps.close();
		} catch (SQLException e) {
			log.error("ERROR", e);
		}
		if (newstate == MapleClient.LOGIN_NOTLOGGEDIN) {
			loggedIn = false;
			serverTransition = false;
		} else if (newstate == MapleClient.LOGIN_WAITING) {
			loggedIn = false;
			serverTransition = false;
		} else {
			serverTransition = (newstate == MapleClient.LOGIN_SERVER_TRANSITION);
			loggedIn = !serverTransition;
		}
	}

	public int getLoginState() { // TODO hide?
		Connection con = DatabaseConnection.getConnection();
		try {
			PreparedStatement ps;
			ps = con.prepareStatement("SELECT loggedin, lastlogin, UNIX_TIMESTAMP(birthday) as birthday FROM accounts WHERE id = ?");
			ps.setInt(1, getAccID());
			ResultSet rs = ps.executeQuery();
			if (!rs.next()) {
				ps.close();
				throw new DatabaseException("Everything sucks");
			}
			birthday = Calendar.getInstance();
			long blubb = rs.getLong("birthday");
			if (blubb > 0) {
				birthday.setTimeInMillis(blubb * 1000);
			}
			int state = rs.getInt("loggedin");
			if (state == MapleClient.LOGIN_SERVER_TRANSITION) {
				Timestamp ts = rs.getTimestamp("lastlogin");
				long t = ts.getTime();
				long now = System.currentTimeMillis();
				if (t + 30000 < now) { // connecting to chanserver timeout
					state = MapleClient.LOGIN_NOTLOGGEDIN;
					updateLoginState(MapleClient.LOGIN_NOTLOGGEDIN);
				}
			}
			rs.close();
			ps.close();
			if (state == MapleClient.LOGIN_LOGGEDIN) {
				loggedIn = true;
			} else {
				loggedIn = false;
			}
			return state;
		} catch (SQLException e) {
			loggedIn = false;
			log.error("ERROR", e);
			throw new DatabaseException("Everything sucks", e);
		}
	}

	public boolean checkBirthDate(Calendar date) {
		if (date.get(Calendar.YEAR) == birthday.get(Calendar.YEAR) &&
			date.get(Calendar.MONTH) == birthday.get(Calendar.MONTH) &&
			date.get(Calendar.DAY_OF_MONTH) == birthday.get(Calendar.DAY_OF_MONTH)) {
			return true;
		}
		return false;
	}

	public void disconnect() {
		// pingTask.cancel(true);
		MapleCharacter chr = this.getPlayer();
		if (chr != null && isLoggedIn()) {
                    if(chr.hasFakeChar())
                    {
                        for (FakeCharacter ch : chr.getFakeChars()) {
                            ch.getFakeChar().getMap().removePlayer(ch.getFakeChar());
                        }
                    }

                    if (chr.getTrade() != null) {
                      MapleTrade.cancelTrade(chr);
                    }
                    chr.cancelAllBuffs();
                    if (chr.getEventInstance() != null) {
                      chr.getEventInstance().playerDisconnected(chr);
                    }

                    try {
                      WorldChannelInterface wci = getChannelServer().getWorldInterface();
                      if (chr.getMessenger() != null) {
                        MapleMessengerCharacter messengerplayer = new MapleMessengerCharacter(chr);
                        wci.leaveMessenger(chr.getMessenger().getId(), messengerplayer);
                        chr.setMessenger(null);
                      }
                    }
                    catch (RemoteException e) {
                      getChannelServer().reconnectWorld();
                    }
                    
                    getPlayer().unequipAllPets();

                    int returnMapId = -1;
                    if (!chr.isAlive()) {
                      chr.setHp(50, true);
                      returnMapId = chr.getMap().getReturnMapId();
                    }
                    
                    int forcedReturnID = chr.getMap().getForcedReturnId();
                    if (forcedReturnID != 999999999 && forcedReturnID != chr.getMap().getId()) {
                      //chr.saveToDB(true, forcedReturnID);
                      returnMapId = forcedReturnID;
                    }

                    if(returnMapId > -1)
                      chr.saveToDB(true, returnMapId);
                    else
                      chr.saveToDB(true);

                    chr.setMessenger(null);
                    chr.getCheatTracker().dispose();
                    //chr.saveToDB(true);
                    chr.getMap().removePlayer(chr);

                    try {
                      WorldChannelInterface wci = getChannelServer().getWorldInterface();
                      if (chr.getParty() != null) {
                        MaplePartyCharacter chrp = new MaplePartyCharacter(chr);
                        chrp.setOnline(false);
                        wci.updateParty(chr.getParty().getId(), PartyOperation.LOG_ONOFF, chrp);
                      }
                      if (!this.serverTransition && isLoggedIn())
                        wci.loggedOff(chr.getName(), chr.getId(), channel, chr.getBuddylist().getBuddyIds());
                      else //Change channel
                        wci.loggedOn(chr.getName(), chr.getId(), channel, chr.getBuddylist().getBuddyIds());
                      //We can also use the loggedOn function for CC.
                      //To create a function with another name that does exactly the same is bloated

                      if (chr.getGuildId() > 0)
                      wci.setGuildMemberOnline(chr.getMGC(), false, -1);
                    } catch (RemoteException e) {
                      getChannelServer().reconnectWorld();
                    } catch (Exception e) {
                      log.error(getLogMessage(this, "ERROR"), e);
                    } finally {
                      if (getChannelServer() != null)
                        getChannelServer().removePlayer(chr);
                      else
                        log.error(getLogMessage(this, "No channelserver associated to char {}", chr.getName()));
                    }
                }
                
		if (!this.serverTransition && isLoggedIn()) {
			this.updateLoginState(MapleClient.LOGIN_NOTLOGGEDIN);
		}
		NPCScriptManager npcsm = NPCScriptManager.getInstance();
		if (npcsm != null) {
			npcsm.dispose(this);
		}
     }

	public void dropDebugMessage(MessageCallback mc) {
		StringBuilder builder = new StringBuilder();
		builder.append("Connected: ");
		builder.append(getSession().isConnected());
		builder.append(" Closing: ");
		builder.append(getSession().isClosing());
		builder.append(" ClientKeySet: ");
		builder.append(getSession().getAttribute(MapleClient.CLIENT_KEY) != null);
		builder.append(" loggedin: ");
		builder.append(isLoggedIn());
		builder.append(" has char: ");
		builder.append(getPlayer() != null);
		mc.dropMessage(builder.toString());
	}

	/**
	 * Undefined when not logged to a channel
	 * 
	 * @return the channel the client is connected to
	 */
	public int getChannel() {
		return channel;
	}

	/**
	 * Convinence method to get the ChannelServer object this client is logged
	 * on to.
	 * 
	 * @return The ChannelServer instance of the client.
	 */
	public ChannelServer getChannelServer() {
		return ChannelServer.getInstance(getChannel());
	}

	public boolean deleteCharacter(int cid) {
		Connection con = DatabaseConnection.getConnection();
		try {
			PreparedStatement ps = con.prepareStatement("SELECT id, guildid, guildrank, name FROM characters WHERE id = ? AND accountid = ?");
			ps.setInt(1, cid);
			ps.setInt(2, accId);
			ResultSet rs = ps.executeQuery();
			if (!rs.next()) {
				rs.close();
				ps.close();
				return false;
			}
			if (rs.getInt("guildid") > 0) // is in a guild when deleted
			{
				MapleGuildCharacter mgc = new MapleGuildCharacter(cid, 0, rs.getString("name"), -1, 0, rs.getInt("guildrank"), rs.getInt("guildid"), false);
				try {
					LoginServer.getInstance().getWorldInterface().deleteGuildCharacter(mgc);
				} catch (RemoteException re) {
					log.error("Unable to remove member from guild list.");
					return false;
				}
			}
			rs.close();
			ps.close();
			// ok this is actually our character, delete it
			ps = con.prepareStatement("DELETE FROM characters WHERE id = ?");
			ps.setInt(1, cid);
			ps.executeUpdate();
			ps.close();
			return true;
		} catch (SQLException e) {
			log.error("ERROR", e);
		}
		return false;
	}

	public String getAccountName() {
		return accountName;
	}

	public void setAccountName(String accountName) {
		this.accountName = accountName;
	}

	public void setChannel(int channel) {
		this.channel = channel;
	}

	public int getWorld() {
		return world;
	}

	public void setWorld(int world) {
		this.world = world;
	}

	public void pongReceived() {
		lastPong = System.currentTimeMillis();
	}

	public void sendPing() {
		final long then = System.currentTimeMillis();
		getSession().write(MaplePacketCreator.getPing());
		TimerManager.getInstance().schedule(new Runnable() {
			@Override
			public void run() {
				try {
					if (lastPong - then < 0) {
						if (getSession().isConnected()) {
							log.info(getLogMessage(MapleClient.this, "Autodc"));
							getSession().close();
						}
					}
				} catch (NullPointerException e) {
					// client already gone
				}
			}
		}, 15000); // note: idletime gets added to this too
	}

	public static String getLogMessage(MapleClient cfor, String message) {
		return getLogMessage(cfor, message, new Object[0]);
	}

	public static String getLogMessage(MapleCharacter cfor, String message) {
		return getLogMessage(cfor == null ? null : cfor.getClient(), message);
	}

	public static String getLogMessage(MapleCharacter cfor, String message, Object... parms) {
		return getLogMessage(cfor == null ? null : cfor.getClient(), message, parms);
	}

	public static String getLogMessage(MapleClient cfor, String message, Object... parms) {
		StringBuilder builder = new StringBuilder();
		if (cfor != null) {
			if (cfor.getPlayer() != null) {
				builder.append("<");
				builder.append(MapleCharacterUtil.makeMapleReadable(cfor.getPlayer().getName()));
				builder.append(" (cid: ");
				builder.append(cfor.getPlayer().getId());
				builder.append(")> ");
			}
			if (cfor.getAccountName() != null) {
				builder.append("(Account: ");
				builder.append(MapleCharacterUtil.makeMapleReadable(cfor.getAccountName()));
				builder.append(") ");
			}
		}
		builder.append(message);
		for (Object parm : parms) {
			int start = builder.indexOf("{}");
			builder.replace(start, start + 2, parm.toString());
		}
		return builder.toString();
	}

	public static int findAccIdForCharacterName(String charName) {
		Connection con = DatabaseConnection.getConnection();
	
		try {
			PreparedStatement ps = con.prepareStatement("SELECT accountid FROM characters WHERE name = ?");
			ps.setString(1, charName);
			ResultSet rs = ps.executeQuery();
			
			int ret = -1;
			if (rs.next()) {
				ret = rs.getInt("accountid");
			}
			return ret;
		} catch (SQLException e) {
			log.error("SQL THROW");
		}
		return -1;
	}
	
	public Set<String> getMacs() {
		return Collections.unmodifiableSet(macs);
	}

	public boolean isGm() {
		return gm;
	}

	public void setScriptEngine(String name, ScriptEngine e) {
		engines.put(name, e);
	}

	public ScriptEngine getScriptEngine(String name) {
		return engines.get(name);
	}

	public void removeScriptEngine(String name) {
		engines.remove(name);
	}

	public ScheduledFuture<?> getIdleTask() {
		return idleTask;
	}

	public void setIdleTask(ScheduledFuture<?> idleTask) {
		this.idleTask = idleTask;
	}

	private static class CharNameAndId {
		public String name;
		public int id;

		public CharNameAndId(String name, int id) {
			super();
			this.name = name;
			this.id = id;
		}
	}
}

FacialExpressionHandler:
Code:
/*
	This file is part of the OdinMS Maple Story Server
    Copyright (C) 2008 Patrick Huy <patrick.huy@frz.cc> 
                       Matthias Butz <matze@odinms.de>
                       Jan Christian Meyer <vimes@odinms.de>

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License version 3
    as published by the Free Software Foundation. You may not use, modify
    or distribute this program under any other version of the
    GNU Affero General Public License.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Affero General Public License for more details.

    You should have received a copy of the GNU Affero General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package net.sf.odinms.net.channel.handler;

import net.sf.odinms.client.MapleClient;
import net.sf.odinms.client.MapleInventory;
import net.sf.odinms.client.MapleInventoryType;
import net.sf.odinms.server.maps.FakeCharacter;
import net.sf.odinms.client.anticheat.CheatingOffense;
import net.sf.odinms.net.AbstractMaplePacketHandler;
import net.sf.odinms.server.MapleItemInformationProvider;
import net.sf.odinms.tools.MaplePacketCreator;
import net.sf.odinms.tools.data.input.SeekableLittleEndianAccessor;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class FaceExpressionHandler extends AbstractMaplePacketHandler {
	private static Logger log = LoggerFactory.getLogger(FaceExpressionHandler.class);

	@Override
	public void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
		int emote = slea.readInt();
		if (emote > 7) {
			int emoteid = 5159992 + emote;
			MapleInventoryType type = MapleItemInformationProvider.getInstance().getInventoryType(emoteid);
			MapleInventory iv = c.getPlayer().getInventory(type);
			if (iv.findById(emoteid) == null) {
				log.info("[h4x] Player {} is using a face expression he does not have: {}", c.getPlayer().getName(), Integer.valueOf(emoteid));
				c.getPlayer().getCheatTracker().registerOffense(CheatingOffense.USING_UNAVAILABLE_ITEM, Integer.toString(emoteid));
				return;
			}
		}
		c.getPlayer().getMap().broadcastMessage(c.getPlayer(), MaplePacketCreator.facialExpression(c.getPlayer(), emote), false);
                for (FakeCharacter ch : c.getPlayer().getFakeChars()) {
                    c.getPlayer().getMap().broadcastMessage(ch.getFakeChar(), MaplePacketCreator.facialExpression(ch.getFakeChar(), emote), false);
                }

	}
}

CloseRangeDamageHandler:
Code:
/*
	This file is part of the OdinMS Maple Story Server
    Copyright (C) 2008 Patrick Huy <patrick.huy@frz.cc> 
                       Matthias Butz <matze@odinms.de>
                       Jan Christian Meyer <vimes@odinms.de>

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License version 3
    as published by the Free Software Foundation. You may not use, modify
    or distribute this program under any other version of the
    GNU Affero General Public License.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Affero General Public License for more details.

    You should have received a copy of the GNU Affero General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

package net.sf.odinms.net.channel.handler;

import java.util.concurrent.ScheduledFuture;
import net.sf.odinms.client.ISkill;
import net.sf.odinms.client.MapleBuffStat;
import net.sf.odinms.client.MapleCharacter;
import net.sf.odinms.client.MapleCharacter.CancelCooldownAction;
import net.sf.odinms.client.MapleClient;
import net.sf.odinms.client.MapleStat;
import net.sf.odinms.server.maps.FakeCharacter;
import net.sf.odinms.client.SkillFactory;
import net.sf.odinms.net.MaplePacket;
import net.sf.odinms.server.MapleStatEffect;
import net.sf.odinms.server.TimerManager;
import net.sf.odinms.tools.MaplePacketCreator;
import net.sf.odinms.tools.data.input.SeekableLittleEndianAccessor;

public class CloseRangeDamageHandler extends AbstractDealDamageHandler {
	private boolean isFinisher(int skillId) {
		return skillId >= 1111003 && skillId <= 1111006;
	}
	
	@Override
	public void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
		// attack 15 monsters *_*
		// 23 00 03 F1 29 4F 4C 00' 00 AA 01 04' 81 1C 5D 00' 04 00 00 00' 06 80 01 01' F7 02 D7 00' FA 02 D7 00' 6A 03'
		// 22 14 00 00 0A 00 00 00 06 00 00 01 FB 02 D7 00 F8 02 D7 00 B0 03 A4 13 00 00 0C 00 00 00 06 80 04 01 C4 02
		// AB FF C6 02 AB FF F6 03 10 14 00 00 0F 00 00 00 06 80 01 01 B7 02 AB FF B9 02 AB FF 3C 04 29 14 00 00 00 00
		// 00 00 06 80 00 01 B4 02 D7 00 B6 02 D7 00 82 04 1B 14 00 00 02 00 00 00 06 80 00 01 7E 02 D7 00 80 02 D7 00
		// 82 04 15 14 00 00 01 00 00 00 06 80 02 01 6F 02 D7 00 71 02 D7 00 82 04 BE 14 00 00 0D 00 00 00 06 80 00 01
		// 69 02 AB FF 6B 02 AB FF 82 04 E4 13 00 00 05 00 00 00 06 80 02 01 5E 02 D7 00 60 02 D7 00 82 04 B5 13 00 00
		// 09 00 00 00 06 80 03 01 50 02 D7 00 52 02 D7 00 82 04 05 14 00 00 08 00 00 00 06 80 03 01 3D 02 D7 00 3F 02
		// D7 00 82 04 61 14 00 00 06 00 00 00 06 80 02 01 3C 02 D7 00 3E 02 D7 00 82 04 90 14 00 00 03 00 00 00 06 80
		// 00 01 42 02 D7 00 44 02 D7 00 82 04 E0 13 00 00 0B 00 00 00 06 00 03 01 37 02 D7 00 33 02 D7 00 82 04 7B 14
		// 00 00 07 00 00 00 06 00 01 01 21 02 D7 00 20 02 D7 00 82 04 DC 13 00 00 9C 02 27 00
		// attack CC CC CC CC mm
		// 23 00 03 11 00 00 00 00' 00 06 01 04' 91 EA 4E 00' CC CC CC CC' 06 80 04 01' B3 FD D7 00' B7 FD D7 00' 89 01'
		// 01 00 00 00 38 FD D7 00
		// attack one monster again
		// 23 00 03 11 00 00 00 00' 00 05 01 04' 41 AE 65 00' 24 00 00 00' 06 81 00 01' 04 00 BB FE' 04 00 BB FE' 89 01'
		// 0F 02 00 00 B5 FF 9C FE
		// attack air
		// 23 00 03 01 00 00 00 00' 00 90 01 04' DB 82 A9 00' FB FC D7 00
		// attack air again
		// 23 00 03 01 00 00 00 00' 00 05 01 04' E9 0B 60 00' 42 02 AB FF
		// 26 00 01 1F 3E 41 40 00' 00 B8 01 04' AD 86 EF' 11 01 CF 5F 00 06 80 00 03 56 FE 3E 00 54 FE 3E 00 0F 3C 01 00 00 0E 01 00 00 F3 00 00 00 4A 01 00 00 4E 01 00 00 D6 00 00 00 0C 01 00 00 3C 01 00 00 0E 01 00 00 F3 00 00 00 4A 01 00 00 4E 01 00 00 D6 00 00 00 0C 01 00 00 3C 01 00 00 02 FF 3E 00 13 5A 21 00 00 01 5B 21 00 00 01 5C 21 00 00 01 5D 21 00 00 01 5E 21 00 00 01 5F 21 00 00 01 60 21 00 00 01 61 21 00 00 01 62 21 00 00 01 63 21 00 00 01 64 21 00 00 01 65 21 00 00 01 66 21 00 00 01 67 21 00 00 01 68 21 00 00 01 69 21 00 00 00 6A 21 00 00 00 6B 21 00 00 00 6C 21 00 00 00 63 02
		// 26 00 01 00 3E 41 40 00' 00 B8 01 04' D9 47 E4' 11 2B FF 3E 00 14 C4 1F 00 00 00 B2 1F 00 00 00 BA 1F 00 00 00 B9 1F 00 00 00 C6 1F 00 00 00 BD 1F 00 00 00 BF 1F 00 00 00 C5 1F 00 00 00 B4 1F 00 00 00 BC 1F 00 00 00 B1 1F 00 00 00 BB 1F 00 00 00 B7 1F 00 00 00 C3 1F 00 00 00 C2 1F 00 00 00 B6 1F 00 00 00 BE 1F 00 00 00 B5 1F 00 00 00 B8 1F 00 00 00 C1 1F 00 00 00 63 02
		// seems to contain a list of things that get damaged <3
		
		AttackInfo attack = parseDamage(slea, false);
		MapleCharacter player = c.getPlayer();
		
		MaplePacket packet = MaplePacketCreator.closeRangeAttack(player.getId(), attack.skill, attack.stance,
			attack.numAttackedAndDamage, attack.allDamage, attack.speed);
		player.getMap().broadcastMessage(player, packet, false, true);
		// MaplePacket packet = MaplePacketCreator.closeRangeAttack(30000, attack.skill, attack.stance,
		// attack.numAttackedAndDamage, attack.allDamage);
		// player.getMap().broadcastMessage(player, packet, true);

		// handle combo orbconsume
		int numFinisherOrbs = 0;
		Integer comboBuff = player.getBuffedValue(MapleBuffStat.COMBO);
		if (isFinisher(attack.skill)) {
			if (comboBuff != null) {
				numFinisherOrbs = comboBuff.intValue() - 1; 
			}
			player.handleOrbconsume();
		} else if (attack.numAttacked > 0 && comboBuff != null) {
			// handle combo orbgain
			if (attack.skill != 1111008) { // shout should not give orbs
				player.handleOrbgain();
			}
		}

		// handle sacrifice hp loss
		if(attack.numAttacked > 0 && attack.skill == 1311005) {
			int totDamageToOneMonster = attack.allDamage.get(0).getRight().get(0).intValue(); // sacrifice attacks only 1 mob with 1 attack
			player.setHp(player.getHp() - totDamageToOneMonster * attack.getAttackEffect(player).getX() / 100);
			player.updateSingleStat(MapleStat.HP, player.getHp());
		}

		// handle charged blow
		if (attack.numAttacked > 0 && attack.skill == 1211002) {
			boolean advcharge_prob = false;
			int advcharge_level = player.getSkillLevel(SkillFactory.getSkill(1220010));
			if (advcharge_level > 0) {
				MapleStatEffect advcharge_effect = SkillFactory.getSkill(1220010).getEffect(advcharge_level);
				advcharge_prob = advcharge_effect.makeChanceResult();
			} else {
				advcharge_prob = false;
			}
			if (!advcharge_prob) {
				player.cancelEffectFromBuffStat(MapleBuffStat.WK_CHARGE);
			}
		}
		
		int maxdamage = c.getPlayer().getCurrentMaxBaseDamage();
		int attackCount = 1;
		if (attack.skill != 0) {
			MapleStatEffect effect = attack.getAttackEffect(c.getPlayer());
			attackCount = effect.getAttackCount();
			maxdamage *= effect.getDamage() / 100.0;
			maxdamage *= attackCount;
		}
		maxdamage = Math.min(maxdamage, 99999);
		if (attack.skill == 4211006) {
			maxdamage = 700000;
		} else if (numFinisherOrbs > 0) {
			maxdamage *= numFinisherOrbs;
		} else if (comboBuff != null) {
			ISkill combo = SkillFactory.getSkill(1111002);
			int comboLevel = player.getSkillLevel(combo);
			MapleStatEffect comboEffect = combo.getEffect(comboLevel);
			double comboMod = 1.0 + (comboEffect.getDamage() / 100.0 - 1.0) * (comboBuff.intValue() - 1);
			maxdamage *= comboMod;
		}
		if (numFinisherOrbs == 0 && isFinisher(attack.skill)) {
			return; // can only happen when lagging o.o
		}
		if (isFinisher(attack.skill)) {
			maxdamage = 99999; // FIXME reenable damage calculation for finishers
		}
		if (attack.skill > 0) {
			ISkill skill = SkillFactory.getSkill(attack.skill);
			int skillLevel = c.getPlayer().getSkillLevel(skill);
			MapleStatEffect effect_ = skill.getEffect(skillLevel);
			if (effect_.getCooldown() > 0) {
				c.getSession().write(MaplePacketCreator.skillCooldown(attack.skill, effect_.getCooldown()));
				ScheduledFuture<?> timer = TimerManager.getInstance().schedule(new CancelCooldownAction(c.getPlayer(), attack.skill), effect_.getCooldown() * 1000);
				c.getPlayer().addCooldown(attack.skill, System.currentTimeMillis(), effect_.getCooldown() * 1000, timer);
			}
		}
		applyAttack(attack, player, maxdamage, attackCount);
                if(c.getPlayer().hasFakeChar())
                {
                    for (FakeCharacter ch : c.getPlayer().getFakeChars()) {
                        MaplePacket packett = MaplePacketCreator.closeRangeAttack(ch.getFakeChar().getId(), attack.skill, attack.stance,
            attack.numAttackedAndDamage, attack.allDamage, attack.speed);
                        player.getMap().broadcastMessage(ch.getFakeChar(), packett, false, true);
                        applyAttack(attack, ch.getFakeChar(), maxdamage, attackCount);
                    }
                }

	}
}

MovePlayerHandler:
Code:
/*
	This file is part of the OdinMS Maple Story Server
    Copyright (C) 2008 Patrick Huy <patrick.huy@frz.cc> 
                       Matthias Butz <matze@odinms.de>
                       Jan Christian Meyer <vimes@odinms.de>

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License version 3
    as published by the Free Software Foundation. You may not use, modify
    or distribute this program under any other version of the
    GNU Affero General Public License.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Affero General Public License for more details.

    You should have received a copy of the GNU Affero General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

package net.sf.odinms.net.channel.handler;

import java.util.List;

import net.sf.odinms.client.MapleCharacter;
import net.sf.odinms.server.maps.FakeCharacter;
import net.sf.odinms.server.TimerManager;
import java.util.concurrent.ScheduledFuture;
import net.sf.odinms.client.MapleClient;
import net.sf.odinms.client.anticheat.CheatingOffense;
import net.sf.odinms.net.MaplePacket;
import net.sf.odinms.server.movement.AbsoluteLifeMovement;
import net.sf.odinms.server.movement.LifeMovementFragment;
import net.sf.odinms.tools.MaplePacketCreator;
import net.sf.odinms.tools.data.input.SeekableLittleEndianAccessor;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class MovePlayerHandler extends AbstractMovementPacketHandler {
	private static Logger log = LoggerFactory.getLogger(MovePlayerHandler.class);

	@Override
	public void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
		slea.readByte();
		slea.readInt();
		// log.trace("Movement command received: unk1 {} unk2 {}", new Object[] { unk1, unk2 });
final List<LifeMovementFragment> res = parseMovement(slea);
		// TODO more validation of input data
		if (res != null) {
			if (slea.available() != 18) {
				log.warn("slea.available != 18 (movement parsing error)");
				return;
			}
			MapleCharacter player = c.getPlayer();
			if (!player.isHidden()) {
				MaplePacket packet = MaplePacketCreator.movePlayer(player.getId(), res);
				c.getPlayer().getMap().broadcastMessage(player, packet, false);
			}
			// c.getSession().write(MaplePacketCreator.movePlayer(30000, res));
			if (CheatingOffense.FAST_MOVE.isEnabled() || CheatingOffense.HIGH_JUMP.isEnabled()) {
				checkMovementSpeed (c.getPlayer(), res);
			}
			updatePosition (res, c.getPlayer(), 0);
			c.getPlayer().getMap().movePlayer(c.getPlayer(), c.getPlayer().getPosition());
		if(c.getPlayer().hasFakeChar())
                        {
                            int i = 0;
                            for (final FakeCharacter ch : c.getPlayer().getFakeChars()) {
                                ScheduledFuture<?> scheduleRemove = TimerManager.getInstance().schedule(new Runnable() {
                                    @Override
                                    public void run() {
                                        MaplePacket packet = MaplePacketCreator.movePlayer(ch.getFakeChar().getId(), res);
                                        ch.getFakeChar().getMap().broadcastMessage(ch.getFakeChar(), packet, false);
                                        updatePosition (res, ch.getFakeChar(), 0);
                                        ch.getFakeChar().getMap().movePlayer(ch.getFakeChar(), ch.getFakeChar().getPosition());
                                    }
                                }, i * 300);
                                i++;
                            }
                        }
}
	}
	
	private static void checkMovementSpeed(MapleCharacter chr, List<LifeMovementFragment> moves) {
		// boolean wasALM = true;
		// Point oldPosition = new Point (c.getPlayer().getPosition());
		double playerSpeedMod = chr.getSpeedMod() + 0.005;
		// double playerJumpMod = c.getPlayer().getJumpMod() + 0.005;
		boolean encounteredUnk0 = false;
		for (LifeMovementFragment lmf : moves) {
			if (lmf.getClass() == AbsoluteLifeMovement.class) {
				final AbsoluteLifeMovement alm = (AbsoluteLifeMovement) lmf;
				double speedMod = Math.abs(alm.getPixelsPerSecond().x) / 125.0;
				// int distancePerSec = Math.abs(alm.getPixelsPerSecond().x);
				// double jumpMod = Math.abs(alm.getPixelsPerSecond().y) / 525.0;
				// double normalSpeed = distancePerSec / playerSpeedMod;
				// System.out.println(speedMod + "(" + playerSpeedMod + ") " + alm.getUnk());
				if (speedMod > playerSpeedMod) {
					if (alm.getUnk() == 0) { // to prevent FJ Ducking us
						encounteredUnk0 = true;
					}
					if (!encounteredUnk0) {
						if (speedMod > playerSpeedMod) {
							chr.getCheatTracker().registerOffense(CheatingOffense.FAST_MOVE);
						}
					}
				}
				// if (wasALM && (oldPosition.y == newPosition.y)) {
				// int distance = Math.abs(oldPosition.x - newPosition.x);
				// if (alm.getDuration() > 60) { // short durations are strange and show too fast movement
				// double distancePerSec = (distance / (double) ((LifeMovement) move).getDuration()) * 1000.0;
				// double speedMod = distancePerSec / 125.0;
				// double normalSpeed = distancePerSec / playerSpeedMod;
				// System.out.println(speedMod + " " + normalSpeed + " " + distancePerSec + " " + distance + " "
				// + alm.getWobble());
				// }
				// }
				// oldPosition = newPosition;
				// wasALM = true;
				// } else {
				// wasALM = false;
			}
		}
	}
}

Build:
Code:
C:\Documents and Settings\Owner.Justin\Desktop\ashurms\src\net\sf\odinms\provider\xmlwz\FileStoredPngMapleCanvas.java:14: warning: com.sun.imageio.plugins.png.PNGImageReaderSpi is Sun proprietary API and may be removed in a future release
import com.sun.imageio.plugins.png.PNGImageReaderSpi;
C:\Documents and Settings\Owner.Justin\Desktop\ashurms\src\net\sf\odinms\client\MapleCharacter.java:1589: incompatible types
found   : java.lang.Object
required: net.sf.odinms.server.maps.FakeCharacter
            for (FakeCharacter ch : getFakeChars()) {
C:\Documents and Settings\Owner.Justin\Desktop\ashurms\src\net\sf\odinms\client\MapleClient.java:595: incompatible types
found   : java.lang.Object
required: net.sf.odinms.server.maps.FakeCharacter
                        for (FakeCharacter ch : chr.getFakeChars()) {
C:\Documents and Settings\Owner.Justin\Desktop\ashurms\src\net\sf\odinms\net\channel\handler\CloseRangeDamageHandler.java:157: incompatible types
found   : java.lang.Object
required: net.sf.odinms.server.maps.FakeCharacter
                    for (FakeCharacter ch : c.getPlayer().getFakeChars()) {
C:\Documents and Settings\Owner.Justin\Desktop\ashurms\src\net\sf\odinms\net\channel\handler\FaceExpressionHandler.java:54: incompatible types
found   : java.lang.Object
required: net.sf.odinms.server.maps.FakeCharacter
                for (FakeCharacter ch : c.getPlayer().getFakeChars()) {
C:\Documents and Settings\Owner.Justin\Desktop\ashurms\src\net\sf\odinms\net\channel\handler\MovePlayerHandler.java:70: incompatible types
found   : java.lang.Object
required: net.sf.odinms.server.maps.FakeCharacter
                            for (final FakeCharacter ch : c.getPlayer().getFakeChars()) {
C:\Documents and Settings\Owner.Justin\Desktop\ashurms\src\net\sf\odinms\provider\xmlwz\FileStoredPngMapleCanvas.java:47: warning: com.sun.imageio.plugins.png.PNGImageReaderSpi is Sun proprietary API and may be removed in a future release
                        ImageReaderSpi readerSpi = iioRegistry.getServiceProviderByClass(PNGImageReaderSpi.class);
                                                                                         ^
5 errors
2 warnings
BUILD FAILED (total time: 5 seconds)
(I did choose Clean and Build Main Project)
 
Junior Spellweaver
Joined
Aug 9, 2008
Messages
111
Reaction score
0
I followed guide on the first day it came out on. no error, compiled fine, worked fine. if you get errors, you are doing something wrong.
 
Status
Not open for further replies.
Back
Top