public final void addPlayer(final MapleCharacter chr) {
//        for (int i = 0; i < 50; i++) {
//            System.out.println("new char on map");
//        }
        mapobjectlocks.get(MapleMapObjectType.PLAYER).writeLock().lock();
        try {
            mapobjects.get(MapleMapObjectType.PLAYER).put(chr.getObjectId(), chr);
        } finally {
            mapobjectlocks.get(MapleMapObjectType.PLAYER).writeLock().unlock();
        }

        charactersLock.writeLock().lock();
        try {
            characters.add(chr);
        } finally {
            charactersLock.writeLock().unlock();
        }
        chr.setChangeTime();
        if (GameConstants.isTeamMap(mapid) && !chr.inPVP()) {
            chr.setTeam(getAndSwitchTeam() ? 0 : 1);
        }
        final byte[] packet = CField.spawnPlayerMapobject(chr);
        if (!chr.isHidden()) {
            broadcastMessage(chr, packet, false);
            if (chr.isIntern() && speedRunStart > 0) {
                endSpeedRun();
                broadcastMessage(CWvsContext.broadcastMsg(5, "The speed run has ended."));
            }
        } else {
            broadcastGMMessage(chr, packet, false);
        }

        if (!chr.isClone()) {
            if (!onFirstUserEnter.equals("")) {
                if (getCharactersSize() == 1) {
                    MapScriptMethods.startScript_FirstUser(chr.getClient(), onFirstUserEnter);
                }
            }
            sendObjectPlacement(chr);

            if (!onUserEnter.equals("")) {
                MapScriptMethods.startScript_User(chr.getClient(), onUserEnter);
            }
        
            GameConstants.achievementRatio(chr.getClient());
            //chr.getClient().getSession().write(CField.spawnFlags(nodes.getFlags()));
            if (GameConstants.isTeamMap(mapid) && !chr.inPVP()) {
                chr.getClient().getSession().write(CField.showEquipEffect(chr.getTeam()));
            }
            switch (mapid) {
                case 809000101:
                case 809000201:
                    chr.getClient().getSession().write(CField.showEquipEffect());
                    break;
                case 689000000:
                case 689000010:
                    chr.getClient().getSession().write(CField.getCaptureFlags(this));
                    break;
            }
        }
        for (final MaplePet pet : chr.getPets()) {
            if (pet.getSummoned()) {
                broadcastMessage(chr, PetPacket.showPet(chr, pet, false, false), false);
            }
        }
        if (chr.getSummonedFamiliar() != null) {
            chr.spawnFamiliar(chr.getSummonedFamiliar(), true);
        }
        if (chr.getAndroid() != null) {
            chr.getAndroid().setPos(chr.getPosition());
            broadcastMessage(CField.spawnAndroid(chr, chr.getAndroid()));
        }
        if (chr.getParty() != null && !chr.isClone()) {
            chr.silentPartyUpdate();
            chr.getClient().getSession().write(PartyPacket.updateParty(chr.getClient().getChannel(), chr.getParty(), PartyOperation.SILENT_UPDATE, null));
            chr.updatePartyMemberHP();
            chr.receivePartyMemberHP();
        }
        if (!chr.isInBlockedMap() && chr.getLevel() > 10 && isTown() && chr.getMapId() % 1000000 == 0 && chr.getMapId() <= 600000000) {
            for (QuickMove qm : QuickMove.values()) {
                if (qm.getMap() == chr.getMapId()) {
                    List<QuickMoveNPC> qmn = new LinkedList();
                    int npcs = qm.getNPCFlag();
                    for (QuickMoveNPC npc : QuickMoveNPC.values()) {
                        if ((npcs & npc.getValue()) != 0 && npc.show()) {
                            qmn.add(npc);
                        }
                    }
                    //chr.getClient().getSession().write(CField.getQuickMoveInfo(true, qmn));
                    break;
                }
            }
        } else {
            //chr.getClient().getSession().write(CField.getQuickMoveInfo(false, new LinkedList()));
        }
        
        if (getNPCById(9073000) != null && getId() == 931050410) {
            chr.getClient().getSession().write(CField.NPCPacket.toggleNPCShow(getNPCById(9073000).getObjectId(), true));
        }
        if (GameConstants.isPhantom(chr.getJob())) {
            chr.getClient().getSession().write(PhantomPacket.updateCardStack(chr.getCardStack()));
        }
        if (!chr.isClone()) {
            final List<MapleSummon> ss = chr.getSummonsReadLock();
            try {
                for (MapleSummon summon : ss) {
                    summon.setPosition(chr.getTruePosition());
                    chr.addVisibleMapObject(summon);
                    this.spawnSummon(summon);
                }
            } finally {
                chr.unlockSummonsReadLock();
            }
        }
        if (mapEffect != null) {
            mapEffect.sendStartData(chr.getClient());
        }
        if (timeLimit > 0 && getForcedReturnMap() != null && !chr.isClone()) {
            chr.startMapTimeLimitTask(timeLimit, getForcedReturnMap());
        }
        if (chr.getBuffedValue(MapleBuffStat.MONSTER_RIDING) != null && !GameConstants.isResistance(chr.getJob())) {
            if (FieldLimitType.Mount.check(fieldLimit)) {
                chr.cancelEffectFromBuffStat(MapleBuffStat.MONSTER_RIDING);
            }
        }
        if (!chr.isClone()) {
            if (chr.getEventInstance() != null && chr.getEventInstance().isTimerStarted() && !chr.isClone()) {
                if (chr.inPVP()) {
                    chr.getClient().getSession().write(CField.getPVPClock(Integer.parseInt(chr.getEventInstance().getProperty("type")), (int) (chr.getEventInstance().getTimeLeft() / 1000)));
                } else {
                    chr.getClient().getSession().write(CField.getClock((int) (chr.getEventInstance().getTimeLeft() / 1000)));
                }
            }
            if (hasClock()) {
                final Calendar cal = Calendar.getInstance();
                chr.getClient().getSession().write((CField.getClockTime(cal.get(Calendar.HOUR_OF_DAY), cal.get(Calendar.MINUTE), cal.get(Calendar.SECOND))));
            }
            if (chr.getCarnivalParty() != null && chr.getEventInstance() != null) {
                chr.getEventInstance().onMapLoad(chr);
            }
            MapleEvent.mapLoad(chr, channel);
            if (getSquadBegin() != null && getSquadBegin().getTimeLeft() > 0 && getSquadBegin().getStatus() == 1) {
                chr.getClient().getSession().write(CField.getClock((int) (getSquadBegin().getTimeLeft() / 1000)));
            }
            if (mapid / 1000 != 105100 && mapid / 100 != 8020003 && mapid / 100 != 8020008 && mapid != 271040100) { //no boss_balrog/2095/coreblaze/auf/cygnus. but coreblaze/auf/cygnus does AFTER
                final MapleSquad sqd = getSquadByMap(); //for all squads
                final EventManager em = getEMByMap();
                if (!squadTimer && sqd != null && chr.getName().equals(sqd.getLeaderName()) && em != null && em.getProperty("leader") != null && em.getProperty("leader").equals("true") && checkStates) {
                    //leader? display
                    doShrine(false);
                    squadTimer = true;
                }
            }
            if (getNumMonsters() > 0 && (mapid == 280030001 || mapid == 240060201 || mapid == 280030000 || mapid == 240060200 || mapid == 220080001 || mapid == 541020800 || mapid == 541010100)) {
                String music = "Bgm09/TimeAttack";
                switch (mapid) {
                    case 240060200:
                    case 240060201:
                        music = "Bgm14/HonTale";
                        break;
                    case 280030000:
                    case 280030001:
                        music = "Bgm06/FinalFight";
                        break;
                }
                chr.getClient().getSession().write(CField.musicChange(music));
                chr.getClient().getSession().write(CWvsContext.sendWelcomeBack(chr));
                //maybe timer too for zak/ht
            }
            for (final WeakReference<MapleCharacter> chrz : chr.getClones()) {
                if (chrz.get() != null) {
                    chrz.get().setPosition(chr.getTruePosition());
                    chrz.get().setMap(this);
                    addPlayer(chrz.get());
                }
            }
            if (mapid == 914000000 || mapid == 927000000) {
                chr.getClient().getSession().write(CWvsContext.temporaryStats_Aran());
            } else if (mapid == 105100300 && chr.getLevel() >= 91) {
                chr.getClient().getSession().write(CWvsContext.temporaryStats_Balrog(chr));
            } else if (mapid == 140090000 || mapid == 105100301 || mapid == 105100401 || mapid == 105100100) {
                chr.getClient().getSession().write(CWvsContext.temporaryStats_Reset());
            }
        }
        if (GameConstants.isEvan(chr.getJob()) && chr.getJob() >= 2200) {
            if (chr.getDragon() == null) {
                chr.makeDragon();
            } else {
                chr.getDragon().setPosition(chr.getPosition());
            }
            if (chr.getDragon() != null) {
                broadcastMessage(CField.spawnDragon(chr.getDragon()));
            }
        }
        if (GameConstants.isKanna(chr.getJob())) {
            if (chr.getHaku() == null && chr.getBuffedValue(MapleBuffStat.HAKU_REBORN) == null) {
                chr.makeHaku();
            } else {
                chr.getHaku().setPosition(chr.getPosition());
            }
            if (chr.getHaku() != null) {
                if (chr.getBuffSource(MapleBuffStat.HAKU_REBORN) > 0) {
                    chr.getHaku().sendStats();
                    chr.getMap().broadcastMessage(chr, CField.spawnHaku_change0(chr.getId()), true);
                    chr.getMap().broadcastMessage(chr, CField.spawnHaku_change1(chr.getHaku()), true);
                    chr.getMap().broadcastMessage(chr, CField.spawnHaku_bianshen(chr.getId(), chr.getHaku().getObjectId(), chr.getHaku().getStats()), true);
                } else {
                    broadcastMessage(CField.spawnHaku(chr.getHaku()));
                }
            }
        }
        if (permanentWeather > 0) {
            chr.getClient().getSession().write(CField.startMapEffect("", permanentWeather, false)); //snow, no msg
        }
        if (getPlatforms().size() > 0) {
            chr.getClient().getSession().write(CField.getMovingPlatforms(this));
        }
        if (environment.size() > 0) {
            chr.getClient().getSession().write(CField.getUpdateEnvironment(this));
        }
        //if (partyBonusRate > 0) {
        //    chr.dropMessage(-1, partyBonusRate + "% additional EXP will be applied per each party member here.");
        //    chr.dropMessage(-1, "You've entered the party play zone.");
        //}
        if (isTown()) {
            chr.cancelEffectFromBuffStat(MapleBuffStat.RAINING_MINES);
        }
        if (!canSoar()) {
            chr.cancelEffectFromBuffStat(MapleBuffStat.SOARING);
        }
        if (chr.getJob() < 3200 || chr.getJob() > 3212) {
            //chr.cancelEffectFromBuffStat(MapleBuffStat.AURA);
        }
        if (chr.getCustomBGState() == 1) {
            chr.removeBGLayers();
        }
        //chr.getClient().getSession().write(CField.getUpdateEnvironmentMapChange(this));
        //chr.getClient().getSession().write(CField.getMapleEventList());
        List<Triple<String, Integer, Boolean>> backgrounds = new LinkedList<>(); //boolean for randomize
        Triple<String, Integer, Boolean>[] bg = new Triple[]{ //boolean for randomize
        new Triple<>("22556", 0, false),
        new Triple<>("22556", 0, false),
        new Triple<>("22556", 0, false),
        new Triple<>("22556", 0, false),
        new Triple<>("24068", 0, false),
        }; 
        backgrounds.addAll(Arrays.asList(bg));
        chr.getClient().getSession().write(LoginPacket.changeBackground(backgrounds));
        chr.getClient().getSession().write(CField.NPCPacket.setNPCScriptable(GameConstants.SCRIPTABLE_NPCS));
    }