Switch to Maven file structure

This commit is contained in:
P0nk
2021-03-30 21:07:35 +02:00
parent 4acc5675d6
commit 813643036b
817 changed files with 16 additions and 0 deletions

View File

@@ -0,0 +1,106 @@
/*
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 as
published by the Free Software Foundation 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.server;
import client.MapleDisease;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.locks.Lock;
import server.life.MobSkill;
import tools.Pair;
import net.server.audit.locks.MonitoredLockType;
import net.server.audit.locks.factory.MonitoredReentrantLockFactory;
/**
*
* @author Danny//changed to map :3
* @author Ronan//debuffs to storage as well
*/
public class PlayerBuffStorage {
private int id = (int) (Math.random() * 100);
private final Lock lock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.BUFF_STORAGE, true);
private Map<Integer, List<PlayerBuffValueHolder>> buffs = new HashMap<>();
private Map<Integer, Map<MapleDisease, Pair<Long, MobSkill>>> diseases = new HashMap<>();
public void addBuffsToStorage(int chrid, List<PlayerBuffValueHolder> toStore) {
lock.lock();
try {
buffs.put(chrid, toStore);//Old one will be replaced if it's in here.
} finally {
lock.unlock();
}
}
public List<PlayerBuffValueHolder> getBuffsFromStorage(int chrid) {
lock.lock();
try {
return buffs.remove(chrid);
} finally {
lock.unlock();
}
}
public void addDiseasesToStorage(int chrid, Map<MapleDisease, Pair<Long, MobSkill>> toStore) {
lock.lock();
try {
diseases.put(chrid, toStore);
} finally {
lock.unlock();
}
}
public Map<MapleDisease, Pair<Long, MobSkill>> getDiseasesFromStorage(int chrid) {
lock.lock();
try {
return diseases.remove(chrid);
} finally {
lock.unlock();
}
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + id;
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final PlayerBuffStorage other = (PlayerBuffStorage) obj;
if (id != other.id) {
return false;
}
return true;
}
}

View File

@@ -0,0 +1,38 @@
/*
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 as
published by the Free Software Foundation 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.server;
import server.MapleStatEffect;
/**
*
* @author Danny
*/
public class PlayerBuffValueHolder {
public int usedTime;
public MapleStatEffect effect;
public PlayerBuffValueHolder(int usedTime, MapleStatEffect effect) {
this.usedTime = usedTime;
this.effect = effect;
}
}

View File

@@ -0,0 +1,38 @@
/*
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 as
published by the Free Software Foundation 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.server;
/**
*
* @author Danny
*/
public class PlayerCoolDownValueHolder {
public int skillId;
public long startTime;
public long length;
public PlayerCoolDownValueHolder(int skillId, long startTime, long length) {
this.skillId = skillId;
this.startTime = startTime;
this.length = length;
}
}

View File

@@ -0,0 +1,36 @@
/*
This file is part of the OdinMS Maple Story Server
Copyright (C) 2008 ~ 2010 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.server;
import client.MapleDisease;
public class PlayerDiseaseValueHolder {//Thanks Celino
public long startTime;
public long length;
public MapleDisease disease;
public PlayerDiseaseValueHolder(final MapleDisease disease, final long startTime, final long length) {
this.disease = disease;
this.startTime = startTime;
this.length = length;
}
}

View File

@@ -0,0 +1,126 @@
/*
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 as
published by the Free Software Foundation 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.server;
import client.MapleClient;
import client.MapleCharacter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.LinkedHashMap;
import java.util.Map;
import net.server.audit.locks.MonitoredLockType;
import net.server.audit.locks.MonitoredReadLock;
import net.server.audit.locks.MonitoredReentrantReadWriteLock;
import net.server.audit.locks.MonitoredWriteLock;
import net.server.audit.locks.factory.MonitoredReadLockFactory;
import net.server.audit.locks.factory.MonitoredWriteLockFactory;
public class PlayerStorage {
private final MonitoredReentrantReadWriteLock locks = new MonitoredReentrantReadWriteLock(MonitoredLockType.PLAYER_STORAGE, true);
private final Map<Integer, MapleCharacter> storage = new LinkedHashMap<>();
private final Map<String, MapleCharacter> nameStorage = new LinkedHashMap<>();
private MonitoredReadLock rlock = MonitoredReadLockFactory.createLock(locks);
private MonitoredWriteLock wlock = MonitoredWriteLockFactory.createLock(locks);
public void addPlayer(MapleCharacter chr) {
wlock.lock();
try {
storage.put(chr.getId(), chr);
nameStorage.put(chr.getName().toLowerCase(), chr);
} finally {
wlock.unlock();
}
}
public MapleCharacter removePlayer(int chr) {
wlock.lock();
try {
MapleCharacter mc = storage.remove(chr);
if(mc != null) nameStorage.remove(mc.getName().toLowerCase());
return mc;
} finally {
wlock.unlock();
}
}
public MapleCharacter getCharacterByName(String name) {
rlock.lock();
try {
return nameStorage.get(name.toLowerCase());
} finally {
rlock.unlock();
}
}
public MapleCharacter getCharacterById(int id) {
rlock.lock();
try {
return storage.get(id);
} finally {
rlock.unlock();
}
}
public Collection<MapleCharacter> getAllCharacters() {
rlock.lock();
try {
return new ArrayList<>(storage.values());
} finally {
rlock.unlock();
}
}
public final void disconnectAll() {
List<MapleCharacter> chrList;
rlock.lock();
try {
chrList = new ArrayList<>(storage.values());
} finally {
rlock.unlock();
}
for(MapleCharacter mc : chrList) {
MapleClient client = mc.getClient();
if(client != null) {
client.forceDisconnect();
}
}
wlock.lock();
try {
storage.clear();
} finally {
wlock.unlock();
}
}
public int getSize() {
rlock.lock();
try {
return storage.size();
} finally {
rlock.unlock();
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,75 @@
/*
This file is part of the HeavenMS MapleStory Server
Copyleft (L) 2016 - 2019 RonanLana
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation 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.server.audit;
import java.util.ArrayList;
import java.util.List;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
*
* @author Ronan
*/
public class LockCollector {
private static final LockCollector instance = new LockCollector();
public static LockCollector getInstance() {
return instance;
}
private Map<Runnable, Integer> disposableLocks = new HashMap<>(200);
private final Lock lock = new ReentrantLock(true);
public void registerDisposeAction(Runnable r) {
lock.lock();
try {
disposableLocks.put(r, 0);
} finally {
lock.unlock();
}
}
public void runLockCollector() {
List<Runnable> toDispose = new ArrayList<>();
lock.lock();
try {
for(Entry<Runnable, Integer> e : disposableLocks.entrySet()) {
Integer eVal = e.getValue();
if(eVal > 5) { // updates each 2min
toDispose.add(e.getKey());
} else {
disposableLocks.put(e.getKey(), ++eVal);
}
}
} finally {
lock.unlock();
}
for(Runnable r : toDispose) {
r.run();
}
}
}

View File

@@ -0,0 +1,291 @@
/*
This file is part of the HeavenMS MapleStory Server
Copyleft (L) 2016 - 2019 RonanLana
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation 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.server.audit;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.TimeZone;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import net.server.audit.locks.MonitoredLockType;
import server.TimerManager;
import tools.FilePrinter;
/**
*
* @author RonanLana
*
* This tool has the main purpose of auditing deadlocks throughout the server and must be used only for debugging. The flag is USE_THREAD_TRACKER.
*/
public class ThreadTracker {
private static ThreadTracker instance = null;
public static ThreadTracker getInstance() {
if (instance == null) {
instance = new ThreadTracker();
}
return instance;
}
private final Lock ttLock = new ReentrantLock(true);
private final Map<Long, List<MonitoredLockType>> threadTracker = new HashMap<>();
private final Map<Long, Integer> threadUpdate = new HashMap<>();
private final Map<Long, Thread> threads = new HashMap<>();
private final Map<Long, AtomicInteger> lockCount = new HashMap<>();
private final Map<Long, MonitoredLockType> lockIds = new HashMap<>();
private final Map<Long, Long> lockThreads = new HashMap<>();
private final Map<Long, Integer> lockUpdate = new HashMap<>();
private final Map<MonitoredLockType, Map<Long, Integer>> locks = new HashMap<>();
ScheduledFuture<?> threadTrackerSchedule;
private String printThreadTrackerState(String dateFormat) {
Map<MonitoredLockType, List<Integer>> lockValues = new HashMap<>();
Set<Long> executingThreads = new HashSet<>();
for(Map.Entry<Long, AtomicInteger> lc : lockCount.entrySet()) {
if(lc.getValue().get() != 0) {
executingThreads.add(lockThreads.get(lc.getKey()));
MonitoredLockType lockId = lockIds.get(lc.getKey());
List<Integer> list = lockValues.get(lockId);
if(list == null) {
list = new ArrayList<>();
lockValues.put(lockId, list);
}
list.add(lc.getValue().get());
}
}
String s = "----------------------------\r\n" + dateFormat + "\r\n ";
s += "Lock-thread usage count:";
for(Map.Entry<MonitoredLockType, List<Integer>> lock : lockValues.entrySet()) {
s += ("\r\n " + lock.getKey().name() + ": ");
for(Integer i : lock.getValue()) {
s += (i + " ");
}
}
s += "\r\n\r\nThread opened lock path:";
for(Long tid : executingThreads) {
s += "\r\n";
for(MonitoredLockType lockid : threadTracker.get(tid)) {
s += (lockid.name() + " ");
}
s += "|";
}
s += "\r\n\r\n";
return s;
}
private static String printThreadLog(List<MonitoredLockType> stillLockedPath, String dateFormat) {
String s = "----------------------------\r\n" + dateFormat + "\r\n ";
for(MonitoredLockType lock : stillLockedPath) {
s += (lock.name() + " ");
}
s += "\r\n\r\n";
return s;
}
private static String printThreadStack(StackTraceElement[] list, String dateFormat) {
String s = "----------------------------\r\n" + dateFormat + "\r\n";
for(int i = 0; i < list.length; i++) {
s += (" " + list[i].toString() + "\r\n");
}
return s;
}
public void accessThreadTracker(boolean update, boolean lock, MonitoredLockType lockId, long lockOid) {
ttLock.lock();
try {
if(update) {
if(!lock) { // update tracker
List<Long> toRemove = new ArrayList<>();
for(Long l : threadUpdate.keySet()) {
int next = threadUpdate.get(l) + 1;
if(next == 4) {
List<MonitoredLockType> tt = threadTracker.get(l);
if(tt.isEmpty()) {
toRemove.add(l);
} else {
StackTraceElement[] ste = threads.get(l).getStackTrace();
if(ste.length > 0) {
DateFormat dateFormat = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss");
dateFormat.setTimeZone(TimeZone.getDefault());
String df = dateFormat.format(new Date());
FilePrinter.print(FilePrinter.DEADLOCK_LOCKS, printThreadLog(tt, df));
FilePrinter.print(FilePrinter.DEADLOCK_STACK, printThreadStack(ste, df));
}
}
}
threadUpdate.put(l, next);
}
for(Long l : toRemove) {
threadTracker.remove(l);
threadUpdate.remove(l);
threads.remove(l);
for(Map<Long, Integer> threadLock : locks.values()) {
threadLock.remove(l);
}
}
toRemove.clear();
for(Entry<Long, Integer> it : lockUpdate.entrySet()) {
int val = it.getValue() + 1;
if(val < 60) {
lockUpdate.put(it.getKey(), val);
} else {
toRemove.add(it.getKey()); // free the structure after 60 silent updates
}
}
for(Long l : toRemove) {
lockCount.remove(l);
lockIds.remove(l);
lockThreads.remove(l);
lockUpdate.remove(l);
}
} else { // print status
DateFormat dateFormat = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss");
dateFormat.setTimeZone(TimeZone.getDefault());
FilePrinter.printError(FilePrinter.DEADLOCK_STATE, printThreadTrackerState(dateFormat.format(new Date())));
//FilePrinter.printError(FilePrinter.DEADLOCK_STATE, "[" + dateFormat.format(new Date()) + "] Presenting current lock path for lockid " + lockId.name() + ".\r\n" + printLockStatus(lockId) + "\r\n-------------------------------");
}
} else {
long tid = Thread.currentThread().getId();
if(lock) {
AtomicInteger c = lockCount.get(lockOid);
if(c == null) {
c = new AtomicInteger(0);
lockCount.put(lockOid, c);
lockIds.put(lockOid, lockId);
lockThreads.put(lockOid, tid);
lockUpdate.put(lockOid, 0);
}
c.incrementAndGet();
List<MonitoredLockType> list = threadTracker.get(tid);
if(list == null) {
list = new ArrayList<>(5);
threadTracker.put(tid, list);
threadUpdate.put(tid, 0);
threads.put(tid, Thread.currentThread());
} else if(list.isEmpty()) {
threadUpdate.put(tid, 0);
}
list.add(lockId);
Map<Long, Integer> threadLock = locks.get(lockId);
if(threadLock == null) {
threadLock = new HashMap<>(5);
locks.put(lockId, threadLock);
}
Integer lc = threadLock.get(tid);
if(lc != null) {
threadLock.put(tid, lc + 1);
} else {
threadLock.put(tid, 1);
}
}
else {
AtomicInteger c = lockCount.get(lockOid);
if (c != null) { // thanks BHB for detecting an NPE here
c.decrementAndGet();
}
lockUpdate.put(lockOid, 0);
List<MonitoredLockType> list = threadTracker.get(tid);
for(int i = list.size() - 1; i >= 0; i--) {
if(lockId.equals(list.get(i))) {
list.remove(i);
break;
}
}
Map<Long, Integer> threadLock = locks.get(lockId);
threadLock.put(tid, threadLock.get(tid) - 1);
}
}
} finally {
ttLock.unlock();
}
}
private String printLockStatus(MonitoredLockType lockId) {
String s = "";
for(Long threadid : locks.get(lockId).keySet()) {
for(MonitoredLockType lockid : threadTracker.get(threadid)) {
s += (" " + lockid.name());
}
s += " |\r\n";
}
return s;
}
public void registerThreadTrackerTask() {
threadTrackerSchedule = TimerManager.getInstance().register(new Runnable() {
@Override
public void run() {
accessThreadTracker(true, false, MonitoredLockType.UNDEFINED, -1);
}
}, 10000, 10000);
}
public void cancelThreadTrackerTask() {
threadTrackerSchedule.cancel(false);
}
}

View File

@@ -0,0 +1,112 @@
/*
This file is part of the HeavenMS MapleStory Server
Copyleft (L) 2016 - 2019 RonanLana
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation 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.server.audit.locks;
/**
*
* @author RonanLana
*/
public enum MonitoredLockType {
UNDEFINED,
INTERVAL,
CHARACTER_CHR,
CHARACTER_CPN,
CHARACTER_EFF,
CHARACTER_PET,
CHARACTER_PRT,
CHARACTER_EVT,
CHARACTER_STA,
CLIENT,
CLIENT_ANNOUNCER,
CLIENT_ENCODER,
CLIENT_SESSION,
CLIENT_LOGIN,
BOOK,
ITEM,
INVENTORY,
SRVHANDLER_IDLE,
SRVHANDLER_TEMP,
BUFF_STORAGE,
PLAYER_STORAGE,
PLAYER_DOOR,
SERVER,
SERVER_DISEASES,
SERVER_LOGIN,
SERVER_LOGIN_COORD,
SERVER_WORLDS,
MERCHANT,
CHANNEL,
CHANNEL_EVENTS,
CHANNEL_FACEEXPRS,
CHANNEL_FACESCHDL,
CHANNEL_MOBACTION,
CHANNEL_MOBANIMAT,
CHANNEL_MOBMIST,
CHANNEL_MOBSKILL,
CHANNEL_MOBSTATUS,
CHANNEL_OVTSTATUS,
CHANNEL_OVERALL,
GUILD,
PARTY,
WORLD_PARTY,
WORLD_PARTY_SEARCH_ECHELON,
WORLD_PARTY_SEARCH_QUEUE,
WORLD_PARTY_SEARCH_STORAGE,
WORLD_SRVMESSAGES,
WORLD_PETS,
WORLD_CHARS,
WORLD_CHANNELS,
WORLD_MOUNTS,
WORLD_PSHOPS,
WORLD_MERCHS,
WORLD_MAPOBJS,
WORLD_SAVECHARS,
WORLD_SUGGEST,
EIM,
EIM_PARTY,
EIM_SCRIPT,
EM_LOBBY,
EM_QUEUE,
EM_SCHDL,
EM_START,
CASHSHOP,
VISITOR_PSHOP,
STORAGE,
MOB,
MOB_AGGRO,
MOB_ANI,
MOB_EXT,
MOB_STATI,
MOBSKILL_FACTORY,
PORTAL,
VISITOR_MERCH,
MAP_CHRS,
MAP_OBJS,
MAP_MANAGER,
MAP_ITEM,
MAP_LOOT,
MAP_BOUNDS,
MAP_AGGRO,
MAP_AGGRO_IDLE,
MINIDUNGEON,
REACTOR,
REACTOR_HIT;
}

View File

@@ -0,0 +1,36 @@
/*
This file is part of the HeavenMS MapleStory Server
Copyleft (L) 2016 - 2019 RonanLana
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation 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.server.audit.locks;
/**
*
* @author RonanLana
*/
public interface MonitoredReadLock {
public void lock();
public void unlock();
public boolean tryLock();
public MonitoredReadLock dispose();
}

View File

@@ -0,0 +1,36 @@
/*
This file is part of the HeavenMS MapleStory Server
Copyleft (L) 2016 - 2019 RonanLana
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation 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.server.audit.locks;
/**
*
* @author RonanLana
*/
public interface MonitoredReentrantLock {
public void lock();
public void unlock();
public boolean tryLock();
public MonitoredReentrantLock dispose();
}

View File

@@ -0,0 +1,50 @@
/*
This file is part of the HeavenMS MapleStory Server
Copyleft (L) 2016 - 2019 RonanLana
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation 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.server.audit.locks;
import java.util.concurrent.locks.ReentrantReadWriteLock;
/**
*
* @author RonanLana
*/
public class MonitoredReentrantReadWriteLock extends ReentrantReadWriteLock {
public final MonitoredLockType id;
public MonitoredReentrantReadWriteLock(MonitoredLockType id) {
super();
this.id = id;
}
public MonitoredReentrantReadWriteLock(MonitoredLockType id, boolean fair) {
super(fair);
this.id = id;
}
@Override
public ReadLock readLock() {
return super.readLock();
}
@Override
public WriteLock writeLock() {
return super.writeLock();
}
}

View File

@@ -0,0 +1,36 @@
/*
This file is part of the HeavenMS MapleStory Server
Copyleft (L) 2016 - 2019 RonanLana
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation 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.server.audit.locks;
/**
*
* @author RonanLana
*/
public interface MonitoredWriteLock {
public void lock();
public void unlock();
public boolean tryLock();
public MonitoredWriteLock dispose();
}

View File

@@ -0,0 +1,171 @@
/*
This file is part of the HeavenMS MapleStory Server
Copyleft (L) 2016 - 2019 RonanLana
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation 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.server.audit.locks.active;
import config.YamlConfig;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimeZone;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.ScheduledFuture;
import server.TimerManager;
import net.server.audit.ThreadTracker;
import net.server.audit.locks.MonitoredLockType;
import net.server.audit.locks.MonitoredReadLock;
import net.server.audit.locks.MonitoredReentrantReadWriteLock;
import net.server.audit.locks.empty.EmptyReadLock;
import tools.FilePrinter;
/**
*
* @author RonanLana
*/
public class TrackerReadLock extends ReentrantReadWriteLock.ReadLock implements MonitoredReadLock {
private ScheduledFuture<?> timeoutSchedule = null;
private StackTraceElement[] deadlockedState = null;
private final MonitoredLockType id;
private final int hashcode;
private final Lock state = new ReentrantLock(true);
private final AtomicInteger reentrantCount = new AtomicInteger(0);
public TrackerReadLock(MonitoredReentrantReadWriteLock lock) {
super(lock);
this.id = lock.id;
hashcode = this.hashCode();
}
@Override
public void lock() {
if(YamlConfig.config.server.USE_THREAD_TRACKER) {
if(deadlockedState != null) {
DateFormat dateFormat = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss");
dateFormat.setTimeZone(TimeZone.getDefault());
//FilePrinter.printError(FilePrinter.DEADLOCK_ERROR, "[CRITICAL] " + dateFormat.format(new Date()) + " Deadlock occurred when trying to use the '" + id.name() + "' lock resources:\r\n" + printStackTrace(deadlockedState));
ThreadTracker.getInstance().accessThreadTracker(true, true, id, hashcode);
deadlockedState = null;
}
registerLocking();
}
super.lock();
}
@Override
public void unlock() {
if(YamlConfig.config.server.USE_THREAD_TRACKER) {
unregisterLocking();
}
super.unlock();
}
@Override
public boolean tryLock() {
if(super.tryLock()) {
if(YamlConfig.config.server.USE_THREAD_TRACKER) {
if(deadlockedState != null) {
//FilePrinter.printError(FilePrinter.DEADLOCK_ERROR, "Deadlock occurred when trying to use the '" + id.name() + "' lock resources:\r\n" + printStackTrace(deadlockedState));
ThreadTracker.getInstance().accessThreadTracker(true, true, id, hashcode);
deadlockedState = null;
}
registerLocking();
}
return true;
} else {
return false;
}
}
private void registerLocking() {
state.lock();
try {
ThreadTracker.getInstance().accessThreadTracker(false, true, id, hashcode);
if(reentrantCount.incrementAndGet() == 1) {
final Thread t = Thread.currentThread();
timeoutSchedule = TimerManager.getInstance().schedule(new Runnable() {
@Override
public void run() {
issueDeadlock(t);
}
}, YamlConfig.config.server.LOCK_MONITOR_TIME);
}
} finally {
state.unlock();
}
}
private void unregisterLocking() {
state.lock();
try {
if(reentrantCount.decrementAndGet() == 0) {
if(timeoutSchedule != null) {
timeoutSchedule.cancel(false);
timeoutSchedule = null;
}
}
ThreadTracker.getInstance().accessThreadTracker(false, false, id, hashcode);
} finally {
state.unlock();
}
}
private void issueDeadlock(Thread t) {
deadlockedState = t.getStackTrace();
//super.unlock();
}
private static String printStackTrace(StackTraceElement[] list) {
String s = "";
for(int i = 0; i < list.length; i++) {
s += (" " + list[i].toString() + "\r\n");
}
return s;
}
@Override
public MonitoredReadLock dispose() {
state.lock();
try {
if(timeoutSchedule != null) {
timeoutSchedule.cancel(false);
timeoutSchedule = null;
}
reentrantCount.set(Integer.MAX_VALUE);
} finally {
state.unlock();
}
//unlock();
return new EmptyReadLock(id);
}
}

View File

@@ -0,0 +1,174 @@
/*
This file is part of the HeavenMS MapleStory Server
Copyleft (L) 2016 - 2019 RonanLana
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation 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.server.audit.locks.active;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.ScheduledFuture;
import config.YamlConfig;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimeZone;
import server.TimerManager;
import net.server.audit.ThreadTracker;
import net.server.audit.locks.MonitoredLockType;
import net.server.audit.locks.MonitoredReentrantLock;
import net.server.audit.locks.empty.EmptyReentrantLock;
import tools.FilePrinter;
/**
*
* @author RonanLana
*/
public class TrackerReentrantLock extends ReentrantLock implements MonitoredReentrantLock {
private ScheduledFuture<?> timeoutSchedule = null;
private StackTraceElement[] deadlockedState = null;
private final MonitoredLockType id;
private final int hashcode;
private final Lock state = new ReentrantLock(true);
private final AtomicInteger reentrantCount = new AtomicInteger(0);
public TrackerReentrantLock(MonitoredLockType id) {
super();
this.id = id;
hashcode = this.hashCode();
}
public TrackerReentrantLock(MonitoredLockType id, boolean fair) {
super(fair);
this.id = id;
hashcode = this.hashCode();
}
@Override
public void lock() {
if(YamlConfig.config.server.USE_THREAD_TRACKER) {
if(deadlockedState != null) {
DateFormat dateFormat = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss");
dateFormat.setTimeZone(TimeZone.getDefault());
//FilePrinter.printError(FilePrinter.DEADLOCK_ERROR, "[CRITICAL] " + dateFormat.format(new Date()) + " Deadlock occurred when trying to use the '" + id.name() + "' lock resources:\r\n" + printStackTrace(deadlockedState));
ThreadTracker.getInstance().accessThreadTracker(true, true, id, hashcode);
deadlockedState = null;
}
registerLocking();
}
super.lock();
}
@Override
public void unlock() {
if(YamlConfig.config.server.USE_THREAD_TRACKER) {
unregisterLocking();
}
super.unlock();
}
@Override
public boolean tryLock() {
if(super.tryLock()) {
if(YamlConfig.config.server.USE_THREAD_TRACKER) {
if(deadlockedState != null) {
//FilePrinter.printError(FilePrinter.DEADLOCK_ERROR, "Deadlock occurred when trying to use the '" + id.name() + "' lock resources:\r\n" + printStackTrace(deadlockedState));
ThreadTracker.getInstance().accessThreadTracker(true, true, id, hashcode);
deadlockedState = null;
}
registerLocking();
}
return true;
} else {
return false;
}
}
private void registerLocking() {
state.lock();
try {
ThreadTracker.getInstance().accessThreadTracker(false, true, id, hashcode);
if(reentrantCount.incrementAndGet() == 1) {
final Thread t = Thread.currentThread();
timeoutSchedule = TimerManager.getInstance().schedule(new Runnable() {
@Override
public void run() {
issueDeadlock(t);
}
}, YamlConfig.config.server.LOCK_MONITOR_TIME);
}
} finally {
state.unlock();
}
}
private void unregisterLocking() {
state.lock();
try {
if(reentrantCount.decrementAndGet() == 0) {
if(timeoutSchedule != null) {
timeoutSchedule.cancel(false);
timeoutSchedule = null;
}
}
ThreadTracker.getInstance().accessThreadTracker(false, false, id, hashcode);
} finally {
state.unlock();
}
}
private void issueDeadlock(Thread t) {
deadlockedState = t.getStackTrace();
//super.unlock();
}
private static String printStackTrace(StackTraceElement[] list) {
String s = "";
for(int i = 0; i < list.length; i++) {
s += (" " + list[i].toString() + "\r\n");
}
return s;
}
@Override
public MonitoredReentrantLock dispose() {
state.lock();
try {
if(timeoutSchedule != null) {
timeoutSchedule.cancel(false);
timeoutSchedule = null;
}
reentrantCount.set(Integer.MAX_VALUE);
} finally {
state.unlock();
}
//unlock();
return new EmptyReentrantLock(id);
}
}

View File

@@ -0,0 +1,169 @@
/*
This file is part of the HeavenMS MapleStory Server
Copyleft (L) 2016 - 2019 RonanLana
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation 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.server.audit.locks.active;
import config.YamlConfig;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimeZone;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.ScheduledFuture;
import server.TimerManager;
import net.server.audit.ThreadTracker;
import net.server.audit.locks.MonitoredLockType;
import net.server.audit.locks.MonitoredReentrantReadWriteLock;
import net.server.audit.locks.MonitoredWriteLock;
import net.server.audit.locks.empty.EmptyWriteLock;
import tools.FilePrinter;
/**
*
* @author RonanLana
*/
public class TrackerWriteLock extends ReentrantReadWriteLock.WriteLock implements MonitoredWriteLock {
private ScheduledFuture<?> timeoutSchedule = null;
private StackTraceElement[] deadlockedState = null;
private final MonitoredLockType id;
private final int hashcode;
private final Lock state = new ReentrantLock(true);
private final AtomicInteger reentrantCount = new AtomicInteger(0);
public TrackerWriteLock(MonitoredReentrantReadWriteLock lock) {
super(lock);
this.id = lock.id;
hashcode = this.hashCode();
}
@Override
public void lock() {
if(YamlConfig.config.server.USE_THREAD_TRACKER) {
if(deadlockedState != null) {
DateFormat dateFormat = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss");
dateFormat.setTimeZone(TimeZone.getDefault());
//FilePrinter.printError(FilePrinter.DEADLOCK_ERROR, "[CRITICAL] " + dateFormat.format(new Date()) + " Deadlock occurred when trying to use the '" + id.name() + "' lock resources:\r\n" + printStackTrace(deadlockedState));
ThreadTracker.getInstance().accessThreadTracker(true, true, id, hashcode);
deadlockedState = null;
}
registerLocking();
}
super.lock();
}
@Override
public void unlock() {
if(YamlConfig.config.server.USE_THREAD_TRACKER) {
unregisterLocking();
}
super.unlock();
}
@Override
public boolean tryLock() {
if(super.tryLock()) {
if(YamlConfig.config.server.USE_THREAD_TRACKER) {
if(deadlockedState != null) {
//FilePrinter.printError(FilePrinter.DEADLOCK_ERROR, "Deadlock occurred when trying to use the '" + id.name() + "' lock resources:\r\n" + printStackTrace(deadlockedState));
ThreadTracker.getInstance().accessThreadTracker(true, true, id, hashcode);
deadlockedState = null;
}
registerLocking();
}
return true;
} else {
return false;
}
}
private void registerLocking() {
state.lock();
try {
ThreadTracker.getInstance().accessThreadTracker(false, true, id, hashcode);
if(reentrantCount.incrementAndGet() == 1) {
final Thread t = Thread.currentThread();
timeoutSchedule = TimerManager.getInstance().schedule(new Runnable() {
@Override
public void run() {
issueDeadlock(t);
}
}, YamlConfig.config.server.LOCK_MONITOR_TIME);
}
} finally {
state.unlock();
}
}
private void unregisterLocking() {
state.lock();
try {
if(reentrantCount.decrementAndGet() == 0) {
if(timeoutSchedule != null) {
timeoutSchedule.cancel(false);
timeoutSchedule = null;
}
}
ThreadTracker.getInstance().accessThreadTracker(false, false, id, hashcode);
} finally {
state.unlock();
}
}
private void issueDeadlock(Thread t) {
deadlockedState = t.getStackTrace();
//super.unlock();
}
private static String printStackTrace(StackTraceElement[] list) {
String s = "";
for(int i = 0; i < list.length; i++) {
s += (" " + list[i].toString() + "\r\n");
}
return s;
}
@Override
public MonitoredWriteLock dispose() {
state.lock();
try {
if(timeoutSchedule != null) {
timeoutSchedule.cancel(false);
timeoutSchedule = null;
}
reentrantCount.set(Integer.MAX_VALUE);
} finally {
state.unlock();
}
//unlock();
return new EmptyWriteLock(id);
}
}

View File

@@ -0,0 +1,24 @@
package net.server.audit.locks.empty;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimeZone;
public abstract class AbstractEmptyLock {
protected static String printThreadStack(StackTraceElement[] list) {
DateFormat dateFormat = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss"); // DRY-code opportunity performed by jtumidanski
dateFormat.setTimeZone(TimeZone.getDefault());
String df = dateFormat.format(new Date());
String s = "\r\n" + df + "\r\n";
for(int i = 0; i < list.length; i++) {
s += (" " + list[i].toString() + "\r\n");
}
s += "----------------------------\r\n\r\n";
return s;
}
}

View File

@@ -0,0 +1,55 @@
/*
This file is part of the HeavenMS MapleStory Server
Copyleft (L) 2016 - 2019 RonanLana
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation 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.server.audit.locks.empty;
import net.server.audit.locks.MonitoredLockType;
import net.server.audit.locks.MonitoredReadLock;
import tools.FilePrinter;
/**
*
* @author RonanLana
*/
public class EmptyReadLock extends AbstractEmptyLock implements MonitoredReadLock {
private final MonitoredLockType id;
public EmptyReadLock(MonitoredLockType type) {
this.id = type;
}
@Override
public void lock() {
FilePrinter.printError(FilePrinter.DISPOSED_LOCKS, "Captured locking tentative on disposed lock " + id + ":" + printThreadStack(Thread.currentThread().getStackTrace()));
}
@Override
public void unlock() {}
@Override
public boolean tryLock() {
FilePrinter.printError(FilePrinter.DISPOSED_LOCKS, "Captured try-locking tentative on disposed lock " + id + ":" + printThreadStack(Thread.currentThread().getStackTrace()));
return false;
}
@Override
public MonitoredReadLock dispose() {
return this;
}
}

View File

@@ -0,0 +1,55 @@
/*
This file is part of the HeavenMS MapleStory Server
Copyleft (L) 2016 - 2019 RonanLana
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation 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.server.audit.locks.empty;
import net.server.audit.locks.MonitoredLockType;
import net.server.audit.locks.MonitoredReentrantLock;
import tools.FilePrinter;
/**
*
* @author RonanLana
*/
public class EmptyReentrantLock extends AbstractEmptyLock implements MonitoredReentrantLock {
private final MonitoredLockType id;
public EmptyReentrantLock(MonitoredLockType type) {
this.id = type;
}
@Override
public void lock() {
FilePrinter.printError(FilePrinter.DISPOSED_LOCKS, "Captured locking tentative on disposed lock " + id + ":" + printThreadStack(Thread.currentThread().getStackTrace()));
}
@Override
public void unlock() {}
@Override
public boolean tryLock() {
FilePrinter.printError(FilePrinter.DISPOSED_LOCKS, "Captured try-locking tentative on disposed lock " + id + ":" + printThreadStack(Thread.currentThread().getStackTrace()));
return false;
}
@Override
public MonitoredReentrantLock dispose() {
return this;
}
}

View File

@@ -0,0 +1,55 @@
/*
This file is part of the HeavenMS MapleStory Server
Copyleft (L) 2016 - 2019 RonanLana
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation 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.server.audit.locks.empty;
import net.server.audit.locks.MonitoredLockType;
import net.server.audit.locks.MonitoredWriteLock;
import tools.FilePrinter;
/**
*
* @author RonanLana
*/
public class EmptyWriteLock extends AbstractEmptyLock implements MonitoredWriteLock {
private final MonitoredLockType id;
public EmptyWriteLock(MonitoredLockType type) {
this.id = type;
}
@Override
public void lock() {
FilePrinter.printError(FilePrinter.DISPOSED_LOCKS, "Captured locking tentative on disposed lock " + id + ":" + printThreadStack(Thread.currentThread().getStackTrace()));
}
@Override
public void unlock() {}
@Override
public boolean tryLock() {
FilePrinter.printError(FilePrinter.DISPOSED_LOCKS, "Captured try-locking tentative on disposed lock " + id + ":" + printThreadStack(Thread.currentThread().getStackTrace()));
return false;
}
@Override
public MonitoredWriteLock dispose() {
return this;
}
}

View File

@@ -0,0 +1,33 @@
/*
This file is part of the HeavenMS MapleStory Server
Copyleft (L) 2016 - 2019 RonanLana
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation 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.server.audit.locks.factory;
import net.server.audit.locks.MonitoredReentrantReadWriteLock;
import net.server.audit.locks.active.TrackerReadLock;
/**
*
* @author RonanLana
*/
public class MonitoredReadLockFactory {
public static TrackerReadLock createLock(MonitoredReentrantReadWriteLock lock) {
return new TrackerReadLock(lock);
}
}

View File

@@ -0,0 +1,37 @@
/*
This file is part of the HeavenMS MapleStory Server
Copyleft (L) 2016 - 2019 RonanLana
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation 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.server.audit.locks.factory;
import net.server.audit.locks.MonitoredLockType;
import net.server.audit.locks.active.TrackerReentrantLock;
/**
*
* @author RonanLana
*/
public class MonitoredReentrantLockFactory {
public static TrackerReentrantLock createLock(MonitoredLockType id) {
return new TrackerReentrantLock(id);
}
public static TrackerReentrantLock createLock(MonitoredLockType id, boolean fair) {
return new TrackerReentrantLock(id, fair);
}
}

View File

@@ -0,0 +1,33 @@
/*
This file is part of the HeavenMS MapleStory Server
Copyleft (L) 2016 - 2019 RonanLana
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation 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.server.audit.locks.factory;
import net.server.audit.locks.MonitoredReentrantReadWriteLock;
import net.server.audit.locks.active.TrackerWriteLock;
/**
*
* @author RonanLana
*/
public class MonitoredWriteLockFactory {
public static TrackerWriteLock createLock(MonitoredReentrantReadWriteLock lock) {
return new TrackerWriteLock(lock);
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,47 @@
/*
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 as
published by the Free Software Foundation 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.server.channel;
/**
*
* @author Frz
*/
public class CharacterIdChannelPair {
private int charid;
private int channel;
public CharacterIdChannelPair() {
}
public CharacterIdChannelPair(int charid, int channel) {
this.charid = charid;
this.channel = channel;
}
public int getCharacterId() {
return charid;
}
public int getChannel() {
return channel;
}
}

View File

@@ -0,0 +1,943 @@
/*
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 as
published by the Free Software Foundation 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.server.channel.handlers;
import java.awt.Point;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import config.YamlConfig;
import net.AbstractMaplePacketHandler;
import server.MapleStatEffect;
import server.TimerManager;
import server.life.Element;
import server.life.ElementalEffectiveness;
import server.life.MapleMonster;
import server.life.MapleMonsterInformationProvider;
import server.life.MobSkill;
import server.life.MobSkillFactory;
import server.life.MonsterDropEntry;
import server.maps.MapleMap;
import server.maps.MapleMapItem;
import server.maps.MapleMapObject;
import server.maps.MapleMapObjectType;
import tools.MaplePacketCreator;
import tools.Pair;
import tools.Randomizer;
import tools.data.input.LittleEndianAccessor;
import client.MapleBuffStat;
import client.MapleCharacter;
import client.MapleJob;
import client.Skill;
import client.SkillFactory;
import client.autoban.AutobanFactory;
import client.status.MonsterStatus;
import client.status.MonsterStatusEffect;
import constants.game.GameConstants;
import constants.skills.Aran;
import constants.skills.Assassin;
import constants.skills.Bandit;
import constants.skills.Beginner;
import constants.skills.Bishop;
import constants.skills.BlazeWizard;
import constants.skills.Bowmaster;
import constants.skills.Brawler;
import constants.skills.Buccaneer;
import constants.skills.ChiefBandit;
import constants.skills.Cleric;
import constants.skills.Corsair;
import constants.skills.Crossbowman;
import constants.skills.Crusader;
import constants.skills.DawnWarrior;
import constants.skills.DragonKnight;
import constants.skills.Evan;
import constants.skills.FPArchMage;
import constants.skills.FPMage;
import constants.skills.FPWizard;
import constants.skills.Fighter;
import constants.skills.Gunslinger;
import constants.skills.Hermit;
import constants.skills.Hero;
import constants.skills.Hunter;
import constants.skills.ILArchMage;
import constants.skills.ILMage;
import constants.skills.Legend;
import constants.skills.Marauder;
import constants.skills.Marksman;
import constants.skills.NightLord;
import constants.skills.NightWalker;
import constants.skills.Noblesse;
import constants.skills.Outlaw;
import constants.skills.Page;
import constants.skills.Paladin;
import constants.skills.Ranger;
import constants.skills.Rogue;
import constants.skills.Shadower;
import constants.skills.Sniper;
import constants.skills.Spearman;
import constants.skills.SuperGM;
import constants.skills.ThunderBreaker;
import constants.skills.WhiteKnight;
import constants.skills.WindArcher;
import net.server.PlayerBuffValueHolder;
import scripting.AbstractPlayerInteraction;
public abstract class AbstractDealDamageHandler extends AbstractMaplePacketHandler {
public static class AttackInfo {
public int numAttacked, numDamage, numAttackedAndDamage, skill, skilllevel, stance, direction, rangedirection, charge, display;
public Map<Integer, List<Integer>> allDamage;
public boolean ranged, magic;
public int speed = 4;
public Point position = new Point();
public MapleStatEffect getAttackEffect(MapleCharacter chr, Skill theSkill) {
Skill mySkill = theSkill;
if (mySkill == null) {
mySkill = SkillFactory.getSkill(skill);
}
int skillLevel = chr.getSkillLevel(mySkill);
if(skillLevel == 0 && GameConstants.isPqSkillMap(chr.getMapId()) && GameConstants.isPqSkill(mySkill.getId())) skillLevel = 1;
if (skillLevel == 0) {
return null;
}
if (display > 80) { //Hmm
if (!mySkill.getAction()) {
AutobanFactory.FAST_ATTACK.autoban(chr, "WZ Edit; adding action to a skill: " + display);
return null;
}
}
return mySkill.getEffect(skillLevel);
}
}
protected void applyAttack(AttackInfo attack, final MapleCharacter player, int attackCount) {
final MapleMap map = player.getMap();
if (map.isOwnershipRestricted(player)) {
return;
}
Skill theSkill = null;
MapleStatEffect attackEffect = null;
final int job = player.getJob().getId();
try {
if (player.isBanned()) {
return;
}
if (attack.skill != 0) {
theSkill = SkillFactory.getSkill(attack.skill); // thanks Conrad for noticing some Aran skills not consuming MP
attackEffect = attack.getAttackEffect(player, theSkill); //returns back the player's attack effect so we are gucci
if (attackEffect == null) {
player.announce(MaplePacketCreator.enableActions());
return;
}
if (player.getMp() < attackEffect.getMpCon()) {
AutobanFactory.MPCON.addPoint(player.getAutobanManager(), "Skill: " + attack.skill + "; Player MP: " + player.getMp() + "; MP Needed: " + attackEffect.getMpCon());
}
int mobCount = attackEffect.getMobCount();
if (attack.skill != Cleric.HEAL) {
if (player.isAlive()) {
if(attack.skill == Aran.BODY_PRESSURE || attack.skill == Marauder.ENERGY_CHARGE || attack.skill == ThunderBreaker.ENERGY_CHARGE) { // thanks IxianMace for noticing Energy Charge skills refreshing on touch
// prevent touch dmg skills refreshing
} else if(attack.skill == DawnWarrior.FINAL_ATTACK || attack.skill == WindArcher.FINAL_ATTACK) {
// prevent cygnus FA refreshing
mobCount = 15;
} else if(attack.skill == NightWalker.POISON_BOMB) {// Poison Bomb
attackEffect.applyTo(player, new Point(attack.position.x, attack.position.y));
} else {
attackEffect.applyTo(player);
if (attack.skill == Page.FINAL_ATTACK_BW || attack.skill == Page.FINAL_ATTACK_SWORD || attack.skill == Fighter.FINAL_ATTACK_SWORD
|| attack.skill == Fighter.FINAL_ATTACK_AXE || attack.skill == Spearman.FINAL_ATTACK_SPEAR || attack.skill == Spearman.FINAL_ATTACK_POLEARM
|| attack.skill == Hunter.FINAL_ATTACK || attack.skill == Crossbowman.FINAL_ATTACK) {
mobCount = 15;//:(
} else if (attack.skill == Aran.HIDDEN_FULL_DOUBLE || attack.skill == Aran.HIDDEN_FULL_TRIPLE || attack.skill == Aran.HIDDEN_OVER_DOUBLE || attack.skill == Aran.HIDDEN_OVER_TRIPLE) {
mobCount = 12;
}
}
} else {
player.announce(MaplePacketCreator.enableActions());
}
}
if (attack.numAttacked > mobCount) {
AutobanFactory.MOB_COUNT.autoban(player, "Skill: " + attack.skill + "; Count: " + attack.numAttacked + " Max: " + attackEffect.getMobCount());
return;
}
}
if (!player.isAlive()) {
return;
}
//WTF IS THIS F3,1
/*if (attackCount != attack.numDamage && attack.skill != ChiefBandit.MESO_EXPLOSION && attack.skill != NightWalker.VAMPIRE && attack.skill != WindArcher.WIND_SHOT && attack.skill != Aran.COMBO_SMASH && attack.skill != Aran.COMBO_FENRIR && attack.skill != Aran.COMBO_TEMPEST && attack.skill != NightLord.NINJA_AMBUSH && attack.skill != Shadower.NINJA_AMBUSH) {
return;
}*/
int totDamage = 0;
if (attack.skill == ChiefBandit.MESO_EXPLOSION) {
int delay = 0;
for (Integer oned : attack.allDamage.keySet()) {
MapleMapObject mapobject = map.getMapObject(oned.intValue());
if (mapobject != null && mapobject.getType() == MapleMapObjectType.ITEM) {
final MapleMapItem mapitem = (MapleMapItem) mapobject;
if (mapitem.getMeso() == 0) { //Maybe it is possible some how?
return;
}
mapitem.lockItem();
try {
if (mapitem.isPickedUp()) {
return;
}
TimerManager.getInstance().schedule(new Runnable() {
@Override
public void run() {
mapitem.lockItem();
try {
if (mapitem.isPickedUp()) {
return;
}
map.pickItemDrop(MaplePacketCreator.removeItemFromMap(mapitem.getObjectId(), 4, 0), mapitem);
} finally {
mapitem.unlockItem();
}
}
}, delay);
delay += 100;
} finally {
mapitem.unlockItem();
}
} else if (mapobject != null && mapobject.getType() != MapleMapObjectType.MONSTER) {
return;
}
}
}
for (Integer oned : attack.allDamage.keySet()) {
final MapleMonster monster = map.getMonsterByOid(oned.intValue());
if (monster != null) {
double distance = player.getPosition().distanceSq(monster.getPosition());
double distanceToDetect = 200000.0;
if(attack.ranged)
distanceToDetect += 400000;
if(attack.magic)
distanceToDetect += 200000;
if(player.getJob().isA(MapleJob.ARAN1))
distanceToDetect += 200000; // Arans have extra range over normal warriors.
if(attack.skill == Aran.COMBO_SMASH || attack.skill == Aran.BODY_PRESSURE)
distanceToDetect += 40000;
else if(attack.skill == Bishop.GENESIS || attack.skill == ILArchMage.BLIZZARD || attack.skill == FPArchMage.METEOR_SHOWER)
distanceToDetect += 275000;
else if(attack.skill == Hero.BRANDISH || attack.skill == DragonKnight.SPEAR_CRUSHER || attack.skill == DragonKnight.POLE_ARM_CRUSHER)
distanceToDetect += 40000;
else if(attack.skill == DragonKnight.DRAGON_ROAR || attack.skill == SuperGM.SUPER_DRAGON_ROAR)
distanceToDetect += 250000;
else if(attack.skill == Shadower.BOOMERANG_STEP)
distanceToDetect += 60000;
if (distance > distanceToDetect) {
AutobanFactory.DISTANCE_HACK.alert(player, "Distance Sq to monster: " + distance + " SID: " + attack.skill + " MID: " + monster.getId());
monster.refreshMobPosition();
}
int totDamageToOneMonster = 0;
List<Integer> onedList = attack.allDamage.get(oned);
if (attack.magic) { // thanks BHB, Alex (CanIGetaPR) for noticing no immunity status check here
if (monster.isBuffed(MonsterStatus.MAGIC_IMMUNITY)) {
Collections.fill(onedList, 1);
}
} else {
if (monster.isBuffed(MonsterStatus.WEAPON_IMMUNITY)) {
Collections.fill(onedList, 1);
}
}
if (GameConstants.isDojoBoss(monster.getId())) {
if (attack.skill == 1009 || attack.skill == 10001009 || attack.skill == 20001009) {
int dmgLimit = (int) Math.ceil(0.3 * monster.getMaxHp());
List<Integer> _onedList = new LinkedList<>();
for (Integer i : onedList) {
_onedList.add(i < dmgLimit ? i : dmgLimit);
}
onedList = _onedList;
}
}
for (Integer eachd : onedList) {
if(eachd < 0) eachd += Integer.MAX_VALUE;
totDamageToOneMonster += eachd;
}
totDamage += totDamageToOneMonster;
monster.aggroMonsterDamage(player, totDamageToOneMonster);
if (player.getBuffedValue(MapleBuffStat.PICKPOCKET) != null && (attack.skill == 0 || attack.skill == Rogue.DOUBLE_STAB || attack.skill == Bandit.SAVAGE_BLOW || attack.skill == ChiefBandit.ASSAULTER || attack.skill == ChiefBandit.BAND_OF_THIEVES || attack.skill == Shadower.ASSASSINATE || attack.skill == Shadower.TAUNT || attack.skill == Shadower.BOOMERANG_STEP)) {
Skill pickpocket = SkillFactory.getSkill(ChiefBandit.PICKPOCKET);
int picklv = (player.isGM()) ? pickpocket.getMaxLevel() : player.getSkillLevel(pickpocket);
if(picklv > 0) {
int delay = 0;
final int maxmeso = player.getBuffedValue(MapleBuffStat.PICKPOCKET).intValue();
for (Integer eachd : onedList) {
eachd += Integer.MAX_VALUE;
if (pickpocket.getEffect(picklv).makeChanceResult()) {
final Integer eachdf;
if(eachd < 0)
eachdf = eachd + Integer.MAX_VALUE;
else
eachdf = eachd;
TimerManager.getInstance().schedule(new Runnable() {
@Override
public void run() {
map.spawnMesoDrop(Math.min((int) Math.max(((double) eachdf / (double) 20000) * (double) maxmeso, (double) 1), maxmeso), new Point((int) (monster.getPosition().getX() + Randomizer.nextInt(100) - 50), (int) (monster.getPosition().getY())), monster, player, true, (byte) 2);
}
}, delay);
delay += 100;
}
}
}
} else if (attack.skill == Marauder.ENERGY_DRAIN || attack.skill == ThunderBreaker.ENERGY_DRAIN || attack.skill == NightWalker.VAMPIRE || attack.skill == Assassin.DRAIN) {
player.addHP(Math.min(monster.getMaxHp(), Math.min((int) ((double) totDamage * (double) SkillFactory.getSkill(attack.skill).getEffect(player.getSkillLevel(SkillFactory.getSkill(attack.skill))).getX() / 100.0), player.getCurrentMaxHp() / 2)));
} else if (attack.skill == Bandit.STEAL) {
Skill steal = SkillFactory.getSkill(Bandit.STEAL);
if (monster.getStolen().size() < 1) { // One steal per mob <3
if (steal.getEffect(player.getSkillLevel(steal)).makeChanceResult()) {
monster.addStolen(0);
MapleMonsterInformationProvider mi = MapleMonsterInformationProvider.getInstance();
List<Integer> dropPool = mi.retrieveDropPool(monster.getId());
if(!dropPool.isEmpty()) {
Integer rndPool = (int) Math.floor(Math.random() * dropPool.get(dropPool.size() - 1));
int i = 0;
while(rndPool >= dropPool.get(i)) i++;
List<MonsterDropEntry> toSteal = new ArrayList<>();
toSteal.add(mi.retrieveDrop(monster.getId()).get(i));
map.dropItemsFromMonster(toSteal, player, monster);
monster.addStolen(toSteal.get(0).itemId);
}
}
}
} else if (attack.skill == FPArchMage.FIRE_DEMON) {
monster.setTempEffectiveness(Element.ICE, ElementalEffectiveness.WEAK, SkillFactory.getSkill(FPArchMage.FIRE_DEMON).getEffect(player.getSkillLevel(SkillFactory.getSkill(FPArchMage.FIRE_DEMON))).getDuration() * 1000);
} else if (attack.skill == ILArchMage.ICE_DEMON) {
monster.setTempEffectiveness(Element.FIRE, ElementalEffectiveness.WEAK, SkillFactory.getSkill(ILArchMage.ICE_DEMON).getEffect(player.getSkillLevel(SkillFactory.getSkill(ILArchMage.ICE_DEMON))).getDuration() * 1000);
} else if (attack.skill == Outlaw.HOMING_BEACON || attack.skill == Corsair.BULLSEYE) {
MapleStatEffect beacon = SkillFactory.getSkill(attack.skill).getEffect(player.getSkillLevel(attack.skill));
beacon.applyBeaconBuff(player, monster.getObjectId());
} else if (attack.skill == Outlaw.FLAME_THROWER) {
if (!monster.isBoss()) {
Skill type = SkillFactory.getSkill(Outlaw.FLAME_THROWER);
if (player.getSkillLevel(type) > 0) {
MapleStatEffect DoT = type.getEffect(player.getSkillLevel(type));
MonsterStatusEffect monsterStatusEffect = new MonsterStatusEffect(Collections.singletonMap(MonsterStatus.POISON, 1), type, null, false);
monster.applyStatus(player, monsterStatusEffect, true, DoT.getDuration(), false);
}
}
}
if (player.isAran()) {
if (player.getBuffedValue(MapleBuffStat.WK_CHARGE) != null) {
Skill snowCharge = SkillFactory.getSkill(Aran.SNOW_CHARGE);
if (totDamageToOneMonster > 0) {
MonsterStatusEffect monsterStatusEffect = new MonsterStatusEffect(Collections.singletonMap(MonsterStatus.SPEED, snowCharge.getEffect(player.getSkillLevel(snowCharge)).getX()), snowCharge, null, false);
monster.applyStatus(player, monsterStatusEffect, false, snowCharge.getEffect(player.getSkillLevel(snowCharge)).getY() * 1000);
}
}
}
if (player.getBuffedValue(MapleBuffStat.HAMSTRING) != null) {
Skill hamstring = SkillFactory.getSkill(Bowmaster.HAMSTRING);
if (hamstring.getEffect(player.getSkillLevel(hamstring)).makeChanceResult()) {
MonsterStatusEffect monsterStatusEffect = new MonsterStatusEffect(Collections.singletonMap(MonsterStatus.SPEED, hamstring.getEffect(player.getSkillLevel(hamstring)).getX()), hamstring, null, false);
monster.applyStatus(player, monsterStatusEffect, false, hamstring.getEffect(player.getSkillLevel(hamstring)).getY() * 1000);
}
}
if (player.getBuffedValue(MapleBuffStat.SLOW) != null) {
Skill slow = SkillFactory.getSkill(Evan.SLOW);
if (slow.getEffect(player.getSkillLevel(slow)).makeChanceResult()) {
MonsterStatusEffect monsterStatusEffect = new MonsterStatusEffect(Collections.singletonMap(MonsterStatus.SPEED, slow.getEffect(player.getSkillLevel(slow)).getX()), slow, null, false);
monster.applyStatus(player, monsterStatusEffect, false, slow.getEffect(player.getSkillLevel(slow)).getY() * 60 * 1000);
}
}
if (player.getBuffedValue(MapleBuffStat.BLIND) != null) {
Skill blind = SkillFactory.getSkill(Marksman.BLIND);
if (blind.getEffect(player.getSkillLevel(blind)).makeChanceResult()) {
MonsterStatusEffect monsterStatusEffect = new MonsterStatusEffect(Collections.singletonMap(MonsterStatus.ACC, blind.getEffect(player.getSkillLevel(blind)).getX()), blind, null, false);
monster.applyStatus(player, monsterStatusEffect, false, blind.getEffect(player.getSkillLevel(blind)).getY() * 1000);
}
}
if (job == 121 || job == 122) {
for (int charge = 1211005; charge < 1211007; charge++) {
Skill chargeSkill = SkillFactory.getSkill(charge);
if (player.isBuffFrom(MapleBuffStat.WK_CHARGE, chargeSkill)) {
if (totDamageToOneMonster > 0) {
if (charge == WhiteKnight.BW_ICE_CHARGE || charge == WhiteKnight.SWORD_ICE_CHARGE) {
monster.setTempEffectiveness(Element.ICE, ElementalEffectiveness.WEAK, chargeSkill.getEffect(player.getSkillLevel(chargeSkill)).getY() * 1000);
break;
}
if (charge == WhiteKnight.BW_FIRE_CHARGE || charge == WhiteKnight.SWORD_FIRE_CHARGE) {
monster.setTempEffectiveness(Element.FIRE, ElementalEffectiveness.WEAK, chargeSkill.getEffect(player.getSkillLevel(chargeSkill)).getY() * 1000);
break;
}
}
}
}
if (job == 122) {
for (int charge = 1221003; charge < 1221004; charge++) {
Skill chargeSkill = SkillFactory.getSkill(charge);
if (player.isBuffFrom(MapleBuffStat.WK_CHARGE, chargeSkill)) {
if (totDamageToOneMonster > 0) {
monster.setTempEffectiveness(Element.HOLY, ElementalEffectiveness.WEAK, chargeSkill.getEffect(player.getSkillLevel(chargeSkill)).getY() * 1000);
break;
}
}
}
}
} else if (player.getBuffedValue(MapleBuffStat.COMBO_DRAIN) != null) {
Skill skill;
if (player.getBuffedValue(MapleBuffStat.COMBO_DRAIN) != null) {
skill = SkillFactory.getSkill(21100005);
player.addHP(((totDamage * skill.getEffect(player.getSkillLevel(skill)).getX()) / 100));
}
} else if (job == 412 || job == 422 || job == 1411) {
Skill type = SkillFactory.getSkill(player.getJob().getId() == 412 ? 4120005 : (player.getJob().getId() == 1411 ? 14110004 : 4220005));
if (player.getSkillLevel(type) > 0) {
MapleStatEffect venomEffect = type.getEffect(player.getSkillLevel(type));
for (int i = 0; i < attackCount; i++) {
if (venomEffect.makeChanceResult()) {
if (monster.getVenomMulti() < 3) {
monster.setVenomMulti((monster.getVenomMulti() + 1));
MonsterStatusEffect monsterStatusEffect = new MonsterStatusEffect(Collections.singletonMap(MonsterStatus.POISON, 1), type, null, false);
monster.applyStatus(player, monsterStatusEffect, false, venomEffect.getDuration(), true);
}
}
}
}
} else if (job >= 311 && job <= 322) {
if (!monster.isBoss()) {
Skill mortalBlow;
if (job == 311 || job == 312) {
mortalBlow = SkillFactory.getSkill(Ranger.MORTAL_BLOW);
} else {
mortalBlow = SkillFactory.getSkill(Sniper.MORTAL_BLOW);
}
int skillLevel = player.getSkillLevel(mortalBlow);
if (skillLevel > 0) {
MapleStatEffect mortal = mortalBlow.getEffect(skillLevel);
if (monster.getHp() <= (monster.getStats().getHp() * mortal.getX()) / 100) {
if (Randomizer.rand(1, 100) <= mortal.getY()) {
map.damageMonster(player, monster, Integer.MAX_VALUE); // thanks Conrad for noticing reduced EXP gain from skill kill
}
}
}
}
}
if (attack.skill != 0) {
if (attackEffect.getFixDamage() != -1) {
if (totDamageToOneMonster != attackEffect.getFixDamage() && totDamageToOneMonster != 0) {
AutobanFactory.FIX_DAMAGE.autoban(player, String.valueOf(totDamageToOneMonster) + " damage");
}
int threeSnailsId = player.getJobType() * 10000000 + 1000;
if(attack.skill == threeSnailsId) {
if(YamlConfig.config.server.USE_ULTRA_THREE_SNAILS) {
int skillLv = player.getSkillLevel(threeSnailsId);
if(skillLv > 0) {
AbstractPlayerInteraction api = player.getAbstractPlayerInteraction();
int shellId;
switch(skillLv) {
case 1:
shellId = 4000019;
break;
case 2:
shellId = 4000000;
break;
default:
shellId = 4000016;
}
if(api.haveItem(shellId, 1)) {
api.gainItem(shellId, (short) -1, false);
totDamageToOneMonster *= player.getLevel();
} else {
player.dropMessage(5, "You have ran out of shells to activate the hidden power of Three Snails.");
}
} else {
totDamageToOneMonster = 0;
}
}
}
}
}
if (totDamageToOneMonster > 0 && attackEffect != null) {
Map<MonsterStatus, Integer> attackEffectStati = attackEffect.getMonsterStati();
if(!attackEffectStati.isEmpty()) {
if (attackEffect.makeChanceResult()) {
monster.applyStatus(player, new MonsterStatusEffect(attackEffectStati, theSkill, null, false), attackEffect.isPoison(), attackEffect.getDuration());
}
}
}
if (attack.skill == Paladin.HEAVENS_HAMMER) {
if(!monster.isBoss()) {
damageMonsterWithSkill(player, map, monster, monster.getHp() - 1, attack.skill, 1777);
} else {
int HHDmg = (player.calculateMaxBaseDamage(player.getTotalWatk()) * (SkillFactory.getSkill(Paladin.HEAVENS_HAMMER).getEffect(player.getSkillLevel(SkillFactory.getSkill(Paladin.HEAVENS_HAMMER))).getDamage() / 100));
damageMonsterWithSkill(player, map, monster, (int) (Math.floor(Math.random() * (HHDmg / 5) + HHDmg * .8)), attack.skill, 1777);
}
} else if (attack.skill == Aran.COMBO_TEMPEST) {
if(!monster.isBoss()) {
damageMonsterWithSkill(player, map, monster, monster.getHp(), attack.skill, 0);
} else {
int TmpDmg = (player.calculateMaxBaseDamage(player.getTotalWatk()) * (SkillFactory.getSkill(Aran.COMBO_TEMPEST).getEffect(player.getSkillLevel(SkillFactory.getSkill(Aran.COMBO_TEMPEST))).getDamage() / 100));
damageMonsterWithSkill(player, map, monster, (int) (Math.floor(Math.random() * (TmpDmg / 5) + TmpDmg * .8)), attack.skill, 0);
}
} else {
if(attack.skill == Aran.BODY_PRESSURE) {
map.broadcastMessage(MaplePacketCreator.damageMonster(monster.getObjectId(), totDamageToOneMonster));
}
map.damageMonster(player, monster, totDamageToOneMonster);
}
if (monster.isBuffed(MonsterStatus.WEAPON_REFLECT) && !attack.magic) {
List<Pair<Integer, Integer>> mobSkills = monster.getSkills();
for (Pair<Integer, Integer> ms : mobSkills) {
if (ms.left == 145) {
MobSkill toUse = MobSkillFactory.getMobSkill(ms.left, ms.right);
player.addHP(-toUse.getX());
map.broadcastMessage(player, MaplePacketCreator.damagePlayer(0, monster.getId(), player.getId(), toUse.getX(), 0, 0, false, 0, true, monster.getObjectId(), 0, 0), true);
}
}
}
if (monster.isBuffed(MonsterStatus.MAGIC_REFLECT) && attack.magic) {
List<Pair<Integer, Integer>> mobSkills = monster.getSkills();
for (Pair<Integer, Integer> ms : mobSkills) {
if (ms.left == 145) {
MobSkill toUse = MobSkillFactory.getMobSkill(ms.left, ms.right);
player.addHP(-toUse.getY());
map.broadcastMessage(player, MaplePacketCreator.damagePlayer(0, monster.getId(), player.getId(), toUse.getY(), 0, 0, false, 0, true, monster.getObjectId(), 0, 0), true);
}
}
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
private static void damageMonsterWithSkill(final MapleCharacter attacker, final MapleMap map, final MapleMonster monster, final int damage, int skillid, int fixedTime) {
int animationTime;
if(fixedTime == 0) animationTime = SkillFactory.getSkill(skillid).getAnimationTime();
else animationTime = fixedTime;
if(animationTime > 0) { // be sure to only use LIMITED ATTACKS with animation time here
TimerManager.getInstance().schedule(new Runnable() {
@Override
public void run() {
map.broadcastMessage(MaplePacketCreator.damageMonster(monster.getObjectId(), damage), monster.getPosition());
map.damageMonster(attacker, monster, damage);
}
}, animationTime);
} else {
map.broadcastMessage(MaplePacketCreator.damageMonster(monster.getObjectId(), damage), monster.getPosition());
map.damageMonster(attacker, monster, damage);
}
}
protected AttackInfo parseDamage(LittleEndianAccessor lea, MapleCharacter chr, boolean ranged, boolean magic) {
//2C 00 00 01 91 A1 12 00 A5 57 62 FC E2 75 99 10 00 47 80 01 04 01 C6 CC 02 DD FF 5F 00
AttackInfo ret = new AttackInfo();
lea.readByte();
ret.numAttackedAndDamage = lea.readByte();
ret.numAttacked = (ret.numAttackedAndDamage >>> 4) & 0xF;
ret.numDamage = ret.numAttackedAndDamage & 0xF;
ret.allDamage = new HashMap<>();
ret.skill = lea.readInt();
ret.ranged = ranged;
ret.magic = magic;
if (ret.skill > 0) {
ret.skilllevel = chr.getSkillLevel(ret.skill);
if(ret.skilllevel == 0 && GameConstants.isPqSkillMap(chr.getMapId()) && GameConstants.isPqSkill(ret.skill)) ret.skilllevel = 1;
}
if (ret.skill == Evan.ICE_BREATH || ret.skill == Evan.FIRE_BREATH || ret.skill == FPArchMage.BIG_BANG || ret.skill == ILArchMage.BIG_BANG || ret.skill == Bishop.BIG_BANG || ret.skill == Gunslinger.GRENADE || ret.skill == Brawler.CORKSCREW_BLOW || ret.skill == ThunderBreaker.CORKSCREW_BLOW || ret.skill == NightWalker.POISON_BOMB) {
ret.charge = lea.readInt();
} else {
ret.charge = 0;
}
lea.skip(8);
ret.display = lea.readByte();
ret.direction = lea.readByte();
ret.stance = lea.readByte();
if (ret.skill == ChiefBandit.MESO_EXPLOSION) {
if (ret.numAttackedAndDamage == 0) {
lea.skip(10);
int bullets = lea.readByte();
for (int j = 0; j < bullets; j++) {
int mesoid = lea.readInt();
lea.skip(1);
ret.allDamage.put(Integer.valueOf(mesoid), null);
}
return ret;
} else {
lea.skip(6);
}
for (int i = 0; i < ret.numAttacked + 1; i++) {
int oid = lea.readInt();
if (i < ret.numAttacked) {
lea.skip(12);
int bullets = lea.readByte();
List<Integer> allDamageNumbers = new ArrayList<>();
for (int j = 0; j < bullets; j++) {
int damage = lea.readInt();
allDamageNumbers.add(Integer.valueOf(damage));
}
ret.allDamage.put(Integer.valueOf(oid), allDamageNumbers);
lea.skip(4);
} else {
int bullets = lea.readByte();
for (int j = 0; j < bullets; j++) {
int mesoid = lea.readInt();
lea.skip(1);
ret.allDamage.put(Integer.valueOf(mesoid), null);
}
}
}
return ret;
}
if (ranged) {
lea.readByte();
ret.speed = lea.readByte();
lea.readByte();
ret.rangedirection = lea.readByte();
lea.skip(7);
if (ret.skill == Bowmaster.HURRICANE || ret.skill == Marksman.PIERCING_ARROW || ret.skill == Corsair.RAPID_FIRE || ret.skill == WindArcher.HURRICANE) {
lea.skip(4);
}
} else {
lea.readByte();
ret.speed = lea.readByte();
lea.skip(4);
}
// Find the base damage to base futher calculations on.
// Several skills have their own formula in this section.
long calcDmgMax;
if(magic && ret.skill != 0) { // thanks onechord for noticing a few false positives stemming from maxdmg as 0
calcDmgMax = (long) (Math.ceil((chr.getTotalMagic() * Math.ceil(chr.getTotalMagic() / 1000.0) + chr.getTotalMagic()) / 30.0) + Math.ceil(chr.getTotalInt() / 200.0));
} else if(ret.skill == 4001344 || ret.skill == NightWalker.LUCKY_SEVEN || ret.skill == NightLord.TRIPLE_THROW) {
calcDmgMax = (long) ((chr.getTotalLuk() * 5) * Math.ceil(chr.getTotalWatk() / 100.0));
} else if(ret.skill == DragonKnight.DRAGON_ROAR) {
calcDmgMax = (long) ((chr.getTotalStr() * 4 + chr.getTotalDex()) * Math.ceil(chr.getTotalWatk() / 100.0));
} else if(ret.skill == NightLord.VENOMOUS_STAR || ret.skill == Shadower.VENOMOUS_STAB) {
calcDmgMax = (long) (Math.ceil((18.5 * (chr.getTotalStr() + chr.getTotalLuk()) + chr.getTotalDex() * 2) / 100.0) * chr.calculateMaxBaseDamage(chr.getTotalWatk()));
} else {
calcDmgMax = chr.calculateMaxBaseDamage(chr.getTotalWatk());
}
if(ret.skill != 0) {
Skill skill = SkillFactory.getSkill(ret.skill);
MapleStatEffect effect = skill.getEffect(ret.skilllevel);
if (magic) {
// Since the skill is magic based, use the magic formula
if(chr.getJob() == MapleJob.IL_ARCHMAGE || chr.getJob() == MapleJob.IL_MAGE) {
int skillLvl = chr.getSkillLevel(ILMage.ELEMENT_AMPLIFICATION);
if(skillLvl > 0)
calcDmgMax = calcDmgMax * SkillFactory.getSkill(ILMage.ELEMENT_AMPLIFICATION).getEffect(skillLvl).getY() / 100;
} else if(chr.getJob() == MapleJob.FP_ARCHMAGE || chr.getJob() == MapleJob.FP_MAGE) {
int skillLvl = chr.getSkillLevel(FPMage.ELEMENT_AMPLIFICATION);
if(skillLvl > 0)
calcDmgMax = calcDmgMax * SkillFactory.getSkill(FPMage.ELEMENT_AMPLIFICATION).getEffect(skillLvl).getY() / 100;
} else if(chr.getJob() == MapleJob.BLAZEWIZARD3 || chr.getJob() == MapleJob.BLAZEWIZARD4) {
int skillLvl = chr.getSkillLevel(BlazeWizard.ELEMENT_AMPLIFICATION);
if(skillLvl > 0)
calcDmgMax = calcDmgMax * SkillFactory.getSkill(BlazeWizard.ELEMENT_AMPLIFICATION).getEffect(skillLvl).getY() / 100;
} else if(chr.getJob() == MapleJob.EVAN7 || chr.getJob() == MapleJob.EVAN8 || chr.getJob() == MapleJob.EVAN9 || chr.getJob() == MapleJob.EVAN10) {
int skillLvl = chr.getSkillLevel(Evan.MAGIC_AMPLIFICATION);
if(skillLvl > 0)
calcDmgMax = calcDmgMax * SkillFactory.getSkill(Evan.MAGIC_AMPLIFICATION).getEffect(skillLvl).getY() / 100;
}
calcDmgMax *= effect.getMatk();
if(ret.skill == Cleric.HEAL) {
// This formula is still a bit wonky, but it is fairly accurate.
calcDmgMax = (int) Math.round((chr.getTotalInt() * 4.8 + chr.getTotalLuk() * 4) * chr.getTotalMagic() / 1000);
calcDmgMax = calcDmgMax * effect.getHp() / 100;
ret.speed = 7;
}
} else if(ret.skill == Hermit.SHADOW_MESO) {
// Shadow Meso also has its own formula
calcDmgMax = effect.getMoneyCon() * 10;
calcDmgMax = (int) Math.floor(calcDmgMax * 1.5);
} else {
// Normal damage formula for skills
calcDmgMax = calcDmgMax * effect.getDamage() / 100;
}
}
Integer comboBuff = chr.getBuffedValue(MapleBuffStat.COMBO);
if(comboBuff != null && comboBuff > 0) {
int oid = chr.isCygnus() ? DawnWarrior.COMBO : Crusader.COMBO;
int advcomboid = chr.isCygnus() ? DawnWarrior.ADVANCED_COMBO : Hero.ADVANCED_COMBO;
if(comboBuff > 6) {
// Advanced Combo
MapleStatEffect ceffect = SkillFactory.getSkill(advcomboid).getEffect(chr.getSkillLevel(advcomboid));
calcDmgMax = (long) Math.floor(calcDmgMax * (ceffect.getDamage() + 50) / 100 + 0.20 + (comboBuff - 5) * 0.04);
} else {
// Normal Combo
int skillLv = chr.getSkillLevel(oid);
if(skillLv <= 0 || chr.isGM()) skillLv = SkillFactory.getSkill(oid).getMaxLevel();
if(skillLv > 0) {
MapleStatEffect ceffect = SkillFactory.getSkill(oid).getEffect(skillLv);
calcDmgMax = (long) Math.floor(calcDmgMax * (ceffect.getDamage() + 50) / 100 + Math.floor((comboBuff - 1) * (skillLv / 6)) / 100);
}
}
if(GameConstants.isFinisherSkill(ret.skill)) {
// Finisher skills do more damage based on how many orbs the player has.
int orbs = comboBuff - 1;
if(orbs == 2)
calcDmgMax *= 1.2;
else if(orbs == 3)
calcDmgMax *= 1.54;
else if(orbs == 4)
calcDmgMax *= 2;
else if(orbs >= 5)
calcDmgMax *= 2.5;
}
}
if(chr.getEnergyBar() == 15000) {
int energycharge = chr.isCygnus() ? ThunderBreaker.ENERGY_CHARGE : Marauder.ENERGY_CHARGE;
MapleStatEffect ceffect = SkillFactory.getSkill(energycharge).getEffect(chr.getSkillLevel(energycharge));
calcDmgMax *= (100 + ceffect.getDamage()) / 100;
}
int bonusDmgBuff = 100;
for (PlayerBuffValueHolder pbvh : chr.getAllBuffs()) {
int bonusDmg = pbvh.effect.getDamage() - 100;
bonusDmgBuff += bonusDmg;
}
if (bonusDmgBuff != 100) {
float dmgBuff = bonusDmgBuff / 100.0f;
calcDmgMax = (long) Math.ceil(calcDmgMax * dmgBuff);
}
if(chr.getMapId() >= 914000000 && chr.getMapId() <= 914000500) {
calcDmgMax += 80000; // Aran Tutorial.
}
boolean canCrit = false;
if(chr.getJob().isA((MapleJob.BOWMAN)) || chr.getJob().isA(MapleJob.THIEF) || chr.getJob().isA(MapleJob.NIGHTWALKER1) || chr.getJob().isA(MapleJob.WINDARCHER1) || chr.getJob() == MapleJob.ARAN3 || chr.getJob() == MapleJob.ARAN4 || chr.getJob() == MapleJob.MARAUDER || chr.getJob() == MapleJob.BUCCANEER) {
canCrit = true;
}
if(chr.getBuffEffect(MapleBuffStat.SHARP_EYES) != null) {
// Any class that has sharp eyes can crit. Also, since it stacks with normal crit go ahead
// and calc it in.
canCrit = true;
calcDmgMax *= 1.4;
}
boolean shadowPartner = false;
if(chr.getBuffEffect(MapleBuffStat.SHADOWPARTNER) != null) {
shadowPartner = true;
}
if(ret.skill != 0) {
int fixed = ret.getAttackEffect(chr, SkillFactory.getSkill(ret.skill)).getFixDamage();
if(fixed > 0)
calcDmgMax = fixed;
}
for (int i = 0; i < ret.numAttacked; i++) {
int oid = lea.readInt();
lea.skip(14);
List<Integer> allDamageNumbers = new ArrayList<>();
MapleMonster monster = chr.getMap().getMonsterByOid(oid);
if(chr.getBuffEffect(MapleBuffStat.WK_CHARGE) != null) {
// Charge, so now we need to check elemental effectiveness
int sourceID = chr.getBuffSource(MapleBuffStat.WK_CHARGE);
int level = chr.getBuffedValue(MapleBuffStat.WK_CHARGE);
if(monster != null) {
if(sourceID == WhiteKnight.BW_FIRE_CHARGE || sourceID == WhiteKnight.SWORD_FIRE_CHARGE) {
if(monster.getStats().getEffectiveness(Element.FIRE) == ElementalEffectiveness.WEAK) {
calcDmgMax *= 1.05 + level * 0.015;
}
} else if(sourceID == WhiteKnight.BW_ICE_CHARGE || sourceID == WhiteKnight.SWORD_ICE_CHARGE) {
if(monster.getStats().getEffectiveness(Element.ICE) == ElementalEffectiveness.WEAK) {
calcDmgMax *= 1.05 + level * 0.015;
}
} else if(sourceID == WhiteKnight.BW_LIT_CHARGE || sourceID == WhiteKnight.SWORD_LIT_CHARGE) {
if(monster.getStats().getEffectiveness(Element.LIGHTING) == ElementalEffectiveness.WEAK) {
calcDmgMax *= 1.05 + level * 0.015;
}
} else if(sourceID == Paladin.BW_HOLY_CHARGE || sourceID == Paladin.SWORD_HOLY_CHARGE) {
if(monster.getStats().getEffectiveness(Element.HOLY) == ElementalEffectiveness.WEAK) {
calcDmgMax *= 1.2 + level * 0.015;
}
}
} else {
// Since we already know the skill has an elemental attribute, but we dont know if the monster is weak or not, lets
// take the safe approach and just assume they are weak.
calcDmgMax *= 1.5;
}
}
if(ret.skill != 0) {
Skill skill = SkillFactory.getSkill(ret.skill);
if(skill.getElement() != Element.NEUTRAL && chr.getBuffedValue(MapleBuffStat.ELEMENTAL_RESET) == null) {
// The skill has an element effect, so we need to factor that in.
if(monster != null) {
ElementalEffectiveness eff = monster.getElementalEffectiveness(skill.getElement());
if(eff == ElementalEffectiveness.WEAK) {
calcDmgMax *= 1.5;
} else if(eff == ElementalEffectiveness.STRONG) {
//calcDmgMax *= 0.5;
}
} else {
// Since we already know the skill has an elemental attribute, but we dont know if the monster is weak or not, lets
// take the safe approach and just assume they are weak.
calcDmgMax *= 1.5;
}
}
if(ret.skill == FPWizard.POISON_BREATH || ret.skill == FPMage.POISON_MIST || ret.skill == FPArchMage.FIRE_DEMON || ret.skill == ILArchMage.ICE_DEMON) {
if(monster != null) {
// Turns out poison is completely server side, so I don't know why I added this. >.<
//calcDmgMax = monster.getHp() / (70 - chr.getSkillLevel(skill));
}
} else if(ret.skill == Hermit.SHADOW_WEB) {
if(monster != null) {
calcDmgMax = monster.getHp() / (50 - chr.getSkillLevel(skill));
}
} else if(ret.skill == Hermit.SHADOW_MESO) {
if(monster != null) {
monster.debuffMob(Hermit.SHADOW_MESO);
}
} else if (ret.skill == Aran.BODY_PRESSURE) {
if (monster != null) {
int bodyPressureDmg = (int) Math.ceil(monster.getMaxHp() * SkillFactory.getSkill(Aran.BODY_PRESSURE).getEffect(ret.skilllevel).getDamage() / 100.0);
if (bodyPressureDmg > calcDmgMax) {
calcDmgMax = bodyPressureDmg;
}
}
}
}
for (int j = 0; j < ret.numDamage; j++) {
int damage = lea.readInt();
long hitDmgMax = calcDmgMax;
if(ret.skill == Buccaneer.BARRAGE || ret.skill == ThunderBreaker.BARRAGE) {
if(j > 3)
hitDmgMax *= Math.pow(2, (j - 3));
}
if(shadowPartner) {
// For shadow partner, the second half of the hits only do 50% damage. So calc that
// in for the crit effects.
if(j >= ret.numDamage / 2) {
hitDmgMax *= 0.5;
}
}
if(ret.skill == Marksman.SNIPE) {
damage = 195000 + Randomizer.nextInt(5000);
hitDmgMax = 200000;
} else if (ret.skill == Beginner.BAMBOO_RAIN || ret.skill == Noblesse.BAMBOO_RAIN || ret.skill == Evan.BAMBOO_THRUST || ret.skill == Legend.BAMBOO_THRUST) {
hitDmgMax = 82569000; // 30% of Max HP of strongest Dojo boss
}
long maxWithCrit = hitDmgMax;
if(canCrit) // They can crit, so up the max.
maxWithCrit *= 2;
// Warn if the damage is over 1.5x what we calculated above.
if(damage > maxWithCrit * 1.5) {
AutobanFactory.DAMAGE_HACK.alert(chr, "DMG: " + damage + " MaxDMG: " + maxWithCrit + " SID: " + ret.skill + " MobID: " + (monster != null ? monster.getId() : "null") + " Map: " + chr.getMap().getMapName() + " (" + chr.getMapId() + ")");
}
// Add a ab point if its over 5x what we calculated.
if(damage > maxWithCrit * 5) {
AutobanFactory.DAMAGE_HACK.addPoint(chr.getAutobanManager(), "DMG: " + damage + " MaxDMG: " + maxWithCrit + " SID: " + ret.skill + " MobID: " + (monster != null ? monster.getId() : "null") + " Map: " + chr.getMap().getMapName() + " (" + chr.getMapId() + ")");
}
if (ret.skill == Marksman.SNIPE || (canCrit && damage > hitDmgMax)) {
// If the skill is a crit, inverse the damage to make it show up on clients.
damage = -Integer.MAX_VALUE + damage - 1;
}
allDamageNumbers.add(damage);
}
if (ret.skill != Corsair.RAPID_FIRE || ret.skill != Aran.HIDDEN_FULL_DOUBLE || ret.skill != Aran.HIDDEN_FULL_TRIPLE || ret.skill != Aran.HIDDEN_OVER_DOUBLE || ret.skill != Aran.HIDDEN_OVER_TRIPLE) {
lea.skip(4);
}
ret.allDamage.put(Integer.valueOf(oid), allDamageNumbers);
}
if (ret.skill == NightWalker.POISON_BOMB) { // Poison Bomb
lea.skip(4);
ret.position.setLocation(lea.readShort(), lea.readShort());
}
return ret;
}
private static int rand(int l, int u) {
return (int) ((Math.random() * (u - l + 1)) + l);
}
}

View File

@@ -0,0 +1,244 @@
/*
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 as
published by the Free Software Foundation 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.server.channel.handlers;
import java.awt.Point;
import java.util.ArrayList;
import java.util.List;
import net.AbstractMaplePacketHandler;
import server.maps.AnimatedMapleMapObject;
import server.movement.AbsoluteLifeMovement;
import server.movement.ChangeEquip;
import server.movement.JumpDownMovement;
import server.movement.LifeMovementFragment;
import server.movement.RelativeLifeMovement;
import server.movement.TeleportMovement;
import tools.data.input.LittleEndianAccessor;
import tools.exceptions.EmptyMovementException;
public abstract class AbstractMovementPacketHandler extends AbstractMaplePacketHandler {
protected List<LifeMovementFragment> parseMovement(LittleEndianAccessor lea) throws EmptyMovementException {
List<LifeMovementFragment> res = new ArrayList<>();
byte numCommands = lea.readByte();
if (numCommands < 1) throw new EmptyMovementException(lea);
for (byte i = 0; i < numCommands; i++) {
byte command = lea.readByte();
switch (command) {
case 0: // normal move
case 5:
case 17: { // Float
short xpos = lea.readShort();
short ypos = lea.readShort();
short xwobble = lea.readShort();
short ywobble = lea.readShort();
short fh = lea.readShort();
byte newstate = lea.readByte();
short duration = lea.readShort();
AbsoluteLifeMovement alm = new AbsoluteLifeMovement(command, new Point(xpos, ypos), duration, newstate);
alm.setFh(fh);
alm.setPixelsPerSecond(new Point(xwobble, ywobble));
res.add(alm);
break;
}
case 1:
case 2:
case 6: // fj
case 12:
case 13: // Shot-jump-back thing
case 16: // Float
case 18:
case 19: // Springs on maps
case 20: // Aran Combat Step
case 22: {
short xpos = lea.readShort();
short ypos = lea.readShort();
byte newstate = lea.readByte();
short duration = lea.readShort();
RelativeLifeMovement rlm = new RelativeLifeMovement(command, new Point(xpos, ypos), duration, newstate);
res.add(rlm);
break;
}
case 3:
case 4: // tele... -.-
case 7: // assaulter
case 8: // assassinate
case 9: // rush
case 11: //chair
{
// case 14: {
short xpos = lea.readShort();
short ypos = lea.readShort();
short xwobble = lea.readShort();
short ywobble = lea.readShort();
byte newstate = lea.readByte();
TeleportMovement tm = new TeleportMovement(command, new Point(xpos, ypos), newstate);
tm.setPixelsPerSecond(new Point(xwobble, ywobble));
res.add(tm);
break;
}
case 14:
lea.skip(9); // jump down (?)
break;
case 10: // Change Equip
res.add(new ChangeEquip(lea.readByte()));
break;
/*case 11: { // Chair
short xpos = lea.readShort();
short ypos = lea.readShort();
short fh = lea.readShort();
byte newstate = lea.readByte();
short duration = lea.readShort();
ChairMovement cm = new ChairMovement(command, new Point(xpos, ypos), duration, newstate);
cm.setFh(fh);
res.add(cm);
break;
}*/
case 15: {
short xpos = lea.readShort();
short ypos = lea.readShort();
short xwobble = lea.readShort();
short ywobble = lea.readShort();
short fh = lea.readShort();
short ofh = lea.readShort();
byte newstate = lea.readByte();
short duration = lea.readShort();
JumpDownMovement jdm = new JumpDownMovement(command, new Point(xpos, ypos), duration, newstate);
jdm.setFh(fh);
jdm.setPixelsPerSecond(new Point(xwobble, ywobble));
jdm.setOriginFh(ofh);
res.add(jdm);
break;
}
case 21: {//Causes aran to do weird stuff when attacking o.o
/*byte newstate = lea.readByte();
short unk = lea.readShort();
AranMovement am = new AranMovement(command, null, unk, newstate);
res.add(am);*/
lea.skip(3);
break;
}
default:
System.out.println("Unhandled Case:" + command);
throw new EmptyMovementException(lea);
}
}
if (res.isEmpty()) {
throw new EmptyMovementException(lea);
}
return res;
}
protected void updatePosition(LittleEndianAccessor lea, AnimatedMapleMapObject target, int yOffset) throws EmptyMovementException {
byte numCommands = lea.readByte();
if (numCommands < 1) throw new EmptyMovementException(lea);
for (byte i = 0; i < numCommands; i++) {
byte command = lea.readByte();
switch (command) {
case 0: // normal move
case 5:
case 17: { // Float
//Absolute movement - only this is important for the server, other movement can be passed to the client
short xpos = lea.readShort(); //is signed fine here?
short ypos = lea.readShort();
target.setPosition(new Point(xpos, ypos + yOffset));
lea.skip(6); //xwobble = lea.readShort(); ywobble = lea.readShort(); fh = lea.readShort();
byte newstate = lea.readByte();
target.setStance(newstate);
lea.readShort(); //duration
break;
}
case 1:
case 2:
case 6: // fj
case 12:
case 13: // Shot-jump-back thing
case 16: // Float
case 18:
case 19: // Springs on maps
case 20: // Aran Combat Step
case 22: {
//Relative movement - server only cares about stance
lea.skip(4); //xpos = lea.readShort(); ypos = lea.readShort();
byte newstate = lea.readByte();
target.setStance(newstate);
lea.readShort(); //duration
break;
}
case 3:
case 4: // tele... -.-
case 7: // assaulter
case 8: // assassinate
case 9: // rush
case 11: //chair
{
// case 14: {
//Teleport movement - same as above
lea.skip(8); //xpos = lea.readShort(); ypos = lea.readShort(); xwobble = lea.readShort(); ywobble = lea.readShort();
byte newstate = lea.readByte();
target.setStance(newstate);
break;
}
case 14:
lea.skip(9); // jump down (?)
break;
case 10: // Change Equip
//ignored server-side
lea.readByte();
break;
/*case 11: { // Chair
short xpos = lea.readShort();
short ypos = lea.readShort();
short fh = lea.readShort();
byte newstate = lea.readByte();
short duration = lea.readShort();
ChairMovement cm = new ChairMovement(command, new Point(xpos, ypos), duration, newstate);
cm.setFh(fh);
res.add(cm);
break;
}*/
case 15: {
//Jump down movement - stance only
lea.skip(12); //short xpos = lea.readShort(); ypos = lea.readShort(); xwobble = lea.readShort(); ywobble = lea.readShort(); fh = lea.readShort(); ofh = lea.readShort();
byte newstate = lea.readByte();
target.setStance(newstate);
lea.readShort(); // duration
break;
}
case 21: {//Causes aran to do weird stuff when attacking o.o
/*byte newstate = lea.readByte();
short unk = lea.readShort();
AranMovement am = new AranMovement(command, null, unk, newstate);
res.add(am);*/
lea.skip(3);
break;
}
default:
System.out.println("Unhandled Case:" + command);
throw new EmptyMovementException(lea);
}
}
}
}

View File

@@ -0,0 +1,153 @@
/*
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 as
published by the Free Software Foundation 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.server.channel.handlers;
import config.YamlConfig;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import client.MapleCharacter;
import client.MapleClient;
import client.MapleFamily;
import client.MapleFamilyEntry;
import net.AbstractMaplePacketHandler;
import net.server.coordinator.world.MapleInviteCoordinator;
import net.server.coordinator.world.MapleInviteCoordinator.InviteResult;
import net.server.coordinator.world.MapleInviteCoordinator.InviteType;
import net.server.coordinator.world.MapleInviteCoordinator.MapleInviteResult;
import tools.DatabaseConnection;
import tools.FilePrinter;
import tools.MaplePacketCreator;
import tools.data.input.SeekableLittleEndianAccessor;
/**
*
* @author Jay Estrella
* @author Ubaware
*/
public final class AcceptFamilyHandler extends AbstractMaplePacketHandler {
@Override
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
if(!YamlConfig.config.server.USE_FAMILY_SYSTEM) {
return;
}
MapleCharacter chr = c.getPlayer();
int inviterId = slea.readInt();
slea.readMapleAsciiString();
boolean accept = slea.readByte() != 0;
// String inviterName = slea.readMapleAsciiString();
MapleCharacter inviter = c.getWorldServer().getPlayerStorage().getCharacterById(inviterId);
if(inviter != null) {
MapleInviteResult inviteResult = MapleInviteCoordinator.answerInvite(InviteType.FAMILY, c.getPlayer().getId(), c.getPlayer(), accept);
if(inviteResult.result == InviteResult.NOT_FOUND) return; //was never invited. (or expired on server only somehow?)
if(accept) {
if(inviter.getFamily() != null) {
if(chr.getFamily() == null) {
MapleFamilyEntry newEntry = new MapleFamilyEntry(inviter.getFamily(), chr.getId(), chr.getName(), chr.getLevel(), chr.getJob());
newEntry.setCharacter(chr);
if(!newEntry.setSenior(inviter.getFamilyEntry(), true)) {
inviter.announce(MaplePacketCreator.sendFamilyMessage(1, 0));
return;
} else {
// save
inviter.getFamily().addEntry(newEntry);
insertNewFamilyRecord(chr.getId(), inviter.getFamily().getID(), inviter.getId(), false);
}
} else { //absorb target family
MapleFamilyEntry targetEntry = chr.getFamilyEntry();
MapleFamily targetFamily = targetEntry.getFamily();
if(targetFamily.getLeader() != targetEntry) return;
if(inviter.getFamily().getTotalGenerations() + targetFamily.getTotalGenerations() <= YamlConfig.config.server.FAMILY_MAX_GENERATIONS) {
targetEntry.join(inviter.getFamilyEntry());
} else {
inviter.announce(MaplePacketCreator.sendFamilyMessage(76, 0));
chr.announce(MaplePacketCreator.sendFamilyMessage(76, 0));
return;
}
}
} else { // create new family
if(chr.getFamily() != null && inviter.getFamily() != null && chr.getFamily().getTotalGenerations() + inviter.getFamily().getTotalGenerations() >= YamlConfig.config.server.FAMILY_MAX_GENERATIONS) {
inviter.announce(MaplePacketCreator.sendFamilyMessage(76, 0));
chr.announce(MaplePacketCreator.sendFamilyMessage(76, 0));
return;
}
MapleFamily newFamily = new MapleFamily(-1, c.getWorld());
c.getWorldServer().addFamily(newFamily.getID(), newFamily);
MapleFamilyEntry inviterEntry = new MapleFamilyEntry(newFamily, inviter.getId(), inviter.getName(), inviter.getLevel(), inviter.getJob());
inviterEntry.setCharacter(inviter);
newFamily.setLeader(inviter.getFamilyEntry());
newFamily.addEntry(inviterEntry);
if(chr.getFamily() == null) { //completely new family
MapleFamilyEntry newEntry = new MapleFamilyEntry(newFamily, chr.getId(), chr.getName(), chr.getLevel(), chr.getJob());
newEntry.setCharacter(chr);
newEntry.setSenior(inviterEntry, true);
// save new family
insertNewFamilyRecord(inviter.getId(), newFamily.getID(), 0, true);
insertNewFamilyRecord(chr.getId(), newFamily.getID(), inviter.getId(), false); // char was already saved from setSenior() above
newFamily.setMessage("", true);
} else { //new family for inviter, absorb invitee family
insertNewFamilyRecord(inviter.getId(), newFamily.getID(), 0 , true);
newFamily.setMessage("", true);
chr.getFamilyEntry().join(inviterEntry);
}
}
c.getPlayer().getFamily().broadcast(MaplePacketCreator.sendFamilyJoinResponse(true, c.getPlayer().getName()), c.getPlayer().getId());
c.announce(MaplePacketCreator.getSeniorMessage(inviter.getName()));
c.announce(MaplePacketCreator.getFamilyInfo(chr.getFamilyEntry()));
chr.getFamilyEntry().updateSeniorFamilyInfo(true);
} else {
inviter.announce(MaplePacketCreator.sendFamilyJoinResponse(false, c.getPlayer().getName()));
}
}
c.announce(MaplePacketCreator.sendFamilyMessage(0, 0));
}
private static void insertNewFamilyRecord(int characterID, int familyID, int seniorID, boolean updateChar) {
try(Connection con = DatabaseConnection.getConnection()) {
try(PreparedStatement ps = con.prepareStatement("INSERT INTO family_character (cid, familyid, seniorid) VALUES (?, ?, ?)")) {
ps.setInt(1, characterID);
ps.setInt(2, familyID);
ps.setInt(3, seniorID);
ps.executeUpdate();
} catch(SQLException e) {
FilePrinter.printError(FilePrinter.FAMILY_ERROR, e, "Could not save new family record for char id " + characterID + ".");
e.printStackTrace();
}
if(updateChar) {
try(PreparedStatement ps = con.prepareStatement("UPDATE characters SET familyid = ? WHERE id = ?")) {
ps.setInt(1, familyID);
ps.setInt(2, characterID);
ps.executeUpdate();
} catch(SQLException e) {
FilePrinter.printError(FilePrinter.FAMILY_ERROR, e, "Could not update 'characters' 'familyid' record for char id " + characterID + ".");
e.printStackTrace();
}
}
} catch(SQLException e) {
FilePrinter.printError(FilePrinter.FAMILY_ERROR, e, "Could not get connection to DB.");
e.printStackTrace();
}
}
}

View File

@@ -0,0 +1,47 @@
package net.server.channel.handlers;
import client.MapleClient;
import config.YamlConfig;
import net.AbstractMaplePacketHandler;
import tools.LogHelper;
import tools.MaplePacketCreator;
import tools.data.input.SeekableLittleEndianAccessor;
/**
*
* @author kevintjuh93
*/
public class AdminChatHandler extends AbstractMaplePacketHandler {
@Override
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
if (!c.getPlayer().isGM()) {//if ( (signed int)CWvsContext::GetAdminLevel((void *)v294) > 2 )
return;
}
byte mode = slea.readByte();
//not saving slides...
String message = slea.readMapleAsciiString();
byte[] packet = MaplePacketCreator.serverNotice(slea.readByte(), message);//maybe I should make a check for the slea.readByte()... but I just hope gm's don't fuck things up :)
switch (mode) {
case 0:// /alertall, /noticeall, /slideall
c.getWorldServer().broadcastPacket(packet);
if (YamlConfig.config.server.USE_ENABLE_CHAT_LOG) {
LogHelper.logChat(c, "Alert All", message);
}
break;
case 1:// /alertch, /noticech, /slidech
c.getChannelServer().broadcastPacket(packet);
if (YamlConfig.config.server.USE_ENABLE_CHAT_LOG) {
LogHelper.logChat(c, "Alert Ch", message);
}
break;
case 2:// /alertm /alertmap, /noticem /noticemap, /slidem /slidemap
c.getPlayer().getMap().broadcastMessage(packet);
if (YamlConfig.config.server.USE_ENABLE_CHAT_LOG) {
LogHelper.logChat(c, "Alert Map", message);
}
break;
}
}
}

View File

@@ -0,0 +1,184 @@
/*
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 as
published by the Free Software Foundation 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.server.channel.handlers;
import java.util.Arrays;
import java.util.List;
import net.AbstractMaplePacketHandler;
import server.MapleItemInformationProvider;
import server.life.MapleLifeFactory;
import server.life.MapleMonster;
import server.maps.MapleMapObject;
import server.maps.MapleMapObjectType;
import server.quest.MapleQuest;
import tools.MaplePacketCreator;
import tools.Randomizer;
import tools.data.input.SeekableLittleEndianAccessor;
import client.MapleCharacter;
import client.MapleClient;
import client.inventory.MapleInventory;
import client.inventory.MapleInventoryType;
import client.inventory.manipulator.MapleInventoryManipulator;
public final class AdminCommandHandler extends AbstractMaplePacketHandler {
@Override
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
if (!c.getPlayer().isGM()) {
return;
}
byte mode = slea.readByte();
String victim;
MapleCharacter target;
switch (mode) {
case 0x00: // Level1~Level8 & Package1~Package2
int[][] toSpawn = MapleItemInformationProvider.getInstance().getSummonMobs(slea.readInt());
for (int z = 0; z < toSpawn.length; z++) {
int[] toSpawnChild = toSpawn[z];
if (Randomizer.nextInt(100) < toSpawnChild[1]) {
c.getPlayer().getMap().spawnMonsterOnGroundBelow(MapleLifeFactory.getMonster(toSpawnChild[0]), c.getPlayer().getPosition());
}
}
c.announce(MaplePacketCreator.enableActions());
break;
case 0x01: { // /d (inv)
byte type = slea.readByte();
MapleInventory in = c.getPlayer().getInventory(MapleInventoryType.getByType(type));
for (short i = 1; i <= in.getSlotLimit(); i++) { //TODO What is the point of this loop?
if (in.getItem(i) != null) {
MapleInventoryManipulator.removeFromSlot(c, MapleInventoryType.getByType(type), i, in.getItem(i).getQuantity(), false);
}
return;
}
break;
}
case 0x02: // Exp
c.getPlayer().setExp(slea.readInt());
break;
case 0x03: // /ban <name>
c.getPlayer().yellowMessage("Please use !ban <IGN> <Reason>");
break;
case 0x04: // /block <name> <duration (in days)> <HACK/BOT/AD/HARASS/CURSE/SCAM/MISCONDUCT/SELL/ICASH/TEMP/GM/IPROGRAM/MEGAPHONE>
victim = slea.readMapleAsciiString();
int type = slea.readByte(); //reason
int duration = slea.readInt();
String description = slea.readMapleAsciiString();
String reason = c.getPlayer().getName() + " used /ban to ban";
target = c.getChannelServer().getPlayerStorage().getCharacterByName(victim);
if (target != null) {
String readableTargetName = MapleCharacter.makeMapleReadable(target.getName());
String ip = target.getClient().getSession().getRemoteAddress().toString().split(":")[0];
reason += readableTargetName + " (IP: " + ip + ")";
if (duration == -1) {
target.ban(description + " " + reason);
} else {
target.block(type, duration, description);
target.sendPolice(duration, reason, 6000);
}
c.announce(MaplePacketCreator.getGMEffect(4, (byte) 0));
} else if (MapleCharacter.ban(victim, reason, false)) {
c.announce(MaplePacketCreator.getGMEffect(4, (byte) 0));
} else {
c.announce(MaplePacketCreator.getGMEffect(6, (byte) 1));
}
break;
case 0x10: // /h, information added by vana -- <and tele mode f1> ... hide ofcourse
c.getPlayer().Hide(slea.readByte() == 1);
break;
case 0x11: // Entering a map
switch (slea.readByte()) {
case 0:// /u
StringBuilder sb = new StringBuilder("USERS ON THIS MAP: ");
for (MapleCharacter mc : c.getPlayer().getMap().getCharacters()) {
sb.append(mc.getName());
sb.append(" ");
}
c.getPlayer().message(sb.toString());
break;
case 12:// /uclip and entering a map
break;
}
break;
case 0x12: // Send
victim = slea.readMapleAsciiString();
int mapId = slea.readInt();
c.getChannelServer().getPlayerStorage().getCharacterByName(victim).changeMap(c.getChannelServer().getMapFactory().getMap(mapId));
break;
case 0x15: // Kill
int mobToKill = slea.readInt();
int amount = slea.readInt();
List<MapleMapObject> monsterx = c.getPlayer().getMap().getMapObjectsInRange(c.getPlayer().getPosition(), Double.POSITIVE_INFINITY, Arrays.asList(MapleMapObjectType.MONSTER));
for (int x = 0; x < amount; x++) {
MapleMonster monster = (MapleMonster) monsterx.get(x);
if (monster.getId() == mobToKill) {
c.getPlayer().getMap().killMonster(monster, c.getPlayer(), true);
}
}
break;
case 0x16: // Questreset
MapleQuest.getInstance(slea.readShort()).reset(c.getPlayer());
break;
case 0x17: // Summon
int mobId = slea.readInt();
int quantity = slea.readInt();
for (int i = 0; i < quantity; i++) {
c.getPlayer().getMap().spawnMonsterOnGroundBelow(MapleLifeFactory.getMonster(mobId), c.getPlayer().getPosition());
}
break;
case 0x18: // Maple & Mobhp
int mobHp = slea.readInt();
c.getPlayer().dropMessage("Monsters HP");
List<MapleMapObject> monsters = c.getPlayer().getMap().getMapObjectsInRange(c.getPlayer().getPosition(), Double.POSITIVE_INFINITY, Arrays.asList(MapleMapObjectType.MONSTER));
for (MapleMapObject mobs : monsters) {
MapleMonster monster = (MapleMonster) mobs;
if (monster.getId() == mobHp) {
c.getPlayer().dropMessage(monster.getName() + ": " + monster.getHp());
}
}
break;
case 0x1E: // Warn
victim = slea.readMapleAsciiString();
String message = slea.readMapleAsciiString();
target = c.getChannelServer().getPlayerStorage().getCharacterByName(victim);
if (target != null) {
target.getClient().announce(MaplePacketCreator.serverNotice(1, message));
c.announce(MaplePacketCreator.getGMEffect(0x1E, (byte) 1));
} else {
c.announce(MaplePacketCreator.getGMEffect(0x1E, (byte) 0));
}
break;
case 0x24:// /Artifact Ranking
break;
case 0x77: //Testing purpose
if (slea.available() == 4) {
System.out.println(slea.readInt());
} else if (slea.available() == 2) {
System.out.println(slea.readShort());
}
break;
default:
System.out.println("New GM packet encountered (MODE : " + mode + ": " + slea.toString());
break;
}
}
}

View File

@@ -0,0 +1,34 @@
/*
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 as
published by the Free Software Foundation 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.server.channel.handlers;
import client.MapleClient;
import net.AbstractMaplePacketHandler;
import tools.data.input.SeekableLittleEndianAccessor;
public final class AdminLogHandler extends AbstractMaplePacketHandler {
@Override
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
//harhar
}
}

View File

@@ -0,0 +1,278 @@
/*
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 as
published by the Free Software Foundation 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.server.channel.handlers;
import client.MapleCharacter;
import client.MapleClient;
import net.AbstractMaplePacketHandler;
import net.opcodes.SendOpcode;
import net.server.Server;
import net.server.guild.MapleGuild;
import net.server.guild.MapleGuildCharacter;
import net.server.guild.MapleAlliance;
import tools.MaplePacketCreator;
import tools.data.input.SeekableLittleEndianAccessor;
import tools.data.output.MaplePacketLittleEndianWriter;
/**
*
* @author XoticStory, Ronan
*/
public final class AllianceOperationHandler extends AbstractMaplePacketHandler {
@Override
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
MapleAlliance alliance = null;
MapleCharacter chr = c.getPlayer();
if (chr.getGuild() == null) {
c.announce(MaplePacketCreator.enableActions());
return;
}
if (chr.getGuild().getAllianceId() > 0) {
alliance = chr.getAlliance();
}
byte b = slea.readByte();
if (alliance == null) {
if (b != 4) {
c.announce(MaplePacketCreator.enableActions());
return;
}
} else {
if (b == 4) {
chr.dropMessage(5, "Your guild is already registered on a guild alliance.");
c.announce(MaplePacketCreator.enableActions());
return;
}
if (chr.getMGC().getAllianceRank() > 2 || !alliance.getGuilds().contains(chr.getGuildId())) {
c.announce(MaplePacketCreator.enableActions());
return;
}
}
// "alliance" is only null at case 0x04
switch (b) {
case 0x01:
Server.getInstance().allianceMessage(alliance.getId(), sendShowInfo(chr.getGuild().getAllianceId(), chr.getId()), -1, -1);
break;
case 0x02: { // Leave Alliance
if (chr.getGuild().getAllianceId() == 0 || chr.getGuildId() < 1 || chr.getGuildRank() != 1) {
return;
}
MapleAlliance.removeGuildFromAlliance(chr.getGuild().getAllianceId(), chr.getGuildId(), chr.getWorld());
break;
}
case 0x03: // Send Invite
String guildName = slea.readMapleAsciiString();
if (alliance.getGuilds().size() == alliance.getCapacity()) {
chr.dropMessage(5, "Your alliance cannot comport any more guilds at the moment.");
} else {
MapleAlliance.sendInvitation(c, guildName, alliance.getId());
}
break;
case 0x04: { // Accept Invite
MapleGuild guild = chr.getGuild();
if (guild.getAllianceId() != 0 || chr.getGuildRank() != 1 || chr.getGuildId() < 1) {
return;
}
int allianceid = slea.readInt();
//slea.readMapleAsciiString(); //recruiter's guild name
alliance = Server.getInstance().getAlliance(allianceid);
if (alliance == null) {
return;
}
if (!MapleAlliance.answerInvitation(c.getPlayer().getId(), guild.getName(), alliance.getId(), true)) {
return;
}
if (alliance.getGuilds().size() == alliance.getCapacity()) {
chr.dropMessage(5, "Your alliance cannot comport any more guilds at the moment.");
return;
}
int guildid = chr.getGuildId();
Server.getInstance().addGuildtoAlliance(alliance.getId(), guildid);
Server.getInstance().resetAllianceGuildPlayersRank(guildid);
chr.getMGC().setAllianceRank(2);
MapleGuild g = Server.getInstance().getGuild(chr.getGuildId());
if (g != null) {
g.getMGC(chr.getId()).setAllianceRank(2);
}
chr.saveGuildStatus();
Server.getInstance().allianceMessage(alliance.getId(), MaplePacketCreator.addGuildToAlliance(alliance, guildid, c), -1, -1);
Server.getInstance().allianceMessage(alliance.getId(), MaplePacketCreator.updateAllianceInfo(alliance, c.getWorld()), -1, -1);
Server.getInstance().allianceMessage(alliance.getId(), MaplePacketCreator.allianceNotice(alliance.getId(), alliance.getNotice()), -1, -1);
guild.dropMessage("Your guild has joined the [" + alliance.getName() + "] union.");
break;
}
case 0x06: { // Expel Guild
int guildid = slea.readInt();
int allianceid = slea.readInt();
if (chr.getGuild().getAllianceId() == 0 || chr.getGuild().getAllianceId() != allianceid) {
return;
}
Server.getInstance().allianceMessage(alliance.getId(), MaplePacketCreator.removeGuildFromAlliance(alliance, guildid, c.getWorld()), -1, -1);
Server.getInstance().removeGuildFromAlliance(alliance.getId(), guildid);
Server.getInstance().allianceMessage(alliance.getId(), MaplePacketCreator.getGuildAlliances(alliance, c.getWorld()), -1, -1);
Server.getInstance().allianceMessage(alliance.getId(), MaplePacketCreator.allianceNotice(alliance.getId(), alliance.getNotice()), -1, -1);
Server.getInstance().guildMessage(guildid, MaplePacketCreator.disbandAlliance(allianceid));
alliance.dropMessage("[" + Server.getInstance().getGuild(guildid).getName() + "] guild has been expelled from the union.");
break;
}
case 0x07: { // Change Alliance Leader
if (chr.getGuild().getAllianceId() == 0 || chr.getGuildId() < 1) {
return;
}
int victimid = slea.readInt();
MapleCharacter player = Server.getInstance().getWorld(c.getWorld()).getPlayerStorage().getCharacterById(victimid);
if (player.getAllianceRank() != 2) {
return;
}
//Server.getInstance().allianceMessage(alliance.getId(), sendChangeLeader(chr.getGuild().getAllianceId(), chr.getId(), slea.readInt()), -1, -1);
changeLeaderAllianceRank(alliance, player);
break;
}
case 0x08:
String ranks[] = new String[5];
for (int i = 0; i < 5; i++) {
ranks[i] = slea.readMapleAsciiString();
}
Server.getInstance().setAllianceRanks(alliance.getId(), ranks);
Server.getInstance().allianceMessage(alliance.getId(), MaplePacketCreator.changeAllianceRankTitle(alliance.getId(), ranks), -1, -1);
break;
case 0x09: {
int int1 = slea.readInt();
byte byte1 = slea.readByte();
//Server.getInstance().allianceMessage(alliance.getId(), sendChangeRank(chr.getGuild().getAllianceId(), chr.getId(), int1, byte1), -1, -1);
MapleCharacter player = Server.getInstance().getWorld(c.getWorld()).getPlayerStorage().getCharacterById(int1);
changePlayerAllianceRank(alliance, player, (byte1 > 0));
break;
}
case 0x0A:
String notice = slea.readMapleAsciiString();
Server.getInstance().setAllianceNotice(alliance.getId(), notice);
Server.getInstance().allianceMessage(alliance.getId(), MaplePacketCreator.allianceNotice(alliance.getId(), notice), -1, -1);
alliance.dropMessage(5, "* Alliance Notice : " + notice);
break;
default:
chr.dropMessage("Feature not available");
}
alliance.saveToDB();
}
private void changeLeaderAllianceRank(MapleAlliance alliance, MapleCharacter newLeader) {
MapleGuildCharacter lmgc = alliance.getLeader();
MapleCharacter leader = newLeader.getWorldServer().getPlayerStorage().getCharacterById(lmgc.getId());
leader.getMGC().setAllianceRank(2);
leader.saveGuildStatus();
newLeader.getMGC().setAllianceRank(1);
newLeader.saveGuildStatus();
Server.getInstance().allianceMessage(alliance.getId(), MaplePacketCreator.getGuildAlliances(alliance, newLeader.getWorld()), -1, -1);
alliance.dropMessage("'" + newLeader.getName() + "' has been appointed as the new head of this Alliance.");
}
private void changePlayerAllianceRank(MapleAlliance alliance, MapleCharacter chr, boolean raise) {
int newRank = chr.getAllianceRank() + (raise ? -1 : 1);
if(newRank < 3 || newRank > 5) return;
chr.getMGC().setAllianceRank(newRank);
chr.saveGuildStatus();
Server.getInstance().allianceMessage(alliance.getId(), MaplePacketCreator.getGuildAlliances(alliance, chr.getWorld()), -1, -1);
alliance.dropMessage("'" + chr.getName() + "' has been reassigned to '" + alliance.getRankTitle(newRank) + "' in this Alliance.");
}
private static byte[] sendShowInfo(int allianceid, int playerid) {
MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
mplew.writeShort(SendOpcode.ALLIANCE_OPERATION.getValue());
mplew.write(0x02);
mplew.writeInt(allianceid);
mplew.writeInt(playerid);
return mplew.getPacket();
}
private static byte[] sendInvitation(int allianceid, int playerid, final String guildname) {
MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
mplew.writeShort(SendOpcode.ALLIANCE_OPERATION.getValue());
mplew.write(0x05);
mplew.writeInt(allianceid);
mplew.writeInt(playerid);
mplew.writeMapleAsciiString(guildname);
return mplew.getPacket();
}
private static byte[] sendChangeGuild(int allianceid, int playerid, int guildid, int option) {
MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
mplew.writeShort(SendOpcode.ALLIANCE_OPERATION.getValue());
mplew.write(0x07);
mplew.writeInt(allianceid);
mplew.writeInt(guildid);
mplew.writeInt(playerid);
mplew.write(option);
return mplew.getPacket();
}
private static byte[] sendChangeLeader(int allianceid, int playerid, int victim) {
MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
mplew.writeShort(SendOpcode.ALLIANCE_OPERATION.getValue());
mplew.write(0x08);
mplew.writeInt(allianceid);
mplew.writeInt(playerid);
mplew.writeInt(victim);
return mplew.getPacket();
}
private static byte[] sendChangeRank(int allianceid, int playerid, int int1, byte byte1) {
MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
mplew.writeShort(SendOpcode.ALLIANCE_OPERATION.getValue());
mplew.write(0x09);
mplew.writeInt(allianceid);
mplew.writeInt(playerid);
mplew.writeInt(int1);
mplew.writeInt(byte1);
return mplew.getPacket();
}
}

View File

@@ -0,0 +1,64 @@
/*
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 as
published by the Free Software Foundation 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.server.channel.handlers;
import client.MapleCharacter;
import client.MapleClient;
import client.SkillFactory;
import constants.game.GameConstants;
import constants.skills.Aran;
import net.AbstractMaplePacketHandler;
import tools.data.input.SeekableLittleEndianAccessor;
public class AranComboHandler extends AbstractMaplePacketHandler {
@Override
public void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
final MapleCharacter player = c.getPlayer();
int skillLevel = player.getSkillLevel(SkillFactory.getSkill(Aran.COMBO_ABILITY));
if (GameConstants.isAran(player.getJob().getId()) && (skillLevel > 0 || player.getJob().getId() == 2000)) {
final long currentTime = currentServerTime();
short combo = player.getCombo();
if ((currentTime - player.getLastCombo()) > 3000 && combo > 0) {
combo = 0;
}
combo++;
switch (combo) {
case 10:
case 20:
case 30:
case 40:
case 50:
case 60:
case 70:
case 80:
case 90:
case 100:
if (player.getJob().getId() != 2000 && (combo / 10) > skillLevel) break;
SkillFactory.getSkill(Aran.COMBO_ABILITY).getEffect(combo / 10).applyComboBuff(player, combo);
break;
}
player.setCombo(combo);
player.setLastCombo(currentTime);
}
}
}

View File

@@ -0,0 +1,46 @@
/*
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 as
published by the Free Software Foundation 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.server.channel.handlers;
import client.MapleClient;
import net.AbstractMaplePacketHandler;
import server.life.MapleMonster;
import server.maps.MapleMap;
import tools.data.input.SeekableLittleEndianAccessor;
import client.MapleCharacter;
public final class AutoAggroHandler extends AbstractMaplePacketHandler {
@Override
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
MapleCharacter player = c.getPlayer();
if (player.isHidden()) return; // Don't auto aggro GM's in hide...
MapleMap map = player.getMap();
int oid = slea.readInt();
MapleMonster monster = map.getMonsterByOid(oid);
if (monster != null) {
monster.aggroAutoAggroUpdate(player);
}
}
}

View File

@@ -0,0 +1,39 @@
/*
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 as
published by the Free Software Foundation 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.server.channel.handlers;
import client.MapleClient;
import client.processor.stat.AssignAPProcessor;
import net.AbstractMaplePacketHandler;
import tools.data.input.SeekableLittleEndianAccessor;
/**
*
* @author Generic, Ronan
*/
public class AutoAssignHandler extends AbstractMaplePacketHandler {
@Override
public void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
AssignAPProcessor.APAutoAssignAction(slea, c);
}
}

View File

@@ -0,0 +1,335 @@
/*
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 as
published by the Free Software Foundation 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.server.channel.handlers;
import client.MapleCharacter;
import client.MapleClient;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import net.AbstractMaplePacketHandler;
import tools.DatabaseConnection;
import tools.MaplePacketCreator;
import tools.data.input.SeekableLittleEndianAccessor;
public final class BBSOperationHandler extends AbstractMaplePacketHandler {
private String correctLength(String in, int maxSize) {
return in.length() > maxSize ? in.substring(0, maxSize) : in;
}
@Override
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
if (c.getPlayer().getGuildId() < 1) {
return;
}
byte mode = slea.readByte();
int localthreadid = 0;
switch (mode) {
case 0:
boolean bEdit = slea.readByte() == 1;
if (bEdit) {
localthreadid = slea.readInt();
}
boolean bNotice = slea.readByte() == 1;
String title = correctLength(slea.readMapleAsciiString(), 25);
String text = correctLength(slea.readMapleAsciiString(), 600);
int icon = slea.readInt();
if (icon >= 0x64 && icon <= 0x6a) {
if (!c.getPlayer().haveItemWithId(5290000 + icon - 0x64, false)) {
return;
}
} else if (icon < 0 || icon > 3) {
return;
}
if (!bEdit) {
newBBSThread(c, title, text, icon, bNotice);
} else {
editBBSThread(c, title, text, icon, localthreadid);
}
break;
case 1:
localthreadid = slea.readInt();
deleteBBSThread(c, localthreadid);
break;
case 2:
int start = slea.readInt();
listBBSThreads(c, start * 10);
break;
case 3: // list thread + reply, following by id (int)
localthreadid = slea.readInt();
displayThread(c, localthreadid);
break;
case 4: // reply
localthreadid = slea.readInt();
text = correctLength(slea.readMapleAsciiString(), 25);
newBBSReply(c, localthreadid, text);
break;
case 5: // delete reply
slea.readInt(); // we don't use this
int replyid = slea.readInt();
deleteBBSReply(c, replyid);
break;
default:
//System.out.println("Unhandled BBS mode: " + slea.toString());
}
}
private static void listBBSThreads(MapleClient c, int start) {
try {
Connection con = DatabaseConnection.getConnection();
try (PreparedStatement ps = con.prepareStatement("SELECT * FROM bbs_threads WHERE guildid = ? ORDER BY localthreadid DESC")) {
ps.setInt(1, c.getPlayer().getGuildId());
try (ResultSet rs = ps.executeQuery()) {
c.announce(MaplePacketCreator.BBSThreadList(rs, start));
}
}
con.close();
} catch (SQLException se) {
se.printStackTrace();
}
}
private static void newBBSReply(MapleClient c, int localthreadid, String text) {
if (c.getPlayer().getGuildId() <= 0) {
return;
}
Connection con = null;
try {
con = DatabaseConnection.getConnection();
PreparedStatement ps = con.prepareStatement("SELECT threadid FROM bbs_threads WHERE guildid = ? AND localthreadid = ?");
ps.setInt(1, c.getPlayer().getGuildId());
ps.setInt(2, localthreadid);
ResultSet threadRS = ps.executeQuery();
if (!threadRS.next()) {
threadRS.close();
ps.close();
return;
}
int threadid = threadRS.getInt("threadid");
threadRS.close();
ps.close();
ps = con.prepareStatement("INSERT INTO bbs_replies " + "(`threadid`, `postercid`, `timestamp`, `content`) VALUES " + "(?, ?, ?, ?)");
ps.setInt(1, threadid);
ps.setInt(2, c.getPlayer().getId());
ps.setLong(3, currentServerTime());
ps.setString(4, text);
ps.execute();
ps.close();
ps = con.prepareStatement("UPDATE bbs_threads SET replycount = replycount + 1 WHERE threadid = ?");
ps.setInt(1, threadid);
ps.execute();
ps.close();
con.close();
displayThread(c, localthreadid);
} catch (SQLException se) {
se.printStackTrace();
}
}
private static void editBBSThread(MapleClient client, String title, String text, int icon, int localthreadid) {
MapleCharacter chr = client.getPlayer();
if (chr.getGuildId() < 1) {
return;
}
try {
Connection con = DatabaseConnection.getConnection();
try (PreparedStatement ps = con.prepareStatement("UPDATE bbs_threads SET `name` = ?, `timestamp` = ?, " + "`icon` = ?, " + "`startpost` = ? WHERE guildid = ? AND localthreadid = ? AND (postercid = ? OR ?)")) {
ps.setString(1, title);
ps.setLong(2, currentServerTime());
ps.setInt(3, icon);
ps.setString(4, text);
ps.setInt(5, chr.getGuildId());
ps.setInt(6, localthreadid);
ps.setInt(7, chr.getId());
ps.setBoolean(8, chr.getGuildRank() < 3);
ps.execute();
}
con.close();
displayThread(client, localthreadid);
} catch (SQLException se) {
se.printStackTrace();
}
}
private static void newBBSThread(MapleClient client, String title, String text, int icon, boolean bNotice) {
MapleCharacter chr = client.getPlayer();
if (chr.getGuildId() <= 0) {
return;
}
int nextId = 0;
try {
Connection con = DatabaseConnection.getConnection();
PreparedStatement ps;
if (!bNotice) {
ps = con.prepareStatement("SELECT MAX(localthreadid) AS lastLocalId FROM bbs_threads WHERE guildid = ?");
ps.setInt(1, chr.getGuildId());
try (ResultSet rs = ps.executeQuery()) {
rs.next();
nextId = rs.getInt("lastLocalId") + 1;
}
ps.close();
}
ps = con.prepareStatement("INSERT INTO bbs_threads " + "(`postercid`, `name`, `timestamp`, `icon`, `startpost`, " + "`guildid`, `localthreadid`) " + "VALUES(?, ?, ?, ?, ?, ?, ?)");
ps.setInt(1, chr.getId());
ps.setString(2, title);
ps.setLong(3, currentServerTime());
ps.setInt(4, icon);
ps.setString(5, text);
ps.setInt(6, chr.getGuildId());
ps.setInt(7, nextId);
ps.execute();
ps.close();
con.close();
displayThread(client, nextId);
} catch (SQLException se) {
se.printStackTrace();
}
}
public static void deleteBBSThread(MapleClient client, int localthreadid) {
MapleCharacter mc = client.getPlayer();
if (mc.getGuildId() <= 0) {
return;
}
Connection con = null;
try {
con = DatabaseConnection.getConnection();
PreparedStatement ps = con.prepareStatement("SELECT threadid, postercid FROM bbs_threads WHERE guildid = ? AND localthreadid = ?");
ps.setInt(1, mc.getGuildId());
ps.setInt(2, localthreadid);
ResultSet threadRS = ps.executeQuery();
if (!threadRS.next()) {
threadRS.close();
ps.close();
return;
}
if (mc.getId() != threadRS.getInt("postercid") && mc.getGuildRank() > 2) {
threadRS.close();
ps.close();
return;
}
int threadid = threadRS.getInt("threadid");
ps.close();
ps = con.prepareStatement("DELETE FROM bbs_replies WHERE threadid = ?");
ps.setInt(1, threadid);
ps.execute();
ps.close();
ps = con.prepareStatement("DELETE FROM bbs_threads WHERE threadid = ?");
ps.setInt(1, threadid);
ps.execute();
threadRS.close();
ps.close();
con.close();
} catch (SQLException se) {
se.printStackTrace();
}
}
public static void deleteBBSReply(MapleClient client, int replyid) {
MapleCharacter mc = client.getPlayer();
if (mc.getGuildId() <= 0) {
return;
}
int threadid;
Connection con = null;
try {
con = DatabaseConnection.getConnection();
PreparedStatement ps = con.prepareStatement("SELECT postercid, threadid FROM bbs_replies WHERE replyid = ?");
ps.setInt(1, replyid);
ResultSet rs = ps.executeQuery();
if (!rs.next()) {
rs.close();
ps.close();
return;
}
if (mc.getId() != rs.getInt("postercid") && mc.getGuildRank() > 2) {
rs.close();
ps.close();
return;
}
threadid = rs.getInt("threadid");
rs.close();
ps.close();
ps = con.prepareStatement("DELETE FROM bbs_replies WHERE replyid = ?");
ps.setInt(1, replyid);
ps.execute();
ps.close();
ps = con.prepareStatement("UPDATE bbs_threads SET replycount = replycount - 1 WHERE threadid = ?");
ps.setInt(1, threadid);
ps.execute();
ps.close();
con.close();
displayThread(client, threadid, false);
} catch (SQLException se) {
se.printStackTrace();
}
}
public static void displayThread(MapleClient client, int threadid) {
displayThread(client, threadid, true);
}
public static void displayThread(MapleClient client, int threadid, boolean bIsThreadIdLocal) {
MapleCharacter mc = client.getPlayer();
if (mc.getGuildId() <= 0) {
return;
}
Connection con;
try {
con = DatabaseConnection.getConnection();
PreparedStatement ps2;
try (PreparedStatement ps = con.prepareStatement("SELECT * FROM bbs_threads WHERE guildid = ? AND " + (bIsThreadIdLocal ? "local" : "") + "threadid = ?")) {
ps.setInt(1, mc.getGuildId());
ps.setInt(2, threadid);
ResultSet threadRS = ps.executeQuery();
if (!threadRS.next()) {
threadRS.close();
ps.close();
return;
}
ResultSet repliesRS = null;
ps2 = null;
if (threadRS.getInt("replycount") >= 0) {
ps2 = con.prepareStatement("SELECT * FROM bbs_replies WHERE threadid = ?");
ps2.setInt(1, !bIsThreadIdLocal ? threadid : threadRS.getInt("threadid"));
repliesRS = ps2.executeQuery();
}
client.announce(MaplePacketCreator.showThread(bIsThreadIdLocal ? threadid : threadRS.getInt("localthreadid"), threadRS, repliesRS));
repliesRS.close();
}
if (ps2 != null) {
ps2.close();
}
con.close();
} catch (SQLException se) {
se.printStackTrace();
} catch (RuntimeException re) {//btw we get this everytime for some reason, but replies work!
re.printStackTrace();
System.out.println("The number of reply rows does not match the replycount in thread.");
}
}
}

View File

@@ -0,0 +1,59 @@
/*
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 as
published by the Free Software Foundation 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.server.channel.handlers;
import client.MapleClient;
import constants.skills.DarkKnight;
import java.util.Collection;
import net.AbstractMaplePacketHandler;
import server.maps.MapleSummon;
import tools.data.input.SeekableLittleEndianAccessor;
/**
*
* @author BubblesDev
*/
public final class BeholderHandler extends AbstractMaplePacketHandler {//Summon Skills noobs
@Override
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
//System.out.println(slea.toString());
Collection<MapleSummon> summons = c.getPlayer().getSummonsValues();
int oid = slea.readInt();
MapleSummon summon = null;
for (MapleSummon sum : summons) {
if (sum.getObjectId() == oid) {
summon = sum;
}
}
if (summon != null) {
int skillId = slea.readInt();
if (skillId == DarkKnight.AURA_OF_BEHOLDER) {
slea.readShort(); //Not sure.
} else if (skillId == DarkKnight.HEX_OF_BEHOLDER) {
slea.readByte(); //Not sure.
} //show to others here
} else {
c.getPlayer().clearSummons();
}
}
}

View File

@@ -0,0 +1,209 @@
/*
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 as
published by the Free Software Foundation 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.server.channel.handlers;
import client.BuddyList;
import client.BuddyList.BuddyAddResult;
import client.BuddyList.BuddyOperation;
import static client.BuddyList.BuddyOperation.ADDED;
import client.BuddylistEntry;
import client.CharacterNameAndId;
import client.MapleCharacter;
import client.MapleClient;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import net.AbstractMaplePacketHandler;
import net.server.world.World;
import tools.DatabaseConnection;
import tools.MaplePacketCreator;
import tools.data.input.SeekableLittleEndianAccessor;
public class BuddylistModifyHandler extends AbstractMaplePacketHandler {
private static class CharacterIdNameBuddyCapacity extends CharacterNameAndId {
private int buddyCapacity;
public CharacterIdNameBuddyCapacity(int id, String name, int buddyCapacity) {
super(id, name);
this.buddyCapacity = buddyCapacity;
}
public int getBuddyCapacity() {
return buddyCapacity;
}
}
private void nextPendingRequest(MapleClient c) {
CharacterNameAndId pendingBuddyRequest = c.getPlayer().getBuddylist().pollPendingRequest();
if (pendingBuddyRequest != null) {
c.announce(MaplePacketCreator.requestBuddylistAdd(pendingBuddyRequest.getId(), c.getPlayer().getId(), pendingBuddyRequest.getName()));
}
}
private CharacterIdNameBuddyCapacity getCharacterIdAndNameFromDatabase(String name) throws SQLException {
Connection con = DatabaseConnection.getConnection();
CharacterIdNameBuddyCapacity ret;
try (PreparedStatement ps = con.prepareStatement("SELECT id, name, buddyCapacity FROM characters WHERE name LIKE ?")) {
ps.setString(1, name);
try (ResultSet rs = ps.executeQuery()) {
ret = null;
if (rs.next()) {
ret = new CharacterIdNameBuddyCapacity(rs.getInt("id"), rs.getString("name"), rs.getInt("buddyCapacity"));
}
}
}
con.close();
return ret;
}
@Override
public void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
int mode = slea.readByte();
MapleCharacter player = c.getPlayer();
BuddyList buddylist = player.getBuddylist();
if (mode == 1) { // add
String addName = slea.readMapleAsciiString();
String group = slea.readMapleAsciiString();
if (group.length() > 16 || addName.length() < 4 || addName.length() > 13) {
return; //hax.
}
BuddylistEntry ble = buddylist.get(addName);
if (ble != null && !ble.isVisible() && group.equals(ble.getGroup())) {
c.announce(MaplePacketCreator.serverNotice(1, "You already have \"" + ble.getName() + "\" on your Buddylist"));
} else if (buddylist.isFull() && ble == null) {
c.announce(MaplePacketCreator.serverNotice(1, "Your buddylist is already full"));
} else if (ble == null) {
try {
World world = c.getWorldServer();
CharacterIdNameBuddyCapacity charWithId;
int channel;
MapleCharacter otherChar = c.getChannelServer().getPlayerStorage().getCharacterByName(addName);
if (otherChar != null) {
channel = c.getChannel();
charWithId = new CharacterIdNameBuddyCapacity(otherChar.getId(), otherChar.getName(), otherChar.getBuddylist().getCapacity());
} else {
channel = world.find(addName);
charWithId = getCharacterIdAndNameFromDatabase(addName);
}
if (charWithId != null) {
BuddyAddResult buddyAddResult = null;
if (channel != -1) {
buddyAddResult = world.requestBuddyAdd(addName, c.getChannel(), player.getId(), player.getName());
} else {
Connection con = DatabaseConnection.getConnection();
PreparedStatement ps = con.prepareStatement("SELECT COUNT(*) as buddyCount FROM buddies WHERE characterid = ? AND pending = 0");
ps.setInt(1, charWithId.getId());
ResultSet rs = ps.executeQuery();
if (!rs.next()) {
throw new RuntimeException("Result set expected");
} else if (rs.getInt("buddyCount") >= charWithId.getBuddyCapacity()) {
buddyAddResult = BuddyAddResult.BUDDYLIST_FULL;
}
rs.close();
ps.close();
ps = con.prepareStatement("SELECT pending FROM buddies WHERE characterid = ? AND buddyid = ?");
ps.setInt(1, charWithId.getId());
ps.setInt(2, player.getId());
rs = ps.executeQuery();
if (rs.next()) {
buddyAddResult = BuddyAddResult.ALREADY_ON_LIST;
}
rs.close();
ps.close();
con.close();
}
if (buddyAddResult == BuddyAddResult.BUDDYLIST_FULL) {
c.announce(MaplePacketCreator.serverNotice(1, "\"" + addName + "\"'s Buddylist is full"));
} else {
int displayChannel;
displayChannel = -1;
int otherCid = charWithId.getId();
if (buddyAddResult == BuddyAddResult.ALREADY_ON_LIST && channel != -1) {
displayChannel = channel;
notifyRemoteChannel(c, channel, otherCid, ADDED);
} else if (buddyAddResult != BuddyAddResult.ALREADY_ON_LIST && channel == -1) {
Connection con = DatabaseConnection.getConnection();
try (PreparedStatement ps = con.prepareStatement("INSERT INTO buddies (characterid, `buddyid`, `pending`) VALUES (?, ?, 1)")) {
ps.setInt(1, charWithId.getId());
ps.setInt(2, player.getId());
ps.executeUpdate();
}
con.close();
}
buddylist.put(new BuddylistEntry(charWithId.getName(), group, otherCid, displayChannel, true));
c.announce(MaplePacketCreator.updateBuddylist(buddylist.getBuddies()));
}
} else {
c.announce(MaplePacketCreator.serverNotice(1, "A character called \"" + addName + "\" does not exist"));
}
} catch (SQLException e) {
e.printStackTrace();
}
} else {
ble.changeGroup(group);
c.announce(MaplePacketCreator.updateBuddylist(buddylist.getBuddies()));
}
} else if (mode == 2) { // accept buddy
int otherCid = slea.readInt();
if (!buddylist.isFull()) {
try {
int channel = c.getWorldServer().find(otherCid);//worldInterface.find(otherCid);
String otherName = null;
MapleCharacter otherChar = c.getChannelServer().getPlayerStorage().getCharacterById(otherCid);
if (otherChar == null) {
Connection con = DatabaseConnection.getConnection();
try (PreparedStatement ps = con.prepareStatement("SELECT name FROM characters WHERE id = ?")) {
ps.setInt(1, otherCid);
try (ResultSet rs = ps.executeQuery()) {
if (rs.next()) {
otherName = rs.getString("name");
}
}
}
con.close();
} else {
otherName = otherChar.getName();
}
if (otherName != null) {
buddylist.put(new BuddylistEntry(otherName, "Default Group", otherCid, channel, true));
c.announce(MaplePacketCreator.updateBuddylist(buddylist.getBuddies()));
notifyRemoteChannel(c, channel, otherCid, ADDED);
}
} catch (SQLException e) {
e.printStackTrace();
}
}
nextPendingRequest(c);
} else if (mode == 3) { // delete
int otherCid = slea.readInt();
player.deleteBuddy(otherCid);
}
}
private void notifyRemoteChannel(MapleClient c, int remoteChannel, int otherCid, BuddyOperation operation) {
MapleCharacter player = c.getPlayer();
if (remoteChannel != -1) {
c.getWorldServer().buddyChanged(otherCid, player.getId(), player.getName(), c.getChannel(), operation);
}
}
}

View File

@@ -0,0 +1,63 @@
/*
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 as
published by the Free Software Foundation 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.server.channel.handlers;
import client.MapleClient;
import client.SkillFactory;
import constants.skills.Bishop;
import constants.skills.Bowmaster;
import constants.skills.Corsair;
import constants.skills.Evan;
import constants.skills.FPArchMage;
import constants.skills.ILArchMage;
import constants.skills.Marksman;
import constants.skills.WindArcher;
import net.AbstractMaplePacketHandler;
import net.MaplePacketHandler;
import tools.MaplePacketCreator;
import tools.data.input.SeekableLittleEndianAccessor;
public final class CancelBuffHandler extends AbstractMaplePacketHandler implements MaplePacketHandler {
@Override
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
int sourceid = slea.readInt();
switch (sourceid) {
case FPArchMage.BIG_BANG:
case ILArchMage.BIG_BANG:
case Bishop.BIG_BANG:
case Bowmaster.HURRICANE:
case Marksman.PIERCING_ARROW:
case Corsair.RAPID_FIRE:
case WindArcher.HURRICANE:
case Evan.FIRE_BREATH:
case Evan.ICE_BREATH:
c.getPlayer().getMap().broadcastMessage(c.getPlayer(), MaplePacketCreator.skillCancel(c.getPlayer(), sourceid), false);
break;
default:
c.getPlayer().cancelEffect(SkillFactory.getSkill(sourceid).getEffect(1), false, -1);
break;
}
}
}

View File

@@ -0,0 +1,48 @@
/*
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 as
published by the Free Software Foundation 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.server.channel.handlers;
import client.MapleClient;
import client.MapleCharacter;
import net.AbstractMaplePacketHandler;
import tools.data.input.SeekableLittleEndianAccessor;
public final class CancelChairHandler extends AbstractMaplePacketHandler {
@Override
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
int id = slea.readShort();
MapleCharacter mc = c.getPlayer();
if (id >= mc.getMap().getSeats()) {
return;
}
if (c.tryacquireClient()) {
try {
mc.sitChair(id);
} finally {
c.releaseClient();
}
}
}
}

View File

@@ -0,0 +1,45 @@
/*
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 as
published by the Free Software Foundation 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.server.channel.handlers;
import client.MapleClient;
import net.AbstractMaplePacketHandler;
import tools.data.input.SeekableLittleEndianAccessor;
public final class CancelDebuffHandler extends AbstractMaplePacketHandler {//TIP: BAD STUFF LOL!
@Override
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
/*List<MapleDisease> diseases = c.getPlayer().getDiseases();
List<MapleDisease> diseases_ = new ArrayList<MapleDisease>();
for (MapleDisease disease : diseases) {
List<MapleDisease> disease_ = new ArrayList<MapleDisease>();
disease_.add(disease);
diseases_.add(disease);
c.announce(MaplePacketCreator.cancelDebuff(disease_));
c.getPlayer().getMap().broadcastMessage(c.getPlayer(), MaplePacketCreator.cancelForeignDebuff(c.getPlayer().getId(), disease_), false);
}
for (MapleDisease disease : diseases_) {
c.getPlayer().removeDisease(disease);
}*/
}
}

View File

@@ -0,0 +1,39 @@
/*
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 as
published by the Free Software Foundation 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.server.channel.handlers;
import client.MapleClient;
import net.AbstractMaplePacketHandler;
import server.MapleItemInformationProvider;
import tools.data.input.SeekableLittleEndianAccessor;
public final class CancelItemEffectHandler extends AbstractMaplePacketHandler {
@Override
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
int itemId = -slea.readInt();
if (MapleItemInformationProvider.getInstance().noCancelMouse(itemId)) {
return;
}
c.getPlayer().cancelEffect(itemId);
}
}

View File

@@ -0,0 +1,494 @@
/*
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 as
published by the Free Software Foundation 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.server.channel.handlers;
import client.MapleCharacter;
import client.MapleClient;
import client.MapleRing;
import client.inventory.Equip;
import client.inventory.Item;
import client.inventory.MapleInventory;
import client.inventory.MapleInventoryType;
import config.YamlConfig;
import constants.inventory.ItemConstants;
import java.sql.SQLException;
import java.util.Calendar;
import java.util.List;
import java.util.Map;
import net.AbstractMaplePacketHandler;
import net.server.Server;
import server.CashShop;
import server.CashShop.CashItem;
import server.CashShop.CashItemFactory;
import client.inventory.manipulator.MapleInventoryManipulator;
import server.MapleItemInformationProvider;
import tools.FilePrinter;
import tools.MaplePacketCreator;
import tools.Pair;
import tools.data.input.SeekableLittleEndianAccessor;
public final class CashOperationHandler extends AbstractMaplePacketHandler {
@Override
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
MapleCharacter chr = c.getPlayer();
CashShop cs = chr.getCashShop();
if (!cs.isOpened()) {
c.announce(MaplePacketCreator.enableActions());
return;
}
if (c.tryacquireClient()) { // thanks Thora for finding out an exploit within cash operations
try {
final int action = slea.readByte();
if (action == 0x03 || action == 0x1E) {
slea.readByte();
final int useNX = slea.readInt();
final int snCS = slea.readInt();
CashItem cItem = CashItemFactory.getItem(snCS);
if (!canBuy(chr, cItem, cs.getCash(useNX))) {
FilePrinter.printError(FilePrinter.ITEM, "Denied to sell cash item with SN " + snCS); // preventing NPE here thanks to MedicOP
c.enableCSActions();
return;
}
if (action == 0x03) { // Item
if (ItemConstants.isCashStore(cItem.getItemId()) && chr.getLevel() < 16) {
c.enableCSActions();
return;
} else if (ItemConstants.isRateCoupon(cItem.getItemId()) && !YamlConfig.config.server.USE_SUPPLY_RATE_COUPONS) {
chr.dropMessage(1, "Rate coupons are currently unavailable to purchase.");
c.enableCSActions();
return;
} else if (ItemConstants.isMapleLife(cItem.getItemId()) && chr.getLevel() < 30) {
c.enableCSActions();
return;
}
Item item = cItem.toItem();
cs.gainCash(useNX, cItem, chr.getWorld()); // thanks Rohenn for noticing cash operations after item acquisition
cs.addToInventory(item);
c.announce(MaplePacketCreator.showBoughtCashItem(item, c.getAccID()));
} else { // Package
cs.gainCash(useNX, cItem, chr.getWorld());
List<Item> cashPackage = CashItemFactory.getPackage(cItem.getItemId());
for (Item item : cashPackage) {
cs.addToInventory(item);
}
c.announce(MaplePacketCreator.showBoughtCashPackage(cashPackage, c.getAccID()));
}
c.announce(MaplePacketCreator.showCash(chr));
} else if (action == 0x04) {//TODO check for gender
int birthday = slea.readInt();
CashItem cItem = CashItemFactory.getItem(slea.readInt());
Map<String, String> recipient = MapleCharacter.getCharacterFromDatabase(slea.readMapleAsciiString());
String message = slea.readMapleAsciiString();
if (!canBuy(chr, cItem, cs.getCash(4)) || message.length() < 1 || message.length() > 73) {
c.enableCSActions();
return;
}
if (!checkBirthday(c, birthday)) {
c.announce(MaplePacketCreator.showCashShopMessage((byte) 0xC4));
return;
} else if (recipient == null) {
c.announce(MaplePacketCreator.showCashShopMessage((byte) 0xA9));
return;
} else if (recipient.get("accountid").equals(String.valueOf(c.getAccID()))) {
c.announce(MaplePacketCreator.showCashShopMessage((byte) 0xA8));
return;
}
cs.gainCash(4, cItem, chr.getWorld());
cs.gift(Integer.parseInt(recipient.get("id")), chr.getName(), message, cItem.getSN());
c.announce(MaplePacketCreator.showGiftSucceed(recipient.get("name"), cItem));
c.announce(MaplePacketCreator.showCash(chr));
try {
chr.sendNote(recipient.get("name"), chr.getName() + " has sent you a gift! Go check out the Cash Shop.", (byte) 0); //fame or not
} catch (SQLException ex) {
ex.printStackTrace();
}
MapleCharacter receiver = c.getChannelServer().getPlayerStorage().getCharacterByName(recipient.get("name"));
if (receiver != null) receiver.showNote();
} else if (action == 0x05) { // Modify wish list
cs.clearWishList();
for (byte i = 0; i < 10; i++) {
int sn = slea.readInt();
CashItem cItem = CashItemFactory.getItem(sn);
if (cItem != null && cItem.isOnSale() && sn != 0) {
cs.addToWishList(sn);
}
}
c.announce(MaplePacketCreator.showWishList(chr, true));
} else if (action == 0x06) { // Increase Inventory Slots
slea.skip(1);
int cash = slea.readInt();
byte mode = slea.readByte();
if (mode == 0) {
byte type = slea.readByte();
if (cs.getCash(cash) < 4000) {
c.enableCSActions();
return;
}
int qty = 4;
if (!chr.canGainSlots(type, qty)) {
c.enableCSActions();
return;
}
cs.gainCash(cash, -4000);
if (chr.gainSlots(type, qty, false)) {
c.announce(MaplePacketCreator.showBoughtInventorySlots(type, chr.getSlots(type)));
c.announce(MaplePacketCreator.showCash(chr));
} else {
FilePrinter.printError(FilePrinter.CASHITEM_BOUGHT, "Could not add " + qty + " slots of type " + type + " for player " + MapleCharacter.makeMapleReadable(chr.getName()));
}
} else {
CashItem cItem = CashItemFactory.getItem(slea.readInt());
int type = (cItem.getItemId() - 9110000) / 1000;
if (!canBuy(chr, cItem, cs.getCash(cash))) {
c.enableCSActions();
return;
}
int qty = 8;
if (!chr.canGainSlots(type, qty)) {
c.enableCSActions();
return;
}
cs.gainCash(cash, cItem, chr.getWorld());
if (chr.gainSlots(type, qty, false)) {
c.announce(MaplePacketCreator.showBoughtInventorySlots(type, chr.getSlots(type)));
c.announce(MaplePacketCreator.showCash(chr));
} else {
FilePrinter.printError(FilePrinter.CASHITEM_BOUGHT, "Could not add " + qty + " slots of type " + type + " for player " + MapleCharacter.makeMapleReadable(chr.getName()));
}
}
} else if (action == 0x07) { // Increase Storage Slots
slea.skip(1);
int cash = slea.readInt();
byte mode = slea.readByte();
if (mode == 0) {
if (cs.getCash(cash) < 4000) {
c.enableCSActions();
return;
}
int qty = 4;
if (!chr.getStorage().canGainSlots(qty)) {
c.enableCSActions();
return;
}
cs.gainCash(cash, -4000);
if (chr.getStorage().gainSlots(qty)) {
FilePrinter.print(FilePrinter.STORAGE + c.getAccountName() + ".txt", c.getPlayer().getName() + " bought " + qty + " slots to their account storage.");
chr.setUsedStorage();
c.announce(MaplePacketCreator.showBoughtStorageSlots(chr.getStorage().getSlots()));
c.announce(MaplePacketCreator.showCash(chr));
} else {
FilePrinter.printError(FilePrinter.CASHITEM_BOUGHT, "Could not add " + qty + " slots to " + MapleCharacter.makeMapleReadable(chr.getName()) + "'s account.");
}
} else {
CashItem cItem = CashItemFactory.getItem(slea.readInt());
if (!canBuy(chr, cItem, cs.getCash(cash))) {
c.enableCSActions();
return;
}
int qty = 8;
if (!chr.getStorage().canGainSlots(qty)) {
c.enableCSActions();
return;
}
cs.gainCash(cash, cItem, chr.getWorld());
if (chr.getStorage().gainSlots(qty)) { // thanks ABaldParrot & Thora for detecting storage issues here
FilePrinter.print(FilePrinter.STORAGE + c.getAccountName() + ".txt", c.getPlayer().getName() + " bought " + qty + " slots to their account storage.");
chr.setUsedStorage();
c.announce(MaplePacketCreator.showBoughtStorageSlots(chr.getStorage().getSlots()));
c.announce(MaplePacketCreator.showCash(chr));
} else {
FilePrinter.printError(FilePrinter.CASHITEM_BOUGHT, "Could not add " + qty + " slots to " + MapleCharacter.makeMapleReadable(chr.getName()) + "'s account.");
}
}
} else if (action == 0x08) { // Increase Character Slots
slea.skip(1);
int cash = slea.readInt();
CashItem cItem = CashItemFactory.getItem(slea.readInt());
if (!canBuy(chr, cItem, cs.getCash(cash))) {
c.enableCSActions();
return;
}
if (!c.canGainCharacterSlot()) {
chr.dropMessage(1, "You have already used up all 12 extra character slots.");
c.enableCSActions();
return;
}
cs.gainCash(cash, cItem, chr.getWorld());
if (c.gainCharacterSlot()) {
c.announce(MaplePacketCreator.showBoughtCharacterSlot(c.getCharacterSlots()));
c.announce(MaplePacketCreator.showCash(chr));
} else {
FilePrinter.printError(FilePrinter.CASHITEM_BOUGHT, "Could not add a character slot to " + MapleCharacter.makeMapleReadable(chr.getName()) + "'s account.");
c.enableCSActions();
return;
}
} else if (action == 0x0D) { // Take from Cash Inventory
Item item = cs.findByCashId(slea.readInt());
if (item == null) {
c.enableCSActions();
return;
}
if (chr.getInventory(item.getInventoryType()).addItem(item) != -1) {
cs.removeFromInventory(item);
c.announce(MaplePacketCreator.takeFromCashInventory(item));
if(item instanceof Equip) {
Equip equip = (Equip) item;
if(equip.getRingId() >= 0) {
MapleRing ring = MapleRing.loadFromDb(equip.getRingId());
chr.addPlayerRing(ring);
}
}
}
} else if (action == 0x0E) { // Put into Cash Inventory
int cashId = slea.readInt();
slea.skip(4);
byte invType = slea.readByte();
if (invType < 1 || invType > 5) {
c.disconnect(false, false);
return;
}
MapleInventory mi = chr.getInventory(MapleInventoryType.getByType(invType));
Item item = mi.findByCashId(cashId);
if (item == null) {
c.enableCSActions();
return;
} else if (c.getPlayer().getPetIndex(item.getPetId()) > -1) {
chr.getClient().announce(MaplePacketCreator.serverNotice(1, "You cannot put the pet you currently equip into the Cash Shop inventory."));
c.enableCSActions();
return;
} else if (ItemConstants.isWeddingRing(item.getItemId()) || ItemConstants.isWeddingToken(item.getItemId())) {
chr.getClient().announce(MaplePacketCreator.serverNotice(1, "You cannot put relationship items into the Cash Shop inventory."));
c.enableCSActions();
return;
}
cs.addToInventory(item);
mi.removeSlot(item.getPosition());
c.announce(MaplePacketCreator.putIntoCashInventory(item, c.getAccID()));
} else if (action == 0x1D) { //crush ring (action 28)
int birthday = slea.readInt();
if (checkBirthday(c, birthday)) {
int toCharge = slea.readInt();
int SN = slea.readInt();
String recipientName = slea.readMapleAsciiString();
String text = slea.readMapleAsciiString();
CashItem itemRing = CashItemFactory.getItem(SN);
MapleCharacter partner = c.getChannelServer().getPlayerStorage().getCharacterByName(recipientName);
if (partner == null) {
chr.getClient().announce(MaplePacketCreator.serverNotice(1, "The partner you specified cannot be found.\r\nPlease make sure your partner is online and in the same channel."));
} else {
/* if (partner.getGender() == chr.getGender()) {
chr.dropMessage(5, "You and your partner are the same gender, please buy a friendship ring.");
c.enableCSActions();
return;
}*/ //Gotta let them faggots marry too, hence why this is commented out <3
if(itemRing.toItem() instanceof Equip) {
Equip eqp = (Equip) itemRing.toItem();
Pair<Integer, Integer> rings = MapleRing.createRing(itemRing.getItemId(), chr, partner);
eqp.setRingId(rings.getLeft());
cs.addToInventory(eqp);
c.announce(MaplePacketCreator.showBoughtCashItem(eqp, c.getAccID()));
cs.gainCash(toCharge, itemRing, chr.getWorld());
cs.gift(partner.getId(), chr.getName(), text, eqp.getSN(), rings.getRight());
chr.addCrushRing(MapleRing.loadFromDb(rings.getLeft()));
try {
chr.sendNote(partner.getName(), text, (byte) 1);
} catch (SQLException ex) {
ex.printStackTrace();
}
partner.showNote();
}
}
} else {
c.announce(MaplePacketCreator.showCashShopMessage((byte) 0xC4));
}
c.announce(MaplePacketCreator.showCash(c.getPlayer()));
} else if (action == 0x20) {
int serialNumber = slea.readInt(); // thanks GabrielSin for detecting a potential exploit with 1 meso cash items.
if (serialNumber / 10000000 != 8) {
c.announce(MaplePacketCreator.showCashShopMessage((byte) 0xC0));
return;
}
CashItem item = CashItemFactory.getItem(serialNumber);
if (item == null || !item.isOnSale()) {
c.announce(MaplePacketCreator.showCashShopMessage((byte) 0xC0));
return;
}
int itemId = item.getItemId();
int itemPrice = item.getPrice();
if (itemPrice <= 0) {
c.announce(MaplePacketCreator.showCashShopMessage((byte) 0xC0));
return;
}
if (chr.getMeso() >= itemPrice) {
if (chr.canHold(itemId)) {
chr.gainMeso(-itemPrice, false);
MapleInventoryManipulator.addById(c, itemId, (short) 1, "", -1);
c.announce(MaplePacketCreator.showBoughtQuestItem(itemId));
}
}
c.announce(MaplePacketCreator.showCash(c.getPlayer()));
} else if (action == 0x23) { //Friendship :3
int birthday = slea.readInt();
if (checkBirthday(c, birthday)) {
int payment = slea.readByte();
slea.skip(3); //0s
int snID = slea.readInt();
CashItem itemRing = CashItemFactory.getItem(snID);
String sentTo = slea.readMapleAsciiString();
int available = slea.readShort() - 1;
String text = slea.readAsciiString(available);
slea.readByte();
MapleCharacter partner = c.getChannelServer().getPlayerStorage().getCharacterByName(sentTo);
if (partner == null) {
c.announce(MaplePacketCreator.showCashShopMessage((byte)0xBE));
} else {
// Need to check to make sure its actually an equip and the right SN...
if(itemRing.toItem() instanceof Equip) {
Equip eqp = (Equip) itemRing.toItem();
Pair<Integer, Integer> rings = MapleRing.createRing(itemRing.getItemId(), chr, partner);
eqp.setRingId(rings.getLeft());
cs.addToInventory(eqp);
c.announce(MaplePacketCreator.showBoughtCashRing(eqp, partner.getName(), c.getAccID()));
cs.gainCash(payment, -itemRing.getPrice());
cs.gift(partner.getId(), chr.getName(), text, eqp.getSN(), rings.getRight());
chr.addFriendshipRing(MapleRing.loadFromDb(rings.getLeft()));
try {
chr.sendNote(partner.getName(), text, (byte) 1);
} catch (SQLException ex) {
ex.printStackTrace();
}
partner.showNote();
}
}
} else {
c.announce(MaplePacketCreator.showCashShopMessage((byte) 0xC4));
}
c.announce(MaplePacketCreator.showCash(c.getPlayer()));
} else if (action == 0x2E) { //name change
CashItem cItem = CashItemFactory.getItem(slea.readInt());
if (cItem == null || !canBuy(chr, cItem, cs.getCash(4))) {
c.announce(MaplePacketCreator.showCashShopMessage((byte)0));
c.enableCSActions();
return;
}
if(cItem.getSN() == 50600000 && YamlConfig.config.server.ALLOW_CASHSHOP_NAME_CHANGE) {
slea.readMapleAsciiString(); //old name
String newName = slea.readMapleAsciiString();
if(!MapleCharacter.canCreateChar(newName) || chr.getLevel() < 10) { //(longest ban duration isn't tracked currently)
c.announce(MaplePacketCreator.showCashShopMessage((byte)0));
c.enableCSActions();
return;
} else if(c.getTempBanCalendar() != null && c.getTempBanCalendar().getTimeInMillis() + (30*24*60*60*1000) > Calendar.getInstance().getTimeInMillis()) {
c.announce(MaplePacketCreator.showCashShopMessage((byte)0));
c.enableCSActions();
return;
}
if(chr.registerNameChange(newName)) { //success
Item item = cItem.toItem();
c.announce(MaplePacketCreator.showNameChangeSuccess(item, c.getAccID()));
cs.gainCash(4, cItem, chr.getWorld());
cs.addToInventory(item);
} else {
c.announce(MaplePacketCreator.showCashShopMessage((byte)0));
}
}
c.enableCSActions();
} else if(action == 0x31) { //world transfer
CashItem cItem = CashItemFactory.getItem(slea.readInt());
if (cItem == null || !canBuy(chr, cItem, cs.getCash(4))) {
c.announce(MaplePacketCreator.showCashShopMessage((byte)0));
c.enableCSActions();
return;
}
if(cItem.getSN() == 50600001 && YamlConfig.config.server.ALLOW_CASHSHOP_WORLD_TRANSFER) {
int newWorldSelection = slea.readInt();
int worldTransferError = chr.checkWorldTransferEligibility();
if(worldTransferError != 0 || newWorldSelection >= Server.getInstance().getWorldsSize() || Server.getInstance().getWorldsSize() <= 1) {
c.announce(MaplePacketCreator.showCashShopMessage((byte)0));
return;
} else if(newWorldSelection == c.getWorld()) {
c.announce(MaplePacketCreator.showCashShopMessage((byte)0xDC));
return;
} else if(c.getAvailableCharacterWorldSlots(newWorldSelection) < 1 || Server.getInstance().getAccountWorldCharacterCount(c.getAccID(), newWorldSelection) >= 3) {
c.announce(MaplePacketCreator.showCashShopMessage((byte)0xDF));
return;
} else if(chr.registerWorldTransfer(newWorldSelection)) {
Item item = cItem.toItem();
c.announce(MaplePacketCreator.showWorldTransferSuccess(item, c.getAccID()));
cs.gainCash(4, cItem, chr.getWorld());
cs.addToInventory(item);
} else {
c.announce(MaplePacketCreator.showCashShopMessage((byte)0));
}
}
c.enableCSActions();
} else {
System.out.println("Unhandled action: " + action + "\n" + slea);
}
} finally {
c.releaseClient();
}
} else {
c.announce(MaplePacketCreator.enableActions());
}
}
public static boolean checkBirthday(MapleClient c, int idate) {
int year = idate / 10000;
int month = (idate - year * 10000) / 100;
int day = idate - year * 10000 - month * 100;
Calendar cal = Calendar.getInstance();
cal.setTimeInMillis(0);
cal.set(year, month - 1, day);
return c.checkBirthDate(cal);
}
private static boolean canBuy(MapleCharacter chr, CashItem item, int cash) {
if (item != null && item.isOnSale() && item.getPrice() <= cash) {
FilePrinter.print(FilePrinter.CASHITEM_BOUGHT, chr + " bought " + MapleItemInformationProvider.getInstance().getName(item.getItemId()) + " (SN " + item.getSN() + ") for " + item.getPrice());
return true;
} else {
return false;
}
}
}

View File

@@ -0,0 +1,50 @@
/*
This file is part of the HeavenMS MapleStory Server
Copyleft (L) 2016 - 2019 RonanLana
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation 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.server.channel.handlers;
import client.MapleClient;
import client.inventory.Item;
import net.AbstractMaplePacketHandler;
import server.CashShop;
import tools.data.input.SeekableLittleEndianAccessor;
import tools.MaplePacketCreator;
import tools.Pair;
/**
*
* @author RonanLana
*/
public class CashShopSurpriseHandler extends AbstractMaplePacketHandler {
@Override
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
CashShop cs = c.getPlayer().getCashShop();
if(cs.isOpened()) {
Pair<Item, Item> cssResult = cs.openCashShopSurprise();
if(cssResult != null) {
Item cssItem = cssResult.getLeft(), cssBox = cssResult.getRight();
c.announce(MaplePacketCreator.onCashGachaponOpenSuccess(c.getAccID(), cssBox.getSN(), cssBox.getQuantity(), cssItem, cssItem.getItemId(), cssItem.getQuantity(), true));
} else {
c.announce(MaplePacketCreator.onCashItemGachaponOpenFailed());
}
}
}
}

View File

@@ -0,0 +1,51 @@
/*
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 as
published by the Free Software Foundation 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.server.channel.handlers;
import net.AbstractMaplePacketHandler;
import tools.data.input.SeekableLittleEndianAccessor;
import client.MapleClient;
import client.autoban.AutobanFactory;
import net.server.Server;
/**
*
* @author Matze
*/
public final class ChangeChannelHandler extends AbstractMaplePacketHandler {
@Override
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
int channel = slea.readByte() + 1;
slea.readInt();
c.getPlayer().getAutobanManager().setTimestamp(6, Server.getInstance().getCurrentTimestamp(), 3);
if(c.getChannel() == channel) {
AutobanFactory.GENERAL.alert(c.getPlayer(), "CCing to same channel.");
c.disconnect(false, false);
return;
} else if (c.getPlayer().getCashShop().isOpened() || c.getPlayer().getMiniGame() != null || c.getPlayer().getPlayerShop() != null) {
return;
}
c.changeChannel(channel);
}
}

View File

@@ -0,0 +1,173 @@
/*
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 as
published by the Free Software Foundation 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.server.channel.handlers;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Calendar;
import net.AbstractMaplePacketHandler;
import client.MapleCharacter;
import client.MapleClient;
import client.inventory.MapleInventoryType;
import client.inventory.manipulator.MapleInventoryManipulator;
import server.maps.MaplePortal;
import server.MapleTrade;
import server.maps.MapleMap;
import tools.FilePrinter;
import tools.MaplePacketCreator;
import tools.data.input.SeekableLittleEndianAccessor;
public final class ChangeMapHandler extends AbstractMaplePacketHandler {
@Override
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
MapleCharacter chr = c.getPlayer();
if (chr.isChangingMaps() || chr.isBanned()) {
if(chr.isChangingMaps()) {
FilePrinter.printError(FilePrinter.PORTAL_STUCK + chr.getName() + ".txt", "Player " + chr.getName() + " got stuck when changing maps. Timestamp: " + Calendar.getInstance().getTime().toString() + " Last visited mapids: " + chr.getLastVisitedMapids());
}
c.announce(MaplePacketCreator.enableActions());
return;
}
if (chr.getTrade() != null) {
MapleTrade.cancelTrade(chr, MapleTrade.TradeResult.UNSUCCESSFUL_ANOTHER_MAP);
}
if (slea.available() == 0) { //Cash Shop :)
if(!chr.getCashShop().isOpened()) {
c.disconnect(false, false);
return;
}
String[] socket = c.getChannelServer().getIP().split(":");
chr.getCashShop().open(false);
chr.setSessionTransitionState();
try {
c.announce(MaplePacketCreator.getChannelChange(InetAddress.getByName(socket[0]), Integer.parseInt(socket[1])));
} catch (UnknownHostException ex) {
ex.printStackTrace();
}
} else {
if(chr.getCashShop().isOpened()) {
c.disconnect(false, false);
return;
}
try {
slea.readByte(); // 1 = from dying 0 = regular portals
int targetid = slea.readInt();
String startwp = slea.readMapleAsciiString();
MaplePortal portal = chr.getMap().getPortal(startwp);
slea.readByte();
boolean wheel = slea.readShort() > 0;
if (targetid != -1) {
if (!chr.isAlive()) {
MapleMap map = chr.getMap();
if (wheel && chr.haveItemWithId(5510000, false)) {
// thanks lucasziron (lziron) for showing revivePlayer() triggering by Wheel
MapleInventoryManipulator.removeById(c, MapleInventoryType.CASH, 5510000, 1, true, false);
chr.announce(MaplePacketCreator.showWheelsLeft(chr.getItemQuantity(5510000, false)));
chr.updateHp(50);
chr.changeMap(map, map.findClosestPlayerSpawnpoint(chr.getPosition()));
} else {
boolean executeStandardPath = true;
if (chr.getEventInstance() != null) {
executeStandardPath = chr.getEventInstance().revivePlayer(chr);
}
if (executeStandardPath) {
chr.respawn(map.getReturnMapId());
}
}
} else {
if (chr.isGM()) {
MapleMap to = chr.getWarpMap(targetid);
chr.changeMap(to, to.getPortal(0));
} else {
final int divi = chr.getMapId() / 100;
boolean warp = false;
if (divi == 0) {
if (targetid == 10000) {
warp = true;
}
} else if (divi == 20100) {
if (targetid == 104000000) {
c.announce(MaplePacketCreator.lockUI(false));
c.announce(MaplePacketCreator.disableUI(false));
warp = true;
}
} else if (divi == 9130401) { // Only allow warp if player is already in Intro map, or else = hack
if (targetid == 130000000 || targetid / 100 == 9130401) { // Cygnus introduction
warp = true;
}
} else if (divi == 9140900) { // Aran Introduction
if (targetid == 914090011 || targetid == 914090012 || targetid == 914090013 || targetid == 140090000) {
warp = true;
}
} else if (divi / 10 == 1020) { // Adventurer movie clip Intro
if (targetid == 1020000) {
warp = true;
}
} else if(divi / 10 >= 980040 && divi / 10 <= 980045) {
if(targetid == 980040000) {
warp = true;
}
}
if (warp) {
final MapleMap to = chr.getWarpMap(targetid);
chr.changeMap(to, to.getPortal(0));
}
}
}
}
if (portal != null && !portal.getPortalStatus()) {
c.announce(MaplePacketCreator.blockedMessage(1));
c.announce(MaplePacketCreator.enableActions());
return;
}
if (chr.getMapId() == 109040004) {
chr.getFitness().resetTimes();
} else if (chr.getMapId() == 109030003 || chr.getMapId() == 109030103) {
chr.getOla().resetTimes();
}
if (portal != null) {
if(portal.getPosition().distanceSq(chr.getPosition()) > 400000) {
c.announce(MaplePacketCreator.enableActions());
return;
}
portal.enterPortal(c);
} else {
c.announce(MaplePacketCreator.enableActions());
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}

View File

@@ -0,0 +1,52 @@
/*
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 as
published by the Free Software Foundation 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.server.channel.handlers;
import client.MapleClient;
import net.AbstractMaplePacketHandler;
import server.maps.MaplePortal;
import server.MapleTrade;
import server.MapleTrade.TradeResult;
import tools.MaplePacketCreator;
import tools.data.input.SeekableLittleEndianAccessor;
public final class ChangeMapSpecialHandler extends AbstractMaplePacketHandler {
@Override
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
slea.readByte();
String startwp = slea.readMapleAsciiString();
slea.readShort();
MaplePortal portal = c.getPlayer().getMap().getPortal(startwp);
if (portal == null || c.getPlayer().portalDelay() > currentServerTime() || c.getPlayer().getBlockedPortals().contains(portal.getScriptName())) {
c.announce(MaplePacketCreator.enableActions());
return;
}
if (c.getPlayer().isChangingMaps() || c.getPlayer().isBanned()) {
c.announce(MaplePacketCreator.enableActions());
return;
}
if (c.getPlayer().getTrade() != null) {
MapleTrade.cancelTrade(c.getPlayer(), TradeResult.UNSUCCESSFUL_ANOTHER_MAP);
}
portal.enterPortal(c);
}
}

View File

@@ -0,0 +1,49 @@
/*
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 as
published by the Free Software Foundation 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.server.channel.handlers;
import client.MapleCharacter;
import client.MapleClient;
import net.AbstractMaplePacketHandler;
import server.maps.MapleMapObject;
import tools.MaplePacketCreator;
import tools.data.input.SeekableLittleEndianAccessor;
public final class CharInfoRequestHandler extends AbstractMaplePacketHandler {
@Override
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
slea.skip(4);
int cid = slea.readInt();
MapleMapObject target = c.getPlayer().getMap().getMapObject(cid);
if (target != null) {
if (target instanceof MapleCharacter) {
MapleCharacter player = (MapleCharacter) target;
if(c.getPlayer().getId() != player.getId()) {
player.exportExcludedItems(c);
}
c.announce(MaplePacketCreator.charInfo(player));
}
}
}
}

View File

@@ -0,0 +1,45 @@
/*
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 as
published by the Free Software Foundation 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.server.channel.handlers;
import client.MapleClient;
import client.MapleJob;
import net.AbstractMaplePacketHandler;
import scripting.npc.NPCScriptManager;
import tools.data.input.SeekableLittleEndianAccessor;
/**
*
* @author kevintjuh93
*/
public class ClickGuideHandler extends AbstractMaplePacketHandler {
@Override
public void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
if (c.getPlayer().getJob().equals(MapleJob.NOBLESSE)) {
NPCScriptManager.getInstance().start(c, 1101008, null);
} else {
NPCScriptManager.getInstance().start(c, 1202000, null);
}
}
}

View File

@@ -0,0 +1,40 @@
/*
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 as
published by the Free Software Foundation 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.server.channel.handlers;
import client.MapleClient;
import net.AbstractMaplePacketHandler;
import tools.MaplePacketCreator;
import tools.data.input.SeekableLittleEndianAccessor;
/**
*
* @author Xterminator
*/
public final class CloseChalkboardHandler extends AbstractMaplePacketHandler {
@Override
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
c.getPlayer().setChalkboard(null);
c.getPlayer().getMap().broadcastMessage(MaplePacketCreator.useChalkboard(c.getPlayer(), true));
}
}

View File

@@ -0,0 +1,184 @@
/*
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 as
published by the Free Software Foundation 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.server.channel.handlers;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import config.YamlConfig;
import client.MapleBuffStat;
import client.MapleCharacter;
import client.MapleClient;
import client.MapleJob;
import client.Skill;
import client.SkillFactory;
import constants.game.GameConstants;
import constants.skills.Crusader;
import constants.skills.DawnWarrior;
import constants.skills.DragonKnight;
import constants.skills.Hero;
import constants.skills.NightWalker;
import constants.skills.Rogue;
import constants.skills.WindArcher;
import server.MapleStatEffect;
import tools.MaplePacketCreator;
import tools.Pair;
import tools.data.input.SeekableLittleEndianAccessor;
public final class CloseRangeDamageHandler extends AbstractDealDamageHandler {
@Override
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
MapleCharacter chr = c.getPlayer();
/*long timeElapsed = currentServerTime() - chr.getAutobanManager().getLastSpam(8);
if(timeElapsed < 300) {
AutobanFactory.FAST_ATTACK.alert(chr, "Time: " + timeElapsed);
}
chr.getAutobanManager().spam(8);*/
AttackInfo attack = parseDamage(slea, chr, false, false);
if (chr.getBuffEffect(MapleBuffStat.MORPH) != null) {
if(chr.getBuffEffect(MapleBuffStat.MORPH).isMorphWithoutAttack()) {
// How are they attacking when the client won't let them?
chr.getClient().disconnect(false, false);
return;
}
}
if (chr.getDojoEnergy() < 10000 && (attack.skill == 1009 || attack.skill == 10001009 || attack.skill == 20001009)) // PE hacking or maybe just lagging
return;
if (GameConstants.isDojo(chr.getMap().getId()) && attack.numAttacked > 0) {
chr.setDojoEnergy(chr.getDojoEnergy() + YamlConfig.config.server.DOJO_ENERGY_ATK);
c.announce(MaplePacketCreator.getEnergy("energy", chr.getDojoEnergy()));
}
chr.getMap().broadcastMessage(chr, MaplePacketCreator.closeRangeAttack(chr, attack.skill, attack.skilllevel, attack.stance, attack.numAttackedAndDamage, attack.allDamage, attack.speed, attack.direction, attack.display), false, true);
int numFinisherOrbs = 0;
Integer comboBuff = chr.getBuffedValue(MapleBuffStat.COMBO);
if (GameConstants.isFinisherSkill(attack.skill)) {
if (comboBuff != null) {
numFinisherOrbs = comboBuff.intValue() - 1;
}
chr.handleOrbconsume();
} else if (attack.numAttacked > 0) {
if (attack.skill != 1111008 && comboBuff != null) {
int orbcount = chr.getBuffedValue(MapleBuffStat.COMBO);
int oid = chr.isCygnus() ? DawnWarrior.COMBO : Crusader.COMBO;
int advcomboid = chr.isCygnus() ? DawnWarrior.ADVANCED_COMBO : Hero.ADVANCED_COMBO;
Skill combo = SkillFactory.getSkill(oid);
Skill advcombo = SkillFactory.getSkill(advcomboid);
MapleStatEffect ceffect;
int advComboSkillLevel = chr.getSkillLevel(advcombo);
if (advComboSkillLevel > 0) {
ceffect = advcombo.getEffect(advComboSkillLevel);
} else {
int comboLv = chr.getSkillLevel(combo);
if(comboLv <= 0 || chr.isGM()) comboLv = SkillFactory.getSkill(oid).getMaxLevel();
if(comboLv > 0) ceffect = combo.getEffect(comboLv);
else ceffect = null;
}
if(ceffect != null) {
if (orbcount < ceffect.getX() + 1) {
int neworbcount = orbcount + 1;
if (advComboSkillLevel > 0 && ceffect.makeChanceResult()) {
if (neworbcount <= ceffect.getX()) {
neworbcount++;
}
}
int olv = chr.getSkillLevel(oid);
if(olv <= 0) olv = SkillFactory.getSkill(oid).getMaxLevel();
int duration = combo.getEffect(olv).getDuration();
List<Pair<MapleBuffStat, Integer>> stat = Collections.singletonList(new Pair<>(MapleBuffStat.COMBO, neworbcount));
chr.setBuffedValue(MapleBuffStat.COMBO, neworbcount);
duration -= (int) (currentServerTime() - chr.getBuffedStarttime(MapleBuffStat.COMBO));
c.announce(MaplePacketCreator.giveBuff(oid, duration, stat));
chr.getMap().broadcastMessage(chr, MaplePacketCreator.giveForeignBuff(chr.getId(), stat), false);
}
}
} else if (chr.getSkillLevel(chr.isCygnus() ? SkillFactory.getSkill(15100004) : SkillFactory.getSkill(5110001)) > 0 && (chr.getJob().isA(MapleJob.MARAUDER) || chr.getJob().isA(MapleJob.THUNDERBREAKER2))) {
for (int i = 0; i < attack.numAttacked; i++) {
chr.handleEnergyChargeGain();
}
}
}
if (attack.numAttacked > 0 && attack.skill == DragonKnight.SACRIFICE) {
int totDamageToOneMonster = 0; // sacrifice attacks only 1 mob with 1 attack
final Iterator<List<Integer>> dmgIt = attack.allDamage.values().iterator();
if (dmgIt.hasNext()) {
totDamageToOneMonster = dmgIt.next().get(0).intValue();
}
chr.safeAddHP(-1 * totDamageToOneMonster * attack.getAttackEffect(chr, null).getX() / 100);
}
if (attack.numAttacked > 0 && attack.skill == 1211002) {
boolean advcharge_prob = false;
int advcharge_level = chr.getSkillLevel(SkillFactory.getSkill(1220010));
if (advcharge_level > 0) {
advcharge_prob = SkillFactory.getSkill(1220010).getEffect(advcharge_level).makeChanceResult();
}
if (!advcharge_prob) {
chr.cancelEffectFromBuffStat(MapleBuffStat.WK_CHARGE);
}
}
int attackCount = 1;
if (attack.skill != 0) {
attackCount = attack.getAttackEffect(chr, null).getAttackCount();
}
if (numFinisherOrbs == 0 && GameConstants.isFinisherSkill(attack.skill)) {
return;
}
if (attack.skill % 10000000 == 1009) { // bamboo
if (chr.getDojoEnergy() < 10000) { // PE hacking or maybe just lagging
return;
}
chr.setDojoEnergy(0);
c.announce(MaplePacketCreator.getEnergy("energy", chr.getDojoEnergy()));
c.announce(MaplePacketCreator.serverNotice(5, "As you used the secret skill, your energy bar has been reset."));
} else if (attack.skill > 0) {
Skill skill = SkillFactory.getSkill(attack.skill);
MapleStatEffect effect_ = skill.getEffect(chr.getSkillLevel(skill));
if (effect_.getCooldown() > 0) {
if (chr.skillIsCooling(attack.skill)) {
return;
} else {
c.announce(MaplePacketCreator.skillCooldown(attack.skill, effect_.getCooldown()));
chr.addCooldown(attack.skill, currentServerTime(), effect_.getCooldown() * 1000);
}
}
}
if ((chr.getSkillLevel(SkillFactory.getSkill(NightWalker.VANISH)) > 0 || chr.getSkillLevel(SkillFactory.getSkill(Rogue.DARK_SIGHT)) > 0) && chr.getBuffedValue(MapleBuffStat.DARKSIGHT) != null) {// && chr.getBuffSource(MapleBuffStat.DARKSIGHT) != 9101004
chr.cancelEffectFromBuffStat(MapleBuffStat.DARKSIGHT);
chr.cancelBuffStats(MapleBuffStat.DARKSIGHT);
} else if(chr.getSkillLevel(SkillFactory.getSkill(WindArcher.WIND_WALK)) > 0 && chr.getBuffedValue(MapleBuffStat.WIND_WALK) != null) {
chr.cancelEffectFromBuffStat(MapleBuffStat.WIND_WALK);
chr.cancelBuffStats(MapleBuffStat.WIND_WALK);
}
applyAttack(attack, chr, attackCount);
}
}

View File

@@ -0,0 +1,85 @@
/*
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 as
published by the Free Software Foundation 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.server.channel.handlers;
import client.MapleClient;
import net.AbstractMaplePacketHandler;
import server.events.gm.MapleCoconut;
import server.events.gm.MapleCoconuts;
import server.maps.MapleMap;
import tools.MaplePacketCreator;
import tools.data.input.SeekableLittleEndianAccessor;
/**
*
* @author kevintjuh93
*/
public final class CoconutHandler extends AbstractMaplePacketHandler {
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
/*CB 00 A6 00 06 01
* A6 00 = coconut id
* 06 01 = ?
*/
int id = slea.readShort();
MapleMap map = c.getPlayer().getMap();
MapleCoconut event = map.getCoconut();
MapleCoconuts nut = event.getCoconut(id);
if (!nut.isHittable()){
return;
}
if (event == null){
return;
}
if (currentServerTime() < nut.getHitTime()){
return;
}
if (nut.getHits() > 2 && Math.random() < 0.4) {
if (Math.random() < 0.01 && event.getStopped() > 0) {
nut.setHittable(false);
event.stopCoconut();
map.broadcastMessage(MaplePacketCreator.hitCoconut(false, id, 1));
return;
}
nut.setHittable(false); // for sure :)
nut.resetHits(); // For next event (without restarts)
if (Math.random() < 0.05 && event.getBombings() > 0) {
map.broadcastMessage(MaplePacketCreator.hitCoconut(false, id, 2));
event.bombCoconut();
} else if (event.getFalling() > 0) {
map.broadcastMessage(MaplePacketCreator.hitCoconut(false, id, 3));
event.fallCoconut();
if (c.getPlayer().getTeam() == 0) {
event.addMapleScore();
map.broadcastMessage(MaplePacketCreator.serverNotice(5, c.getPlayer().getName() + " of Team Maple knocks down a coconut."));
} else {
event.addStoryScore();
map.broadcastMessage(MaplePacketCreator.serverNotice(5, c.getPlayer().getName() + " of Team Story knocks down a coconut."));
}
map.broadcastMessage(MaplePacketCreator.coconutScore(event.getMapleScore(), event.getStoryScore()));
}
} else {
nut.hit();
map.broadcastMessage(MaplePacketCreator.hitCoconut(false, id, 1));
}
}
}

View File

@@ -0,0 +1,279 @@
/*
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>
Copyleft (L) 2016 - 2019 RonanLana (HeavenMS)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation 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.server.channel.handlers;
import client.MapleClient;
import client.MapleCharacter;
import client.inventory.Item;
import client.inventory.manipulator.MapleInventoryManipulator;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import net.AbstractMaplePacketHandler;
import net.server.Server;
import server.CashShop;
import server.MapleItemInformationProvider;
import tools.DatabaseConnection;
import tools.FilePrinter;
import tools.MaplePacketCreator;
import tools.Pair;
import tools.data.input.SeekableLittleEndianAccessor;
/**
*
* @author Penguins (Acrylic)
* @author Ronan (HeavenMS)
*/
public final class CouponCodeHandler extends AbstractMaplePacketHandler {
private static List<Pair<Integer, Pair<Integer, Integer>>> getNXCodeItems(MapleCharacter chr, Connection con, int codeid) throws SQLException {
Map<Integer, Integer> couponItems = new HashMap<>();
Map<Integer, Integer> couponPoints = new HashMap<>(5);
PreparedStatement ps = con.prepareStatement("SELECT * FROM nxcode_items WHERE codeid = ?");
ps.setInt(1, codeid);
ResultSet rs = ps.executeQuery();
while (rs.next()) {
int type = rs.getInt("type"), quantity = rs.getInt("quantity");
if (type < 5) {
Integer i = couponPoints.get(type);
if (i != null) {
couponPoints.put(type, i + quantity);
} else {
couponPoints.put(type, quantity);
}
} else {
int item = rs.getInt("item");
Integer i = couponItems.get(item);
if (i != null) {
couponItems.put(item, i + quantity);
} else {
couponItems.put(item, quantity);
}
}
}
rs.close();
ps.close();
List<Pair<Integer, Pair<Integer, Integer>>> ret = new LinkedList<>();
if (!couponItems.isEmpty()) {
for (Entry<Integer, Integer> e : couponItems.entrySet()) {
int item = e.getKey(), qty = e.getValue();
if (MapleItemInformationProvider.getInstance().getName(item) == null) {
item = 4000000;
qty = 1;
FilePrinter.printError(FilePrinter.UNHANDLED_EVENT, "Error trying to redeem itemid " + item + " from codeid " + codeid + ".");
}
if (!chr.canHold(item, qty)) {
return null;
}
ret.add(new Pair<>(5, new Pair<>(item, qty)));
}
}
if (!couponPoints.isEmpty()) {
for (Entry<Integer, Integer> e : couponPoints.entrySet()) {
ret.add(new Pair<>(e.getKey(), new Pair<>(777, e.getValue())));
}
}
return ret;
}
private static Pair<Integer, List<Pair<Integer, Pair<Integer, Integer>>>> getNXCodeResult(MapleCharacter chr, String code) {
MapleClient c = chr.getClient();
List<Pair<Integer, Pair<Integer, Integer>>> ret = new LinkedList<>();
try {
if (!c.attemptCsCoupon()) {
return new Pair<>(-5, null);
}
Connection con = DatabaseConnection.getConnection();
PreparedStatement ps = con.prepareStatement("SELECT * FROM nxcode WHERE code = ?");
ps.setString(1, code);
ResultSet rs = ps.executeQuery();
if (!rs.next()) {
return new Pair<>(-1, null);
}
if (rs.getString("retriever") != null) {
return new Pair<>(-2, null);
}
if (rs.getLong("expiration") < Server.getInstance().getCurrentTime()) {
return new Pair<>(-3, null);
}
int codeid = rs.getInt("id");
rs.close();
ps.close();
ret = getNXCodeItems(chr, con, codeid);
if (ret == null) {
return new Pair<>(-4, null);
}
ps = con.prepareStatement("UPDATE nxcode SET retriever = ? WHERE code = ?");
ps.setString(1, chr.getName());
ps.setString(2, code);
ps.executeUpdate();
ps.close();
con.close();
} catch (SQLException ex) {
ex.printStackTrace();
}
c.resetCsCoupon();
return new Pair<>(0, ret);
}
private static int parseCouponResult(int res) {
switch (res) {
case -1:
return 0xB0;
case -2:
return 0xB3;
case -3:
return 0xB2;
case -4:
return 0xBB;
default:
return 0xB1;
}
}
@Override
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
slea.skip(2);
String code = slea.readMapleAsciiString();
if (c.tryacquireClient()) {
try {
Pair<Integer, List<Pair<Integer, Pair<Integer, Integer>>>> codeRes = getNXCodeResult(c.getPlayer(), code.toUpperCase());
int type = codeRes.getLeft();
if (type < 0) {
c.announce(MaplePacketCreator.showCashShopMessage((byte) parseCouponResult(type)));
} else {
List<Item> cashItems = new LinkedList<Item>();
List<Pair<Integer, Integer>> items = new LinkedList<Pair<Integer, Integer>>();
int nxCredit = 0;
int maplePoints = 0;
int nxPrepaid = 0;
int mesos = 0;
for (Pair<Integer, Pair<Integer, Integer>> p : codeRes.getRight()) {
type = p.getLeft();
int quantity = p.getRight().getRight();
CashShop cs = c.getPlayer().getCashShop();
switch (type) {
case 0:
c.getPlayer().gainMeso(quantity, false); //mesos
mesos += quantity;
break;
case 4:
cs.gainCash(1, quantity); //nxCredit
nxCredit += quantity;
break;
case 1:
cs.gainCash(2, quantity); //maplePoint
maplePoints += quantity;
break;
case 2:
cs.gainCash(4, quantity); //nxPrepaid
nxPrepaid += quantity;
break;
case 3:
cs.gainCash(1, quantity);
nxCredit += quantity;
cs.gainCash(4, (quantity / 5000));
nxPrepaid += quantity / 5000;
break;
default:
int item = p.getRight().getLeft();
short qty;
if (quantity > Short.MAX_VALUE) {
qty = Short.MAX_VALUE;
} else if (quantity < Short.MIN_VALUE) {
qty = Short.MIN_VALUE;
} else {
qty = (short) quantity;
}
if (MapleItemInformationProvider.getInstance().isCash(item)) {
Item it = CashShop.generateCouponItem(item, qty);
cs.addToInventory(it);
cashItems.add(it);
} else {
MapleInventoryManipulator.addById(c, item, qty, "", -1);
items.add(new Pair<Integer, Integer>((int)qty, item));
}
break;
}
}
if(cashItems.size() > 255) {
List<Item> oldList = cashItems;
cashItems = Arrays.asList(new Item[255]);
int index = 0;
for(Item item : oldList) {
cashItems.set(index, item);
index++;
}
}
if (nxCredit != 0 || nxPrepaid != 0) { //coupon packet can only show maple points (afaik)
c.announce(MaplePacketCreator.showBoughtQuestItem(0));
} else {
c.announce(MaplePacketCreator.showCouponRedeemedItems(c.getAccID(), maplePoints, mesos, cashItems, items));
}
c.enableCSActions();
}
} finally {
c.releaseClient();
}
}
}
}

View File

@@ -0,0 +1,54 @@
/*
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 as
published by the Free Software Foundation 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.server.channel.handlers;
import client.MapleBuffStat;
import client.MapleCharacter;
import client.MapleClient;
import net.AbstractMaplePacketHandler;
import server.maps.MapleSummon;
import server.maps.MapleMapObject;
import tools.MaplePacketCreator;
import tools.data.input.SeekableLittleEndianAccessor;
public final class DamageSummonHandler extends AbstractMaplePacketHandler {
@Override
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
int oid = slea.readInt();
slea.skip(1); // -1
int damage = slea.readInt();
int monsterIdFrom = slea.readInt();
MapleCharacter player = c.getPlayer();
MapleMapObject mmo = player.getMap().getMapObject(oid);
if(mmo != null && mmo instanceof MapleSummon) {
MapleSummon summon = (MapleSummon) mmo;
summon.addHP(-damage);
if (summon.getHP() <= 0) {
player.cancelEffectFromBuffStat(MapleBuffStat.PUPPET);
}
player.getMap().broadcastMessage(player, MaplePacketCreator.damageSummon(player.getId(), oid, damage, monsterIdFrom), summon.getPosition());
}
}
}

View File

@@ -0,0 +1,47 @@
/*
This file is part of the HeavenMS MapleStory Server
Copyleft (L) 2016 - 2019 RonanLana
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation 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.server.channel.handlers;
import client.MapleClient;
import client.MapleCharacter;
import net.AbstractMaplePacketHandler;
import net.server.guild.MapleAlliance;
import tools.data.input.SeekableLittleEndianAccessor;
/**
* @author Ronan
*/
public final class DenyAllianceRequestHandler extends AbstractMaplePacketHandler {
@Override
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
slea.readByte();
String inviterName = slea.readMapleAsciiString();
String guildName = slea.readMapleAsciiString();
MapleCharacter chr = c.getWorldServer().getPlayerStorage().getCharacterByName(inviterName);
if (chr != null) {
MapleAlliance alliance = chr.getAlliance();
if (alliance != null) {
MapleAlliance.answerInvitation(c.getPlayer().getId(), guildName, alliance.getId(), false);
}
}
}
}

View File

@@ -0,0 +1,44 @@
/*
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 as
published by the Free Software Foundation 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.server.channel.handlers;
import client.MapleCharacter;
import client.MapleClient;
import net.AbstractMaplePacketHandler;
import net.server.guild.MapleGuild;
import tools.data.input.SeekableLittleEndianAccessor;
/**
*
* @author Xterminator
*/
public final class DenyGuildRequestHandler extends AbstractMaplePacketHandler {
@Override
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
slea.readByte();
MapleCharacter cfrom = c.getWorldServer().getPlayerStorage().getCharacterByName(slea.readMapleAsciiString());
if (cfrom != null) {
MapleGuild.answerInvitation(c.getPlayer().getId(), c.getPlayer().getName(), cfrom.getGuildId(), false);
}
}
}

View File

@@ -0,0 +1,50 @@
/*
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 as
published by the Free Software Foundation 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.server.channel.handlers;
import client.MapleCharacter;
import client.MapleClient;
import net.AbstractMaplePacketHandler;
import net.server.coordinator.world.MapleInviteCoordinator;
import net.server.coordinator.world.MapleInviteCoordinator.InviteResult;
import net.server.coordinator.world.MapleInviteCoordinator.InviteType;
import tools.MaplePacketCreator;
import tools.data.input.SeekableLittleEndianAccessor;
public final class DenyPartyRequestHandler extends AbstractMaplePacketHandler {
@Override
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
slea.readByte();
String[] cname = slea.readMapleAsciiString().split("PS: ");
MapleCharacter cfrom = c.getChannelServer().getPlayerStorage().getCharacterByName(cname[cname.length - 1]);
if (cfrom != null) {
MapleCharacter chr = c.getPlayer();
if (MapleInviteCoordinator.answerInvite(InviteType.PARTY, chr.getId(), cfrom.getPartyId(), false).result == InviteResult.DENIED) {
chr.updatePartySearchAvailability(chr.getParty() == null);
cfrom.getClient().announce(MaplePacketCreator.partyStatusMessage(23, chr.getName()));
}
}
}
}

View File

@@ -0,0 +1,38 @@
/*
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 as
published by the Free Software Foundation 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.server.channel.handlers;
import client.MapleClient;
import client.processor.stat.AssignAPProcessor;
import net.AbstractMaplePacketHandler;
import tools.data.input.SeekableLittleEndianAccessor;
public final class DistributeAPHandler extends AbstractMaplePacketHandler {
@Override
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
slea.readInt();
int num = slea.readInt();
AssignAPProcessor.APAssignAction(c, num);
}
}

View File

@@ -0,0 +1,37 @@
/*
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 as
published by the Free Software Foundation 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.server.channel.handlers;
import client.MapleClient;
import client.processor.stat.AssignSPProcessor;
import net.AbstractMaplePacketHandler;
import tools.data.input.SeekableLittleEndianAccessor;
public final class DistributeSPHandler extends AbstractMaplePacketHandler {
@Override
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
slea.readInt();
int skillid = slea.readInt();
AssignSPProcessor.SPAssignAction(c, skillid);
}
}

View File

@@ -0,0 +1,61 @@
/*
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 as
published by the Free Software Foundation 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.server.channel.handlers;
import client.MapleCharacter;
import client.MapleClient;
import net.AbstractMaplePacketHandler;
import server.maps.MapleDoorObject;
import server.maps.MapleMapObject;
import tools.MaplePacketCreator;
import tools.data.input.SeekableLittleEndianAccessor;
/**
*
* @author Matze
*/
public final class DoorHandler extends AbstractMaplePacketHandler {
@Override
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
int ownerid = slea.readInt();
slea.readByte(); // specifies if backwarp or not, 1 town to target, 0 target to town
MapleCharacter chr = c.getPlayer();
if (chr.isChangingMaps() || chr.isBanned()) {
c.announce(MaplePacketCreator.enableActions());
return;
}
for (MapleMapObject obj : chr.getMap().getMapObjects()) {
if (obj instanceof MapleDoorObject) {
MapleDoorObject door = (MapleDoorObject) obj;
if (door.getOwnerId() == ownerid) {
door.warp(chr);
return;
}
}
}
c.announce(MaplePacketCreator.blockedMessage(6));
c.announce(MaplePacketCreator.enableActions());
}
}

View File

@@ -0,0 +1,66 @@
/*
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 as
published by the Free Software Foundation 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.server.channel.handlers;
import client.MapleClient;
import client.processor.npc.DueyProcessor;
import config.YamlConfig;
import net.AbstractMaplePacketHandler;
import tools.MaplePacketCreator;
import tools.data.input.SeekableLittleEndianAccessor;
public final class DueyHandler extends AbstractMaplePacketHandler {
@Override
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
if (!YamlConfig.config.server.USE_DUEY){
c.announce(MaplePacketCreator.enableActions());
return;
}
byte operation = slea.readByte();
if (operation == DueyProcessor.Actions.TOSERVER_RECV_ITEM.getCode()) { // on click 'O' Button, thanks inhyuk
DueyProcessor.dueySendTalk(c, false);
} else if (operation == DueyProcessor.Actions.TOSERVER_SEND_ITEM.getCode()) {
byte inventId = slea.readByte();
short itemPos = slea.readShort();
short amount = slea.readShort();
int mesos = slea.readInt();
String recipient = slea.readMapleAsciiString();
boolean quick = slea.readByte() != 0;
String message = quick ? slea.readMapleAsciiString() : null;
DueyProcessor.dueySendItem(c, inventId, itemPos, amount, mesos, message, recipient, quick);
} else if (operation == DueyProcessor.Actions.TOSERVER_REMOVE_PACKAGE.getCode()) {
int packageid = slea.readInt();
DueyProcessor.dueyRemovePackage(c, packageid, true);
} else if (operation == DueyProcessor.Actions.TOSERVER_CLAIM_PACKAGE.getCode()) {
int packageid = slea.readInt();
DueyProcessor.dueyClaimPackage(c, packageid);
} else if (operation == DueyProcessor.Actions.TOSERVER_CLAIM_PACKAGE.getCode()) {
DueyProcessor.dueySendTalk(c, false);
}
}
}

View File

@@ -0,0 +1,96 @@
/*
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.server.channel.handlers;
import client.MapleCharacter;
import client.MapleClient;
import net.AbstractMaplePacketHandler;
import net.server.Server;
import server.maps.MapleMiniDungeonInfo;
import tools.MaplePacketCreator;
import tools.data.input.SeekableLittleEndianAccessor;
/**
*
* @author Flav
*/
public class EnterCashShopHandler extends AbstractMaplePacketHandler {
@Override
public void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
try {
MapleCharacter mc = c.getPlayer();
if (mc.cannotEnterCashShop()) {
c.announce(MaplePacketCreator.enableActions());
return;
}
if(mc.getEventInstance() != null) {
c.announce(MaplePacketCreator.serverNotice(5, "Entering Cash Shop or MTS are disabled when registered on an event."));
c.announce(MaplePacketCreator.enableActions());
return;
}
if(MapleMiniDungeonInfo.isDungeonMap(mc.getMapId())) {
c.announce(MaplePacketCreator.serverNotice(5, "Changing channels or entering Cash Shop or MTS are disabled when inside a Mini-Dungeon."));
c.announce(MaplePacketCreator.enableActions());
return;
}
if (mc.getCashShop().isOpened()) {
return;
}
mc.closePlayerInteractions();
mc.closePartySearchInteractions();
mc.unregisterChairBuff();
Server.getInstance().getPlayerBuffStorage().addBuffsToStorage(mc.getId(), mc.getAllBuffs());
Server.getInstance().getPlayerBuffStorage().addDiseasesToStorage(mc.getId(), mc.getAllDiseases());
mc.setAwayFromChannelWorld();
mc.notifyMapTransferToPartner(-1);
mc.removeIncomingInvites();
mc.cancelAllBuffs(true);
mc.cancelAllDebuffs();
mc.cancelBuffExpireTask();
mc.cancelDiseaseExpireTask();
mc.cancelSkillCooldownTask();
mc.cancelExpirationTask();
mc.forfeitExpirableQuests();
mc.cancelQuestExpirationTask();
c.announce(MaplePacketCreator.openCashShop(c, false));
c.announce(MaplePacketCreator.showCashInventory(c));
c.announce(MaplePacketCreator.showGifts(mc.getCashShop().loadGifts()));
c.announce(MaplePacketCreator.showWishList(mc, false));
c.announce(MaplePacketCreator.showCash(mc));
c.getChannelServer().removePlayer(mc);
mc.getMap().removePlayer(mc);
mc.getCashShop().open(true);
mc.saveCharToDB();
} catch (Exception e) {
e.printStackTrace();
}
}
}

View File

@@ -0,0 +1,287 @@
/*
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 as
published by the Free Software Foundation 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.server.channel.handlers;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import config.YamlConfig;
import client.MapleCharacter;
import client.MapleClient;
import client.inventory.Equip;
import client.inventory.Item;
import client.processor.action.BuybackProcessor;
import net.AbstractMaplePacketHandler;
import net.server.Server;
import server.MTSItemInfo;
import server.maps.FieldLimit;
import server.maps.MapleMiniDungeonInfo;
import tools.DatabaseConnection;
import tools.MaplePacketCreator;
import tools.data.input.SeekableLittleEndianAccessor;
public final class EnterMTSHandler extends AbstractMaplePacketHandler {
@Override
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
MapleCharacter chr = c.getPlayer();
if(!chr.isAlive() && YamlConfig.config.server.USE_BUYBACK_SYSTEM) {
BuybackProcessor.processBuyback(c);
c.announce(MaplePacketCreator.enableActions());
} else {
if (!YamlConfig.config.server.USE_MTS) {
c.announce(MaplePacketCreator.enableActions());
return;
}
if(chr.getEventInstance() != null) {
c.announce(MaplePacketCreator.serverNotice(5, "Entering Cash Shop or MTS are disabled when registered on an event."));
c.announce(MaplePacketCreator.enableActions());
return;
}
if(MapleMiniDungeonInfo.isDungeonMap(chr.getMapId())) {
c.announce(MaplePacketCreator.serverNotice(5, "Changing channels or entering Cash Shop or MTS are disabled when inside a Mini-Dungeon."));
c.announce(MaplePacketCreator.enableActions());
return;
}
if (FieldLimit.CANNOTMIGRATE.check(chr.getMap().getFieldLimit())) {
chr.dropMessage(1, "You can't do it here in this map.");
c.announce(MaplePacketCreator.enableActions());
return;
}
if (!chr.isAlive()) {
c.announce(MaplePacketCreator.enableActions());
return;
}
if (chr.getLevel() < 10) {
c.announce(MaplePacketCreator.blockedMessage2(5));
c.announce(MaplePacketCreator.enableActions());
return;
}
chr.closePlayerInteractions();
chr.closePartySearchInteractions();
chr.unregisterChairBuff();
Server.getInstance().getPlayerBuffStorage().addBuffsToStorage(chr.getId(), chr.getAllBuffs());
Server.getInstance().getPlayerBuffStorage().addDiseasesToStorage(chr.getId(), chr.getAllDiseases());
chr.setAwayFromChannelWorld();
chr.notifyMapTransferToPartner(-1);
chr.removeIncomingInvites();
chr.cancelAllBuffs(true);
chr.cancelAllDebuffs();
chr.cancelBuffExpireTask();
chr.cancelDiseaseExpireTask();
chr.cancelSkillCooldownTask();
chr.cancelExpirationTask();
chr.forfeitExpirableQuests();
chr.cancelQuestExpirationTask();
chr.saveCharToDB();
c.getChannelServer().removePlayer(chr);
chr.getMap().removePlayer(c.getPlayer());
try {
c.announce(MaplePacketCreator.openCashShop(c, true));
} catch (Exception ex) {
ex.printStackTrace();
}
chr.getCashShop().open(true);// xD
c.enableCSActions();
c.announce(MaplePacketCreator.MTSWantedListingOver(0, 0));
c.announce(MaplePacketCreator.showMTSCash(c.getPlayer()));
List<MTSItemInfo> items = new ArrayList<>();
int pages = 0;
try {
Connection con = DatabaseConnection.getConnection();
PreparedStatement ps = con.prepareStatement("SELECT * FROM mts_items WHERE tab = 1 AND transfer = 0 ORDER BY id DESC LIMIT 16, 16");
ResultSet rs = ps.executeQuery();
while (rs.next()) {
if (rs.getInt("type") != 1) {
Item i = new Item(rs.getInt("itemid"), (short) 0, (short) rs.getInt("quantity"));
i.setOwner(rs.getString("owner"));
items.add(new MTSItemInfo(i, rs.getInt("price") + 100 + (int) (rs.getInt("price") * 0.1), rs.getInt("id"), rs.getInt("seller"), rs.getString("sellername"), rs.getString("sell_ends")));
} else {
Equip equip = new Equip(rs.getInt("itemid"), (byte) rs.getInt("position"), -1);
equip.setOwner(rs.getString("owner"));
equip.setQuantity((short) 1);
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.setVicious((short) rs.getInt("vicious"));
equip.setFlag((short) rs.getInt("flag"));
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"));
equip.setItemLevel(rs.getByte("itemlevel"));
equip.setItemExp(rs.getInt("itemexp"));
equip.setRingId(rs.getInt("ringid"));
equip.setExpiration(rs.getLong("expiration"));
equip.setGiftFrom(rs.getString("giftFrom"));
items.add(new MTSItemInfo((Item) equip, rs.getInt("price") + 100 + (int) (rs.getInt("price") * 0.1), rs.getInt("id"), rs.getInt("seller"), rs.getString("sellername"), rs.getString("sell_ends")));
}
}
rs.close();
ps.close();
ps = con.prepareStatement("SELECT COUNT(*) FROM mts_items");
rs = ps.executeQuery();
if (rs.next()) {
pages = (int) Math.ceil(rs.getInt(1) / 16);
}
rs.close();
ps.close();
con.close();
} catch (SQLException e) {
e.printStackTrace();
}
c.announce(MaplePacketCreator.sendMTS(items, 1, 0, 0, pages));
c.announce(MaplePacketCreator.transferInventory(getTransfer(chr.getId())));
c.announce(MaplePacketCreator.notYetSoldInv(getNotYetSold(chr.getId())));
}
}
private List<MTSItemInfo> getNotYetSold(int cid) {
List<MTSItemInfo> items = new ArrayList<>();
try {
Connection con = DatabaseConnection.getConnection();
try (PreparedStatement ps = con.prepareStatement("SELECT * FROM mts_items WHERE seller = ? AND transfer = 0 ORDER BY id DESC")) {
ps.setInt(1, cid);
try (ResultSet rs = ps.executeQuery()) {
while (rs.next()) {
if (rs.getInt("type") != 1) {
Item i = new Item(rs.getInt("itemid"), (short) 0, (short) rs.getInt("quantity"));
i.setOwner(rs.getString("owner"));
items.add(new MTSItemInfo((Item) i, rs.getInt("price"), rs.getInt("id"), rs.getInt("seller"), rs.getString("sellername"), rs.getString("sell_ends")));
} else {
Equip equip = new Equip(rs.getInt("itemid"), (byte) rs.getInt("position"), -1);
equip.setOwner(rs.getString("owner"));
equip.setQuantity((short) 1);
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.setVicious((short) rs.getInt("vicious"));
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"));
equip.setItemLevel(rs.getByte("itemlevel"));
equip.setItemExp(rs.getInt("itemexp"));
equip.setRingId(rs.getInt("ringid"));
equip.setFlag((short) rs.getInt("flag"));
equip.setExpiration(rs.getLong("expiration"));
equip.setGiftFrom(rs.getString("giftFrom"));
items.add(new MTSItemInfo((Item) equip, rs.getInt("price"), rs.getInt("id"), rs.getInt("seller"), rs.getString("sellername"), rs.getString("sell_ends")));
}
}
}
}
con.close();
} catch (SQLException e) {
e.printStackTrace();
}
return items;
}
private List<MTSItemInfo> getTransfer(int cid) {
List<MTSItemInfo> items = new ArrayList<>();
try {
Connection con = DatabaseConnection.getConnection();
try (PreparedStatement ps = con.prepareStatement("SELECT * FROM mts_items WHERE transfer = 1 AND seller = ? ORDER BY id DESC")) {
ps.setInt(1, cid);
try (ResultSet rs = ps.executeQuery()) {
while (rs.next()) {
if (rs.getInt("type") != 1) {
Item i = new Item(rs.getInt("itemid"), (short) 0, (short) rs.getInt("quantity"));
i.setOwner(rs.getString("owner"));
items.add(new MTSItemInfo((Item) i, rs.getInt("price"), rs.getInt("id"), rs.getInt("seller"), rs.getString("sellername"), rs.getString("sell_ends")));
} else {
Equip equip = new Equip(rs.getInt("itemid"), (byte) rs.getInt("position"), -1);
equip.setOwner(rs.getString("owner"));
equip.setQuantity((short) 1);
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.setVicious((short) rs.getInt("vicious"));
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"));
equip.setItemLevel(rs.getByte("itemlevel"));
equip.setItemExp(rs.getInt("itemexp"));
equip.setRingId(rs.getInt("ringid"));
equip.setFlag((short) rs.getInt("flag"));
equip.setExpiration(rs.getLong("expiration"));
equip.setGiftFrom(rs.getString("giftFrom"));
items.add(new MTSItemInfo((Item) equip, rs.getInt("price"), rs.getInt("id"), rs.getInt("seller"), rs.getString("sellername"), rs.getString("sell_ends")));
}
}
}
}
con.close();
} catch (SQLException e) {
e.printStackTrace();
}
return items;
}
}

View File

@@ -0,0 +1,55 @@
/*
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 as
published by the Free Software Foundation 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.server.channel.handlers;
import client.MapleClient;
import client.MapleCharacter;
import constants.inventory.ItemConstants;
import net.AbstractMaplePacketHandler;
import tools.data.input.SeekableLittleEndianAccessor;
public final class FaceExpressionHandler extends AbstractMaplePacketHandler {
@Override
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
MapleCharacter chr = c.getPlayer();
int emote = slea.readInt();
if (emote > 7) {
int itemid = 5159992 + emote; // thanks RajanGrewal (Darter) for reporting unchecked emote itemid
if (!ItemConstants.isFaceExpression(itemid) || chr.getInventory(ItemConstants.getInventoryType(itemid)).findById(itemid) == null) {
return;
}
} else if (emote < 1) {
return;
}
if(c.tryacquireClient()) {
try { // expecting players never intends to wear the emote 0 (default face, that changes back after 5sec timeout)
if (chr.isLoggedinWorld()) {
chr.changeFaceExpression(emote);
}
} finally {
c.releaseClient();
}
}
}
}

View File

@@ -0,0 +1,70 @@
/*
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 as
published by the Free Software Foundation 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.server.channel.handlers;
import config.YamlConfig;
import client.MapleCharacter;
import client.MapleClient;
import net.AbstractMaplePacketHandler;
import net.server.coordinator.world.MapleInviteCoordinator;
import net.server.coordinator.world.MapleInviteCoordinator.InviteType;
import tools.MaplePacketCreator;
import tools.data.input.SeekableLittleEndianAccessor;
/**
*
* @author Jay Estrella
* @author Ubaware
*/
public final class FamilyAddHandler extends AbstractMaplePacketHandler {
@Override
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
if(!YamlConfig.config.server.USE_FAMILY_SYSTEM) {
return;
}
String toAdd = slea.readMapleAsciiString();
MapleCharacter addChr = c.getChannelServer().getPlayerStorage().getCharacterByName(toAdd);
MapleCharacter chr = c.getPlayer();
if(addChr == null) {
c.announce(MaplePacketCreator.sendFamilyMessage(65, 0));
} else if(addChr == chr) { //only possible through packet editing/client editing i think?
c.announce(MaplePacketCreator.enableActions());
} else if(addChr.getMap() != chr.getMap() || (addChr.isHidden()) && chr.gmLevel() < addChr.gmLevel()) {
c.announce(MaplePacketCreator.sendFamilyMessage(69, 0));
} else if(addChr.getLevel() <= 10) {
c.announce(MaplePacketCreator.sendFamilyMessage(77, 0));
} else if(Math.abs(addChr.getLevel() - chr.getLevel()) > 20) {
c.announce(MaplePacketCreator.sendFamilyMessage(72, 0));
} else if(addChr.getFamily() != null && addChr.getFamily() == chr.getFamily()) { //same family
c.announce(MaplePacketCreator.enableActions());
} else if(MapleInviteCoordinator.hasInvite(InviteType.FAMILY, addChr.getId())) {
c.announce(MaplePacketCreator.sendFamilyMessage(73, 0));
} else if(chr.getFamily() != null && addChr.getFamily() != null && addChr.getFamily().getTotalGenerations() + chr.getFamily().getTotalGenerations() > YamlConfig.config.server.FAMILY_MAX_GENERATIONS) {
c.announce(MaplePacketCreator.sendFamilyMessage(76, 0));
} else {
MapleInviteCoordinator.createInvite(InviteType.FAMILY, chr, addChr, addChr.getId());
addChr.getClient().announce(MaplePacketCreator.sendFamilyInvite(chr.getId(), chr.getName()));
chr.dropMessage("The invite has been sent.");
c.announce(MaplePacketCreator.enableActions());
}
}
}

View File

@@ -0,0 +1,23 @@
package net.server.channel.handlers;
import client.MapleClient;
import client.MapleFamily;
import net.AbstractMaplePacketHandler;
import tools.MaplePacketCreator;
import tools.data.input.SeekableLittleEndianAccessor;
public class FamilyPreceptsHandler extends AbstractMaplePacketHandler {
@Override
public void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
MapleFamily family = c.getPlayer().getFamily();
if(family == null) return;
if(family.getLeader().getChr() != c.getPlayer()) return; //only the leader can set the precepts
String newPrecepts = slea.readMapleAsciiString();
if(newPrecepts.length() > 200) return;
family.setMessage(newPrecepts, true);
//family.broadcastFamilyInfoUpdate(); //probably don't need to broadcast for this?
c.announce(MaplePacketCreator.getFamilyInfo(c.getPlayer().getFamilyEntry()));
}
}

View File

@@ -0,0 +1,78 @@
/*
This file is part of the HeavenMS MapleStory Server
Copyleft (L) 2016 - 2019 RonanLana
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation 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.server.channel.handlers;
import client.MapleClient;
import client.MapleFamily;
import client.MapleFamilyEntry;
import config.YamlConfig;
import net.AbstractMaplePacketHandler;
import tools.MaplePacketCreator;
import tools.data.input.SeekableLittleEndianAccessor;
public class FamilySeparateHandler extends AbstractMaplePacketHandler {
@Override
public void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
if(!YamlConfig.config.server.USE_FAMILY_SYSTEM) return;
MapleFamily oldFamily = c.getPlayer().getFamily();
if(oldFamily == null) return;
MapleFamilyEntry forkOn = null;
boolean isSenior;
if(slea.available() > 0) { //packet 0x95 doesn't send id, since there is only one senior
forkOn = c.getPlayer().getFamily().getEntryByID(slea.readInt());
if(!c.getPlayer().getFamilyEntry().isJunior(forkOn)) return; //packet editing?
isSenior = true;
} else {
forkOn = c.getPlayer().getFamilyEntry();
isSenior = false;
}
if(forkOn == null) return;
MapleFamilyEntry senior = forkOn.getSenior();
if(senior == null) return;
int levelDiff = Math.abs(c.getPlayer().getLevel() - senior.getLevel());
int cost = 2500 * levelDiff;
cost += levelDiff * levelDiff;
if(c.getPlayer().getMeso() < cost) {
c.announce(MaplePacketCreator.sendFamilyMessage(isSenior ? 81 : 80, cost));
return;
}
c.getPlayer().gainMeso(-cost);
int repCost = separateRepCost(forkOn);
senior.gainReputation(-repCost, false);
if(senior.getSenior() != null) senior.getSenior().gainReputation(-(repCost/2), false);
forkOn.announceToSenior(MaplePacketCreator.serverNotice(5, forkOn.getName() + " has left the family."), true);
forkOn.fork();
c.announce(MaplePacketCreator.getFamilyInfo(forkOn)); //pedigree info will be requested from the client if the window is open
forkOn.updateSeniorFamilyInfo(true);
c.announce(MaplePacketCreator.sendFamilyMessage(1, 0));
}
private static int separateRepCost(MapleFamilyEntry junior) {
int level = junior.getLevel();
int ret = level / 20;
ret += 10;
ret *= level;
ret *= 2;
return ret;
}
}

View File

@@ -0,0 +1,40 @@
package net.server.channel.handlers;
import client.MapleCharacter;
import client.MapleClient;
import client.MapleFamilyEntitlement;
import client.MapleFamilyEntry;
import config.YamlConfig;
import net.AbstractMaplePacketHandler;
import net.server.coordinator.world.MapleInviteCoordinator;
import net.server.coordinator.world.MapleInviteCoordinator.InviteResult;
import net.server.coordinator.world.MapleInviteCoordinator.InviteType;
import net.server.coordinator.world.MapleInviteCoordinator.MapleInviteResult;
import server.maps.MapleMap;
import tools.MaplePacketCreator;
import tools.data.input.SeekableLittleEndianAccessor;
public class FamilySummonResponseHandler extends AbstractMaplePacketHandler {
@Override
public void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
if(!YamlConfig.config.server.USE_FAMILY_SYSTEM) return;
slea.readMapleAsciiString(); //family name
boolean accept = slea.readByte() != 0;
MapleInviteResult inviteResult = MapleInviteCoordinator.answerInvite(InviteType.FAMILY_SUMMON, c.getPlayer().getId(), c.getPlayer(), accept);
if(inviteResult.result == InviteResult.NOT_FOUND) return;
MapleCharacter inviter = inviteResult.from;
MapleFamilyEntry inviterEntry = inviter.getFamilyEntry();
if(inviterEntry == null) return;
MapleMap map = (MapleMap) inviteResult.params[0];
if(accept && inviter.getMap() == map) { //cancel if inviter has changed maps
c.getPlayer().changeMap(map, map.getPortal(0));
} else {
inviterEntry.refundEntitlement(MapleFamilyEntitlement.SUMMON_FAMILY);
inviterEntry.gainReputation(MapleFamilyEntitlement.SUMMON_FAMILY.getRepCost(), false); //refund rep cost if declined
inviter.announce(MaplePacketCreator.getFamilyInfo(inviterEntry));
inviter.dropMessage(5, c.getPlayer().getName() + " has denied the summon request.");
}
}
}

View File

@@ -0,0 +1,141 @@
/*
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 as
published by the Free Software Foundation 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.server.channel.handlers;
import client.MapleCharacter;
import client.MapleClient;
import client.MapleFamilyEntitlement;
import client.MapleFamilyEntry;
import config.YamlConfig;
import net.AbstractMaplePacketHandler;
import net.server.coordinator.world.MapleInviteCoordinator;
import net.server.coordinator.world.MapleInviteCoordinator.InviteType;
import server.maps.FieldLimit;
import server.maps.MapleMap;
import tools.MaplePacketCreator;
import tools.data.input.SeekableLittleEndianAccessor;
/**
*
* @author Moogra
* @author Ubaware
*/
public final class FamilyUseHandler extends AbstractMaplePacketHandler {
@Override
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
if(!YamlConfig.config.server.USE_FAMILY_SYSTEM) {
return;
}
MapleFamilyEntitlement type = MapleFamilyEntitlement.values()[slea.readInt()];
int cost = type.getRepCost();
MapleFamilyEntry entry = c.getPlayer().getFamilyEntry();
if(entry.getReputation() < cost || entry.isEntitlementUsed(type)) {
return; // shouldn't even be able to request it
}
c.announce(MaplePacketCreator.getFamilyInfo(entry));
MapleCharacter victim;
if(type == MapleFamilyEntitlement.FAMILY_REUINION || type == MapleFamilyEntitlement.SUMMON_FAMILY) {
victim = c.getChannelServer().getPlayerStorage().getCharacterByName(slea.readMapleAsciiString());
if(victim != null && victim != c.getPlayer()) {
if(victim.getFamily() == c.getPlayer().getFamily()) {
MapleMap targetMap = victim.getMap();
MapleMap ownMap = c.getPlayer().getMap();
if(targetMap != null) {
if(type == MapleFamilyEntitlement.FAMILY_REUINION) {
if(!FieldLimit.CANNOTMIGRATE.check(ownMap.getFieldLimit()) && !FieldLimit.CANNOTVIPROCK.check(targetMap.getFieldLimit())
&& (targetMap.getForcedReturnId() == 999999999 || targetMap.getId() < 100000000) && targetMap.getEventInstance() == null) {
c.getPlayer().changeMap(victim.getMap(), victim.getMap().getPortal(0));
useEntitlement(entry, type);
} else {
c.announce(MaplePacketCreator.sendFamilyMessage(75, 0)); // wrong message, but close enough. (client should check this first anyway)
return;
}
} else {
if(!FieldLimit.CANNOTMIGRATE.check(targetMap.getFieldLimit()) && !FieldLimit.CANNOTVIPROCK.check(ownMap.getFieldLimit())
&& (ownMap.getForcedReturnId() == 999999999 || ownMap.getId() < 100000000) && ownMap.getEventInstance() == null) {
if(MapleInviteCoordinator.hasInvite(InviteType.FAMILY_SUMMON, victim.getId())) {
c.announce(MaplePacketCreator.sendFamilyMessage(74, 0));
return;
}
MapleInviteCoordinator.createInvite(InviteType.FAMILY_SUMMON, c.getPlayer(), victim, victim.getId(), c.getPlayer().getMap());
victim.announce(MaplePacketCreator.sendFamilySummonRequest(c.getPlayer().getFamily().getName(), c.getPlayer().getName()));
useEntitlement(entry, type);
} else {
c.announce(MaplePacketCreator.sendFamilyMessage(75, 0));
return;
}
}
}
} else {
c.announce(MaplePacketCreator.sendFamilyMessage(67, 0));
}
}
} else if(type == MapleFamilyEntitlement.FAMILY_BONDING) {
//not implemented
} else {
boolean party = false;
boolean isExp = false;
float rate = 1.5f;
int duration = 15;
do {
switch(type) {
case PARTY_EXP_2_30MIN:
party = true;
isExp = true;
type = MapleFamilyEntitlement.SELF_EXP_2_30MIN;
continue;
case PARTY_DROP_2_30MIN:
party = true;
type = MapleFamilyEntitlement.SELF_DROP_2_30MIN;
continue;
case SELF_DROP_2_30MIN:
duration = 30;
case SELF_DROP_2:
rate = 2.0f;
case SELF_DROP_1_5:
break;
case SELF_EXP_2_30MIN:
duration = 30;
case SELF_EXP_2:
rate = 2.0f;
case SELF_EXP_1_5:
isExp = true;
default:
break;
}
break;
} while(true);
//not implemented
}
}
private boolean useEntitlement(MapleFamilyEntry entry, MapleFamilyEntitlement entitlement) {
if(entry.useEntitlement(entitlement)) {
entry.gainReputation(-entitlement.getRepCost(), false);
entry.getChr().announce(MaplePacketCreator.getFamilyInfo(entry));
return true;
}
return false;
}
}

View File

@@ -0,0 +1,59 @@
/*
This file is part of the HeavenMS MapleStory Server
Copyleft (L) 2016 - 2019 RonanLana
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation 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.server.channel.handlers;
import client.MapleCharacter;
import client.MapleClient;
import constants.game.GameConstants;
import net.AbstractMaplePacketHandler;
import server.life.MapleMonster;
import server.life.MapleMonsterInformationProvider;
import server.maps.MapleMap;
import tools.FilePrinter;
import tools.MaplePacketCreator;
import tools.data.input.SeekableLittleEndianAccessor;
public class FieldDamageMobHandler extends AbstractMaplePacketHandler {
@Override
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
int mobOid = slea.readInt(); // packet structure found thanks to Darter (Rajan)
int dmg = slea.readInt();
MapleCharacter chr = c.getPlayer();
MapleMap map = chr.getMap();
if (map.getEnvironment().isEmpty()) { // no environment objects activated to actually hit the mob
FilePrinter.printError(FilePrinter.EXPLOITS + c.getPlayer().getName() + ".txt", c.getPlayer().getName() + " tried to use an obstacle on mapid " + map.getId() + " to attack.");
return;
}
MapleMonster mob = map.getMonsterByOid(mobOid);
if (mob != null) {
if (dmg < 0 || dmg > GameConstants.MAX_FIELD_MOB_DAMAGE) {
FilePrinter.printError(FilePrinter.EXPLOITS + c.getPlayer().getName() + ".txt", c.getPlayer().getName() + " tried to use an obstacle on mapid " + map.getId() + " to attack " + MapleMonsterInformationProvider.getInstance().getMobNameFromId(mob.getId()) + " with damage " + dmg);
return;
}
map.broadcastMessage(chr, MaplePacketCreator.damageMonster(mobOid, dmg), true);
map.damageMonster(chr, mob, dmg);
}
}
}

View File

@@ -0,0 +1,54 @@
/*
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 as
published by the Free Software Foundation 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.server.channel.handlers;
import client.MapleCharacter;
import client.MapleClient;
import client.processor.npc.FredrickProcessor;
import net.AbstractMaplePacketHandler;
import tools.data.input.SeekableLittleEndianAccessor;
/**
*
* @author kevintjuh93
*/
public class FredrickHandler extends AbstractMaplePacketHandler {
@Override
public void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
MapleCharacter chr = c.getPlayer();
byte operation = slea.readByte();
switch (operation) {
case 0x19: //Will never come...
//c.announce(MaplePacketCreator.getFredrick((byte) 0x24));
break;
case 0x1A:
FredrickProcessor.fredrickRetrieveItems(c);
break;
case 0x1C: //Exit
break;
default:
}
}
}

View File

@@ -0,0 +1,75 @@
/*
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 as
published by the Free Software Foundation 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.server.channel.handlers;
import client.MapleCharacter;
import client.MapleClient;
import client.autoban.AutobanFactory;
import client.command.CommandsExecutor;
import config.YamlConfig;
import net.AbstractMaplePacketHandler;
import tools.FilePrinter;
import tools.LogHelper;
import tools.MaplePacketCreator;
import tools.data.input.SeekableLittleEndianAccessor;
public final class GeneralChatHandler extends AbstractMaplePacketHandler {
@Override
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
String s = slea.readMapleAsciiString();
MapleCharacter chr = c.getPlayer();
if(chr.getAutobanManager().getLastSpam(7) + 200 > currentServerTime()) {
c.announce(MaplePacketCreator.enableActions());
return;
}
if (s.length() > Byte.MAX_VALUE && !chr.isGM()) {
AutobanFactory.PACKET_EDIT.alert(c.getPlayer(), c.getPlayer().getName() + " tried to packet edit in General Chat.");
FilePrinter.printError(FilePrinter.EXPLOITS + c.getPlayer().getName() + ".txt", c.getPlayer().getName() + " tried to send text with length of " + s.length());
c.disconnect(true, false);
return;
}
char heading = s.charAt(0);
if (CommandsExecutor.isCommand(c, s)) {
CommandsExecutor.getInstance().handle(c, s);
} else if (heading != '/') {
int show = slea.readByte();
if(chr.getMap().isMuted() && !chr.isGM()) {
chr.dropMessage(5, "The map you are in is currently muted. Please try again later.");
return;
}
if (!chr.isHidden()) {
chr.getMap().broadcastMessage(MaplePacketCreator.getChatText(chr.getId(), s, chr.getWhiteChat(), show));
if (YamlConfig.config.server.USE_ENABLE_CHAT_LOG) {
LogHelper.logChat(c, "General", s);
}
} else {
chr.getMap().broadcastGMMessage(MaplePacketCreator.getChatText(chr.getId(), s, chr.getWhiteChat(), show));
if (YamlConfig.config.server.USE_ENABLE_CHAT_LOG) {
LogHelper.logChat(c, "GM General", s);
}
}
chr.getAutobanManager().spam(7);
}
}
}

View File

@@ -0,0 +1,64 @@
/*
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 as
published by the Free Software Foundation 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.server.channel.handlers;
import client.MapleCharacter;
import client.MapleCharacter.FameStatus;
import client.autoban.AutobanFactory;
import client.MapleClient;
import client.MapleStat;
import net.AbstractMaplePacketHandler;
import tools.FilePrinter;
import tools.MaplePacketCreator;
import tools.data.input.SeekableLittleEndianAccessor;
public final class GiveFameHandler extends AbstractMaplePacketHandler {
@Override
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
MapleCharacter target = (MapleCharacter) c.getPlayer().getMap().getMapObject(slea.readInt());
int mode = slea.readByte();
int famechange = 2 * mode - 1;
MapleCharacter player = c.getPlayer();
if (target == null || target.getId() == player.getId() || player.getLevel() < 15) {
return;
} else if (famechange != 1 && famechange != -1) {
AutobanFactory.PACKET_EDIT.alert(c.getPlayer(), c.getPlayer().getName() + " tried to packet edit fame.");
FilePrinter.printError(FilePrinter.EXPLOITS + c.getPlayer().getName() + ".txt", c.getPlayer().getName() + " tried to fame hack with famechange " + famechange);
c.disconnect(true, false);
return;
}
FameStatus status = player.canGiveFame(target);
if (status == FameStatus.OK) {
if (target.gainFame(famechange, player, mode)) {
if (!player.isGM()) {
player.hasGivenFame(target);
}
} else {
player.message("Could not process the request, since this character currently has the minimum/maximum level of fame.");
}
} else {
c.announce(MaplePacketCreator.giveFameErrorResponse(status == FameStatus.NOT_TODAY ? 3 : 4));
}
}
}

View File

@@ -0,0 +1,57 @@
/*
This file is part of the HeavenMS MapleStory Server
Copyleft (L) 2016 - 2019 RonanLana
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation 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.server.channel.handlers;
import client.MapleClient;
import client.MapleCharacter;
import constants.skills.Gunslinger;
import constants.skills.NightWalker;
import net.AbstractMaplePacketHandler;
import tools.MaplePacketCreator;
import tools.data.input.SeekableLittleEndianAccessor;
import java.awt.Point;
import tools.FilePrinter;
/*
* @author GabrielSin
*/
public class GrenadeEffectHandler extends AbstractMaplePacketHandler {
@Override
public void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
MapleCharacter chr = c.getPlayer();
Point position = new Point(slea.readInt(), slea.readInt());
int keyDown = slea.readInt();
int skillId = slea.readInt();
switch (skillId) {
case NightWalker.POISON_BOMB:
case Gunslinger.GRENADE:
int skillLevel = chr.getSkillLevel(skillId);
if (skillLevel > 0) {
chr.getMap().broadcastMessage(chr, MaplePacketCreator.throwGrenade(chr.getId(), position, keyDown, skillId, skillLevel), position);
}
break;
default:
FilePrinter.printError(FilePrinter.UNHANDLED_EVENT, "The skill id: " + skillId + " is not coded in " + this.getClass().getName() + ".");
}
}
}

View File

@@ -0,0 +1,274 @@
/*
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 as
published by the Free Software Foundation 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.server.channel.handlers;
import config.YamlConfig;
import net.server.guild.MapleGuildResponse;
import net.server.guild.MapleGuild;
import constants.game.GameConstants;
import client.MapleClient;
import net.AbstractMaplePacketHandler;
import tools.data.input.SeekableLittleEndianAccessor;
import tools.MaplePacketCreator;
import client.MapleCharacter;
import java.util.HashSet;
import java.util.Set;
import net.server.Server;
import net.server.coordinator.matchchecker.MatchCheckerListenerFactory.MatchCheckerType;
import net.server.guild.MapleAlliance;
import net.server.world.MapleParty;
import net.server.world.World;
public final class GuildOperationHandler extends AbstractMaplePacketHandler {
private boolean isGuildNameAcceptable(String name) {
if (name.length() < 3 || name.length() > 12) {
return false;
}
for (int i = 0; i < name.length(); i++) {
if (!Character.isLowerCase(name.charAt(i)) && !Character.isUpperCase(name.charAt(i))) {
return false;
}
}
return true;
}
@Override
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
MapleCharacter mc = c.getPlayer();
byte type = slea.readByte();
int allianceId = -1;
switch (type) {
case 0x00:
//c.announce(MaplePacketCreator.showGuildInfo(mc));
break;
case 0x02:
if (mc.getGuildId() > 0) {
mc.dropMessage(1, "You cannot create a new Guild while in one.");
return;
}
if (mc.getMeso() < YamlConfig.config.server.CREATE_GUILD_COST) {
mc.dropMessage(1, "You do not have " + GameConstants.numberWithCommas(YamlConfig.config.server.CREATE_GUILD_COST) + " mesos to create a Guild.");
return;
}
String guildName = slea.readMapleAsciiString();
if (!isGuildNameAcceptable(guildName)) {
mc.dropMessage(1, "The Guild name you have chosen is not accepted.");
return;
}
Set<MapleCharacter> eligibleMembers = new HashSet<>(MapleGuild.getEligiblePlayersForGuild(mc));
if (eligibleMembers.size() < YamlConfig.config.server.CREATE_GUILD_MIN_PARTNERS) {
if (mc.getMap().getAllPlayers().size() < YamlConfig.config.server.CREATE_GUILD_MIN_PARTNERS) {
// thanks NovaStory for noticing message in need of smoother info
mc.dropMessage(1, "Your Guild doesn't have enough cofounders present here and therefore cannot be created at this time.");
} else {
// players may be unaware of not belonging on a party in order to become eligible, thanks Hair (Legalize) for pointing this out
mc.dropMessage(1, "Please make sure everyone you are trying to invite is neither on a guild nor on a party.");
}
return;
}
if (!MapleParty.createParty(mc, true)) {
mc.dropMessage(1, "You cannot create a new Guild while in a party.");
return;
}
Set<Integer> eligibleCids = new HashSet<>();
for (MapleCharacter chr : eligibleMembers) {
eligibleCids.add(chr.getId());
}
c.getWorldServer().getMatchCheckerCoordinator().createMatchConfirmation(MatchCheckerType.GUILD_CREATION, c.getWorld(), mc.getId(), eligibleCids, guildName);
break;
case 0x05:
if (mc.getGuildId() <= 0 || mc.getGuildRank() > 2) {
return;
}
String targetName = slea.readMapleAsciiString();
MapleGuildResponse mgr = MapleGuild.sendInvitation(c, targetName);
if (mgr != null) {
c.announce(mgr.getPacket(targetName));
} else {} // already sent invitation, do nothing
break;
case 0x06:
if (mc.getGuildId() > 0) {
System.out.println("[Hack] " + mc.getName() + " attempted to join a guild when s/he is already in one.");
return;
}
int gid = slea.readInt();
int cid = slea.readInt();
if (cid != mc.getId()) {
System.out.println("[Hack] " + mc.getName() + " attempted to join a guild with a different character id.");
return;
}
if (!MapleGuild.answerInvitation(cid, mc.getName(), gid, true)) {
return;
}
mc.getMGC().setGuildId(gid); // joins the guild
mc.getMGC().setGuildRank(5); // start at lowest rank
mc.getMGC().setAllianceRank(5);
int s = Server.getInstance().addGuildMember(mc.getMGC(), mc);
if (s == 0) {
mc.dropMessage(1, "The guild you are trying to join is already full.");
mc.getMGC().setGuildId(0);
return;
}
c.announce(MaplePacketCreator.showGuildInfo(mc));
allianceId = mc.getGuild().getAllianceId();
if(allianceId > 0) Server.getInstance().getAlliance(allianceId).updateAlliancePackets(mc);
mc.saveGuildStatus(); // update database
mc.getMap().broadcastMessage(mc, MaplePacketCreator.guildNameChanged(mc.getId(), mc.getGuild().getName())); // thanks Vcoc for pointing out an issue with updating guild tooltip to players in the map
mc.getMap().broadcastMessage(mc, MaplePacketCreator.guildMarkChanged(mc.getId(), mc.getGuild()));
break;
case 0x07:
cid = slea.readInt();
String name = slea.readMapleAsciiString();
if (cid != mc.getId() || !name.equals(mc.getName()) || mc.getGuildId() <= 0) {
System.out.println("[Hack] " + mc.getName() + " tried to quit guild under the name \"" + name + "\" and current guild id of " + mc.getGuildId() + ".");
return;
}
allianceId = mc.getGuild().getAllianceId();
c.announce(MaplePacketCreator.updateGP(mc.getGuildId(), 0));
Server.getInstance().leaveGuild(mc.getMGC());
c.announce(MaplePacketCreator.showGuildInfo(null));
if(allianceId > 0) Server.getInstance().getAlliance(allianceId).updateAlliancePackets(mc);
mc.getMGC().setGuildId(0);
mc.getMGC().setGuildRank(5);
mc.saveGuildStatus();
mc.getMap().broadcastMessage(mc, MaplePacketCreator.guildNameChanged(mc.getId(), ""));
break;
case 0x08:
allianceId = mc.getGuild().getAllianceId();
cid = slea.readInt();
name = slea.readMapleAsciiString();
if (mc.getGuildRank() > 2 || mc.getGuildId() <= 0) {
System.out.println("[Hack] " + mc.getName() + " is trying to expel without rank 1 or 2.");
return;
}
Server.getInstance().expelMember(mc.getMGC(), name, cid);
if(allianceId > 0) Server.getInstance().getAlliance(allianceId).updateAlliancePackets(mc);
break;
case 0x0d:
if (mc.getGuildId() <= 0 || mc.getGuildRank() != 1) {
System.out.println("[Hack] " + mc.getName() + " tried to change guild rank titles when s/he does not have permission.");
return;
}
String ranks[] = new String[5];
for (int i = 0; i < 5; i++) {
ranks[i] = slea.readMapleAsciiString();
}
Server.getInstance().changeRankTitle(mc.getGuildId(), ranks);
break;
case 0x0e:
cid = slea.readInt();
byte newRank = slea.readByte();
if (mc.getGuildRank() > 2 || (newRank <= 2 && mc.getGuildRank() != 1) || mc.getGuildId() <= 0) {
System.out.println("[Hack] " + mc.getName() + " is trying to change rank outside of his/her permissions.");
return;
}
if (newRank <= 1 || newRank > 5) {
return;
}
Server.getInstance().changeRank(mc.getGuildId(), cid, newRank);
break;
case 0x0f:
if (mc.getGuildId() <= 0 || mc.getGuildRank() != 1 || mc.getMapId() != 200000301) {
System.out.println("[Hack] " + mc.getName() + " tried to change guild emblem without being the guild leader.");
return;
}
if (mc.getMeso() < YamlConfig.config.server.CHANGE_EMBLEM_COST) {
c.announce(MaplePacketCreator.serverNotice(1, "You do not have " + GameConstants.numberWithCommas(YamlConfig.config.server.CHANGE_EMBLEM_COST) + " mesos to change the Guild emblem."));
return;
}
short bg = slea.readShort();
byte bgcolor = slea.readByte();
short logo = slea.readShort();
byte logocolor = slea.readByte();
Server.getInstance().setGuildEmblem(mc.getGuildId(), bg, bgcolor, logo, logocolor);
if (mc.getGuild() != null && mc.getGuild().getAllianceId() > 0) {
MapleAlliance alliance = mc.getAlliance();
Server.getInstance().allianceMessage(alliance.getId(), MaplePacketCreator.getGuildAlliances(alliance, c.getWorld()), -1, -1);
}
mc.gainMeso(-YamlConfig.config.server.CHANGE_EMBLEM_COST, true, false, true);
mc.getGuild().broadcastNameChanged();
mc.getGuild().broadcastEmblemChanged();
break;
case 0x10:
if (mc.getGuildId() <= 0 || mc.getGuildRank() > 2) {
if(mc.getGuildId() <= 0) System.out.println("[Hack] " + mc.getName() + " tried to change guild notice while not in a guild.");
return;
}
String notice = slea.readMapleAsciiString();
if (notice.length() > 100) {
return;
}
Server.getInstance().setGuildNotice(mc.getGuildId(), notice);
break;
case 0x1E:
slea.readInt();
World wserv = c.getWorldServer();
if (mc.getParty() != null) {
wserv.getMatchCheckerCoordinator().dismissMatchConfirmation(mc.getId());
return;
}
int leaderid = wserv.getMatchCheckerCoordinator().getMatchConfirmationLeaderid(mc.getId());
if (leaderid != -1) {
boolean result = slea.readByte() != 0;
if (result && wserv.getMatchCheckerCoordinator().isMatchConfirmationActive(mc.getId())) {
MapleCharacter leader = wserv.getPlayerStorage().getCharacterById(leaderid);
if (leader != null) {
int partyid = leader.getPartyId();
if (partyid != -1) {
MapleParty.joinParty(mc, partyid, true); // GMS gimmick "party to form guild" recalled thanks to Vcoc
}
}
}
wserv.getMatchCheckerCoordinator().answerMatchConfirmation(mc.getId(), result);
}
break;
default:
System.out.println("Unhandled GUILD_OPERATION packet: \n" + slea.toString());
}
}
}

View File

@@ -0,0 +1,71 @@
/*
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 as
published by the Free Software Foundation 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.server.channel.handlers;
import client.MapleCharacter;
import client.MapleClient;
import client.autoban.AutobanFactory;
import client.autoban.AutobanManager;
import net.AbstractMaplePacketHandler;
import net.server.Server;
import server.maps.MapleMap;
import tools.data.input.SeekableLittleEndianAccessor;
import tools.MaplePacketCreator;
public final class HealOvertimeHandler extends AbstractMaplePacketHandler {
@Override
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
MapleCharacter chr = c.getPlayer();
if(!chr.isLoggedinWorld()) return;
AutobanManager abm = chr.getAutobanManager();
int timestamp = Server.getInstance().getCurrentTimestamp();
slea.skip(8);
short healHP = slea.readShort();
if (healHP != 0) {
abm.setTimestamp(8, timestamp, 28); // thanks Vcoc & Thora for pointing out d/c happening here
if ((abm.getLastSpam(0) + 1500) > timestamp) AutobanFactory.FAST_HP_HEALING.addPoint(abm, "Fast hp healing");
MapleMap map = chr.getMap();
int abHeal = (int)(77 * map.getRecovery() * 1.5); // thanks Ari for noticing players not getting healed in sauna in certain cases
if (healHP > abHeal) {
AutobanFactory.HIGH_HP_HEALING.autoban(chr, "Healing: " + healHP + "; Max is " + abHeal + ".");
return;
}
chr.addHP(healHP);
chr.getMap().broadcastMessage(chr, MaplePacketCreator.showHpHealed(chr.getId(), healHP), false);
abm.spam(0, timestamp);
}
short healMP = slea.readShort();
if (healMP != 0 && healMP < 1000) {
abm.setTimestamp(9, timestamp, 28);
if ((abm.getLastSpam(1) + 1500) > timestamp) {
AutobanFactory.FAST_MP_HEALING.addPoint(abm, "Fast mp healing");
return; // thanks resinate for noticing mp being gained even after detection
}
chr.addMP(healMP);
abm.spam(1, timestamp);
}
}
}

View File

@@ -0,0 +1,92 @@
/*
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 as
published by the Free Software Foundation 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.server.channel.handlers;
import client.inventory.ItemFactory;
import client.MapleCharacter;
import java.sql.SQLException;
import java.util.Arrays;
import client.MapleClient;
import constants.game.GameConstants;
import java.awt.Point;
import net.AbstractMaplePacketHandler;
import server.maps.MaplePortal;
import server.maps.MapleMapObject;
import server.maps.MapleMapObjectType;
import server.maps.MaplePlayerShop;
import tools.MaplePacketCreator;
import tools.data.input.SeekableLittleEndianAccessor;
/**
*
* @author XoticStory
*/
public final class HiredMerchantRequest extends AbstractMaplePacketHandler {
@Override
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
MapleCharacter chr = c.getPlayer();
try {
for (MapleMapObject mmo : chr.getMap().getMapObjectsInRange(chr.getPosition(), 23000, Arrays.asList(MapleMapObjectType.HIRED_MERCHANT, MapleMapObjectType.PLAYER))) {
if (mmo instanceof MapleCharacter) {
MapleCharacter mc = (MapleCharacter) mmo;
MaplePlayerShop shop = mc.getPlayerShop();
if (shop != null && shop.isOwner(mc)) {
chr.announce(MaplePacketCreator.getMiniRoomError(13));
return;
}
} else {
chr.announce(MaplePacketCreator.getMiniRoomError(13));
return;
}
}
Point cpos = chr.getPosition();
MaplePortal portal = chr.getMap().findClosestTeleportPortal(cpos);
if (portal != null && portal.getPosition().distance(cpos) < 120.0) {
chr.announce(MaplePacketCreator.getMiniRoomError(10));
return;
}
} catch (Exception e) {
e.printStackTrace();
}
if (GameConstants.isFreeMarketRoom(chr.getMapId())) {
if (!chr.hasMerchant()) {
try {
if (ItemFactory.MERCHANT.loadItems(chr.getId(), false).isEmpty() && chr.getMerchantMeso() == 0) {
c.announce(MaplePacketCreator.hiredMerchantBox());
} else {
chr.announce(MaplePacketCreator.retrieveFirstMessage());
}
} catch (SQLException ex) {
ex.printStackTrace();
}
} else {
chr.dropMessage(1, "You already have a store open.");
}
} else {
chr.dropMessage(1, "You cannot open your hired merchant here.");
}
}
}

View File

@@ -0,0 +1,36 @@
/*
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 as
published by the Free Software Foundation 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.server.channel.handlers;
import client.MapleClient;
import net.AbstractMaplePacketHandler;
import tools.data.input.SeekableLittleEndianAccessor;
/**
*
* @author BubblesDev
*/
public final class InnerPortalHandler extends AbstractMaplePacketHandler {
@Override
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
}
}

View File

@@ -0,0 +1,112 @@
/*
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 as
published by the Free Software Foundation 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.server.channel.handlers;
import config.YamlConfig;
import net.AbstractMaplePacketHandler;
import client.inventory.manipulator.MapleInventoryManipulator;
import tools.MaplePacketCreator;
import tools.data.input.SeekableLittleEndianAccessor;
import client.MapleCharacter;
import client.MapleClient;
import client.inventory.Item;
import client.inventory.MapleInventory;
import client.inventory.MapleInventoryType;
import net.server.Server;
import server.MapleItemInformationProvider;
public final class InventoryMergeHandler extends AbstractMaplePacketHandler {
@Override
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
MapleCharacter chr = c.getPlayer();
slea.readInt();
chr.getAutobanManager().setTimestamp(2, Server.getInstance().getCurrentTimestamp(), 4);
if(!YamlConfig.config.server.USE_ITEM_SORT) {
c.announce(MaplePacketCreator.enableActions());
return;
}
byte invType = slea.readByte();
if (invType < 1 || invType > 5) {
c.disconnect(false, false);
return;
}
MapleInventoryType inventoryType = MapleInventoryType.getByType(invType);
MapleInventory inventory = c.getPlayer().getInventory(inventoryType);
inventory.lockInventory();
try {
//------------------- RonanLana's SLOT MERGER -----------------
MapleItemInformationProvider ii = MapleItemInformationProvider.getInstance();
Item srcItem, dstItem;
for(short dst = 1; dst <= inventory.getSlotLimit(); dst++) {
dstItem = inventory.getItem(dst);
if(dstItem == null) continue;
for(short src = (short)(dst + 1); src <= inventory.getSlotLimit(); src++) {
srcItem = inventory.getItem(src);
if(srcItem == null) continue;
if(dstItem.getItemId() != srcItem.getItemId()) continue;
if(dstItem.getQuantity() == ii.getSlotMax(c, inventory.getItem(dst).getItemId())) break;
MapleInventoryManipulator.move(c, inventoryType, src, dst);
}
}
//------------------------------------------------------------
inventory = c.getPlayer().getInventory(inventoryType);
boolean sorted = false;
while (!sorted) {
short freeSlot = inventory.getNextFreeSlot();
if (freeSlot != -1) {
short itemSlot = -1;
for (short i = (short) (freeSlot + 1); i <= inventory.getSlotLimit(); i = (short) (i + 1)) {
if (inventory.getItem(i) != null) {
itemSlot = i;
break;
}
}
if (itemSlot > 0) {
MapleInventoryManipulator.move(c, inventoryType, itemSlot, freeSlot);
} else {
sorted = true;
}
} else {
sorted = true;
}
}
} finally {
inventory.unlockInventory();
}
c.announce(MaplePacketCreator.finishedSort(inventoryType.getType()));
c.announce(MaplePacketCreator.enableActions());
}
}

View File

@@ -0,0 +1,319 @@
/*
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 as
published by the Free Software Foundation 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.server.channel.handlers;
import java.util.ArrayList;
import java.util.List;
import config.YamlConfig;
import net.AbstractMaplePacketHandler;
import tools.MaplePacketCreator;
import tools.data.input.SeekableLittleEndianAccessor;
import client.MapleCharacter;
import client.MapleClient;
import client.inventory.Item;
import client.inventory.Equip;
import client.inventory.MapleInventory;
import client.inventory.MapleInventoryType;
import client.inventory.ModifyInventory;
import server.MapleItemInformationProvider;
import net.server.Server;
/**
*
* @author BubblesDev
* @author Ronan
*/
class PairedQuicksort {
private int i = 0;
private int j = 0;
private final ArrayList<Integer> intersect;
MapleItemInformationProvider ii = MapleItemInformationProvider.getInstance();
private void PartitionByItemId(int Esq, int Dir, ArrayList<Item> A) {
Item x, w;
i = Esq;
j = Dir;
x = A.get((i + j) / 2);
do {
while (x.getItemId() > A.get(i).getItemId()) i++;
while (x.getItemId() < A.get(j).getItemId()) j--;
if (i <= j) {
w = A.get(i);
A.set(i, A.get(j));
A.set(j, w);
i++;
j--;
}
} while (i <= j);
}
private int getWatkForProjectile(Item item) {
return ii.getWatkForProjectile(item.getItemId());
}
private void PartitionByProjectileAtk(int Esq, int Dir, ArrayList<Item> A) {
Item x, w;
i = Esq;
j = Dir;
x = A.get((i + j) / 2);
do {
int watk = getWatkForProjectile(x);
while (watk < getWatkForProjectile(A.get(i))) i++;
while (watk > getWatkForProjectile(A.get(j))) j--;
if (i <= j) {
w = A.get(i);
A.set(i, A.get(j));
A.set(j, w);
i++;
j--;
}
} while (i <= j);
}
private void PartitionByName(int Esq, int Dir, ArrayList<Item> A) {
Item x, w;
i = Esq;
j = Dir;
x = A.get((i + j) / 2);
do {
while (ii.getName(x.getItemId()).compareTo(ii.getName(A.get(i).getItemId())) > 0) i++;
while (ii.getName(x.getItemId()).compareTo(ii.getName(A.get(j).getItemId())) < 0) j--;
if (i <= j) {
w = A.get(i);
A.set(i, A.get(j));
A.set(j, w);
i++;
j--;
}
} while (i <= j);
}
private void PartitionByQuantity(int Esq, int Dir, ArrayList<Item> A) {
Item x, w;
i = Esq;
j = Dir;
x = A.get((i + j) / 2);
do {
while (x.getQuantity() > A.get(i).getQuantity()) i++;
while (x.getQuantity() < A.get(j).getQuantity()) j--;
if (i <= j) {
w = A.get(i);
A.set(i, A.get(j));
A.set(j, w);
i++;
j--;
}
} while (i <= j);
}
private void PartitionByLevel(int Esq, int Dir, ArrayList<Item> A) {
Equip x, w;
i = Esq;
j = Dir;
x = (Equip)(A.get((i + j) / 2));
do {
while (x.getLevel() > ((Equip)A.get(i)).getLevel()) i++;
while (x.getLevel() < ((Equip)A.get(j)).getLevel()) j--;
if (i <= j) {
w = (Equip)A.get(i);
A.set(i, A.get(j));
A.set(j, (Item)w);
i++;
j--;
}
} while (i <= j);
}
void MapleQuicksort(int Esq, int Dir, ArrayList<Item> A, int sort) {
switch(sort) {
case 3:
PartitionByLevel(Esq, Dir, A);
break;
case 2:
PartitionByName(Esq, Dir, A);
break;
case 1:
PartitionByQuantity(Esq, Dir, A);
break;
default:
PartitionByItemId(Esq, Dir, A);
}
if (Esq < j) MapleQuicksort(Esq, j, A, sort);
if (i < Dir) MapleQuicksort(i, Dir, A, sort);
}
private static int getItemSubtype(Item it) {
return it.getItemId() / 10000;
}
private int[] BinarySearchElement(ArrayList<Item> A, int rangeId) {
int st = 0, en = A.size() - 1;
int mid = -1, idx = -1;
while (en >= st) {
idx = (st + en) / 2;
mid = getItemSubtype(A.get(idx));
if (mid == rangeId) {
break;
} else if (mid < rangeId) {
st = idx + 1;
} else {
en = idx - 1;
}
}
if (en < st) {
return null;
}
st = idx - 1;
en = idx + 1;
while (st >= 0 && getItemSubtype(A.get(st)) == rangeId) {
st -= 1;
}
st += 1;
while (en < A.size() && getItemSubtype(A.get(en)) == rangeId) {
en += 1;
}
en -= 1;
return new int[]{st, en};
}
public void reverseSortSublist(ArrayList<Item> A, int[] range) {
if (range != null) {
PartitionByProjectileAtk(range[0], range[1], A);
}
}
public PairedQuicksort(ArrayList<Item> A, int primarySort, int secondarySort) {
intersect = new ArrayList<>();
if(A.size() > 0) {
MapleQuicksort(0, A.size() - 1, A, primarySort);
if (A.get(0).getInventoryType().equals(MapleInventoryType.USE)) { // thanks KDA & Vcoc for suggesting stronger projectiles coming before weaker ones
reverseSortSublist(A, BinarySearchElement(A, 206)); // arrows
reverseSortSublist(A, BinarySearchElement(A, 207)); // stars
reverseSortSublist(A, BinarySearchElement(A, 233)); // bullets
}
}
intersect.add(0);
for(int ind = 1; ind < A.size(); ind++) {
if(A.get(ind - 1).getItemId() != A.get(ind).getItemId()) {
intersect.add(ind);
}
}
intersect.add(A.size());
for(int ind = 0; ind < intersect.size() - 1; ind++) {
if(intersect.get(ind + 1) > intersect.get(ind)) MapleQuicksort(intersect.get(ind), intersect.get(ind + 1) - 1, A, secondarySort);
}
}
}
public final class InventorySortHandler extends AbstractMaplePacketHandler {
@Override
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
MapleCharacter chr = c.getPlayer();
slea.readInt();
chr.getAutobanManager().setTimestamp(3, Server.getInstance().getCurrentTimestamp(), 4);
if(!YamlConfig.config.server.USE_ITEM_SORT) {
c.announce(MaplePacketCreator.enableActions());
return;
}
byte invType = slea.readByte();
if (invType < 1 || invType > 5) {
c.disconnect(false, false);
return;
}
ArrayList<Item> itemarray = new ArrayList<>();
List<ModifyInventory> mods = new ArrayList<>();
MapleInventory inventory = chr.getInventory(MapleInventoryType.getByType(invType));
inventory.lockInventory();
try {
for (short i = 1; i <= inventory.getSlotLimit(); i++) {
Item item = inventory.getItem(i);
if (item != null) {
itemarray.add((Item) item.copy());
}
}
for (Item item : itemarray) {
inventory.removeSlot(item.getPosition());
mods.add(new ModifyInventory(3, item));
}
int invTypeCriteria = (MapleInventoryType.getByType(invType) == MapleInventoryType.EQUIP) ? 3 : 1;
int sortCriteria = (YamlConfig.config.server.USE_ITEM_SORT_BY_NAME == true) ? 2 : 0;
PairedQuicksort pq = new PairedQuicksort(itemarray, sortCriteria, invTypeCriteria);
for (Item item : itemarray) {
inventory.addItem(item);
mods.add(new ModifyInventory(0, item.copy()));//to prevent crashes
}
itemarray.clear();
} finally {
inventory.unlockInventory();
}
c.announce(MaplePacketCreator.modifyInventory(true, mods));
c.announce(MaplePacketCreator.finishedSort2(invType));
c.announce(MaplePacketCreator.enableActions());
}
}

View File

@@ -0,0 +1,62 @@
/*
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 as
published by the Free Software Foundation 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.server.channel.handlers;
import client.MapleClient;
import client.inventory.MapleInventoryType;
import net.AbstractMaplePacketHandler;
import client.inventory.manipulator.MapleInventoryManipulator;
import tools.MaplePacketCreator;
import tools.data.input.SeekableLittleEndianAccessor;
/**
*
* @author Matze
*/
public final class ItemMoveHandler extends AbstractMaplePacketHandler {
@Override
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
slea.skip(4);
if(c.getPlayer().getAutobanManager().getLastSpam(6) + 300 > currentServerTime()) {
c.announce(MaplePacketCreator.enableActions());
return;
}
MapleInventoryType type = MapleInventoryType.getByType(slea.readByte());
short src = slea.readShort(); //is there any reason to use byte instead of short in src and action?
short action = slea.readShort();
short quantity = slea.readShort();
if (src < 0 && action > 0) {
MapleInventoryManipulator.unequip(c, src, action);
} else if (action < 0) {
MapleInventoryManipulator.equip(c, src, action);
} else if (action == 0) {
MapleInventoryManipulator.drop(c, type, src, quantity);
} else {
MapleInventoryManipulator.move(c, type, src, action);
}
if (c.getPlayer().getMap().getHPDec() > 0) c.getPlayer().resetHpDecreaseTask();
c.getPlayer().getAutobanManager().spam(6);
}
}

View File

@@ -0,0 +1,58 @@
/*
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 as
published by the Free Software Foundation 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.server.channel.handlers;
import net.AbstractMaplePacketHandler;
import server.maps.MapleMapObject;
import tools.data.input.SeekableLittleEndianAccessor;
import client.MapleCharacter;
import client.MapleClient;
import java.awt.Point;
import tools.FilePrinter;
/**
*
* @author Matze
* @author Ronan
*/
public final class ItemPickupHandler extends AbstractMaplePacketHandler {
@Override
public final void handlePacket(final SeekableLittleEndianAccessor slea, final MapleClient c) {
slea.readInt(); //Timestamp
slea.readByte();
slea.readPos(); //cpos
int oid = slea.readInt();
MapleCharacter chr = c.getPlayer();
MapleMapObject ob = chr.getMap().getMapObject(oid);
if(ob == null) return;
Point charPos = chr.getPosition();
Point obPos = ob.getPosition();
if (Math.abs(charPos.getX() - obPos.getX()) > 800 || Math.abs(charPos.getY() - obPos.getY()) > 600) {
FilePrinter.printError(FilePrinter.EXPLOITS + c.getPlayer().getName() + ".txt", c.getPlayer().getName() + " tried to pick up an item too far away. Mapid: " + chr.getMapId() + " Player pos: " + charPos + " Object pos: " + obPos);
return;
}
chr.pickupItem(ob);
}
}

View File

@@ -0,0 +1,81 @@
/*
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 as
published by the Free Software Foundation 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.server.channel.handlers;
import client.MapleClient;
import client.inventory.Item;
import client.inventory.MapleInventoryType;
import constants.inventory.ItemConstants;
import java.util.List;
import net.AbstractMaplePacketHandler;
import net.server.Server;
import client.inventory.manipulator.MapleInventoryManipulator;
import server.MapleItemInformationProvider;
import server.MapleItemInformationProvider.RewardItem;
import tools.MaplePacketCreator;
import tools.Pair;
import tools.Randomizer;
import tools.data.input.SeekableLittleEndianAccessor;
/**
* @author Jay Estrella
* @author kevintjuh93
*/
public final class ItemRewardHandler extends AbstractMaplePacketHandler {
@Override
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
byte slot = (byte) slea.readShort();
int itemId = slea.readInt(); // will load from xml I don't care.
Item it = c.getPlayer().getInventory(MapleInventoryType.USE).getItem(slot); // null check here thanks to Thora
if (it == null || it.getItemId() != itemId || c.getPlayer().getInventory(MapleInventoryType.USE).countById(itemId) < 1) return;
MapleItemInformationProvider ii = MapleItemInformationProvider.getInstance();
Pair<Integer, List<RewardItem>> rewards = ii.getItemReward(itemId);
for (RewardItem reward : rewards.getRight()) {
if (!MapleInventoryManipulator.checkSpace(c, reward.itemid, reward.quantity, "")) {
c.announce(MaplePacketCreator.getShowInventoryFull());
break;
}
if (Randomizer.nextInt(rewards.getLeft()) < reward.prob) {//Is it even possible to get an item with prob 1?
if (ItemConstants.getInventoryType(reward.itemid) == MapleInventoryType.EQUIP) {
final Item item = ii.getEquipById(reward.itemid);
if (reward.period != -1) {
item.setExpiration(currentServerTime() + (reward.period * 60 * 60 * 10));
}
MapleInventoryManipulator.addFromDrop(c, item, false);
} else {
MapleInventoryManipulator.addById(c, reward.itemid, reward.quantity, "", -1);
}
MapleInventoryManipulator.removeById(c, MapleInventoryType.USE, itemId, 1, false, false);
if (reward.worldmsg != null) {
String msg = reward.worldmsg;
msg.replaceAll("/name", c.getPlayer().getName());
msg.replaceAll("/item", ii.getName(reward.itemid));
Server.getInstance().broadcastMessage(c.getWorld(), MaplePacketCreator.serverNotice(6, msg));
}
break;
}
}
c.announce(MaplePacketCreator.enableActions());
}
}

View File

@@ -0,0 +1,85 @@
/*
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 as
published by the Free Software Foundation 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.server.channel.handlers;
import constants.game.GameConstants;
import client.MapleClient;
import client.keybind.MapleKeyBinding;
import client.Skill;
import client.SkillFactory;
import client.autoban.AutobanFactory;
import client.inventory.MapleInventoryType;
import net.AbstractMaplePacketHandler;
import tools.FilePrinter;
import tools.data.input.SeekableLittleEndianAccessor;
public final class KeymapChangeHandler extends AbstractMaplePacketHandler {
@Override
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
if (slea.available() >= 8) {
int mode = slea.readInt();
if(mode == 0) {
int numChanges = slea.readInt();
for (int i = 0; i < numChanges; i++) {
int key = slea.readInt();
int type = slea.readByte();
int action = slea.readInt();
if(type == 1) {
Skill skill = SkillFactory.getSkill(action);
boolean isBanndedSkill;
if (skill != null) {
isBanndedSkill = GameConstants.bannedBindSkills(skill.getId());
if (isBanndedSkill || (!c.getPlayer().isGM() && GameConstants.isGMSkills(skill.getId())) || (!GameConstants.isInJobTree(skill.getId(), c.getPlayer().getJob().getId()) && !c.getPlayer().isGM())) { //for those skills are are "technically" in the beginner tab, like bamboo rain in Dojo or skills you find in PYPQ
//AutobanFactory.PACKET_EDIT.alert(c.getPlayer(), c.getPlayer().getName() + " tried to packet edit keymapping.");
//FilePrinter.printError(FilePrinter.EXPLOITS + c.getPlayer().getName() + ".txt", c.getPlayer().getName() + " tried to use skill " + skill.getId());
//c.disconnect(true, false);
//return;
continue; // fk that
}
/* if (c.getPlayer().getSkillLevel(skill) < 1) { HOW WOULD A SKILL EVEN BE AVAILABLE TO KEYBINDING
continue; IF THERE IS NOT EVEN A SINGLE POINT USED INTO IT??
} */
}
}
c.getPlayer().changeKeybinding(key, new MapleKeyBinding(type, action));
}
} else if(mode == 1) { // Auto HP Potion
int itemID = slea.readInt();
if(itemID != 0 && c.getPlayer().getInventory(MapleInventoryType.USE).findById(itemID) == null) {
c.disconnect(false, false); // Don't let them send a packet with a use item they dont have.
return;
}
c.getPlayer().changeKeybinding(91, new MapleKeyBinding(7, itemID));
} else if(mode == 2) { // Auto MP Potion
int itemID = slea.readInt();
if(itemID != 0 && c.getPlayer().getInventory(MapleInventoryType.USE).findById(itemID) == null) {
c.disconnect(false, false); // Don't let them send a packet with a use item they dont have.
return;
}
c.getPlayer().changeKeybinding(92, new MapleKeyBinding(7, itemID));
}
}
}
}

View File

@@ -0,0 +1,39 @@
/*
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 as
published by the Free Software Foundation 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.server.channel.handlers;
import client.MapleClient;
import net.AbstractMaplePacketHandler;
import tools.MaplePacketCreator;
import tools.data.input.SeekableLittleEndianAccessor;
/**
*
* @author kevintjuh93
*/
public class LeftKnockbackHandler extends AbstractMaplePacketHandler {
public void handlePacket(SeekableLittleEndianAccessor slea, final MapleClient c) {
c.announce(MaplePacketCreator.leftKnockBack());
c.announce(MaplePacketCreator.enableActions());
}
}

View File

@@ -0,0 +1,909 @@
/*
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 as
published by the Free Software Foundation 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.server.channel.handlers;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import net.AbstractMaplePacketHandler;
import net.server.Server;
import net.server.channel.Channel;
import server.MTSItemInfo;
import client.inventory.manipulator.MapleInventoryManipulator;
import server.MapleItemInformationProvider;
import tools.DatabaseConnection;
import tools.MaplePacketCreator;
import tools.Pair;
import tools.data.input.SeekableLittleEndianAccessor;
import client.MapleCharacter;
import client.MapleClient;
import client.inventory.Equip;
import client.inventory.Item;
import client.inventory.MapleInventoryType;
import constants.inventory.ItemConstants;
public final class MTSHandler extends AbstractMaplePacketHandler {
@Override
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
// TODO add karma-to-untradeable flag on sold items here
if (!c.getPlayer().getCashShop().isOpened()) {
return;
}
if (slea.available() > 0) {
byte op = slea.readByte();
if (op == 2) { //put item up for sale
byte itemtype = slea.readByte();
int itemid = slea.readInt();
slea.readShort();
slea.skip(7);
short stars = 1;
if (itemtype == 1) {
slea.skip(32);
} else {
stars = slea.readShort();
}
slea.readMapleAsciiString(); //another useless thing (owner)
if (itemtype == 1) {
slea.skip(32);
} else {
slea.readShort();
}
short slot;
short quantity;
if (itemtype != 1) {
if (itemid / 10000 == 207 || itemid / 10000 == 233) {
slea.skip(8);
}
slot = (short) slea.readInt();
} else {
slot = (short) slea.readInt();
}
if (itemtype != 1) {
if (itemid / 10000 == 207 || itemid / 10000 == 233) {
quantity = stars;
slea.skip(4);
} else {
quantity = (short) slea.readInt();
}
} else {
quantity = (byte) slea.readInt();
}
int price = slea.readInt();
if (itemtype == 1) {
quantity = 1;
}
if (quantity < 0 || price < 110 || c.getPlayer().getItemQuantity(itemid, false) < quantity) {
return;
}
MapleInventoryType invType = ItemConstants.getInventoryType(itemid);
Item i = c.getPlayer().getInventory(invType).getItem(slot).copy();
if (i != null && c.getPlayer().getMeso() >= 5000) {
Connection con = null;
try {
con = DatabaseConnection.getConnection();
PreparedStatement ps = con.prepareStatement("SELECT COUNT(*) FROM mts_items WHERE seller = ?");
ps.setInt(1, c.getPlayer().getId());
ResultSet rs = ps.executeQuery();
if (rs.next()) {
if (rs.getInt(1) > 10) { //They have more than 10 items up for sale already!
c.getPlayer().dropMessage(1, "You already have 10 items up for auction!");
c.announce(getMTS(1, 0, 0));
c.announce(MaplePacketCreator.transferInventory(getTransfer(c.getPlayer().getId())));
c.announce(MaplePacketCreator.notYetSoldInv(getNotYetSold(c.getPlayer().getId())));
rs.close();
ps.close();
return;
}
}
rs.close();
ps.close();
Calendar calendar = Calendar.getInstance();
int year;
int month;
int day;
int oldmax = calendar.getActualMaximum(Calendar.DAY_OF_MONTH);
int oldday = calendar.get(Calendar.DAY_OF_MONTH) + 7;
if (oldmax < oldday) {
if (calendar.get(Calendar.MONTH) + 2 > 12) {
year = calendar.get(Calendar.YEAR) + 1;
month = 1;
calendar.set(year, month, 1);
day = oldday - oldmax;
} else {
month = calendar.get(Calendar.MONTH) + 2;
year = calendar.get(Calendar.YEAR);
calendar.set(year, month, 1);
day = oldday - oldmax;
}
} else {
day = calendar.get(Calendar.DAY_OF_MONTH) + 7;
month = calendar.get(Calendar.MONTH);
year = calendar.get(Calendar.YEAR);
}
String date = year + "-";
if (month < 10) {
date += "0" + month + "-";
} else {
date += month + "-";
}
if (day < 10) {
date += "0" + day;
} else {
date += day + "";
}
if (!i.getInventoryType().equals(MapleInventoryType.EQUIP)) {
Item item = (Item) i;
ps = con.prepareStatement("INSERT INTO mts_items (tab, type, itemid, quantity, expiration, giftFrom, seller, price, owner, sellername, sell_ends) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
ps.setInt(1, 1);
ps.setInt(2, (int) invType.getType());
ps.setInt(3, item.getItemId());
ps.setInt(4, quantity);
ps.setLong(5, item.getExpiration());
ps.setString(6, item.getGiftFrom());
ps.setInt(7, c.getPlayer().getId());
ps.setInt(8, price);
ps.setString(9, item.getOwner());
ps.setString(10, c.getPlayer().getName());
ps.setString(11, date);
} else {
Equip equip = (Equip) i;
ps = con.prepareStatement("INSERT INTO mts_items (tab, type, itemid, quantity, expiration, giftFrom, seller, price, upgradeslots, level, str, dex, `int`, luk, hp, mp, watk, matk, wdef, mdef, acc, avoid, hands, speed, jump, locked, owner, sellername, sell_ends, vicious, flag, itemexp, itemlevel, ringid) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
ps.setInt(1, 1);
ps.setInt(2, (int) invType.getType());
ps.setInt(3, equip.getItemId());
ps.setInt(4, quantity);
ps.setLong(5, equip.getExpiration());
ps.setString(6, equip.getGiftFrom());
ps.setInt(7, c.getPlayer().getId());
ps.setInt(8, price);
ps.setInt(9, equip.getUpgradeSlots());
ps.setInt(10, equip.getLevel());
ps.setInt(11, equip.getStr());
ps.setInt(12, equip.getDex());
ps.setInt(13, equip.getInt());
ps.setInt(14, equip.getLuk());
ps.setInt(15, equip.getHp());
ps.setInt(16, equip.getMp());
ps.setInt(17, equip.getWatk());
ps.setInt(18, equip.getMatk());
ps.setInt(19, equip.getWdef());
ps.setInt(20, equip.getMdef());
ps.setInt(21, equip.getAcc());
ps.setInt(22, equip.getAvoid());
ps.setInt(23, equip.getHands());
ps.setInt(24, equip.getSpeed());
ps.setInt(25, equip.getJump());
ps.setInt(26, 0);
ps.setString(27, equip.getOwner());
ps.setString(28, c.getPlayer().getName());
ps.setString(29, date);
ps.setInt(30, equip.getVicious());
ps.setInt(31, equip.getFlag());
ps.setInt(32, equip.getItemExp());
ps.setByte(33, equip.getItemLevel()); // thanks Jefe for noticing missing itemlevel labels
ps.setInt(34, equip.getRingId());
}
ps.executeUpdate();
ps.close();
MapleInventoryManipulator.removeFromSlot(c, invType, slot, quantity, false);
con.close();
} catch (SQLException e) {
e.printStackTrace();
}
c.getPlayer().gainMeso(-5000, false);
c.announce(MaplePacketCreator.MTSConfirmSell());
c.announce(getMTS(1, 0, 0));
c.enableCSActions();
c.announce(MaplePacketCreator.transferInventory(getTransfer(c.getPlayer().getId())));
c.announce(MaplePacketCreator.notYetSoldInv(getNotYetSold(c.getPlayer().getId())));
}
} else if (op == 3) { //send offer for wanted item
} else if (op == 4) { //list wanted item
slea.readInt();
slea.readInt();
slea.readInt();
slea.readShort();
slea.readMapleAsciiString();
} else if (op == 5) { //change page
int tab = slea.readInt();
int type = slea.readInt();
int page = slea.readInt();
c.getPlayer().changePage(page);
if (tab == 4 && type == 0) {
c.announce(getCart(c.getPlayer().getId()));
} else if (tab == c.getPlayer().getCurrentTab() && type == c.getPlayer().getCurrentType() && c.getPlayer().getSearch() != null) {
c.announce(getMTSSearch(tab, type, c.getPlayer().getCurrentCI(), c.getPlayer().getSearch(), page));
} else {
c.getPlayer().setSearch(null);
c.announce(getMTS(tab, type, page));
}
c.getPlayer().changeTab(tab);
c.getPlayer().changeType(type);
c.enableCSActions();
c.announce(MaplePacketCreator.transferInventory(getTransfer(c.getPlayer().getId())));
c.announce(MaplePacketCreator.notYetSoldInv(getNotYetSold(c.getPlayer().getId())));
} else if (op == 6) { //search
int tab = slea.readInt();
int type = slea.readInt();
slea.readInt();
int ci = slea.readInt();
String search = slea.readMapleAsciiString();
c.getPlayer().setSearch(search);
c.getPlayer().changeTab(tab);
c.getPlayer().changeType(type);
c.getPlayer().changeCI(ci);
c.enableCSActions();
c.announce(MaplePacketCreator.enableActions());
c.announce(getMTSSearch(tab, type, ci, search, c.getPlayer().getCurrentPage()));
c.announce(MaplePacketCreator.showMTSCash(c.getPlayer()));
c.announce(MaplePacketCreator.transferInventory(getTransfer(c.getPlayer().getId())));
c.announce(MaplePacketCreator.notYetSoldInv(getNotYetSold(c.getPlayer().getId())));
} else if (op == 7) { //cancel sale
int id = slea.readInt(); //id of the item
Connection con = null;
try {
con = DatabaseConnection.getConnection();
PreparedStatement ps = con.prepareStatement("UPDATE mts_items SET transfer = 1 WHERE id = ? AND seller = ?");
ps.setInt(1, id);
ps.setInt(2, c.getPlayer().getId());
ps.executeUpdate();
ps.close();
ps = con.prepareStatement("DELETE FROM mts_cart WHERE itemid = ?");
ps.setInt(1, id);
ps.executeUpdate();
ps.close();
con.close();
} catch (SQLException e) {
e.printStackTrace();
}
c.enableCSActions();
c.announce(getMTS(c.getPlayer().getCurrentTab(), c.getPlayer().getCurrentType(), c.getPlayer().getCurrentPage()));
c.announce(MaplePacketCreator.notYetSoldInv(getNotYetSold(c.getPlayer().getId())));
c.announce(MaplePacketCreator.transferInventory(getTransfer(c.getPlayer().getId())));
} else if (op == 8) { //transfer item from transfer inv.
int id = slea.readInt(); //id of the item
Connection con = null;
PreparedStatement ps;
ResultSet rs;
try {
con = DatabaseConnection.getConnection();
ps = con.prepareStatement("SELECT * FROM mts_items WHERE seller = ? AND transfer = 1 AND id= ? ORDER BY id DESC");
ps.setInt(1, c.getPlayer().getId());
ps.setInt(2, id);
rs = ps.executeQuery();
if (rs.next()) {
Item i;
if (rs.getInt("type") != 1) {
Item ii = new Item(rs.getInt("itemid"), (short) 0, (short) rs.getInt("quantity"));
ii.setOwner(rs.getString("owner"));
ii.setPosition(c.getPlayer().getInventory(ItemConstants.getInventoryType(rs.getInt("itemid"))).getNextFreeSlot());
i = ii.copy();
} else {
Equip equip = new Equip(rs.getInt("itemid"), (byte) rs.getInt("position"), -1);
equip.setOwner(rs.getString("owner"));
equip.setQuantity((short) 1);
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"));
equip.setItemLevel(rs.getByte("itemlevel"));
equip.setItemExp(rs.getInt("itemexp"));
equip.setRingId(rs.getInt("ringid"));
equip.setVicious((byte) rs.getInt("vicious"));
equip.setFlag((short) rs.getInt("flag"));
equip.setExpiration(rs.getLong("expiration"));
equip.setGiftFrom(rs.getString("giftFrom"));
equip.setPosition(c.getPlayer().getInventory(ItemConstants.getInventoryType(rs.getInt("itemid"))).getNextFreeSlot());
i = equip.copy();
}
try (PreparedStatement pse = con.prepareStatement("DELETE FROM mts_items WHERE id = ? AND seller = ? AND transfer = 1")) {
pse.setInt(1, id);
pse.setInt(2, c.getPlayer().getId());
pse.executeUpdate();
}
MapleInventoryManipulator.addFromDrop(c, i, false);
c.enableCSActions();
c.announce(getCart(c.getPlayer().getId()));
c.announce(getMTS(c.getPlayer().getCurrentTab(), c.getPlayer().getCurrentType(), c.getPlayer().getCurrentPage()));
c.announce(MaplePacketCreator.MTSConfirmTransfer(i.getQuantity(), i.getPosition()));
c.announce(MaplePacketCreator.transferInventory(getTransfer(c.getPlayer().getId())));
}
rs.close();
ps.close();
con.close();
} catch (SQLException e) {
e.printStackTrace();
System.out.println("MTS Transfer error: " + e);
}
} else if (op == 9) { //add to cart
int id = slea.readInt(); //id of the item
Connection con;
try {
con = DatabaseConnection.getConnection();
try (PreparedStatement ps1 = con.prepareStatement("SELECT id FROM mts_items WHERE id = ? AND seller <> ?")) {
ps1.setInt(1, id); //Dummy query, prevents adding to cart self owned items
ps1.setInt(2, c.getPlayer().getId());
try (ResultSet rs1 = ps1.executeQuery()) {
if (rs1.next()) {
PreparedStatement ps = con.prepareStatement("SELECT cid FROM mts_cart WHERE cid = ? AND itemid = ?");
ps.setInt(1, c.getPlayer().getId());
ps.setInt(2, id);
try (ResultSet rs = ps.executeQuery()) {
if (!rs.next()) {
try (PreparedStatement pse = con.prepareStatement("INSERT INTO mts_cart (cid, itemid) VALUES (?, ?)")) {
pse.setInt(1, c.getPlayer().getId());
pse.setInt(2, id);
pse.executeUpdate();
}
}
}
}
}
}
con.close();
} catch (SQLException e) {
e.printStackTrace();
}
c.announce(getMTS(c.getPlayer().getCurrentTab(), c.getPlayer().getCurrentType(), c.getPlayer().getCurrentPage()));
c.enableCSActions();
c.announce(MaplePacketCreator.enableActions());
c.announce(MaplePacketCreator.transferInventory(getTransfer(c.getPlayer().getId())));
c.announce(MaplePacketCreator.notYetSoldInv(getNotYetSold(c.getPlayer().getId())));
} else if (op == 10) { //delete from cart
int id = slea.readInt(); //id of the item
Connection con = null;
try {
con = DatabaseConnection.getConnection();
try (PreparedStatement ps = con.prepareStatement("DELETE FROM mts_cart WHERE itemid = ? AND cid = ?")) {
ps.setInt(1, id);
ps.setInt(2, c.getPlayer().getId());
ps.executeUpdate();
}
con.close();
} catch (SQLException e) {
e.printStackTrace();
}
c.announce(getCart(c.getPlayer().getId()));
c.enableCSActions();
c.announce(MaplePacketCreator.transferInventory(getTransfer(c.getPlayer().getId())));
c.announce(MaplePacketCreator.notYetSoldInv(getNotYetSold(c.getPlayer().getId())));
} else if (op == 12) { //put item up for auction
} else if (op == 13) { //cancel wanted cart thing
} else if (op == 14) { //buy auction item now
} else if (op == 16) { //buy
int id = slea.readInt(); //id of the item
Connection con = null;
PreparedStatement ps;
ResultSet rs;
try {
con = DatabaseConnection.getConnection();
ps = con.prepareStatement("SELECT * FROM mts_items WHERE id = ? ORDER BY id DESC");
ps.setInt(1, id);
rs = ps.executeQuery();
if (rs.next()) {
int price = rs.getInt("price") + 100 + (int) (rs.getInt("price") * 0.1); //taxes
if (c.getPlayer().getCashShop().getCash(4) >= price) { //FIX
boolean alwaysnull = true;
for (Channel cserv : Server.getInstance().getAllChannels()) {
MapleCharacter victim = cserv.getPlayerStorage().getCharacterById(rs.getInt("seller"));
if (victim != null) {
victim.getCashShop().gainCash(4, rs.getInt("price"));
alwaysnull = false;
}
}
if (alwaysnull) {
ResultSet rse;
try (PreparedStatement pse = con.prepareStatement("SELECT accountid FROM characters WHERE id = ?")) {
pse.setInt(1, rs.getInt("seller"));
rse = pse.executeQuery();
if (rse.next()) {
try (PreparedStatement psee = con.prepareStatement("UPDATE accounts SET nxPrepaid = nxPrepaid + ? WHERE id = ?")) {
psee.setInt(1, rs.getInt("price"));
psee.setInt(2, rse.getInt("accountid"));
psee.executeUpdate();
}
}
}
rse.close();
}
PreparedStatement pse = con.prepareStatement("UPDATE mts_items SET seller = ?, transfer = 1 WHERE id = ?");
pse.setInt(1, c.getPlayer().getId());
pse.setInt(2, id);
pse.executeUpdate();
pse.close();
pse = con.prepareStatement("DELETE FROM mts_cart WHERE itemid = ?");
pse.setInt(1, id);
pse.executeUpdate();
pse.close();
c.getPlayer().getCashShop().gainCash(4, -price);
c.enableCSActions();
c.announce(getMTS(c.getPlayer().getCurrentTab(), c.getPlayer().getCurrentType(), c.getPlayer().getCurrentPage()));
c.announce(MaplePacketCreator.MTSConfirmBuy());
c.announce(MaplePacketCreator.showMTSCash(c.getPlayer()));
c.announce(MaplePacketCreator.transferInventory(getTransfer(c.getPlayer().getId())));
c.announce(MaplePacketCreator.notYetSoldInv(getNotYetSold(c.getPlayer().getId())));
c.announce(MaplePacketCreator.enableActions());
} else {
c.announce(MaplePacketCreator.MTSFailBuy());
}
}
rs.close();
ps.close();
con.close();
} catch (SQLException e) {
e.printStackTrace();
c.announce(MaplePacketCreator.MTSFailBuy());
}
} else if (op == 17) { //buy from cart
int id = slea.readInt(); //id of the item
Connection con = null;
PreparedStatement ps;
ResultSet rs;
try {
con = DatabaseConnection.getConnection();
ps = con.prepareStatement("SELECT * FROM mts_items WHERE id = ? ORDER BY id DESC");
ps.setInt(1, id);
rs = ps.executeQuery();
if (rs.next()) {
int price = rs.getInt("price") + 100 + (int) (rs.getInt("price") * 0.1);
if (c.getPlayer().getCashShop().getCash(4) >= price) {
for (Channel cserv : Server.getInstance().getAllChannels()) {
MapleCharacter victim = cserv.getPlayerStorage().getCharacterById(rs.getInt("seller"));
if (victim != null) {
victim.getCashShop().gainCash(4, rs.getInt("price"));
} else {
ResultSet rse;
try (PreparedStatement pse = con.prepareStatement("SELECT accountid FROM characters WHERE id = ?")) {
pse.setInt(1, rs.getInt("seller"));
rse = pse.executeQuery();
if (rse.next()) {
try (PreparedStatement psee = con.prepareStatement("UPDATE accounts SET nxPrepaid = nxPrepaid + ? WHERE id = ?")) {
psee.setInt(1, rs.getInt("price"));
psee.setInt(2, rse.getInt("accountid"));
psee.executeUpdate();
}
}
}
rse.close();
}
}
PreparedStatement pse = con.prepareStatement("UPDATE mts_items SET seller = ?, transfer = 1 WHERE id = ?");
pse.setInt(1, c.getPlayer().getId());
pse.setInt(2, id);
pse.executeUpdate();
pse.close();
pse = con.prepareStatement("DELETE FROM mts_cart WHERE itemid = ?");
pse.setInt(1, id);
pse.executeUpdate();
pse.close();
c.getPlayer().getCashShop().gainCash(4, -price);
c.announce(getCart(c.getPlayer().getId()));
c.enableCSActions();
c.announce(MaplePacketCreator.MTSConfirmBuy());
c.announce(MaplePacketCreator.showMTSCash(c.getPlayer()));
c.announce(MaplePacketCreator.transferInventory(getTransfer(c.getPlayer().getId())));
c.announce(MaplePacketCreator.notYetSoldInv(getNotYetSold(c.getPlayer().getId())));
} else {
c.announce(MaplePacketCreator.MTSFailBuy());
}
}
rs.close();
ps.close();
con.close();
} catch (SQLException e) {
e.printStackTrace();
c.announce(MaplePacketCreator.MTSFailBuy());
}
} else {
System.out.println("Unhandled OP(MTS): " + op + " Packet: " + slea.toString());
}
} else {
c.announce(MaplePacketCreator.showMTSCash(c.getPlayer()));
}
}
public List<MTSItemInfo> getNotYetSold(int cid) {
List<MTSItemInfo> items = new ArrayList<>();
Connection con = null;
PreparedStatement ps;
ResultSet rs;
try {
con = DatabaseConnection.getConnection();
ps = con.prepareStatement("SELECT * FROM mts_items WHERE seller = ? AND transfer = 0 ORDER BY id DESC");
ps.setInt(1, cid);
rs = ps.executeQuery();
while (rs.next()) {
if (rs.getInt("type") != 1) {
Item i = new Item(rs.getInt("itemid"), (byte) 0, (short) rs.getInt("quantity"));
i.setOwner(rs.getString("owner"));
items.add(new MTSItemInfo((Item) i, rs.getInt("price"), rs.getInt("id"), rs.getInt("seller"), rs.getString("sellername"), rs.getString("sell_ends")));
} else {
Equip equip = new Equip(rs.getInt("itemid"), (byte) rs.getInt("position"), -1);
equip.setOwner(rs.getString("owner"));
equip.setQuantity((short) 1);
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.setVicious((short) rs.getInt("vicious"));
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"));
equip.setFlag((short) rs.getInt("flag"));
equip.setItemLevel(rs.getByte("itemlevel"));
equip.setItemExp(rs.getInt("itemexp"));
equip.setRingId(rs.getInt("ringid"));
equip.setExpiration(rs.getLong("expiration"));
equip.setGiftFrom(rs.getString("giftFrom"));
items.add(new MTSItemInfo((Item) equip, rs.getInt("price"), rs.getInt("id"), rs.getInt("seller"), rs.getString("sellername"), rs.getString("sell_ends")));
}
}
rs.close();
ps.close();
con.close();
} catch (SQLException e) {
e.printStackTrace();
}
return items;
}
public byte[] getCart(int cid) {
List<MTSItemInfo> items = new ArrayList<>();
Connection con = null;
PreparedStatement ps;
ResultSet rs;
int pages = 0;
try {
con = DatabaseConnection.getConnection();
ps = con.prepareStatement("SELECT * FROM mts_cart WHERE cid = ? ORDER BY id DESC");
ps.setInt(1, cid);
rs = ps.executeQuery();
while (rs.next()) {
try (PreparedStatement pse = con.prepareStatement("SELECT * FROM mts_items WHERE id = ?")) {
pse.setInt(1, rs.getInt("itemid"));
ResultSet rse = pse.executeQuery();
if (rse.next()) {
if (rse.getInt("type") != 1) {
Item i = new Item(rse.getInt("itemid"), (short) 0, (short) rse.getInt("quantity"));
i.setOwner(rse.getString("owner"));
items.add(new MTSItemInfo((Item) i, rse.getInt("price"), rse.getInt("id"), rse.getInt("seller"), rse.getString("sellername"), rse.getString("sell_ends")));
} else {
Equip equip = new Equip(rse.getInt("itemid"), (byte) rse.getInt("position"), -1);
equip.setOwner(rse.getString("owner"));
equip.setQuantity((short) 1);
equip.setAcc((short) rse.getInt("acc"));
equip.setAvoid((short) rse.getInt("avoid"));
equip.setDex((short) rse.getInt("dex"));
equip.setHands((short) rse.getInt("hands"));
equip.setHp((short) rse.getInt("hp"));
equip.setInt((short) rse.getInt("int"));
equip.setJump((short) rse.getInt("jump"));
equip.setVicious((short) rse.getInt("vicious"));
equip.setLuk((short) rse.getInt("luk"));
equip.setMatk((short) rse.getInt("matk"));
equip.setMdef((short) rse.getInt("mdef"));
equip.setMp((short) rse.getInt("mp"));
equip.setSpeed((short) rse.getInt("speed"));
equip.setStr((short) rse.getInt("str"));
equip.setWatk((short) rse.getInt("watk"));
equip.setWdef((short) rse.getInt("wdef"));
equip.setUpgradeSlots((byte) rse.getInt("upgradeslots"));
equip.setLevel((byte) rse.getInt("level"));
equip.setItemLevel(rs.getByte("itemlevel"));
equip.setItemExp(rs.getInt("itemexp"));
equip.setRingId(rs.getInt("ringid"));
equip.setFlag((short) rs.getInt("flag"));
equip.setExpiration(rs.getLong("expiration"));
equip.setGiftFrom(rs.getString("giftFrom"));
items.add(new MTSItemInfo((Item) equip, rse.getInt("price"), rse.getInt("id"), rse.getInt("seller"), rse.getString("sellername"), rse.getString("sell_ends")));
}
}
}
}
rs.close();
ps.close();
ps = con.prepareStatement("SELECT COUNT(*) FROM mts_cart WHERE cid = ?");
ps.setInt(1, cid);
rs = ps.executeQuery();
if (rs.next()) {
pages = rs.getInt(1) / 16;
if (rs.getInt(1) % 16 > 0) {
pages += 1;
}
}
rs.close();
ps.close();
con.close();
} catch (SQLException e) {
e.printStackTrace();
}
return MaplePacketCreator.sendMTS(items, 4, 0, 0, pages);
}
public List<MTSItemInfo> getTransfer(int cid) {
List<MTSItemInfo> items = new ArrayList<>();
Connection con = null;
PreparedStatement ps;
ResultSet rs;
try {
con = DatabaseConnection.getConnection();
ps = con.prepareStatement("SELECT * FROM mts_items WHERE transfer = 1 AND seller = ? ORDER BY id DESC");
ps.setInt(1, cid);
rs = ps.executeQuery();
while (rs.next()) {
if (rs.getInt("type") != 1) {
Item i = new Item(rs.getInt("itemid"), (short) 0, (short) rs.getInt("quantity"));
i.setOwner(rs.getString("owner"));
items.add(new MTSItemInfo((Item) i, rs.getInt("price"), rs.getInt("id"), rs.getInt("seller"), rs.getString("sellername"), rs.getString("sell_ends")));
} else {
Equip equip = new Equip(rs.getInt("itemid"), (byte) rs.getInt("position"), -1);
equip.setOwner(rs.getString("owner"));
equip.setQuantity((short) 1);
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.setVicious((short) rs.getInt("vicious"));
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"));
equip.setItemLevel(rs.getByte("itemlevel"));
equip.setItemExp(rs.getInt("itemexp"));
equip.setRingId(rs.getInt("ringid"));
equip.setFlag((short) rs.getInt("flag"));
equip.setExpiration(rs.getLong("expiration"));
equip.setGiftFrom(rs.getString("giftFrom"));
items.add(new MTSItemInfo((Item) equip, rs.getInt("price"), rs.getInt("id"), rs.getInt("seller"), rs.getString("sellername"), rs.getString("sell_ends")));
}
}
rs.close();
ps.close();
con.close();
} catch (SQLException e) {
e.printStackTrace();
}
return items;
}
private static byte[] getMTS(int tab, int type, int page) {
List<MTSItemInfo> items = new ArrayList<>();
Connection con = null;
PreparedStatement ps;
ResultSet rs;
int pages = 0;
try {
con = DatabaseConnection.getConnection();
if (type != 0) {
ps = con.prepareStatement("SELECT * FROM mts_items WHERE tab = ? AND type = ? AND transfer = 0 ORDER BY id DESC LIMIT ?, 16");
} else {
ps = con.prepareStatement("SELECT * FROM mts_items WHERE tab = ? AND transfer = 0 ORDER BY id DESC LIMIT ?, 16");
}
ps.setInt(1, tab);
if (type != 0) {
ps.setInt(2, type);
ps.setInt(3, page * 16);
} else {
ps.setInt(2, page * 16);
}
rs = ps.executeQuery();
while (rs.next()) {
if (rs.getInt("type") != 1) {
Item i = new Item(rs.getInt("itemid"), (short) 0, (short) rs.getInt("quantity"));
i.setOwner(rs.getString("owner"));
items.add(new MTSItemInfo((Item) i, rs.getInt("price"), rs.getInt("id"), rs.getInt("seller"), rs.getString("sellername"), rs.getString("sell_ends")));
} else {
Equip equip = new Equip(rs.getInt("itemid"), (byte) rs.getInt("position"), -1);
equip.setOwner(rs.getString("owner"));
equip.setQuantity((short) 1);
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.setVicious((short) rs.getInt("vicious"));
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"));
equip.setItemLevel(rs.getByte("itemlevel"));
equip.setItemExp(rs.getInt("itemexp"));
equip.setRingId(rs.getInt("ringid"));
equip.setFlag((short) rs.getInt("flag"));
equip.setExpiration(rs.getLong("expiration"));
equip.setGiftFrom(rs.getString("giftFrom"));
items.add(new MTSItemInfo((Item) equip, rs.getInt("price"), rs.getInt("id"), rs.getInt("seller"), rs.getString("sellername"), rs.getString("sell_ends")));
}
}
rs.close();
ps.close();
ps = con.prepareStatement("SELECT COUNT(*) FROM mts_items WHERE tab = ? " + (type != 0 ? "AND type = ?" : "") + "AND transfer = 0");
ps.setInt(1, tab);
if (type != 0) {
ps.setInt(2, type);
}
rs = ps.executeQuery();
if (rs.next()) {
pages = rs.getInt(1) / 16;
if (rs.getInt(1) % 16 > 0) {
pages++;
}
}
rs.close();
ps.close();
con.close();
} catch (SQLException e) {
e.printStackTrace();
}
return MaplePacketCreator.sendMTS(items, tab, type, page, pages); // resniff
}
public byte[] getMTSSearch(int tab, int type, int cOi, String search, int page) {
List<MTSItemInfo> items = new ArrayList<>();
MapleItemInformationProvider ii = MapleItemInformationProvider.getInstance();
String listaitems = "";
if (cOi != 0) {
List<String> retItems = new ArrayList<>();
for (Pair<Integer, String> itemPair : ii.getAllItems()) {
if (itemPair.getRight().toLowerCase().contains(search.toLowerCase())) {
retItems.add(" itemid=" + itemPair.getLeft() + " OR ");
}
}
listaitems += " AND (";
if (retItems != null && retItems.size() > 0) {
for (String singleRetItem : retItems) {
listaitems += singleRetItem;
}
listaitems += " itemid=0 )";
}
} else {
listaitems = " AND sellername LIKE CONCAT('%','" + search + "', '%')";
}
Connection con = null;
PreparedStatement ps;
ResultSet rs;
int pages = 0;
try {
con = DatabaseConnection.getConnection();
if (type != 0) {
ps = con.prepareStatement("SELECT * FROM mts_items WHERE tab = ? " + listaitems + " AND type = ? AND transfer = 0 ORDER BY id DESC LIMIT ?, 16");
} else {
ps = con.prepareStatement("SELECT * FROM mts_items WHERE tab = ? " + listaitems + " AND transfer = 0 ORDER BY id DESC LIMIT ?, 16");
}
ps.setInt(1, tab);
if (type != 0) {
ps.setInt(2, type);
ps.setInt(3, page * 16);
} else {
ps.setInt(2, page * 16);
}
rs = ps.executeQuery();
while (rs.next()) {
if (rs.getInt("type") != 1) {
Item i = new Item(rs.getInt("itemid"), (short) 0, (short) rs.getInt("quantity"));
i.setOwner(rs.getString("owner"));
items.add(new MTSItemInfo((Item) i, rs.getInt("price"), rs.getInt("id"), rs.getInt("seller"), rs.getString("sellername"), rs.getString("sell_ends")));
} else {
Equip equip = new Equip(rs.getInt("itemid"), (byte) rs.getInt("position"), -1);
equip.setOwner(rs.getString("owner"));
equip.setQuantity((short) 1);
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.setVicious((short) rs.getInt("vicious"));
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"));
equip.setItemLevel(rs.getByte("itemlevel"));
equip.setItemExp(rs.getInt("itemexp"));
equip.setRingId(rs.getInt("ringid"));
equip.setFlag((short) rs.getInt("flag"));
equip.setExpiration(rs.getLong("expiration"));
equip.setGiftFrom(rs.getString("giftFrom"));
items.add(new MTSItemInfo((Item) equip, rs.getInt("price"), rs.getInt("id"), rs.getInt("seller"), rs.getString("sellername"), rs.getString("sell_ends")));
}
}
rs.close();
ps.close();
if (type == 0) {
ps = con.prepareStatement("SELECT COUNT(*) FROM mts_items WHERE tab = ? " + listaitems + " AND transfer = 0");
ps.setInt(1, tab);
if (type != 0) {
ps.setInt(2, type);
}
rs = ps.executeQuery();
if (rs.next()) {
pages = rs.getInt(1) / 16;
if (rs.getInt(1) % 16 > 0) {
pages++;
}
}
rs.close();
ps.close();
}
con.close();
} catch (SQLException e) {
e.printStackTrace();
}
return MaplePacketCreator.sendMTS(items, tab, type, page, pages);
}
}

View File

@@ -0,0 +1,89 @@
/*
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 as
published by the Free Software Foundation 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.server.channel.handlers;
import client.MapleBuffStat;
import client.MapleCharacter;
import client.MapleClient;
import client.Skill;
import client.SkillFactory;
import config.YamlConfig;
import constants.game.GameConstants;
import constants.skills.Bishop;
import constants.skills.Evan;
import constants.skills.FPArchMage;
import constants.skills.ILArchMage;
import server.MapleStatEffect;
import tools.MaplePacketCreator;
import tools.data.input.SeekableLittleEndianAccessor;
public final class MagicDamageHandler extends AbstractDealDamageHandler {
@Override
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
MapleCharacter chr = c.getPlayer();
/*long timeElapsed = currentServerTime() - chr.getAutobanManager().getLastSpam(8);
if(timeElapsed < 300) {
AutobanFactory.FAST_ATTACK.alert(chr, "Time: " + timeElapsed);
}
chr.getAutobanManager().spam(8);*/
AttackInfo attack = parseDamage(slea, chr, false, true);
if (chr.getBuffEffect(MapleBuffStat.MORPH) != null) {
if(chr.getBuffEffect(MapleBuffStat.MORPH).isMorphWithoutAttack()) {
// How are they attacking when the client won't let them?
chr.getClient().disconnect(false, false);
return;
}
}
if (GameConstants.isDojo(chr.getMap().getId()) && attack.numAttacked > 0) {
chr.setDojoEnergy(chr.getDojoEnergy() + + YamlConfig.config.server.DOJO_ENERGY_ATK);
c.announce(MaplePacketCreator.getEnergy("energy", chr.getDojoEnergy()));
}
int charge = (attack.skill == Evan.FIRE_BREATH || attack.skill == Evan.ICE_BREATH || attack.skill == FPArchMage.BIG_BANG || attack.skill == ILArchMage.BIG_BANG || attack.skill == Bishop.BIG_BANG) ? attack.charge : -1;
byte[] packet = MaplePacketCreator.magicAttack(chr, attack.skill, attack.skilllevel, attack.stance, attack.numAttackedAndDamage, attack.allDamage, charge, attack.speed, attack.direction, attack.display);
chr.getMap().broadcastMessage(chr, packet, false, true);
MapleStatEffect effect = attack.getAttackEffect(chr, null);
Skill skill = SkillFactory.getSkill(attack.skill);
MapleStatEffect effect_ = skill.getEffect(chr.getSkillLevel(skill));
if (effect_.getCooldown() > 0) {
if (chr.skillIsCooling(attack.skill)) {
return;
} else {
c.announce(MaplePacketCreator.skillCooldown(attack.skill, effect_.getCooldown()));
chr.addCooldown(attack.skill, currentServerTime(), effect_.getCooldown() * 1000);
}
}
applyAttack(attack, chr, effect.getAttackCount());
Skill eaterSkill = SkillFactory.getSkill((chr.getJob().getId() - (chr.getJob().getId() % 10)) * 10000);// MP Eater, works with right job
int eaterLevel = chr.getSkillLevel(eaterSkill);
if (eaterLevel > 0) {
for (Integer singleDamage : attack.allDamage.keySet()) {
eaterSkill.getEffect(eaterLevel).applyPassive(chr, chr.getMap().getMapObject(singleDamage), 0);
}
}
}
}

View File

@@ -0,0 +1,39 @@
/*
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 as
published by the Free Software Foundation 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.server.channel.handlers;
import client.MapleClient;
import client.processor.action.MakerProcessor;
import net.AbstractMaplePacketHandler;
import tools.data.input.SeekableLittleEndianAccessor;
/**
*
* @author Jay Estrella, Ronan
*/
public final class MakerSkillHandler extends AbstractMaplePacketHandler {
@Override
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
MakerProcessor.makerAction(slea, c);
}
}

View File

@@ -0,0 +1,68 @@
/*
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 as
published by the Free Software Foundation 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.server.channel.handlers;
import net.AbstractMaplePacketHandler;
import tools.MaplePacketCreator;
import tools.data.input.SeekableLittleEndianAccessor;
import client.MapleCharacter;
import client.MapleClient;
/**
*
* @author Matze
* @author Ronan - concurrency protection
*/
public final class MesoDropHandler extends AbstractMaplePacketHandler {
@Override
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
MapleCharacter player = c.getPlayer();
if (!player.isAlive()) {
c.announce(MaplePacketCreator.enableActions());
return;
}
slea.skip(4);
int meso = slea.readInt();
if (c.tryacquireClient()) { // thanks imbee for noticing players not being able to throw mesos too fast
try {
if (meso <= player.getMeso() && meso > 9 && meso < 50001) {
player.gainMeso(-meso, false, true, false);
} else {
c.announce(MaplePacketCreator.enableActions());
return;
}
} finally {
c.releaseClient();
}
} else {
c.announce(MaplePacketCreator.enableActions());
return;
}
if (player.attemptCatchFish(meso)) {
player.getMap().disappearingMesoDrop(meso, player, player, player.getPosition());
} else {
player.getMap().spawnMesoDrop(meso, player.getPosition(), player, player, true, (byte) 2);
}
}
}

View File

@@ -0,0 +1,128 @@
/*
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 as
published by the Free Software Foundation 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.server.channel.handlers;
import client.MapleCharacter;
import client.MapleClient;
import net.AbstractMaplePacketHandler;
import net.server.coordinator.world.MapleInviteCoordinator;
import net.server.coordinator.world.MapleInviteCoordinator.InviteResult;
import net.server.coordinator.world.MapleInviteCoordinator.InviteType;
import net.server.coordinator.world.MapleInviteCoordinator.MapleInviteResult;
import net.server.world.MapleMessenger;
import net.server.world.MapleMessengerCharacter;
import net.server.world.World;
import tools.MaplePacketCreator;
import tools.data.input.SeekableLittleEndianAccessor;
public final class MessengerHandler extends AbstractMaplePacketHandler {
@Override
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
if (c.tryacquireClient()) {
try {
String input;
byte mode = slea.readByte();
MapleCharacter player = c.getPlayer();
World world = c.getWorldServer();
MapleMessenger messenger = player.getMessenger();
switch (mode) {
case 0x00:
int messengerid = slea.readInt();
if (messenger == null) {
if (messengerid == 0) {
MapleInviteCoordinator.removeInvite(InviteType.MESSENGER, player.getId());
MapleMessengerCharacter messengerplayer = new MapleMessengerCharacter(player, 0);
messenger = world.createMessenger(messengerplayer);
player.setMessenger(messenger);
player.setMessengerPosition(0);
} else {
messenger = world.getMessenger(messengerid);
if (messenger != null) {
MapleInviteResult inviteRes = MapleInviteCoordinator.answerInvite(InviteType.MESSENGER, player.getId(), messengerid, true);
InviteResult res = inviteRes.result;
if (res == InviteResult.ACCEPTED) {
int position = messenger.getLowestPosition();
MapleMessengerCharacter messengerplayer = new MapleMessengerCharacter(player, position);
if (messenger.getMembers().size() < 3) {
player.setMessenger(messenger);
player.setMessengerPosition(position);
world.joinMessenger(messenger.getId(), messengerplayer, player.getName(), messengerplayer.getChannel());
}
} else {
player.message("Could not verify your Maple Messenger accept since the invitation rescinded.");
}
}
}
} else {
MapleInviteCoordinator.answerInvite(InviteType.MESSENGER, player.getId(), messengerid, false);
}
break;
case 0x02:
player.closePlayerMessenger();
break;
case 0x03:
if (messenger == null) {
c.announce(MaplePacketCreator.messengerChat(player.getName() + " : This Maple Messenger is currently unavailable. Please quit this chat."));
} else if (messenger.getMembers().size() < 3) {
input = slea.readMapleAsciiString();
MapleCharacter target = c.getChannelServer().getPlayerStorage().getCharacterByName(input);
if (target != null) {
if (target.getMessenger() == null) {
if (MapleInviteCoordinator.createInvite(InviteType.MESSENGER, c.getPlayer(), messenger.getId(), target.getId())) {
target.getClient().announce(MaplePacketCreator.messengerInvite(c.getPlayer().getName(), messenger.getId()));
c.announce(MaplePacketCreator.messengerNote(input, 4, 1));
} else {
c.announce(MaplePacketCreator.messengerChat(player.getName() + " : " + input + " is already managing a Maple Messenger invitation"));
}
} else {
c.announce(MaplePacketCreator.messengerChat(player.getName() + " : " + input + " is already using Maple Messenger"));
}
} else {
if (world.find(input) > -1) {
world.messengerInvite(c.getPlayer().getName(), messenger.getId(), input, c.getChannel());
} else {
c.announce(MaplePacketCreator.messengerNote(input, 4, 0));
}
}
} else {
c.announce(MaplePacketCreator.messengerChat(player.getName() + " : You cannot have more than 3 people in the Maple Messenger"));
}
break;
case 0x05:
String targeted = slea.readMapleAsciiString();
world.declineChat(targeted, player);
break;
case 0x06:
if (messenger != null) {
MapleMessengerCharacter messengerplayer = new MapleMessengerCharacter(player, player.getMessengerPosition());
input = slea.readMapleAsciiString();
world.messengerChat(messenger, input, messengerplayer.getName());
}
break;
}
} finally {
c.releaseClient();
}
}
}
}

View File

@@ -0,0 +1,45 @@
/*
This file is part of the HeavenMS MapleStory Server
Copyleft (L) 2016 - 2019 RonanLana
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation 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.server.channel.handlers;
import client.MapleCharacter;
import client.MapleClient;
import server.life.MapleMonster;
import server.life.MapleLifeFactory.BanishInfo;
import net.AbstractMaplePacketHandler;
import tools.data.input.SeekableLittleEndianAccessor;
public final class MobBanishPlayerHandler extends AbstractMaplePacketHandler {
@Override
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
int mobid = slea.readInt(); // mob banish handling detected thanks to MedicOP
MapleCharacter chr = c.getPlayer();
MapleMonster mob = chr.getMap().getMonsterById(mobid);
if (mob != null) {
BanishInfo banishInfo = mob.getBanish();
if (banishInfo != null) {
chr.changeMapBanish(banishInfo.getMap(), banishInfo.getPortal(), banishInfo.getMsg());
}
}
}
}

View File

@@ -0,0 +1,89 @@
/*
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 as
published by the Free Software Foundation 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.server.channel.handlers;
import net.AbstractMaplePacketHandler;
import scripting.event.EventInstanceManager;
import server.life.MapleMonster;
import server.maps.MapleMap;
import tools.MaplePacketCreator;
import tools.Randomizer;
import tools.data.input.SeekableLittleEndianAccessor;
import client.MapleClient;
/**
*
* @author Xotic (XoticStory) & BubblesDev
*/
public final class MobDamageMobFriendlyHandler extends AbstractMaplePacketHandler {
@Override
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
int attacker = slea.readInt();
slea.readInt();
int damaged = slea.readInt();
MapleMap map = c.getPlayer().getMap();
MapleMonster monster = map.getMonsterByOid(damaged);
if (monster == null || map.getMonsterByOid(attacker) == null) {
return;
}
int damage = Randomizer.nextInt(((monster.getMaxHp() / 13 + monster.getPADamage() * 10)) * 2 + 500) / 10; // Formula planned by Beng.
if (monster.getHp() - damage < 1) { // friendly dies
if(monster.getId() == 9300102) {
map.broadcastMessage(MaplePacketCreator.serverNotice(6, "The Watch Hog has been injured by the aliens. Better luck next time..."));
} else if (monster.getId() == 9300061) { //moon bunny
map.broadcastMessage(MaplePacketCreator.serverNotice(6, "The Moon Bunny went home because he was sick."));
} else if(monster.getId() == 9300093) { //tylus
map.broadcastMessage(MaplePacketCreator.serverNotice(6, "Tylus has fallen by the overwhelming forces of the ambush."));
} else if(monster.getId() == 9300137) { //juliet
map.broadcastMessage(MaplePacketCreator.serverNotice(6, "Juliet has fainted in the middle of the combat."));
} else if(monster.getId() == 9300138) { //romeo
map.broadcastMessage(MaplePacketCreator.serverNotice(6, "Romeo has fainted in the middle of the combat."));
} else if(monster.getId() == 9400322 || monster.getId() == 9400327 || monster.getId() == 9400332) { //snowman
map.broadcastMessage(MaplePacketCreator.serverNotice(6, "The Snowman has melted on the heat of the battle."));
} else if(monster.getId() == 9300162) { //delli
map.broadcastMessage(MaplePacketCreator.serverNotice(6, "Delli vanished after the ambush, sheets still laying on the ground..."));
}
map.killFriendlies(monster);
} else {
EventInstanceManager eim = map.getEventInstance();
if (eim != null) {
eim.friendlyDamaged(monster);
}
}
monster.applyAndGetHpDamage(damage, false);
int remainingHp = monster.getHp();
if(remainingHp <= 0) {
remainingHp = 0;
map.removeMapObject(monster);
}
map.broadcastMessage(MaplePacketCreator.MobDamageMobFriendly(monster, damage, remainingHp), monster.getPosition());
c.announce(MaplePacketCreator.enableActions());
}
}

View File

@@ -0,0 +1,114 @@
/*
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 as
published by the Free Software Foundation 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.server.channel.handlers;
import java.util.Map;
import client.MapleClient;
import client.MapleCharacter;
import client.autoban.AutobanFactory;
import client.status.MonsterStatus;
import client.status.MonsterStatusEffect;
import net.AbstractMaplePacketHandler;
import server.life.MapleMonster;
import server.life.MapleMonsterInformationProvider;
import server.maps.MapleMap;
import tools.FilePrinter;
import tools.MaplePacketCreator;
import tools.data.input.SeekableLittleEndianAccessor;
/**
*
* @author Jay Estrella
* @author Ronan
*/
public final class MobDamageMobHandler extends AbstractMaplePacketHandler {
@Override
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
int from = slea.readInt();
slea.readInt();
int to = slea.readInt();
boolean magic = slea.readByte() == 0;
int dmg = slea.readInt();
MapleCharacter chr = c.getPlayer();
MapleMap map = chr.getMap();
MapleMonster attacker = map.getMonsterByOid(from);
MapleMonster damaged = map.getMonsterByOid(to);
if (attacker != null && damaged != null) {
int maxDmg = calcMaxDamage(attacker, damaged, magic); // thanks Darter (YungMoozi) for reporting unchecked dmg
if (dmg > maxDmg) {
AutobanFactory.DAMAGE_HACK.alert(c.getPlayer(), "Possible packet editing hypnotize damage exploit."); // thanks Rien dev team
FilePrinter.printError(FilePrinter.EXPLOITS + c.getPlayer().getName() + ".txt", c.getPlayer().getName() + " had hypnotized " + MapleMonsterInformationProvider.getInstance().getMobNameFromId(attacker.getId()) + " to attack " + MapleMonsterInformationProvider.getInstance().getMobNameFromId(damaged.getId()) + " with damage " + dmg + " (max: " + maxDmg + ")");
dmg = maxDmg;
}
map.damageMonster(chr, damaged, dmg);
map.broadcastMessage(chr, MaplePacketCreator.damageMonster(to, dmg), false);
}
}
private static int calcMaxDamage(MapleMonster attacker, MapleMonster damaged, boolean magic) {
int attackerAtk, damagedDef, attackerLevel = attacker.getLevel();
double maxDamage;
if (magic) {
int atkRate = calcModifier(attacker, MonsterStatus.MAGIC_ATTACK_UP, MonsterStatus.MATK);
attackerAtk = (attacker.getStats().getMADamage() * atkRate) / 100;
int defRate = calcModifier(damaged, MonsterStatus.MAGIC_DEFENSE_UP, MonsterStatus.MDEF);
damagedDef = (damaged.getStats().getMDDamage() * defRate) / 100;
maxDamage = ((attackerAtk * (1.15 + (0.025 * attackerLevel))) - (0.75 * damagedDef)) * (Math.log(Math.abs(damagedDef - attackerAtk)) / Math.log(12));
} else {
int atkRate = calcModifier(attacker, MonsterStatus.WEAPON_ATTACK_UP, MonsterStatus.WATK);
attackerAtk = (attacker.getStats().getPADamage() * atkRate) / 100;
int defRate = calcModifier(damaged, MonsterStatus.WEAPON_DEFENSE_UP, MonsterStatus.WDEF);
damagedDef = (damaged.getStats().getPDDamage() * defRate) / 100;
maxDamage = ((attackerAtk * (1.15 + (0.025 * attackerLevel))) - (0.75 * damagedDef)) * (Math.log(Math.abs(damagedDef - attackerAtk)) / Math.log(17));
}
return (int) maxDamage;
}
private static int calcModifier(MapleMonster monster, MonsterStatus buff, MonsterStatus nerf) {
int atkModifier;
final Map<MonsterStatus, MonsterStatusEffect> monsterStati = monster.getStati();
MonsterStatusEffect atkBuff = monsterStati.get(buff);
if (atkBuff != null) {
atkModifier = atkBuff.getStati().get(buff);
} else {
atkModifier = 100;
}
MonsterStatusEffect atkNerf = monsterStati.get(nerf);
if (atkNerf != null) {
atkModifier -= atkNerf.getStati().get(nerf);
}
return atkModifier;
}
}

View File

@@ -0,0 +1,43 @@
/*
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 as
published by the Free Software Foundation 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.server.channel.handlers;
import client.MapleClient;
import net.AbstractMaplePacketHandler;
import server.life.MapleMonster;
import tools.MaplePacketCreator;
import tools.data.input.SeekableLittleEndianAccessor;
public final class MonsterBombHandler extends AbstractMaplePacketHandler {
@Override
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
int oid = slea.readInt();
MapleMonster monster = c.getPlayer().getMap().getMonsterByOid(oid);
if (!c.getPlayer().isAlive() || monster == null) {
return;
}
if (monster.getId() == 8500003 || monster.getId() == 8500004) {
monster.getMap().broadcastMessage(MaplePacketCreator.killMonster(monster.getObjectId(), 4));
c.getPlayer().getMap().removeMapObject(oid);
}
}
}

View File

@@ -0,0 +1,37 @@
/*
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 as
published by the Free Software Foundation 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.server.channel.handlers;
import client.MapleClient;
import net.AbstractMaplePacketHandler;
import tools.data.input.SeekableLittleEndianAccessor;
import tools.MaplePacketCreator;
public final class MonsterBookCoverHandler extends AbstractMaplePacketHandler {
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
int id = slea.readInt();
if (id == 0 || id / 10000 == 238) {
c.getPlayer().setMonsterBookCover(id);
c.announce(MaplePacketCreator.changeCover(id));
}
}
}

View File

@@ -0,0 +1,181 @@
/*
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 as
published by the Free Software Foundation 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.server.channel.handlers;
import client.MapleCharacter;
import client.MapleClient;
import client.MapleDisease;
import java.awt.Point;
import java.util.List;
import net.AbstractMaplePacketHandler;
import net.server.world.MapleParty;
import net.server.world.MaplePartyCharacter;
import server.life.MapleLifeFactory;
import server.life.MapleMonster;
import server.partyquest.MapleCarnivalFactory;
import server.partyquest.MapleCarnivalFactory.MCSkill;
import server.partyquest.MonsterCarnival;
import tools.MaplePacketCreator;
import tools.Pair;
import tools.data.input.SeekableLittleEndianAccessor;
/**
*@author Drago (Dragohe4rt)
*/
public final class MonsterCarnivalHandler extends AbstractMaplePacketHandler {
@Override
public void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
if (c.tryacquireClient()) {
try {
try {
int tab = slea.readByte();
int num = slea.readByte();
int neededCP = 0;
if (tab == 0) {
final List<Pair<Integer, Integer>> mobs = c.getPlayer().getMap().getMobsToSpawn();
if (num >= mobs.size() || c.getPlayer().getCP() < mobs.get(num).right) {
c.announce(MaplePacketCreator.CPQMessage((byte) 1));
c.announce(MaplePacketCreator.enableActions());
return;
}
final MapleMonster mob = MapleLifeFactory.getMonster(mobs.get(num).left);
MonsterCarnival mcpq = c.getPlayer().getMonsterCarnival();
if (mcpq != null) {
if (!mcpq.canSummonR() && c.getPlayer().getTeam() == 0 || !mcpq.canSummonB() && c.getPlayer().getTeam() == 1) {
c.announce(MaplePacketCreator.CPQMessage((byte) 2));
c.announce(MaplePacketCreator.enableActions());
return;
}
if (c.getPlayer().getTeam() == 0) {
mcpq.summonR();
} else {
mcpq.summonB();
}
Point spawnPos = c.getPlayer().getMap().getRandomSP(c.getPlayer().getTeam());
mob.setPosition(spawnPos);
c.getPlayer().getMap().addMonsterSpawn(mob, 1, c.getPlayer().getTeam());
c.getPlayer().getMap().addAllMonsterSpawn(mob, 1, c.getPlayer().getTeam());
c.announce(MaplePacketCreator.enableActions());
}
neededCP = mobs.get(num).right;
} else if (tab == 1) { //debuffs
final List<Integer> skillid = c.getPlayer().getMap().getSkillIds();
if (num >= skillid.size()) {
c.getPlayer().dropMessage(5, "An unexpected error has occurred.");
c.announce(MaplePacketCreator.enableActions());
return;
}
final MCSkill skill = MapleCarnivalFactory.getInstance().getSkill(skillid.get(num)); //ugh wtf
if (skill == null || c.getPlayer().getCP() < skill.cpLoss) {
c.announce(MaplePacketCreator.CPQMessage((byte) 1));
c.announce(MaplePacketCreator.enableActions());
return;
}
final MapleDisease dis = skill.getDisease();
MapleParty enemies = c.getPlayer().getParty().getEnemy();
if (skill.targetsAll) {
int hitChance = 0;
if (dis.getDisease() == 121 || dis.getDisease() == 122 || dis.getDisease() == 125 || dis.getDisease() == 126) {
hitChance = (int) (Math.random() * 100);
}
if (hitChance <= 80) {
for (MaplePartyCharacter mpc : enemies.getPartyMembers()) {
MapleCharacter mc = mpc.getPlayer();
if (mc != null) {
if (dis == null) {
mc.dispel();
} else {
mc.giveDebuff(dis, skill.getSkill());
}
}
}
}
} else {
int amount = enemies.getMembers().size() - 1;
int randd = (int) Math.floor(Math.random() * amount);
MapleCharacter chrApp = c.getPlayer().getMap().getCharacterById(enemies.getMemberByPos(randd).getId());
if (chrApp != null && chrApp.getMap().isCPQMap()) {
if (dis == null) {
chrApp.dispel();
} else {
chrApp.giveDebuff(dis, skill.getSkill());
}
}
}
neededCP = skill.cpLoss;
c.announce(MaplePacketCreator.enableActions());
} else if (tab == 2) { //protectors
final MCSkill skill = MapleCarnivalFactory.getInstance().getGuardian(num);
if (skill == null || c.getPlayer().getCP() < skill.cpLoss) {
c.announce(MaplePacketCreator.CPQMessage((byte) 1));
c.announce(MaplePacketCreator.enableActions());
return;
}
MonsterCarnival mcpq = c.getPlayer().getMonsterCarnival();
if (mcpq != null) {
if (!mcpq.canGuardianR() && c.getPlayer().getTeam() == 0 || !mcpq.canGuardianB() && c.getPlayer().getTeam() == 1) {
c.announce(MaplePacketCreator.CPQMessage((byte) 2));
c.announce(MaplePacketCreator.enableActions());
return;
}
int success = c.getPlayer().getMap().spawnGuardian(c.getPlayer().getTeam(), num);
if (success != 1) {
switch (success) {
case -1:
c.announce(MaplePacketCreator.CPQMessage((byte) 3));
break;
case 0:
c.announce(MaplePacketCreator.CPQMessage((byte) 4));
break;
default:
c.announce(MaplePacketCreator.CPQMessage((byte) 3));
}
c.announce(MaplePacketCreator.enableActions());
return;
} else {
neededCP = skill.cpLoss;
}
}
}
c.getPlayer().gainCP(-neededCP);
c.getPlayer().getMap().broadcastMessage(MaplePacketCreator.playerSummoned(c.getPlayer().getName(), tab, num));
}catch (Exception e) {
e.printStackTrace();
}
} finally {
c.releaseClient();
}
}
}
}

View File

@@ -0,0 +1,55 @@
/*
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 as
published by the Free Software Foundation 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.server.channel.handlers;
import java.awt.Point;
import client.MapleCharacter;
import client.MapleClient;
import server.maps.MapleDragon;
import tools.MaplePacketCreator;
import tools.data.input.SeekableLittleEndianAccessor;
import tools.exceptions.EmptyMovementException;
public class MoveDragonHandler extends AbstractMovementPacketHandler {
@Override
public void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
final MapleCharacter chr = c.getPlayer();
final Point startPos = new Point(slea.readShort(), slea.readShort());
final MapleDragon dragon = chr.getDragon();
if (dragon != null) {
try {
long movementDataStart = slea.getPosition();
updatePosition(slea, dragon, 0);
long movementDataLength = slea.getPosition() - movementDataStart; //how many bytes were read by updatePosition
slea.seek(movementDataStart);
if (chr.isHidden()) {
chr.getMap().broadcastGMMessage(chr, MaplePacketCreator.moveDragon(dragon, startPos, slea, movementDataLength));
} else {
chr.getMap().broadcastMessage(chr, MaplePacketCreator.moveDragon(dragon, startPos, slea, movementDataLength), dragon.getPosition());
}
} catch (EmptyMovementException e) {}
}
}
}

View File

@@ -0,0 +1,186 @@
/*
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 as
published by the Free Software Foundation 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.server.channel.handlers;
import client.MapleCharacter;
import client.MapleClient;
import java.awt.Point;
import java.util.LinkedList;
import java.util.List;
import config.YamlConfig;
import server.life.MapleMonster;
import server.life.MapleMonsterInformationProvider;
//import server.life.MobAttackInfo;
//import server.life.MobAttackInfoFactory;
import server.life.MobSkill;
import server.life.MobSkillFactory;
import server.maps.MapleMap;
import server.maps.MapleMapObject;
import server.maps.MapleMapObjectType;
import tools.MaplePacketCreator;
import tools.Pair;
import tools.Randomizer;
import tools.data.input.SeekableLittleEndianAccessor;
import tools.exceptions.EmptyMovementException;
/**
* @author Danny (Leifde)
* @author ExtremeDevilz
* @author Ronan (HeavenMS)
*/
public final class MoveLifeHandler extends AbstractMovementPacketHandler {
@Override
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
MapleCharacter player = c.getPlayer();
MapleMap map = player.getMap();
if (player.isChangingMaps()) { // thanks Lame for noticing mob movement shuffle (mob OID on different maps) happening on map transitions
return;
}
int objectid = slea.readInt();
short moveid = slea.readShort();
MapleMapObject mmo = map.getMapObject(objectid);
if (mmo == null || mmo.getType() != MapleMapObjectType.MONSTER) {
return;
}
MapleMonster monster = (MapleMonster) mmo;
List<MapleCharacter> banishPlayers = null;
byte pNibbles = slea.readByte();
byte rawActivity = slea.readByte();
int skillId = slea.readByte() & 0xff;
int skillLv = slea.readByte() & 0xff;
short pOption = slea.readShort();
slea.skip(8);
if (rawActivity >= 0) {
rawActivity = (byte) (rawActivity & 0xFF >> 1);
}
boolean isAttack = inRangeInclusive(rawActivity, 24, 41);
boolean isSkill = inRangeInclusive(rawActivity, 42, 59);
MobSkill toUse = null;
int useSkillId = 0, useSkillLevel = 0;
MobSkill nextUse = null;
int nextSkillId = 0, nextSkillLevel = 0;
boolean nextMovementCouldBeSkill = !(isSkill || (pNibbles != 0));
int castPos;
if (isSkill) {
useSkillId = skillId;
useSkillLevel = skillLv;
castPos = monster.getSkillPos(useSkillId, useSkillLevel);
if (castPos != -1) {
toUse = MobSkillFactory.getMobSkill(useSkillId, useSkillLevel);
if (monster.canUseSkill(toUse, true)) {
int animationTime = MapleMonsterInformationProvider.getInstance().getMobSkillAnimationTime(toUse);
if(animationTime > 0 && toUse.getSkillId() != 129) {
toUse.applyDelayedEffect(player, monster, true, animationTime);
} else {
banishPlayers = new LinkedList<>();
toUse.applyEffect(player, monster, true, banishPlayers);
}
}
}
} else {
castPos = (rawActivity - 24) / 2;
int atkStatus = monster.canUseAttack(castPos, isSkill);
if (atkStatus < 1) {
rawActivity = -1;
pOption = 0;
}
}
int mobMp = monster.getMp();
if (nextMovementCouldBeSkill) {
int noSkills = monster.getNoSkills();
if (noSkills > 0) {
int rndSkill = Randomizer.nextInt(noSkills);
Pair<Integer, Integer> skillToUse = monster.getSkills().get(rndSkill);
nextSkillId = skillToUse.getLeft();
nextSkillLevel = skillToUse.getRight();
nextUse = MobSkillFactory.getMobSkill(nextSkillId, nextSkillLevel);
if (!(nextUse != null && monster.canUseSkill(nextUse, false) && nextUse.getHP() >= (int) (((float) monster.getHp() / monster.getMaxHp()) * 100) && mobMp >= nextUse.getMpCon())) {
// thanks OishiiKawaiiDesu for noticing mobs trying to cast skills they are not supposed to be able
nextSkillId = 0;
nextSkillLevel = 0;
nextUse = null;
}
}
}
slea.readByte();
slea.readInt(); // whatever
short start_x = slea.readShort(); // hmm.. startpos?
short start_y = slea.readShort(); // hmm...
Point startPos = new Point(start_x, start_y - 2);
Point serverStartPos = new Point(monster.getPosition());
Boolean aggro = monster.aggroMoveLifeUpdate(player);
if (aggro == null) return;
if (nextUse != null) {
c.announce(MaplePacketCreator.moveMonsterResponse(objectid, moveid, mobMp, aggro, nextSkillId, nextSkillLevel));
} else {
c.announce(MaplePacketCreator.moveMonsterResponse(objectid, moveid, mobMp, aggro));
}
try {
long movementDataStart = slea.getPosition();
updatePosition(slea, monster, -2); // Thanks Doodle & ZERO傑洛 for noticing sponge-based bosses moving out of stage in case of no-offset applied
long movementDataLength = slea.getPosition() - movementDataStart; //how many bytes were read by updatePosition
slea.seek(movementDataStart);
if (YamlConfig.config.server.USE_DEBUG_SHOW_RCVD_MVLIFE) {
System.out.println((isSkill ? "SKILL " : (isAttack ? "ATTCK " : " ")) + "castPos: " + castPos + " rawAct: " + rawActivity + " opt: " + pOption + " skillID: " + useSkillId + " skillLV: " + useSkillLevel + " " + "allowSkill: " + nextMovementCouldBeSkill + " mobMp: " + mobMp);
}
map.broadcastMessage(player, MaplePacketCreator.moveMonster(objectid, nextMovementCouldBeSkill, rawActivity, useSkillId, useSkillLevel, pOption, startPos, slea, movementDataLength), serverStartPos);
//updatePosition(res, monster, -2); //does this need to be done after the packet is broadcast?
map.moveMonster(monster, monster.getPosition());
} catch (EmptyMovementException e) {}
if (banishPlayers != null) {
for (MapleCharacter chr : banishPlayers) {
chr.changeMapBanish(monster.getBanish().getMap(), monster.getBanish().getPortal(), monster.getBanish().getMsg());
}
}
}
private static boolean inRangeInclusive(Byte pVal, Integer pMin, Integer pMax) {
return !(pVal < pMin) || (pVal > pMax);
}
}

View File

@@ -0,0 +1,53 @@
/*
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 as
published by the Free Software Foundation 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.server.channel.handlers;
import java.util.List;
import client.MapleCharacter;
import client.MapleClient;
import server.movement.LifeMovementFragment;
import tools.MaplePacketCreator;
import tools.data.input.SeekableLittleEndianAccessor;
import tools.exceptions.EmptyMovementException;
public final class MovePetHandler extends AbstractMovementPacketHandler {
@Override
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
int petId = slea.readInt();
slea.readLong();
// Point startPos = StreamUtil.readShortPoint(slea);
List<LifeMovementFragment> res;
try {
res = parseMovement(slea);
} catch (EmptyMovementException e) {
return;
}
MapleCharacter player = c.getPlayer();
byte slot = player.getPetIndex(petId);
if (slot == -1) {
return;
}
player.getPet(slot).updatePosition(res);
player.getMap().broadcastMessage(player, MaplePacketCreator.movePet(player.getId(), petId, slot, res), false);
}
}

View File

@@ -0,0 +1,47 @@
/*
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 as
published by the Free Software Foundation 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.server.channel.handlers;
import client.MapleClient;
import tools.MaplePacketCreator;
import tools.data.input.SeekableLittleEndianAccessor;
import tools.exceptions.EmptyMovementException;
public final class MovePlayerHandler extends AbstractMovementPacketHandler {
@Override
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
slea.skip(9);
try { // thanks Sa for noticing empty movement sequences crashing players
long movementDataStart = slea.getPosition();
updatePosition(slea, c.getPlayer(), 0);
long movementDataLength = slea.getPosition() - movementDataStart; //how many bytes were read by updatePosition
slea.seek(movementDataStart);
c.getPlayer().getMap().movePlayer(c.getPlayer(), c.getPlayer().getPosition());
if (c.getPlayer().isHidden()) {
c.getPlayer().getMap().broadcastGMMessage(c.getPlayer(), MaplePacketCreator.movePlayer(c.getPlayer().getId(), slea, movementDataLength), false);
} else {
c.getPlayer().getMap().broadcastMessage(c.getPlayer(), MaplePacketCreator.movePlayer(c.getPlayer().getId(), slea, movementDataLength), false);
}
} catch (EmptyMovementException e) {}
}
}

Some files were not shown because too many files have changed in this diff Show More