Switch to Maven file structure
This commit is contained in:
106
src/main/java/net/server/PlayerBuffStorage.java
Normal file
106
src/main/java/net/server/PlayerBuffStorage.java
Normal 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;
|
||||
}
|
||||
}
|
||||
38
src/main/java/net/server/PlayerBuffValueHolder.java
Normal file
38
src/main/java/net/server/PlayerBuffValueHolder.java
Normal 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;
|
||||
}
|
||||
}
|
||||
38
src/main/java/net/server/PlayerCoolDownValueHolder.java
Normal file
38
src/main/java/net/server/PlayerCoolDownValueHolder.java
Normal 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;
|
||||
}
|
||||
}
|
||||
36
src/main/java/net/server/PlayerDiseaseValueHolder.java
Normal file
36
src/main/java/net/server/PlayerDiseaseValueHolder.java
Normal 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;
|
||||
}
|
||||
}
|
||||
126
src/main/java/net/server/PlayerStorage.java
Normal file
126
src/main/java/net/server/PlayerStorage.java
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
1961
src/main/java/net/server/Server.java
Normal file
1961
src/main/java/net/server/Server.java
Normal file
File diff suppressed because it is too large
Load Diff
75
src/main/java/net/server/audit/LockCollector.java
Normal file
75
src/main/java/net/server/audit/LockCollector.java
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
291
src/main/java/net/server/audit/ThreadTracker.java
Normal file
291
src/main/java/net/server/audit/ThreadTracker.java
Normal 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);
|
||||
}
|
||||
}
|
||||
112
src/main/java/net/server/audit/locks/MonitoredLockType.java
Normal file
112
src/main/java/net/server/audit/locks/MonitoredLockType.java
Normal 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;
|
||||
}
|
||||
36
src/main/java/net/server/audit/locks/MonitoredReadLock.java
Normal file
36
src/main/java/net/server/audit/locks/MonitoredReadLock.java
Normal 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();
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
36
src/main/java/net/server/audit/locks/MonitoredWriteLock.java
Normal file
36
src/main/java/net/server/audit/locks/MonitoredWriteLock.java
Normal 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();
|
||||
|
||||
}
|
||||
171
src/main/java/net/server/audit/locks/active/TrackerReadLock.java
Normal file
171
src/main/java/net/server/audit/locks/active/TrackerReadLock.java
Normal 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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
1056
src/main/java/net/server/channel/Channel.java
Normal file
1056
src/main/java/net/server/channel/Channel.java
Normal file
File diff suppressed because it is too large
Load Diff
47
src/main/java/net/server/channel/CharacterIdChannelPair.java
Normal file
47
src/main/java/net/server/channel/CharacterIdChannelPair.java
Normal 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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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.");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}*/
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
173
src/main/java/net/server/channel/handlers/ChangeMapHandler.java
Normal file
173
src/main/java/net/server/channel/handlers/ChangeMapHandler.java
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
279
src/main/java/net/server/channel/handlers/CouponCodeHandler.java
Normal file
279
src/main/java/net/server/channel/handlers/CouponCodeHandler.java
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
61
src/main/java/net/server/channel/handlers/DoorHandler.java
Normal file
61
src/main/java/net/server/channel/handlers/DoorHandler.java
Normal 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());
|
||||
}
|
||||
}
|
||||
66
src/main/java/net/server/channel/handlers/DueyHandler.java
Normal file
66
src/main/java/net/server/channel/handlers/DueyHandler.java
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
287
src/main/java/net/server/channel/handlers/EnterMTSHandler.java
Normal file
287
src/main/java/net/server/channel/handlers/EnterMTSHandler.java
Normal 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;
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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()));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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.");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
141
src/main/java/net/server/channel/handlers/FamilyUseHandler.java
Normal file
141
src/main/java/net/server/channel/handlers/FamilyUseHandler.java
Normal 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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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:
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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() + ".");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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.");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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) {
|
||||
}
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
909
src/main/java/net/server/channel/handlers/MTSHandler.java
Normal file
909
src/main/java/net/server/channel/handlers/MTSHandler.java
Normal 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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
128
src/main/java/net/server/channel/handlers/MessengerHandler.java
Normal file
128
src/main/java/net/server/channel/handlers/MessengerHandler.java
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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) {}
|
||||
}
|
||||
}
|
||||
}
|
||||
186
src/main/java/net/server/channel/handlers/MoveLifeHandler.java
Normal file
186
src/main/java/net/server/channel/handlers/MoveLifeHandler.java
Normal 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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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
Reference in New Issue
Block a user