Initial re-upload

This commit is contained in:
2024-01-19 03:56:28 -05:00
commit 170dac174c
25040 changed files with 16444288 additions and 0 deletions

View File

@@ -0,0 +1,30 @@
/*
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 client;
/**
* @author Ronan
*/
public interface AbstractCharacterListener {
void onHpChanged(int oldHp);
void onHpmpPoolUpdate();
void onStatUpdate();
void onAnnounceStatPoolUpdate();
}

View File

@@ -0,0 +1,773 @@
/*
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 client;
import config.YamlConfig;
import constants.game.GameConstants;
import server.maps.AbstractAnimatedMapObject;
import server.maps.MapleMap;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
/**
* @author RonanLana
*/
public abstract class AbstractCharacterObject extends AbstractAnimatedMapObject {
protected MapleMap map;
protected int str, dex, luk, int_, hp, maxhp, mp, maxmp;
protected int hpMpApUsed, remainingAp;
protected int[] remainingSp = new int[10];
protected transient int clientmaxhp, clientmaxmp, localmaxhp = 50, localmaxmp = 5;
protected float transienthp = Float.NEGATIVE_INFINITY, transientmp = Float.NEGATIVE_INFINITY;
private AbstractCharacterListener listener = null;
protected Map<Stat, Integer> statUpdates = new HashMap<>();
protected final Lock effLock = new ReentrantLock(true);
protected final Lock statRlock;
protected final Lock statWlock;
protected AbstractCharacterObject() {
ReadWriteLock statLock = new ReentrantReadWriteLock(true);
this.statRlock = statLock.readLock();
this.statWlock = statLock.writeLock();
for (int i = 0; i < remainingSp.length; i++) {
remainingSp[i] = 0;
}
}
protected void setListener(AbstractCharacterListener listener) {
this.listener = listener;
}
public void setMap(MapleMap map) {
this.map = map;
}
public MapleMap getMap() {
return map;
}
public int getStr() {
statRlock.lock();
try {
return str;
} finally {
statRlock.unlock();
}
}
public int getDex() {
statRlock.lock();
try {
return dex;
} finally {
statRlock.unlock();
}
}
public int getInt() {
statRlock.lock();
try {
return int_;
} finally {
statRlock.unlock();
}
}
public int getLuk() {
statRlock.lock();
try {
return luk;
} finally {
statRlock.unlock();
}
}
public int getRemainingAp() {
statRlock.lock();
try {
return remainingAp;
} finally {
statRlock.unlock();
}
}
protected int getRemainingSp(int jobid) {
statRlock.lock();
try {
return remainingSp[GameConstants.getSkillBook(jobid)];
} finally {
statRlock.unlock();
}
}
public int[] getRemainingSps() {
statRlock.lock();
try {
return Arrays.copyOf(remainingSp, remainingSp.length);
} finally {
statRlock.unlock();
}
}
public int getHpMpApUsed() {
statRlock.lock();
try {
return hpMpApUsed;
} finally {
statRlock.unlock();
}
}
public boolean isAlive() {
statRlock.lock();
try {
return hp > 0;
} finally {
statRlock.unlock();
}
}
public int getHp() {
statRlock.lock();
try {
return hp;
} finally {
statRlock.unlock();
}
}
public int getMp() {
statRlock.lock();
try {
return mp;
} finally {
statRlock.unlock();
}
}
public int getMaxHp() {
statRlock.lock();
try {
return maxhp;
} finally {
statRlock.unlock();
}
}
public int getMaxMp() {
statRlock.lock();
try {
return maxmp;
} finally {
statRlock.unlock();
}
}
public int getClientMaxHp() {
return clientmaxhp;
}
public int getClientMaxMp() {
return clientmaxmp;
}
public int getCurrentMaxHp() {
return localmaxhp;
}
public int getCurrentMaxMp() {
return localmaxmp;
}
private void setHpMpApUsed(int mpApUsed) {
this.hpMpApUsed = mpApUsed;
}
private void dispatchHpChanged(final int oldHp) {
listener.onHpChanged(oldHp);
}
private void dispatchHpmpPoolUpdated() {
listener.onHpmpPoolUpdate();
}
private void dispatchStatUpdated() {
listener.onStatUpdate();
}
private void dispatchStatPoolUpdateAnnounced() {
listener.onAnnounceStatPoolUpdate();
}
protected void setHp(int newHp) {
int oldHp = hp;
int thp = newHp;
if (thp < 0) {
thp = 0;
} else if (thp > localmaxhp) {
thp = localmaxhp;
}
if (this.hp != thp) {
this.transienthp = Float.NEGATIVE_INFINITY;
}
this.hp = thp;
dispatchHpChanged(oldHp);
}
protected void setMp(int newMp) {
int tmp = newMp;
if (tmp < 0) {
tmp = 0;
} else if (tmp > localmaxmp) {
tmp = localmaxmp;
}
if (this.mp != tmp) {
this.transientmp = Float.NEGATIVE_INFINITY;
}
this.mp = tmp;
}
private void setRemainingAp(int remainingAp) {
this.remainingAp = remainingAp;
}
private void setRemainingSp(int remainingSp, int skillbook) {
this.remainingSp[skillbook] = remainingSp;
}
protected void setMaxHp(int hp_) {
if (this.maxhp < hp_) {
this.transienthp = Float.NEGATIVE_INFINITY;
}
this.maxhp = hp_;
this.clientmaxhp = Math.min(30000, hp_);
}
protected void setMaxMp(int mp_) {
if (this.maxmp < mp_) {
this.transientmp = Float.NEGATIVE_INFINITY;
}
this.maxmp = mp_;
this.clientmaxmp = Math.min(30000, mp_);
}
private static long clampStat(int v, int min, int max) {
return (v < min) ? min : ((v > max) ? max : v);
}
private static long calcStatPoolNode(Integer v, int displacement) {
long r;
if (v == null) {
r = -32768;
} else {
r = clampStat(v, -32767, 32767);
}
return ((r & 0x0FFFF) << displacement);
}
private static long calcStatPoolLong(Integer v1, Integer v2, Integer v3, Integer v4) {
long ret = 0;
ret |= calcStatPoolNode(v1, 48);
ret |= calcStatPoolNode(v2, 32);
ret |= calcStatPoolNode(v3, 16);
ret |= calcStatPoolNode(v4, 0);
return ret;
}
private void changeStatPool(Long hpMpPool, Long strDexIntLuk, Long newSp, int newAp, boolean silent) {
effLock.lock();
statWlock.lock();
try {
statUpdates.clear();
boolean poolUpdate = false;
boolean statUpdate = false;
if (hpMpPool != null) {
short newHp = (short) (hpMpPool >> 48);
short newMp = (short) (hpMpPool >> 32);
short newMaxHp = (short) (hpMpPool >> 16);
short newMaxMp = hpMpPool.shortValue();
if (newMaxHp != Short.MIN_VALUE) {
if (newMaxHp < 50) {
newMaxHp = 50;
}
poolUpdate = true;
setMaxHp(newMaxHp);
statUpdates.put(Stat.MAXHP, clientmaxhp);
statUpdates.put(Stat.HP, hp);
}
if (newHp != Short.MIN_VALUE) {
setHp(newHp);
statUpdates.put(Stat.HP, hp);
}
if (newMaxMp != Short.MIN_VALUE) {
if (newMaxMp < 5) {
newMaxMp = 5;
}
poolUpdate = true;
setMaxMp(newMaxMp);
statUpdates.put(Stat.MAXMP, clientmaxmp);
statUpdates.put(Stat.MP, mp);
}
if (newMp != Short.MIN_VALUE) {
setMp(newMp);
statUpdates.put(Stat.MP, mp);
}
}
if (strDexIntLuk != null) {
short newStr = (short) (strDexIntLuk >> 48);
short newDex = (short) (strDexIntLuk >> 32);
short newInt = (short) (strDexIntLuk >> 16);
short newLuk = strDexIntLuk.shortValue();
if (newStr >= 4) {
setStr(newStr);
statUpdates.put(Stat.STR, str);
}
if (newDex >= 4) {
setDex(newDex);
statUpdates.put(Stat.DEX, dex);
}
if (newInt >= 4) {
setInt(newInt);
statUpdates.put(Stat.INT, int_);
}
if (newLuk >= 4) {
setLuk(newLuk);
statUpdates.put(Stat.LUK, luk);
}
if (newAp >= 0) {
setRemainingAp(newAp);
statUpdates.put(Stat.AVAILABLEAP, remainingAp);
}
statUpdate = true;
}
if (newSp != null) {
short sp = (short) (newSp >> 16);
short skillbook = newSp.shortValue();
setRemainingSp(sp, skillbook);
statUpdates.put(Stat.AVAILABLESP, remainingSp[skillbook]);
}
if (!statUpdates.isEmpty()) {
if (poolUpdate) {
dispatchHpmpPoolUpdated();
}
if (statUpdate) {
dispatchStatUpdated();
}
if (!silent) {
dispatchStatPoolUpdateAnnounced();
}
}
} finally {
statWlock.unlock();
effLock.unlock();
}
}
public void healHpMp() {
updateHpMp(30000);
}
public void updateHpMp(int x) {
updateHpMp(x, x);
}
public void updateHpMp(int newhp, int newmp) {
changeHpMp(newhp, newmp, false);
}
protected void changeHpMp(int newhp, int newmp, boolean silent) {
changeHpMpPool(newhp, newmp, null, null, silent);
}
private void changeHpMpPool(Integer hp, Integer mp, Integer maxhp, Integer maxmp, boolean silent) {
long hpMpPool = calcStatPoolLong(hp, mp, maxhp, maxmp);
changeStatPool(hpMpPool, null, null, -1, silent);
}
public void updateHp(int hp) {
updateHpMaxHp(hp, null);
}
public void updateMaxHp(int maxhp) {
updateHpMaxHp(null, maxhp);
}
public void updateHpMaxHp(int hp, int maxhp) {
updateHpMaxHp(Integer.valueOf(hp), Integer.valueOf(maxhp));
}
private void updateHpMaxHp(Integer hp, Integer maxhp) {
changeHpMpPool(hp, null, maxhp, null, false);
}
public void updateMp(int mp) {
updateMpMaxMp(mp, null);
}
public void updateMaxMp(int maxmp) {
updateMpMaxMp(null, maxmp);
}
public void updateMpMaxMp(int mp, int maxmp) {
updateMpMaxMp(Integer.valueOf(mp), Integer.valueOf(maxmp));
}
private void updateMpMaxMp(Integer mp, Integer maxmp) {
changeHpMpPool(null, mp, null, maxmp, false);
}
public void updateMaxHpMaxMp(int maxhp, int maxmp) {
changeHpMpPool(null, null, maxhp, maxmp, false);
}
protected void enforceMaxHpMp() {
effLock.lock();
statWlock.lock();
try {
if (mp > localmaxmp || hp > localmaxhp) {
changeHpMp(hp, mp, false);
}
} finally {
statWlock.unlock();
effLock.unlock();
}
}
public int safeAddHP(int delta) {
effLock.lock();
statWlock.lock();
try {
if (hp + delta <= 0) {
delta = -hp + 1;
}
addHP(delta);
return delta;
} finally {
statWlock.unlock();
effLock.unlock();
}
}
public void addHP(int delta) {
effLock.lock();
statWlock.lock();
try {
updateHp(hp + delta);
} finally {
statWlock.unlock();
effLock.unlock();
}
}
public void addMP(int delta) {
effLock.lock();
statWlock.lock();
try {
updateMp(mp + delta);
} finally {
statWlock.unlock();
effLock.unlock();
}
}
public void addMPHP(int hpDelta, int mpDelta) {
effLock.lock();
statWlock.lock();
try {
updateHpMp(hp + hpDelta, mp + mpDelta);
} finally {
statWlock.unlock();
effLock.unlock();
}
}
protected void addMaxMPMaxHP(int hpdelta, int mpdelta, boolean silent) {
effLock.lock();
statWlock.lock();
try {
changeHpMpPool(null, null, maxhp + hpdelta, maxmp + mpdelta, silent);
} finally {
statWlock.unlock();
effLock.unlock();
}
}
public void addMaxHP(int delta) {
effLock.lock();
statWlock.lock();
try {
updateMaxHp(maxhp + delta);
} finally {
statWlock.unlock();
effLock.unlock();
}
}
public void addMaxMP(int delta) {
effLock.lock();
statWlock.lock();
try {
updateMaxMp(maxmp + delta);
} finally {
statWlock.unlock();
effLock.unlock();
}
}
private void setStr(int str) {
this.str = str;
}
private void setDex(int dex) {
this.dex = dex;
}
private void setInt(int int_) {
this.int_ = int_;
}
private void setLuk(int luk) {
this.luk = luk;
}
public boolean assignStr(int x) {
return assignStrDexIntLuk(x, null, null, null);
}
public boolean assignDex(int x) {
return assignStrDexIntLuk(null, x, null, null);
}
public boolean assignInt(int x) {
return assignStrDexIntLuk(null, null, x, null);
}
public boolean assignLuk(int x) {
return assignStrDexIntLuk(null, null, null, x);
}
public boolean assignHP(int deltaHP, int deltaAp) {
effLock.lock();
statWlock.lock();
try {
if (remainingAp - deltaAp < 0 || hpMpApUsed + deltaAp < 0 || maxhp >= 30000) {
return false;
}
long hpMpPool = calcStatPoolLong(null, null, maxhp + deltaHP, maxmp);
long strDexIntLuk = calcStatPoolLong(str, dex, int_, luk);
changeStatPool(hpMpPool, strDexIntLuk, null, remainingAp - deltaAp, false);
setHpMpApUsed(hpMpApUsed + deltaAp);
return true;
} finally {
statWlock.unlock();
effLock.unlock();
}
}
public boolean assignMP(int deltaMP, int deltaAp) {
effLock.lock();
statWlock.lock();
try {
if (remainingAp - deltaAp < 0 || hpMpApUsed + deltaAp < 0 || maxmp >= 30000) {
return false;
}
long hpMpPool = calcStatPoolLong(null, null, maxhp, maxmp + deltaMP);
long strDexIntLuk = calcStatPoolLong(str, dex, int_, luk);
changeStatPool(hpMpPool, strDexIntLuk, null, remainingAp - deltaAp, false);
setHpMpApUsed(hpMpApUsed + deltaAp);
return true;
} finally {
statWlock.unlock();
effLock.unlock();
}
}
private static int apAssigned(Integer x) {
return x != null ? x : 0;
}
public boolean assignStrDexIntLuk(int deltaStr, int deltaDex, int deltaInt, int deltaLuk) {
return assignStrDexIntLuk(Integer.valueOf(deltaStr), Integer.valueOf(deltaDex), Integer.valueOf(deltaInt), Integer.valueOf(deltaLuk));
}
private boolean assignStrDexIntLuk(Integer deltaStr, Integer deltaDex, Integer deltaInt, Integer deltaLuk) {
effLock.lock();
statWlock.lock();
try {
int apUsed = apAssigned(deltaStr) + apAssigned(deltaDex) + apAssigned(deltaInt) + apAssigned(deltaLuk);
if (apUsed > remainingAp) {
return false;
}
int newStr = str, newDex = dex, newInt = int_, newLuk = luk;
if (deltaStr != null) {
newStr += deltaStr; // thanks Rohenn for noticing an NPE case after "null" started being used
}
if (deltaDex != null) {
newDex += deltaDex;
}
if (deltaInt != null) {
newInt += deltaInt;
}
if (deltaLuk != null) {
newLuk += deltaLuk;
}
if (newStr < 4 || newStr > YamlConfig.config.server.MAX_AP) {
return false;
}
if (newDex < 4 || newDex > YamlConfig.config.server.MAX_AP) {
return false;
}
if (newInt < 4 || newInt > YamlConfig.config.server.MAX_AP) {
return false;
}
if (newLuk < 4 || newLuk > YamlConfig.config.server.MAX_AP) {
return false;
}
int newAp = remainingAp - apUsed;
updateStrDexIntLuk(newStr, newDex, newInt, newLuk, newAp);
return true;
} finally {
statWlock.unlock();
effLock.unlock();
}
}
public void updateStrDexIntLuk(int x) {
updateStrDexIntLuk(x, x, x, x, -1);
}
public void changeRemainingAp(int x, boolean silent) {
effLock.lock();
statWlock.lock();
try {
changeStrDexIntLuk(str, dex, int_, luk, x, silent);
} finally {
statWlock.unlock();
effLock.unlock();
}
}
public void gainAp(int deltaAp, boolean silent) {
effLock.lock();
statWlock.lock();
try {
changeRemainingAp(Math.max(0, remainingAp + deltaAp), silent);
} finally {
statWlock.unlock();
effLock.unlock();
}
}
protected void updateStrDexIntLuk(int str, int dex, int int_, int luk, int remainingAp) {
changeStrDexIntLuk(str, dex, int_, luk, remainingAp, false);
}
private void changeStrDexIntLuk(Integer str, Integer dex, Integer int_, Integer luk, int remainingAp, boolean silent) {
long strDexIntLuk = calcStatPoolLong(str, dex, int_, luk);
changeStatPool(null, strDexIntLuk, null, remainingAp, silent);
}
private void changeStrDexIntLukSp(Integer str, Integer dex, Integer int_, Integer luk, int remainingAp, int remainingSp, int skillbook, boolean silent) {
long strDexIntLuk = calcStatPoolLong(str, dex, int_, luk);
long sp = calcStatPoolLong(0, 0, remainingSp, skillbook);
changeStatPool(null, strDexIntLuk, sp, remainingAp, silent);
}
protected void updateStrDexIntLukSp(int str, int dex, int int_, int luk, int remainingAp, int remainingSp, int skillbook) {
changeStrDexIntLukSp(str, dex, int_, luk, remainingAp, remainingSp, skillbook, false);
}
protected void setRemainingSp(int[] sps) {
effLock.lock();
statWlock.lock();
try {
System.arraycopy(sps, 0, remainingSp, 0, sps.length);
} finally {
statWlock.unlock();
effLock.unlock();
}
}
protected void updateRemainingSp(int remainingSp, int skillbook) {
changeRemainingSp(remainingSp, skillbook, false);
}
protected void changeRemainingSp(int remainingSp, int skillbook, boolean silent) {
long sp = calcStatPoolLong(0, 0, remainingSp, skillbook);
changeStatPool(null, null, sp, Short.MIN_VALUE, silent);
}
public void gainSp(int deltaSp, int skillbook, boolean silent) {
effLock.lock();
statWlock.lock();
try {
changeRemainingSp(Math.max(0, remainingSp[skillbook] + deltaSp), skillbook, silent);
} finally {
statWlock.unlock();
effLock.unlock();
}
}
}

View File

@@ -0,0 +1,177 @@
/*
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 client;
import net.packet.Packet;
import net.server.PlayerStorage;
import tools.DatabaseConnection;
import tools.PacketCreator;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.*;
public class BuddyList {
public enum BuddyOperation {
ADDED, DELETED
}
public enum BuddyAddResult {
BUDDYLIST_FULL, ALREADY_ON_LIST, OK
}
private final Map<Integer, BuddylistEntry> buddies = new LinkedHashMap<>();
private int capacity;
private final Deque<CharacterNameAndId> pendingRequests = new LinkedList<>();
public BuddyList(int capacity) {
this.capacity = capacity;
}
public boolean contains(int characterId) {
synchronized (buddies) {
return buddies.containsKey(characterId);
}
}
public boolean containsVisible(int characterId) {
BuddylistEntry ble;
synchronized (buddies) {
ble = buddies.get(characterId);
}
if (ble == null) {
return false;
}
return ble.isVisible();
}
public int getCapacity() {
return capacity;
}
public void setCapacity(int capacity) {
this.capacity = capacity;
}
public BuddylistEntry get(int characterId) {
synchronized (buddies) {
return buddies.get(characterId);
}
}
public BuddylistEntry get(String characterName) {
String lowerCaseName = characterName.toLowerCase();
for (BuddylistEntry ble : getBuddies()) {
if (ble.getName().toLowerCase().equals(lowerCaseName)) {
return ble;
}
}
return null;
}
public void put(BuddylistEntry entry) {
synchronized (buddies) {
buddies.put(entry.getCharacterId(), entry);
}
}
public void remove(int characterId) {
synchronized (buddies) {
buddies.remove(characterId);
}
}
public Collection<BuddylistEntry> getBuddies() {
synchronized (buddies) {
return Collections.unmodifiableCollection(buddies.values());
}
}
public boolean isFull() {
synchronized (buddies) {
return buddies.size() >= capacity;
}
}
public int[] getBuddyIds() {
synchronized (buddies) {
int[] buddyIds = new int[buddies.size()];
int i = 0;
for (BuddylistEntry ble : buddies.values()) {
buddyIds[i++] = ble.getCharacterId();
}
return buddyIds;
}
}
public void broadcast(Packet packet, PlayerStorage pstorage) {
for (int bid : getBuddyIds()) {
Character chr = pstorage.getCharacterById(bid);
if (chr != null && chr.isLoggedinWorld()) {
chr.sendPacket(packet);
}
}
}
public void loadFromDb(int characterId) {
try (Connection con = DatabaseConnection.getConnection()) {
try (PreparedStatement ps = con.prepareStatement("SELECT b.buddyid, b.pending, b.group, c.name as buddyname FROM buddies as b, characters as c WHERE c.id = b.buddyid AND b.characterid = ?")) {
ps.setInt(1, characterId);
try (ResultSet rs = ps.executeQuery()) {
while (rs.next()) {
if (rs.getInt("pending") == 1) {
pendingRequests.push(new CharacterNameAndId(rs.getInt("buddyid"), rs.getString("buddyname")));
} else {
put(new BuddylistEntry(rs.getString("buddyname"), rs.getString("group"), rs.getInt("buddyid"), (byte) -1, true));
}
}
}
}
try (PreparedStatement ps = con.prepareStatement("DELETE FROM buddies WHERE pending = 1 AND characterid = ?")) {
ps.setInt(1, characterId);
ps.executeUpdate();
}
} catch (SQLException ex) {
ex.printStackTrace();
}
}
public CharacterNameAndId pollPendingRequest() {
return pendingRequests.pollLast();
}
public void addBuddyRequest(Client c, int cidFrom, String nameFrom, int channelFrom) {
put(new BuddylistEntry(nameFrom, "Default Group", cidFrom, channelFrom, false));
if (pendingRequests.isEmpty()) {
c.sendPacket(PacketCreator.requestBuddylistAdd(cidFrom, c.getPlayer().getId(), nameFrom));
} else {
pendingRequests.push(new CharacterNameAndId(cidFrom, nameFrom));
}
}
}

View File

@@ -0,0 +1,106 @@
/*
This file is part of the OdinMS Maple Story Server
Copyright (C) 2008 Patrick Huy <patrick.huy@frz.cc>
Matthias Butz <matze@odinms.de>
Jan Christian Meyer <vimes@odinms.de>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation version 3 as published by
the Free Software Foundation. You may not use, modify or distribute
this program under any other version of the GNU Affero General Public
License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package client;
public class BuddylistEntry {
private final String name;
private String group;
private final int cid;
private int channel;
private boolean visible;
/**
* @param name
* @param characterId
* @param channel should be -1 if the buddy is offline
* @param visible
*/
public BuddylistEntry(String name, String group, int characterId, int channel, boolean visible) {
this.name = name;
this.group = group;
this.cid = characterId;
this.channel = channel;
this.visible = visible;
}
/**
* @return the channel the character is on. If the character is offline returns -1.
*/
public int getChannel() {
return channel;
}
public void setChannel(int channel) {
this.channel = channel;
}
public boolean isOnline() {
return channel >= 0;
}
public String getName() {
return name;
}
public String getGroup() {
return group;
}
public int getCharacterId() {
return cid;
}
public void setVisible(boolean visible) {
this.visible = visible;
}
public boolean isVisible() {
return visible;
}
public void changeGroup(String group) {
this.group = group;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + cid;
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 BuddylistEntry other = (BuddylistEntry) obj;
return cid == other.cid;
}
}

View File

@@ -0,0 +1,148 @@
/*
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 client;
public enum BuffStat {
//SLOW(0x1L),
MORPH(0x2L),
RECOVERY(0x4L),
MAPLE_WARRIOR(0x8L),
STANCE(0x10L),
SHARP_EYES(0x20L),
MANA_REFLECTION(0x40L),
//ALWAYS_RIGHT(0X80L),
SHADOW_CLAW(0x100L),
INFINITY(0x200L),
HOLY_SHIELD(0x400L),
HAMSTRING(0x800L),
BLIND(0x1000L),
CONCENTRATE(0x2000L),
PUPPET(0x4000L),
ECHO_OF_HERO(0x8000L),
MESO_UP_BY_ITEM(0x10000L),
GHOST_MORPH(0x20000L),
AURA(0x40000L),
CONFUSE(0x80000L),
// ------ COUPON feature ------
COUPON_EXP1(0x100000L),
COUPON_EXP2(0x200000L),
COUPON_EXP3(0x400000L), COUPON_EXP4(0x400000L),
COUPON_DRP1(0x800000L),
COUPON_DRP2(0x1000000L), COUPON_DRP3(0x1000000L),
// ------ monster card buffs, thanks to Arnah (Vertisy) ------
ITEM_UP_BY_ITEM(0x100000L),
RESPECT_PIMMUNE(0x200000L),
RESPECT_MIMMUNE(0x400000L),
DEFENSE_ATT(0x800000L),
DEFENSE_STATE(0x1000000L),
HPREC(0x2000000L),
MPREC(0x4000000L),
BERSERK_FURY(0x8000000L),
DIVINE_BODY(0x10000000L),
SPARK(0x20000000L),
MAP_CHAIR(0x40000000L),
FINALATTACK(0x80000000L),
WATK(0x100000000L),
WDEF(0x200000000L),
MATK(0x400000000L),
MDEF(0x800000000L),
ACC(0x1000000000L),
AVOID(0x2000000000L),
HANDS(0x4000000000L),
SPEED(0x8000000000L),
JUMP(0x10000000000L),
MAGIC_GUARD(0x20000000000L),
DARKSIGHT(0x40000000000L),
BOOSTER(0x80000000000L),
POWERGUARD(0x100000000000L),
HYPERBODYHP(0x200000000000L),
HYPERBODYMP(0x400000000000L),
INVINCIBLE(0x800000000000L),
SOULARROW(0x1000000000000L),
STUN(0x2000000000000L),
POISON(0x4000000000000L),
SEAL(0x8000000000000L),
DARKNESS(0x10000000000000L),
COMBO(0x20000000000000L),
SUMMON(0x20000000000000L),
WK_CHARGE(0x40000000000000L),
DRAGONBLOOD(0x80000000000000L),
HOLY_SYMBOL(0x100000000000000L),
MESOUP(0x200000000000000L),
SHADOWPARTNER(0x400000000000000L),
PICKPOCKET(0x800000000000000L),
MESOGUARD(0x1000000000000000L),
EXP_INCREASE(0x2000000000000000L),
WEAKEN(0x4000000000000000L),
MAP_PROTECTION(0x8000000000000000L),
//all incorrect buffstats
SLOW(0x200000000L, true),
ELEMENTAL_RESET(0x200000000L, true),
MAGIC_SHIELD(0x400000000L, true),
MAGIC_RESISTANCE(0x800000000L, true),
// needs Soul Stone
//end incorrect buffstats
WIND_WALK(0x400000000L, true),
ARAN_COMBO(0x1000000000L, true),
COMBO_DRAIN(0x2000000000L, true),
COMBO_BARRIER(0x4000000000L, true),
BODY_PRESSURE(0x8000000000L, true),
SMART_KNOCKBACK(0x10000000000L, true),
BERSERK(0x20000000000L, true),
ENERGY_CHARGE(0x4000000000000L, true),
DASH2(0x8000000000000L, true), // correct (speed)
DASH(0x10000000000000L, true), // correct (jump)
MONSTER_RIDING(0x20000000000000L, true),
SPEED_INFUSION(0x40000000000000L, true),
HOMING_BEACON(0x80000000000000L, true);
private final long i;
private final boolean isFirst;
BuffStat(long i, boolean isFirst) {
this.i = i;
this.isFirst = isFirst;
}
BuffStat(long i) {
this.i = i;
this.isFirst = false;
}
public long getValue() {
return i;
}
public boolean isFirst() {
return isFirst;
}
@Override
public String toString() {
return name();
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,41 @@
/*
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 client;
public class CharacterNameAndId {
private final int id;
private final String name;
public CharacterNameAndId(int id, String name) {
super();
this.id = id;
this.name = name;
}
public int getId() {
return id;
}
public String getName() {
return name;
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,19 @@
package client;
import java.time.LocalDate;
import java.time.LocalDateTime;
final public class DefaultDates {
// May 11 2005 is the date MapleGlobal released, so it's a symbolic default value
private DefaultDates() {
}
public static LocalDate getBirthday() {
return LocalDate.parse("2005-05-11");
}
public static LocalDateTime getTempban() {
return LocalDateTime.parse("2005-05-11T00:00:00");
}
}

View File

@@ -0,0 +1,90 @@
/*
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 client;
import constants.game.GameConstants;
import server.life.MobSkillType;
import java.util.Arrays;
public enum Disease {
NULL(0x0),
SLOW(0x1, MobSkillType.SLOW),
SEDUCE(0x80, MobSkillType.SEDUCE),
FISHABLE(0x100),
ZOMBIFY(0x4000),
CONFUSE(0x80000, MobSkillType.REVERSE_INPUT),
STUN(0x2000000000000L, MobSkillType.STUN),
POISON(0x4000000000000L, MobSkillType.POISON),
SEAL(0x8000000000000L, MobSkillType.SEAL),
DARKNESS(0x10000000000000L, MobSkillType.DARKNESS),
WEAKEN(0x4000000000000000L, MobSkillType.WEAKNESS),
CURSE(0x8000000000000000L, MobSkillType.CURSE);
private final long i;
private final MobSkillType mobSkillType;
Disease(long i) {
this(i, null);
}
Disease(long i, MobSkillType skill) {
this.i = i;
this.mobSkillType = skill;
}
public long getValue() {
return i;
}
public boolean isFirst() {
return false;
}
public MobSkillType getMobSkillType() {
return mobSkillType;
}
public static Disease ordinal(int ord) {
try {
return Disease.values()[ord];
} catch (IndexOutOfBoundsException io) {
return NULL;
}
}
public static final Disease getRandom() {
Disease[] diseases = GameConstants.CPQ_DISEASES;
return diseases[(int) (Math.random() * diseases.length)];
}
public static final Disease getBySkill(MobSkillType skill) {
if (skill == null) {
return null;
}
return Arrays.stream(Disease.values())
.filter(d -> d.mobSkillType == skill)
.findAny()
.orElse(null);
}
}

View File

@@ -0,0 +1,33 @@
/*
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 client;
/**
* @author anybody can do this
*/
public class DiseaseValueHolder {
public long startTime, length;
public DiseaseValueHolder(long start, long length) {
this.startTime = start;
this.length = length;
}
}

View File

@@ -0,0 +1,308 @@
/*
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 client;
import net.packet.Packet;
import net.server.Server;
import net.server.world.World;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import tools.DatabaseConnection;
import tools.PacketCreator;
import tools.Pair;
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 java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
/**
* @author Jay Estrella - Mr.Trash :3
* @author Ubaware
*/
public class Family {
private static final Logger log = LoggerFactory.getLogger(Family.class);
private static final AtomicInteger familyIDCounter = new AtomicInteger();
private final int id, world;
private final Map<Integer, FamilyEntry> members = new ConcurrentHashMap<>();
private FamilyEntry leader;
private String name;
private String preceptsMessage = "";
private int totalGenerations;
public Family(int id, int world) {
int newId = id;
if (id == -1) {
// get next available family id
while (idInUse(newId = familyIDCounter.incrementAndGet())) {
}
}
this.id = newId;
this.world = world;
}
private static boolean idInUse(int id) {
for (World world : Server.getInstance().getWorlds()) {
if (world.getFamily(id) != null) {
return true;
}
}
return false;
}
public int getID() {
return id;
}
public int getWorld() {
return world;
}
public void setLeader(FamilyEntry leader) {
this.leader = leader;
setName(leader.getName());
}
public FamilyEntry getLeader() {
return leader;
}
private void setName(String name) {
this.name = name;
}
public int getTotalMembers() {
return members.size();
}
public int getTotalGenerations() {
return totalGenerations;
}
public void setTotalGenerations(int generations) {
this.totalGenerations = generations;
}
public String getName() {
return this.name;
}
public void setMessage(String message, boolean save) {
this.preceptsMessage = message;
if (save) {
try (Connection con = DatabaseConnection.getConnection();
PreparedStatement ps = con.prepareStatement("UPDATE family_character SET precepts = ? WHERE cid = ?")) {
ps.setString(1, message);
ps.setInt(2, getLeader().getChrId());
ps.executeUpdate();
} catch (SQLException e) {
log.error("Could not save new precepts for family {}", getID(), e);
}
}
}
public String getMessage() {
return preceptsMessage;
}
public void addEntry(FamilyEntry entry) {
members.put(entry.getChrId(), entry);
}
public void removeEntryBranch(FamilyEntry root) {
members.remove(root.getChrId());
for (FamilyEntry junior : root.getJuniors()) {
if (junior != null) {
removeEntryBranch(junior);
}
}
}
public void addEntryTree(FamilyEntry root) {
members.put(root.getChrId(), root);
for (FamilyEntry junior : root.getJuniors()) {
if (junior != null) {
addEntryTree(junior);
}
}
}
public FamilyEntry getEntryByID(int cid) {
return members.get(cid);
}
public void broadcast(Packet packet) {
broadcast(packet, -1);
}
public void broadcast(Packet packet, int ignoreID) {
for (FamilyEntry entry : members.values()) {
Character chr = entry.getChr();
if (chr != null) {
if (chr.getId() == ignoreID) {
continue;
}
chr.sendPacket(packet);
}
}
}
public void broadcastFamilyInfoUpdate() {
for (FamilyEntry entry : members.values()) {
Character chr = entry.getChr();
if (chr != null) {
chr.sendPacket(PacketCreator.getFamilyInfo(entry));
}
}
}
public void resetDailyReps() {
for (FamilyEntry entry : members.values()) {
entry.setTodaysRep(0);
entry.setRepsToSenior(0);
entry.resetEntitlementUsages();
}
}
public static void loadAllFamilies(Connection con) {
List<Pair<Pair<Integer, Integer>, FamilyEntry>> unmatchedJuniors = new ArrayList<>(200); // <<world, seniorid> familyEntry>
try (PreparedStatement psEntries = con.prepareStatement("SELECT * FROM family_character")) {
ResultSet rsEntries = psEntries.executeQuery();
while (rsEntries.next()) { // can be optimized
int cid = rsEntries.getInt("cid");
String name = null;
int level = -1;
int jobID = -1;
int world = -1;
try (PreparedStatement ps = con.prepareStatement("SELECT world, name, level, job FROM characters WHERE id = ?")) {
ps.setInt(1, cid);
ResultSet rs = ps.executeQuery();
if (rs.next()) {
world = rs.getInt("world");
name = rs.getString("name");
level = rs.getInt("level");
jobID = rs.getInt("job");
} else {
log.error("Could not load character information of chrId {} in loadAllFamilies(). (RECORD DOES NOT EXIST)", cid);
continue;
}
} catch (SQLException e) {
log.error("Could not load character information of chrId {} in loadAllFamilies(). (SQL ERROR)", cid, e);
continue;
}
int familyid = rsEntries.getInt("familyid");
int seniorid = rsEntries.getInt("seniorid");
int reputation = rsEntries.getInt("reputation");
int todaysRep = rsEntries.getInt("todaysrep");
int totalRep = rsEntries.getInt("totalreputation");
int repsToSenior = rsEntries.getInt("reptosenior");
String precepts = rsEntries.getString("precepts");
//Timestamp lastResetTime = rsEntries.getTimestamp("lastresettime"); //taken care of by FamilyDailyResetTask
World wserv = Server.getInstance().getWorld(world);
if (wserv == null) {
continue;
}
Family family = wserv.getFamily(familyid);
if (family == null) {
family = new Family(familyid, world);
Server.getInstance().getWorld(world).addFamily(familyid, family);
}
FamilyEntry familyEntry = new FamilyEntry(family, cid, name, level, Job.getById(jobID));
family.addEntry(familyEntry);
if (seniorid <= 0) {
family.setLeader(familyEntry);
family.setMessage(precepts, false);
}
FamilyEntry senior = family.getEntryByID(seniorid);
if (senior != null) {
familyEntry.setSenior(family.getEntryByID(seniorid), false);
} else {
if (seniorid > 0) {
unmatchedJuniors.add(new Pair<>(new Pair<>(world, seniorid), familyEntry));
}
}
familyEntry.setReputation(reputation);
familyEntry.setTodaysRep(todaysRep);
familyEntry.setTotalReputation(totalRep);
familyEntry.setRepsToSenior(repsToSenior);
//load used entitlements
try (PreparedStatement ps = con.prepareStatement("SELECT entitlementid FROM family_entitlement WHERE charid = ?")) {
ps.setInt(1, familyEntry.getChrId());
ResultSet rs = ps.executeQuery();
while (rs.next()) {
familyEntry.setEntitlementUsed(rs.getInt("entitlementid"));
}
}
}
} catch (SQLException e) {
log.error("Could not get family_character entries", e);
}
// link missing ones (out of order)
for (Pair<Pair<Integer, Integer>, FamilyEntry> unmatchedJunior : unmatchedJuniors) {
int world = unmatchedJunior.getLeft().getLeft();
int seniorid = unmatchedJunior.getLeft().getRight();
FamilyEntry junior = unmatchedJunior.getRight();
FamilyEntry senior = Server.getInstance().getWorld(world).getFamily(junior.getFamily().getID()).getEntryByID(seniorid);
if (senior != null) {
junior.setSenior(senior, false);
} else {
log.error("Missing senior for chr {} in world {}", junior.getName(), world);
}
}
for (World world : Server.getInstance().getWorlds()) {
for (Family family : world.getFamilies()) {
family.getLeader().doFullCount();
}
}
}
public void saveAllMembersRep() { //was used for autosave task, but character autosave should be enough
try (Connection con = DatabaseConnection.getConnection()) {
con.setAutoCommit(false);
boolean success = true;
for (FamilyEntry entry : members.values()) {
success = entry.saveReputation(con);
if (!success) {
break;
}
}
if (!success) {
con.rollback();
log.error("Family rep autosave failed for family {}", getID());
}
con.setAutoCommit(true);
//reset repChanged after successful save
for (FamilyEntry entry : members.values()) {
entry.savedSuccessfully();
}
} catch (SQLException e) {
log.error("Could not get connection to DB while saving all members rep", e);
}
}
}

View File

@@ -0,0 +1,41 @@
package client;
public enum FamilyEntitlement {
FAMILY_REUINION(1, 300, "Family Reunion", "[Target] Me\\n[Effect] Teleport directly to the Family member of your choice."),
SUMMON_FAMILY(1, 500, "Summon Family", "[Target] 1 Family member\\n[Effect] Summon a Family member of choice to the map you're in."),
SELF_DROP_1_5(1, 700, "My Drop Rate 1.5x (15 min)", "[Target] Me\\n[Time] 15 min.\\n[Effect] Monster drop rate will be increased #c1.5x#.\\n* If the Drop Rate event is in progress, this will be nullified."),
SELF_EXP_1_5(1, 800, "My EXP 1.5x (15 min)", "[Target] Me\\n[Time] 15 min.\\n[Effect] EXP earned from hunting will be increased #c1.5x#.\\n* If the EXP event is in progress, this will be nullified."),
FAMILY_BONDING(1, 1000, "Family Bonding (30 min)", "[Target] At least 6 Family members online that are below me in the Pedigree\\n[Time] 30 min.\\n[Effect] Monster drop rate and EXP earned will be increased #c2x#. \\n* If the EXP event is in progress, this will be nullified."),
SELF_DROP_2(1, 1200, "My Drop Rate 2x (15 min)", "[Target] Me\\n[Time] 15 min.\\n[Effect] Monster drop rate will be increased #c2x#.\\n* If the Drop Rate event is in progress, this will be nullified."),
SELF_EXP_2(1, 1500, "My EXP 2x (15 min)", "[Target] Me\\n[Time] 15 min.\\n[Effect] EXP earned from hunting will be increased #c2x#.\\n* If the EXP event is in progress, this will be nullified."),
SELF_DROP_2_30MIN(1, 2000, "My Drop Rate 2x (30 min)", "[Target] Me\\n[Time] 30 min.\\n[Effect] Monster drop rate will be increased #c2x#.\\n* If the Drop Rate event is in progress, this will be nullified."),
SELF_EXP_2_30MIN(1, 2500, "My EXP 2x (30 min)", "[Target] Me\\n[Time] 30 min.\\n[Effect] EXP earned from hunting will be increased #c2x#. \\n* If the EXP event is in progress, this will be nullified."),
PARTY_DROP_2_30MIN(1, 4000, "My Party Drop Rate 2x (30 min)", "[Target] My party\\n[Time] 30 min.\\n[Effect] Monster drop rate will be increased #c2x#.\\n* If the Drop Rate event is in progress, this will be nullified."),
PARTY_EXP_2_30MIN(1, 5000, "My Party EXP 2x (30 min)", "[Target] My party\\n[Time] 30 min.\\n[Effect] EXP earned from hunting will be increased #c2x#.\\n* If the EXP event is in progress, this will be nullified.");
private final int usageLimit, repCost;
private final String name, description;
FamilyEntitlement(int usageLimit, int repCost, String name, String description) {
this.usageLimit = usageLimit;
this.repCost = repCost;
this.name = name;
this.description = description;
}
public int getUsageLimit() {
return usageLimit;
}
public int getRepCost() {
return repCost;
}
public String getName() {
return name;
}
public String getDescription() {
return description;
}
}

View File

@@ -0,0 +1,619 @@
/*
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 client;
import net.packet.Packet;
import net.server.Server;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import tools.DatabaseConnection;
import tools.PacketCreator;
import tools.Pair;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
/**
* @author Ubaware
*/
public class FamilyEntry {
private static final Logger log = LoggerFactory.getLogger(FamilyEntry.class);
private final int characterID;
private volatile Family family;
private volatile Character character;
private volatile FamilyEntry senior;
private final FamilyEntry[] juniors = new FamilyEntry[2];
private final int[] entitlements = new int[11];
private volatile int reputation, totalReputation;
private volatile int todaysRep, repsToSenior; //both are daily values
private volatile int totalJuniors, totalSeniors;
private volatile int generation;
private volatile boolean repChanged; //used to ignore saving unchanged rep values
// cached values for offline players
private String charName;
private int level;
private Job job;
public FamilyEntry(Family family, int characterID, String charName, int level, Job job) {
this.family = family;
this.characterID = characterID;
this.charName = charName;
this.level = level;
this.job = job;
}
public Character getChr() {
return character;
}
public void setCharacter(Character newCharacter) {
if (newCharacter == null) {
cacheOffline(newCharacter);
} else {
newCharacter.setFamilyEntry(this);
}
this.character = newCharacter;
}
private void cacheOffline(Character chr) {
if (chr != null) {
charName = chr.getName();
level = chr.getLevel();
job = chr.getJob();
}
}
public synchronized void join(FamilyEntry senior) {
if (senior == null || getSenior() != null) {
return;
}
Family oldFamily = getFamily();
Family newFamily = senior.getFamily();
setSenior(senior, false);
addSeniorCount(newFamily.getTotalGenerations(), newFamily); //count will be overwritten by doFullCount()
newFamily.getLeader().doFullCount(); //easier than keeping track of numbers
oldFamily.setMessage(null, true);
newFamily.addEntryTree(this);
Server.getInstance().getWorld(oldFamily.getWorld()).removeFamily(oldFamily.getID());
//db
try (Connection con = DatabaseConnection.getConnection()) {
con.setAutoCommit(false);
boolean success = updateDBChangeFamily(con, getChrId(), newFamily.getID(), senior.getChrId());
for (FamilyEntry junior : juniors) { // better to duplicate this than the SQL code
if (junior != null) {
success = junior.updateNewFamilyDB(con); // recursively updates juniors in db
if (!success) {
break;
}
}
}
if (!success) {
con.rollback();
log.error("Could not absorb {}'s family into {}'s family. (SQL ERROR)", oldFamily.getName(), newFamily.getName());
}
con.setAutoCommit(true);
} catch (SQLException e) {
log.error("Could not get connection to DB when joining families", e);
}
}
public synchronized void fork() {
Family oldFamily = getFamily();
FamilyEntry oldSenior = getSenior();
family = new Family(-1, oldFamily.getWorld());
Server.getInstance().getWorld(family.getWorld()).addFamily(family.getID(), family);
setSenior(null, false);
family.setLeader(this);
addSeniorCount(-getTotalSeniors(), family);
setTotalSeniors(0);
if (oldSenior != null) {
oldSenior.addJuniorCount(-getTotalJuniors());
oldSenior.removeJunior(this);
oldFamily.getLeader().doFullCount();
}
oldFamily.removeEntryBranch(this);
family.addEntryTree(this);
this.repsToSenior = 0;
this.repChanged = true;
family.setMessage("", true);
doFullCount(); //to make sure all counts are correct
// update db
try (Connection con = DatabaseConnection.getConnection()) {
con.setAutoCommit(false);
boolean success = updateDBChangeFamily(con, getChrId(), getFamily().getID(), 0);
for (FamilyEntry junior : juniors) { // better to duplicate this than the SQL code
if (junior != null) {
success = junior.updateNewFamilyDB(con); // recursively updates juniors in db
if (!success) {
break;
}
}
}
if (!success) {
con.rollback();
log.error("Could not fork family with new leader {}. (Old senior: {}, leader: {})", getName(), oldSenior.getName(), oldFamily.getLeader().getName());
}
con.setAutoCommit(true);
} catch (SQLException e) {
log.error("Could not get connection to DB when forking families", e);
}
}
private synchronized boolean updateNewFamilyDB(Connection con) {
if (!updateFamilyEntryDB(con, getChrId(), getFamily().getID())) {
return false;
}
if (!updateCharacterFamilyDB(con, getChrId(), getFamily().getID(), true)) {
return false;
}
for (FamilyEntry junior : juniors) {
if (junior != null) {
if (!junior.updateNewFamilyDB(con)) {
return false;
}
}
}
return true;
}
private static boolean updateFamilyEntryDB(Connection con, int cid, int familyid) {
try (PreparedStatement ps = con.prepareStatement("UPDATE family_character SET familyid = ? WHERE cid = ?")) {
ps.setInt(1, familyid);
ps.setInt(2, cid);
ps.executeUpdate();
} catch (SQLException e) {
log.error("Could not update family id in 'family_character' for chrId {}. (fork)", cid, e);
return false;
}
return true;
}
private synchronized void addSeniorCount(int seniorCount, Family newFamily) { // traverses tree and subtracts seniors and updates family
if (newFamily != null) {
this.family = newFamily;
}
setTotalSeniors(getTotalSeniors() + seniorCount);
this.generation += seniorCount;
for (FamilyEntry junior : juniors) {
if (junior != null) {
junior.addSeniorCount(seniorCount, newFamily);
}
}
}
private synchronized void addJuniorCount(int juniorCount) { // climbs tree and adds junior count
setTotalJuniors(getTotalJuniors() + juniorCount);
FamilyEntry senior = getSenior();
if (senior != null) {
senior.addJuniorCount(juniorCount);
}
}
public Family getFamily() {
return family;
}
public int getChrId() {
return characterID;
}
public String getName() {
Character chr = character;
if (chr != null) {
return chr.getName();
} else {
return charName;
}
}
public int getLevel() {
Character chr = character;
if (chr != null) {
return chr.getLevel();
} else {
return level;
}
}
public Job getJob() {
Character chr = character;
if (chr != null) {
return chr.getJob();
} else {
return job;
}
}
public int getReputation() {
return reputation;
}
public int getTodaysRep() {
return todaysRep;
}
public void setReputation(int reputation) {
if (reputation != this.reputation) {
this.repChanged = true;
}
this.reputation = reputation;
}
public void setTodaysRep(int today) {
if (today != todaysRep) {
this.repChanged = true;
}
this.todaysRep = today;
}
public int getRepsToSenior() {
return repsToSenior;
}
public void setRepsToSenior(int reputation) {
if (reputation != this.repsToSenior) {
this.repChanged = true;
}
this.repsToSenior = reputation;
}
public void gainReputation(int gain, boolean countTowardsTotal) {
gainReputation(gain, countTowardsTotal, this);
}
private void gainReputation(int gain, boolean countTowardsTotal, FamilyEntry from) {
if (gain != 0) {
repChanged = true;
}
this.reputation += gain;
this.todaysRep += gain;
if (gain > 0 && countTowardsTotal) {
this.totalReputation += gain;
}
Character chr = getChr();
if (chr != null) {
chr.sendPacket(PacketCreator.sendGainRep(gain, from != null ? from.getName() : ""));
}
}
public void giveReputationToSenior(int gain, boolean includeSuperSenior) {
int actualGain = gain;
FamilyEntry senior = getSenior();
if (senior != null && senior.getLevel() < getLevel() && gain > 0) {
actualGain /= 2; //don't halve negative values
}
if (senior != null) {
senior.gainReputation(actualGain, true, this);
if (actualGain > 0) {
this.repsToSenior += actualGain;
this.repChanged = true;
}
if (includeSuperSenior) {
senior = senior.getSenior();
if (senior != null) {
senior.gainReputation(actualGain, true, this);
}
}
}
}
public int getTotalReputation() {
return totalReputation;
}
public void setTotalReputation(int totalReputation) {
if (totalReputation != this.totalReputation) {
this.repChanged = true;
}
this.totalReputation = totalReputation;
}
public FamilyEntry getSenior() {
return senior;
}
public synchronized boolean setSenior(FamilyEntry senior, boolean save) {
if (this.senior == senior) {
return false;
}
FamilyEntry oldSenior = this.senior;
this.senior = senior;
if (senior != null) {
if (senior.addJunior(this)) {
if (save) {
updateDBChangeFamily(getChrId(), senior.getFamily().getID(), senior.getChrId());
}
if (this.repsToSenior != 0) {
this.repChanged = true;
}
this.repsToSenior = 0;
this.addSeniorCount(1, null);
this.setTotalSeniors(senior.getTotalSeniors() + 1);
return true;
}
} else {
if (oldSenior != null) {
oldSenior.removeJunior(this);
}
}
return false;
}
private static boolean updateDBChangeFamily(int cid, int familyid, int seniorid) {
try (Connection con = DatabaseConnection.getConnection()) {
return updateDBChangeFamily(con, cid, familyid, seniorid);
} catch (SQLException e) {
log.error("Could not get connection to DB while changing family", e);
return false;
}
}
private static boolean updateDBChangeFamily(Connection con, int cid, int familyid, int seniorid) {
try (PreparedStatement ps = con.prepareStatement("UPDATE family_character SET familyid = ?, seniorid = ?, reptosenior = 0 WHERE cid = ?")) {
ps.setInt(1, familyid);
ps.setInt(2, seniorid);
ps.setInt(3, cid);
ps.executeUpdate();
} catch (SQLException e) {
log.error("Could not update seniorId in 'family_character' for chrId {}", cid, e);
return false;
}
return updateCharacterFamilyDB(con, cid, familyid, false);
}
private static boolean updateCharacterFamilyDB(Connection con, int charid, int familyid, boolean fork) {
try (PreparedStatement ps = con.prepareStatement("UPDATE characters SET familyid = ? WHERE id = ?")) {
ps.setInt(1, familyid);
ps.setInt(2, charid);
ps.executeUpdate();
} catch (SQLException e) {
log.error("Could not update familyId in 'characters' for chrId {} when changing family. {}", charid, fork ? "(fork)" : "", e);
return false;
}
return true;
}
public List<FamilyEntry> getJuniors() {
return Collections.unmodifiableList(Arrays.asList(juniors));
}
public FamilyEntry getOtherJunior(FamilyEntry junior) {
if (juniors[0] == junior) {
return juniors[1];
} else if (juniors[1] == junior) {
return juniors[0];
}
return null;
}
public int getJuniorCount() { //close enough to be relatively consistent to multiple threads (and the result is not vital)
int juniorCount = 0;
if (juniors[0] != null) {
juniorCount++;
}
if (juniors[1] != null) {
juniorCount++;
}
return juniorCount;
}
public synchronized boolean addJunior(FamilyEntry newJunior) {
for (int i = 0; i < juniors.length; i++) {
if (juniors[i] == null) { // successfully add new junior to family
juniors[i] = newJunior;
addJuniorCount(1);
getFamily().addEntry(newJunior);
return true;
}
}
return false;
}
public synchronized boolean isJunior(FamilyEntry entry) { //require locking since result accuracy is vital
if (juniors[0] == entry) {
return true;
} else {
return juniors[1] == entry;
}
}
public synchronized boolean removeJunior(FamilyEntry junior) {
for (int i = 0; i < juniors.length; i++) {
if (juniors[i] == junior) {
juniors[i] = null;
return true;
}
}
return false;
}
public int getTotalSeniors() {
return totalSeniors;
}
public void setTotalSeniors(int totalSeniors) {
this.totalSeniors = totalSeniors;
}
public int getTotalJuniors() {
return totalJuniors;
}
public void setTotalJuniors(int totalJuniors) {
this.totalJuniors = totalJuniors;
}
public void announceToSenior(Packet packet, boolean includeSuperSenior) {
FamilyEntry senior = getSenior();
if (senior != null) {
Character seniorChr = senior.getChr();
if (seniorChr != null) {
seniorChr.sendPacket(packet);
}
senior = senior.getSenior();
if (includeSuperSenior && senior != null) {
seniorChr = senior.getChr();
if (seniorChr != null) {
seniorChr.sendPacket(packet);
}
}
}
}
public void updateSeniorFamilyInfo(boolean includeSuperSenior) {
FamilyEntry senior = getSenior();
if (senior != null) {
Character seniorChr = senior.getChr();
if (seniorChr != null) {
seniorChr.sendPacket(PacketCreator.getFamilyInfo(senior));
}
senior = senior.getSenior();
if (includeSuperSenior && senior != null) {
seniorChr = senior.getChr();
if (seniorChr != null) {
seniorChr.sendPacket(PacketCreator.getFamilyInfo(senior));
}
}
}
}
/**
* Traverses entire family tree to update senior/junior counts. Call on leader.
*/
public synchronized void doFullCount() {
Pair<Integer, Integer> counts = this.traverseAndUpdateCounts(0);
getFamily().setTotalGenerations(counts.getLeft() + 1);
}
private Pair<Integer, Integer> traverseAndUpdateCounts(int seniors) { // recursion probably limits family size, but it should handle a depth of a few thousand
setTotalSeniors(seniors);
this.generation = seniors;
int juniorCount = 0;
int highestGeneration = this.generation;
for (FamilyEntry entry : juniors) {
if (entry != null) {
Pair<Integer, Integer> counts = entry.traverseAndUpdateCounts(seniors + 1);
juniorCount += counts.getRight(); //total juniors
if (counts.getLeft() > highestGeneration) {
highestGeneration = counts.getLeft();
}
}
}
setTotalJuniors(juniorCount);
return new Pair<>(highestGeneration, juniorCount); //creating new objects to return is a bit inefficient, but cleaner than packing into a long
}
public boolean useEntitlement(FamilyEntitlement entitlement) {
int id = entitlement.ordinal();
if (entitlements[id] >= 1) {
return false;
}
try (Connection con = DatabaseConnection.getConnection(); PreparedStatement ps = con.prepareStatement("INSERT INTO family_entitlement (entitlementid, charid, timestamp) VALUES (?, ?, ?)")) {
ps.setInt(1, id);
ps.setInt(2, getChrId());
ps.setLong(3, System.currentTimeMillis());
ps.executeUpdate();
} catch (SQLException e) {
log.error("Could not insert new row in 'family_entitlement' for chr {}", getName(), e);
}
entitlements[id]++;
return true;
}
public boolean refundEntitlement(FamilyEntitlement entitlement) {
int id = entitlement.ordinal();
try (Connection con = DatabaseConnection.getConnection(); PreparedStatement ps = con.prepareStatement("DELETE FROM family_entitlement WHERE entitlementid = ? AND charid = ?")) {
ps.setInt(1, id);
ps.setInt(2, getChrId());
ps.executeUpdate();
} catch (SQLException e) {
log.error("Could not refund family entitlement \"{}\" for chr {}", entitlement.getName(), getName(), e);
}
entitlements[id] = 0;
return true;
}
public boolean isEntitlementUsed(FamilyEntitlement entitlement) {
return entitlements[entitlement.ordinal()] >= 1;
}
public int getEntitlementUsageCount(FamilyEntitlement entitlement) {
return entitlements[entitlement.ordinal()];
}
public void setEntitlementUsed(int id) {
entitlements[id]++;
}
public void resetEntitlementUsages() {
for (FamilyEntitlement entitlement : FamilyEntitlement.values()) {
entitlements[entitlement.ordinal()] = 0;
}
}
public boolean saveReputation() {
if (!repChanged) {
return true;
}
try (Connection con = DatabaseConnection.getConnection()) {
return saveReputation(con);
} catch (SQLException e) {
log.error("Could not get connection to DB while saving reputation", e);
return false;
}
}
public boolean saveReputation(Connection con) {
if (!repChanged) {
return true;
}
try (PreparedStatement ps = con.prepareStatement("UPDATE family_character SET reputation = ?, todaysrep = ?, totalreputation = ?, reptosenior = ? WHERE cid = ?")) {
ps.setInt(1, getReputation());
ps.setInt(2, getTodaysRep());
ps.setInt(3, getTotalReputation());
ps.setInt(4, getRepsToSenior());
ps.setInt(5, getChrId());
ps.executeUpdate();
} catch (SQLException e) {
log.error("Failed to autosave rep to 'family_character' for chrId {}", getChrId(), e);
return false;
}
return true;
}
public void savedSuccessfully() {
this.repChanged = false;
}
}

View File

@@ -0,0 +1,135 @@
/*
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 client;
public enum Job {
BEGINNER(0),
WARRIOR(100),
FIGHTER(110), CRUSADER(111), HERO(112),
PAGE(120), WHITEKNIGHT(121), PALADIN(122),
SPEARMAN(130), DRAGONKNIGHT(131), DARKKNIGHT(132),
MAGICIAN(200),
FP_WIZARD(210), FP_MAGE(211), FP_ARCHMAGE(212),
IL_WIZARD(220), IL_MAGE(221), IL_ARCHMAGE(222),
CLERIC(230), PRIEST(231), BISHOP(232),
BOWMAN(300),
HUNTER(310), RANGER(311), BOWMASTER(312),
CROSSBOWMAN(320), SNIPER(321), MARKSMAN(322),
THIEF(400),
ASSASSIN(410), HERMIT(411), NIGHTLORD(412),
BANDIT(420), CHIEFBANDIT(421), SHADOWER(422),
PIRATE(500),
BRAWLER(510), MARAUDER(511), BUCCANEER(512),
GUNSLINGER(520), OUTLAW(521), CORSAIR(522),
MAPLELEAF_BRIGADIER(800),
GM(900), SUPERGM(910),
NOBLESSE(1000),
DAWNWARRIOR1(1100), DAWNWARRIOR2(1110), DAWNWARRIOR3(1111), DAWNWARRIOR4(1112),
BLAZEWIZARD1(1200), BLAZEWIZARD2(1210), BLAZEWIZARD3(1211), BLAZEWIZARD4(1212),
WINDARCHER1(1300), WINDARCHER2(1310), WINDARCHER3(1311), WINDARCHER4(1312),
NIGHTWALKER1(1400), NIGHTWALKER2(1410), NIGHTWALKER3(1411), NIGHTWALKER4(1412),
THUNDERBREAKER1(1500), THUNDERBREAKER2(1510), THUNDERBREAKER3(1511), THUNDERBREAKER4(1512),
LEGEND(2000), EVAN(2001),
ARAN1(2100), ARAN2(2110), ARAN3(2111), ARAN4(2112),
EVAN1(2200), EVAN2(2210), EVAN3(2211), EVAN4(2212), EVAN5(2213), EVAN6(2214),
EVAN7(2215), EVAN8(2216), EVAN9(2217), EVAN10(2218);
final int jobid;
final static int maxId = 22; // maxId = (EVAN / 100);
Job(int id) {
jobid = id;
}
public static int getMax() {
return maxId;
}
public int getId() {
return jobid;
}
public static Job getById(int id) {
for (Job l : Job.values()) {
if (l.getId() == id) {
return l;
}
}
return null;
}
public static Job getBy5ByteEncoding(int encoded) {
switch (encoded) {
case 2:
return WARRIOR;
case 4:
return MAGICIAN;
case 8:
return BOWMAN;
case 16:
return THIEF;
case 32:
return PIRATE;
case 1024:
return NOBLESSE;
case 2048:
return DAWNWARRIOR1;
case 4096:
return BLAZEWIZARD1;
case 8192:
return WINDARCHER1;
case 16384:
return NIGHTWALKER1;
case 32768:
return THUNDERBREAKER1;
default:
return BEGINNER;
}
}
public boolean isA(Job basejob) { // thanks Steve (kaito1410) for pointing out an improvement here
int basebranch = basejob.getId() / 10;
return (getId() / 10 == basebranch && getId() >= basejob.getId()) || (basebranch % 10 == 0 && getId() / 100 == basejob.getId() / 100);
}
public int getJobNiche() {
return (jobid / 100) % 10;
/*
case 0: BEGINNER;
case 1: WARRIOR;
case 2: MAGICIAN;
case 3: BOWMAN;
case 4: THIEF;
case 5: PIRATE;
*/
}
}

View File

@@ -0,0 +1,221 @@
/*
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 client;
import tools.DatabaseConnection;
import tools.PacketCreator;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.*;
import java.util.Map.Entry;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public final class MonsterBook {
private int specialCard = 0;
private int normalCard = 0;
private int bookLevel = 1;
private final Map<Integer, Integer> cards = new LinkedHashMap<>();
private final Lock lock = new ReentrantLock();
public Set<Entry<Integer, Integer>> getCardSet() {
lock.lock();
try {
return new HashSet<>(cards.entrySet());
} finally {
lock.unlock();
}
}
public void addCard(final Client c, final int cardid) {
c.getPlayer().getMap().broadcastMessage(c.getPlayer(), PacketCreator.showForeignCardEffect(c.getPlayer().getId()), false);
Integer qty;
lock.lock();
try {
qty = cards.get(cardid);
if (qty != null) {
if (qty < 5) {
cards.put(cardid, qty + 1);
}
} else {
cards.put(cardid, 1);
qty = 0;
if (cardid / 1000 >= 2388) {
specialCard++;
} else {
normalCard++;
}
}
} finally {
lock.unlock();
}
if (qty < 5) {
if (qty == 0) { // leveling system only accounts unique cards
calculateLevel();
}
c.sendPacket(PacketCreator.addCard(false, cardid, qty + 1));
c.sendPacket(PacketCreator.showGainCard());
} else {
c.sendPacket(PacketCreator.addCard(true, cardid, 5));
}
}
private void calculateLevel() {
lock.lock();
try {
int collectionExp = (normalCard + specialCard);
int level = 0, expToNextlevel = 1;
do {
level++;
expToNextlevel += level * 10;
} while (collectionExp >= expToNextlevel);
bookLevel = level; // thanks IxianMace for noticing book level differing between book UI and character info UI
} finally {
lock.unlock();
}
}
public int getBookLevel() {
lock.lock();
try {
return bookLevel;
} finally {
lock.unlock();
}
}
public Map<Integer, Integer> getCards() {
lock.lock();
try {
return Collections.unmodifiableMap(cards);
} finally {
lock.unlock();
}
}
public int getTotalCards() {
lock.lock();
try {
return specialCard + normalCard;
} finally {
lock.unlock();
}
}
public int getNormalCard() {
lock.lock();
try {
return normalCard;
} finally {
lock.unlock();
}
}
public int getSpecialCard() {
lock.lock();
try {
return specialCard;
} finally {
lock.unlock();
}
}
public void loadCards(final int charid) throws SQLException {
lock.lock();
try (Connection con = DatabaseConnection.getConnection();
PreparedStatement ps = con.prepareStatement("SELECT cardid, level FROM monsterbook WHERE charid = ? ORDER BY cardid ASC")) {
ps.setInt(1, charid);
try (ResultSet rs = ps.executeQuery()) {
int cardid;
int level;
while (rs.next()) {
cardid = rs.getInt("cardid");
level = rs.getInt("level");
if (cardid / 1000 >= 2388) {
specialCard++;
} else {
normalCard++;
}
cards.put(cardid, level);
}
}
} finally {
lock.unlock();
}
calculateLevel();
}
public void saveCards(Connection con, int chrId) throws SQLException {
final String query = """
INSERT INTO monsterbook (charid, cardid, level)
VALUES (?, ?, ?)
ON DUPLICATE KEY UPDATE level = ?;
""";
try (final PreparedStatement ps = con.prepareStatement(query)) {
for (Map.Entry<Integer, Integer> cardAndLevel : cards.entrySet()) {
final int card = cardAndLevel.getKey();
final int level = cardAndLevel.getValue();
// insert
ps.setInt(1, chrId);
ps.setInt(2, card);
ps.setInt(3, level);
// update
ps.setInt(4, level);
ps.addBatch();
}
ps.executeBatch();
}
}
public static int[] getCardTierSize() {
try (Connection con = DatabaseConnection.getConnection();
PreparedStatement ps = con.prepareStatement("SELECT COUNT(*) FROM monstercarddata GROUP BY floor(cardid / 1000);", ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
ResultSet rs = ps.executeQuery()) {
rs.last();
int[] tierSizes = new int[rs.getRow()];
rs.beforeFirst();
while (rs.next()) {
tierSizes[rs.getRow() - 1] = rs.getInt(1);
}
return tierSizes;
} catch (SQLException e) {
e.printStackTrace();
return new int[0];
}
}
}

View File

@@ -0,0 +1,130 @@
/*
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 client;
/**
* @author PurpleMadness < Patrick :O >
*/
public class Mount {
private int itemid;
private int skillid;
private int tiredness;
private int exp;
private int level;
private Character owner;
private boolean active;
public Mount(Character owner, int id, int skillid) {
this.itemid = id;
this.skillid = skillid;
this.tiredness = 0;
this.level = 1;
this.exp = 0;
this.owner = owner;
active = true;
}
public int getItemId() {
return itemid;
}
public int getSkillId() {
return skillid;
}
/**
* 1902000 - Hog
* 1902001 - Silver Mane
* 1902002 - Red Draco
* 1902005 - Mimiana
* 1902006 - Mimio
* 1902007 - Shinjou
* 1902008 - Frog
* 1902009 - Ostrich
* 1902010 - Frog
* 1902011 - Turtle
* 1902012 - Yeti
*
* @return the id
*/
public int getId() {
if (this.itemid < 1903000) {
return itemid - 1901999;
}
return 5;
}
public int getTiredness() {
return tiredness;
}
public int getExp() {
return exp;
}
public int getLevel() {
return level;
}
public void setTiredness(int newtiredness) {
this.tiredness = newtiredness;
if (tiredness < 0) {
tiredness = 0;
}
}
public int incrementAndGetTiredness() {
this.tiredness++;
return this.tiredness;
}
public void setExp(int newexp) {
this.exp = newexp;
}
public void setLevel(int newlevel) {
this.level = newlevel;
}
public void setItemId(int newitemid) {
this.itemid = newitemid;
}
public void setSkillId(int newskillid) {
this.skillid = newskillid;
}
public void setActive(boolean set) {
this.active = set;
}
public boolean isActive() {
return active;
}
public void empty() {
if (owner != null) {
owner.getClient().getWorldServer().unregisterMountHunger(owner);
}
this.owner = null;
}
}

View File

@@ -0,0 +1,278 @@
/*
This file is part of the OdinMS Maple Story Server
Copyright (C) 2008 Patrick Huy <patrick.huy@frz.cc>
Matthias Butz <matze@odinms.de>
Jan Christian Meyer <vimes@odinms.de>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation version 3 as published by
the Free Software Foundation. You may not use, modify or distribute
this program under any other version of the GNU Affero General Public
License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package client;
import server.quest.Quest;
import tools.StringUtil;
import java.util.*;
/**
* @author Matze
*/
public class QuestStatus {
public enum Status {
UNDEFINED(-1),
NOT_STARTED(0),
STARTED(1),
COMPLETED(2);
final int status;
Status(int id) {
status = id;
}
public int getId() {
return status;
}
public static Status getById(int id) {
for (Status l : Status.values()) {
if (l.getId() == id) {
return l;
}
}
return null;
}
}
private final short questID;
private Status status;
//private boolean updated; //maybe this can be of use for someone?
private final Map<Integer, String> progress = new LinkedHashMap<>();
private final List<Integer> medalProgress = new LinkedList<>();
private int npc;
private long completionTime, expirationTime;
private int forfeited = 0, completed = 0;
private String customData;
public QuestStatus(Quest quest, Status status) {
this.questID = quest.getId();
this.setStatus(status);
this.completionTime = System.currentTimeMillis();
this.expirationTime = 0;
//this.updated = true;
if (status == Status.STARTED) {
registerMobs();
}
}
public QuestStatus(Quest quest, Status status, int npc) {
this.questID = quest.getId();
this.setStatus(status);
this.setNpc(npc);
this.completionTime = System.currentTimeMillis();
this.expirationTime = 0;
//this.updated = true;
if (status == Status.STARTED) {
registerMobs();
}
}
public Quest getQuest() {
return Quest.getInstance(questID);
}
public short getQuestID() {
return questID;
}
public Status getStatus() {
return status;
}
public final void setStatus(Status status) {
this.status = status;
}
/*
public boolean wasUpdated() {
return updated;
}
private void setUpdated() {
this.updated = true;
}
public void resetUpdated() {
this.updated = false;
}
*/
public int getNpc() {
return npc;
}
public final void setNpc(int npc) {
this.npc = npc;
}
private void registerMobs() {
for (int i : Quest.getInstance(questID).getRelevantMobs()) {
progress.put(i, "000");
}
//this.setUpdated();
}
public boolean addMedalMap(int mapid) {
if (medalProgress.contains(mapid)) {
return false;
}
medalProgress.add(mapid);
//this.setUpdated();
return true;
}
public int getMedalProgress() {
return medalProgress.size();
}
public List<Integer> getMedalMaps() {
return medalProgress;
}
public boolean progress(int id) {
String currentStr = progress.get(id);
if (currentStr == null) {
return false;
}
int current = Integer.parseInt(currentStr);
if (current >= this.getQuest().getMobAmountNeeded(id)) {
return false;
}
String str = StringUtil.getLeftPaddedStr(Integer.toString(++current), '0', 3);
progress.put(id, str);
//this.setUpdated();
return true;
}
public void setProgress(int id, String pr) {
progress.put(id, pr);
//this.setUpdated();
}
public boolean madeProgress() {
return progress.size() > 0;
}
public String getProgress(int id) {
String ret = progress.get(id);
if (ret == null) {
return "";
} else {
return ret;
}
}
public void resetProgress(int id) {
setProgress(id, "000");
}
public void resetAllProgress() {
for (Map.Entry<Integer, String> entry : progress.entrySet()) {
setProgress(entry.getKey(), "000");
}
}
public Map<Integer, String> getProgress() {
return Collections.unmodifiableMap(progress);
}
public short getInfoNumber() {
Quest q = this.getQuest();
Status s = this.getStatus();
return q.getInfoNumber(s);
}
public String getInfoEx(int index) {
Quest q = this.getQuest();
Status s = this.getStatus();
return q.getInfoEx(s, index);
}
public List<String> getInfoEx() {
Quest q = this.getQuest();
Status s = this.getStatus();
return q.getInfoEx(s);
}
public long getCompletionTime() {
return completionTime;
}
public void setCompletionTime(long completionTime) {
this.completionTime = completionTime;
}
public long getExpirationTime() {
return expirationTime;
}
public void setExpirationTime(long expirationTime) {
this.expirationTime = expirationTime;
}
public int getForfeited() {
return forfeited;
}
public int getCompleted() {
return completed;
}
public void setForfeited(int forfeited) {
if (forfeited >= this.forfeited) {
this.forfeited = forfeited;
} else {
throw new IllegalArgumentException("Can't set forfeits to something lower than before.");
}
}
public void setCompleted(int completed) {
if (completed >= this.completed) {
this.completed = completed;
} else {
throw new IllegalArgumentException("Can't set completes to something lower than before.");
}
}
public final void setCustomData(final String customData) {
this.customData = customData;
}
public final String getCustomData() {
return customData;
}
public String getProgressData() {
StringBuilder str = new StringBuilder();
for (String ps : progress.values()) {
str.append(ps);
}
return str.toString();
}
}

View File

@@ -0,0 +1,199 @@
/*
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 client;
import client.inventory.manipulator.CashIdGenerator;
import tools.DatabaseConnection;
import tools.Pair;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
/**
* @author Danny
*/
public class Ring implements Comparable<Ring> {
private final int ringId;
private final int ringId2;
private final int partnerId;
private final int itemId;
private final String partnerName;
private boolean equipped = false;
public Ring(int id, int id2, int partnerId, int itemid, String partnername) {
this.ringId = id;
this.ringId2 = id2;
this.partnerId = partnerId;
this.itemId = itemid;
this.partnerName = partnername;
}
public static Ring loadFromDb(int ringId) {
Ring ret = null;
try (Connection con = DatabaseConnection.getConnection();
PreparedStatement ps = con.prepareStatement("SELECT * FROM rings WHERE id = ?")) {
ps.setInt(1, ringId);
try (ResultSet rs = ps.executeQuery()) {
if (rs.next()) {
ret = new Ring(ringId, rs.getInt("partnerRingId"), rs.getInt("partnerChrId"), rs.getInt("itemid"), rs.getString("partnerName"));
}
}
return ret;
} catch (SQLException ex) {
ex.printStackTrace();
return null;
}
}
public static void removeRing(final Ring ring) {
try {
if (ring == null) {
return;
}
try (Connection con = DatabaseConnection.getConnection()) {
try (PreparedStatement ps = con.prepareStatement("DELETE FROM rings WHERE id=?")) {
ps.setInt(1, ring.getRingId());
ps.addBatch();
ps.setInt(1, ring.getPartnerRingId());
ps.addBatch();
ps.executeBatch();
}
CashIdGenerator.freeCashId(ring.getRingId());
CashIdGenerator.freeCashId(ring.getPartnerRingId());
try (PreparedStatement ps = con.prepareStatement("UPDATE inventoryequipment SET ringid=-1 WHERE ringid=?")) {
ps.setInt(1, ring.getRingId());
ps.addBatch();
ps.setInt(1, ring.getPartnerRingId());
ps.addBatch();
ps.executeBatch();
}
}
} catch (SQLException ex) {
ex.printStackTrace();
}
}
public static Pair<Integer, Integer> createRing(int itemid, final Character partner1, final Character partner2) {
try {
if (partner1 == null) {
return new Pair<>(-3, -3);
} else if (partner2 == null) {
return new Pair<>(-2, -2);
}
int[] ringID = new int[2];
ringID[0] = CashIdGenerator.generateCashId();
ringID[1] = CashIdGenerator.generateCashId();
try (Connection con = DatabaseConnection.getConnection()) {
try (PreparedStatement ps = con.prepareStatement("INSERT INTO rings (id, itemid, partnerRingId, partnerChrId, partnername) VALUES (?, ?, ?, ?, ?)")) {
ps.setInt(1, ringID[0]);
ps.setInt(2, itemid);
ps.setInt(3, ringID[1]);
ps.setInt(4, partner2.getId());
ps.setString(5, partner2.getName());
ps.executeUpdate();
}
try (PreparedStatement ps = con.prepareStatement("INSERT INTO rings (id, itemid, partnerRingId, partnerChrId, partnername) VALUES (?, ?, ?, ?, ?)")) {
ps.setInt(1, ringID[1]);
ps.setInt(2, itemid);
ps.setInt(3, ringID[0]);
ps.setInt(4, partner1.getId());
ps.setString(5, partner1.getName());
ps.executeUpdate();
}
}
return new Pair<>(ringID[0], ringID[1]);
} catch (SQLException ex) {
ex.printStackTrace();
return new Pair<>(-1, -1);
}
}
public int getRingId() {
return ringId;
}
public int getPartnerRingId() {
return ringId2;
}
public int getPartnerChrId() {
return partnerId;
}
public int getItemId() {
return itemId;
}
public String getPartnerName() {
return partnerName;
}
public boolean equipped() {
return equipped;
}
public void equip() {
this.equipped = true;
}
public void unequip() {
this.equipped = false;
}
@Override
public boolean equals(Object o) {
if (o instanceof Ring ring) {
return ring.getRingId() == getRingId();
}
return false;
}
@Override
public int hashCode() {
int hash = 5;
hash = 53 * hash + this.ringId;
return hash;
}
@Override
public int compareTo(Ring other) {
if (ringId < other.getRingId()) {
return -1;
} else if (ringId == other.getRingId()) {
return 0;
}
return 1;
}
}

View File

@@ -0,0 +1,100 @@
/*
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 client;
import server.StatEffect;
import server.life.Element;
import java.util.ArrayList;
import java.util.List;
public class Skill {
private final int id;
private final List<StatEffect> effects = new ArrayList<>();
private Element element;
private int animationTime;
private final int job;
private boolean action;
public Skill(int id) {
this.id = id;
this.job = id / 10000;
}
public int getId() {
return id;
}
public StatEffect getEffect(int level) {
return effects.get(level - 1);
}
public int getMaxLevel() {
return effects.size();
}
public boolean isFourthJob() {
if (job == 2212) {
return false;
}
if (id == 22170001 || id == 22171003 || id == 22171004 || id == 22181002 || id == 22181003) {
return true;
}
return job % 10 == 2;
}
public void setElement(Element elem) {
element = elem;
}
public Element getElement() {
return element;
}
public int getAnimationTime() {
return animationTime;
}
public void setAnimationTime(int time) {
animationTime = time;
}
public void incAnimationTime(int time) {
animationTime += time;
}
public boolean isBeginnerSkill() {
return id % 10000000 < 10000;
}
public void setAction(boolean act) {
action = act;
}
public boolean getAction() {
return action;
}
public void addLevelEffect(StatEffect effect) {
effects.add(effect);
}
}

View File

@@ -0,0 +1,350 @@
/*
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 client;
import constants.skills.*;
import provider.*;
import provider.wz.WZFiles;
import server.StatEffect;
import server.life.Element;
import java.util.HashMap;
import java.util.Map;
public class SkillFactory {
private static volatile Map<Integer, Skill> skills = new HashMap<>();
private static final DataProvider datasource = DataProviderFactory.getDataProvider(WZFiles.SKILL);
public static Skill getSkill(int id) {
return skills.get(id);
}
public static void loadAllSkills() {
final Map<Integer, Skill> loadedSkills = new HashMap<>();
final DataDirectoryEntry root = datasource.getRoot();
for (DataFileEntry topDir : root.getFiles()) { // Loop thru jobs
if (topDir.getName().length() <= 8) {
for (Data data : datasource.getData(topDir.getName())) { // Loop thru each jobs
if (data.getName().equals("skill")) {
for (Data data2 : data) { // Loop thru each jobs
if (data2 != null) {
int skillId = Integer.parseInt(data2.getName());
loadedSkills.put(skillId, loadFromData(skillId, data2));
}
}
}
}
}
}
skills = loadedSkills;
}
private static Skill loadFromData(int id, Data data) {
Skill ret = new Skill(id);
boolean isBuff = false;
int skillType = DataTool.getInt("skillType", data, -1);
String elem = DataTool.getString("elemAttr", data, null);
if (elem != null) {
ret.setElement(Element.getFromChar(elem.charAt(0)));
} else {
ret.setElement(Element.NEUTRAL);
}
Data effect = data.getChildByPath("effect");
if (skillType != -1) {
if (skillType == 2) {
isBuff = true;
}
} else {
Data action_ = data.getChildByPath("action");
boolean action = false;
if (action_ == null) {
if (data.getChildByPath("prepare/action") != null) {
action = true;
} else {
switch (id) {
case Gunslinger.INVISIBLE_SHOT:
case Corsair.HYPNOTIZE:
action = true;
break;
}
}
} else {
action = true;
}
ret.setAction(action);
Data hit = data.getChildByPath("hit");
Data ball = data.getChildByPath("ball");
isBuff = effect != null && hit == null && ball == null;
isBuff |= action_ != null && DataTool.getString("0", action_, "").equals("alert2");
switch (id) {
case Hero.RUSH:
case Paladin.RUSH:
case DarkKnight.RUSH:
case DragonKnight.SACRIFICE:
case FPMage.EXPLOSION:
case FPMage.POISON_MIST:
case Cleric.HEAL:
case Ranger.MORTAL_BLOW:
case Sniper.MORTAL_BLOW:
case Assassin.DRAIN:
case Hermit.SHADOW_WEB:
case Bandit.STEAL:
case Shadower.SMOKE_SCREEN:
case SuperGM.HEAL_PLUS_DISPEL:
case Hero.MONSTER_MAGNET:
case Paladin.MONSTER_MAGNET:
case DarkKnight.MONSTER_MAGNET:
case Evan.ICE_BREATH:
case Evan.FIRE_BREATH:
case Gunslinger.RECOIL_SHOT:
case Marauder.ENERGY_DRAIN:
case BlazeWizard.FLAME_GEAR:
case NightWalker.SHADOW_WEB:
case NightWalker.POISON_BOMB:
case NightWalker.VAMPIRE:
case ChiefBandit.CHAKRA:
case Aran.COMBAT_STEP:
case Evan.RECOVERY_AURA:
isBuff = false;
break;
case Beginner.RECOVERY:
case Beginner.NIMBLE_FEET:
case Beginner.MONSTER_RIDER:
case Beginner.ECHO_OF_HERO:
case Beginner.MAP_CHAIR:
case Warrior.IRON_BODY:
case Fighter.AXE_BOOSTER:
case Fighter.POWER_GUARD:
case Fighter.RAGE:
case Fighter.SWORD_BOOSTER:
case Crusader.ARMOR_CRASH:
case Crusader.COMBO:
case Hero.ENRAGE:
case Hero.HEROS_WILL:
case Hero.MAPLE_WARRIOR:
case Hero.STANCE:
case Page.BW_BOOSTER:
case Page.POWER_GUARD:
case Page.SWORD_BOOSTER:
case Page.THREATEN:
case WhiteKnight.BW_FIRE_CHARGE:
case WhiteKnight.BW_ICE_CHARGE:
case WhiteKnight.BW_LIT_CHARGE:
case WhiteKnight.MAGIC_CRASH:
case WhiteKnight.SWORD_FIRE_CHARGE:
case WhiteKnight.SWORD_ICE_CHARGE:
case WhiteKnight.SWORD_LIT_CHARGE:
case Paladin.BW_HOLY_CHARGE:
case Paladin.HEROS_WILL:
case Paladin.MAPLE_WARRIOR:
case Paladin.STANCE:
case Paladin.SWORD_HOLY_CHARGE:
case Spearman.HYPER_BODY:
case Spearman.IRON_WILL:
case Spearman.POLEARM_BOOSTER:
case Spearman.SPEAR_BOOSTER:
case DragonKnight.DRAGON_BLOOD:
case DragonKnight.POWER_CRASH:
case DarkKnight.AURA_OF_BEHOLDER:
case DarkKnight.BEHOLDER:
case DarkKnight.HEROS_WILL:
case DarkKnight.HEX_OF_BEHOLDER:
case DarkKnight.MAPLE_WARRIOR:
case DarkKnight.STANCE:
case Magician.MAGIC_GUARD:
case Magician.MAGIC_ARMOR:
case FPWizard.MEDITATION:
case FPWizard.SLOW:
case FPMage.SEAL:
case FPMage.SPELL_BOOSTER:
case FPArchMage.HEROS_WILL:
case FPArchMage.INFINITY:
case FPArchMage.MANA_REFLECTION:
case FPArchMage.MAPLE_WARRIOR:
case ILWizard.MEDITATION:
case ILMage.SEAL:
case ILWizard.SLOW:
case ILMage.SPELL_BOOSTER:
case ILArchMage.HEROS_WILL:
case ILArchMage.INFINITY:
case ILArchMage.MANA_REFLECTION:
case ILArchMage.MAPLE_WARRIOR:
case Cleric.INVINCIBLE:
case Cleric.BLESS:
case Priest.DISPEL:
case Priest.DOOM:
case Priest.HOLY_SYMBOL:
case Priest.MYSTIC_DOOR:
case Bishop.HEROS_WILL:
case Bishop.HOLY_SHIELD:
case Bishop.INFINITY:
case Bishop.MANA_REFLECTION:
case Bishop.MAPLE_WARRIOR:
case Archer.FOCUS:
case Hunter.BOW_BOOSTER:
case Hunter.SOUL_ARROW:
case Ranger.PUPPET:
case Bowmaster.CONCENTRATE:
case Bowmaster.HEROS_WILL:
case Bowmaster.MAPLE_WARRIOR:
case Bowmaster.SHARP_EYES:
case Crossbowman.CROSSBOW_BOOSTER:
case Crossbowman.SOUL_ARROW:
case Sniper.PUPPET:
case Marksman.BLIND:
case Marksman.HEROS_WILL:
case Marksman.MAPLE_WARRIOR:
case Marksman.SHARP_EYES:
case Rogue.DARK_SIGHT:
case Assassin.CLAW_BOOSTER:
case Assassin.HASTE:
case Hermit.MESO_UP:
case Hermit.SHADOW_PARTNER:
case NightLord.HEROS_WILL:
case NightLord.MAPLE_WARRIOR:
case NightLord.NINJA_AMBUSH:
case NightLord.SHADOW_STARS:
case Bandit.DAGGER_BOOSTER:
case Bandit.HASTE:
case ChiefBandit.MESO_GUARD:
case ChiefBandit.PICKPOCKET:
case Shadower.HEROS_WILL:
case Shadower.MAPLE_WARRIOR:
case Shadower.NINJA_AMBUSH:
case Pirate.DASH:
case Marauder.TRANSFORMATION:
case Buccaneer.SUPER_TRANSFORMATION:
case Corsair.BATTLE_SHIP:
case GM.HIDE:
case SuperGM.HASTE:
case SuperGM.HOLY_SYMBOL:
case SuperGM.BLESS:
case SuperGM.HIDE:
case SuperGM.HYPER_BODY:
case Noblesse.BLESSING_OF_THE_FAIRY:
case Noblesse.ECHO_OF_HERO:
case Noblesse.MONSTER_RIDER:
case Noblesse.NIMBLE_FEET:
case Noblesse.RECOVERY:
case Noblesse.MAP_CHAIR:
case DawnWarrior.COMBO:
case DawnWarrior.FINAL_ATTACK:
case DawnWarrior.IRON_BODY:
case DawnWarrior.RAGE:
case DawnWarrior.SOUL:
case DawnWarrior.SOUL_CHARGE:
case DawnWarrior.SWORD_BOOSTER:
case BlazeWizard.ELEMENTAL_RESET:
case BlazeWizard.FLAME:
case BlazeWizard.IFRIT:
case BlazeWizard.MAGIC_ARMOR:
case BlazeWizard.MAGIC_GUARD:
case BlazeWizard.MEDITATION:
case BlazeWizard.SEAL:
case BlazeWizard.SLOW:
case BlazeWizard.SPELL_BOOSTER:
case WindArcher.BOW_BOOSTER:
case WindArcher.EAGLE_EYE:
case WindArcher.FINAL_ATTACK:
case WindArcher.FOCUS:
case WindArcher.PUPPET:
case WindArcher.SOUL_ARROW:
case WindArcher.STORM:
case WindArcher.WIND_WALK:
case NightWalker.CLAW_BOOSTER:
case NightWalker.DARKNESS:
case NightWalker.DARK_SIGHT:
case NightWalker.HASTE:
case NightWalker.SHADOW_PARTNER:
case ThunderBreaker.DASH:
case ThunderBreaker.ENERGY_CHARGE:
case ThunderBreaker.ENERGY_DRAIN:
case ThunderBreaker.KNUCKLER_BOOSTER:
case ThunderBreaker.LIGHTNING:
case ThunderBreaker.SPARK:
case ThunderBreaker.LIGHTNING_CHARGE:
case ThunderBreaker.SPEED_INFUSION:
case ThunderBreaker.TRANSFORMATION:
case Legend.BLESSING_OF_THE_FAIRY:
case Legend.AGILE_BODY:
case Legend.ECHO_OF_HERO:
case Legend.RECOVERY:
case Legend.MONSTER_RIDER:
case Legend.MAP_CHAIR:
case Aran.MAPLE_WARRIOR:
case Aran.HEROS_WILL:
case Aran.POLEARM_BOOSTER:
case Aran.COMBO_DRAIN:
case Aran.SNOW_CHARGE:
case Aran.BODY_PRESSURE:
case Aran.SMART_KNOCKBACK:
case Aran.COMBO_BARRIER:
case Aran.COMBO_ABILITY:
case Evan.BLESSING_OF_THE_FAIRY:
case Evan.RECOVERY:
case Evan.NIMBLE_FEET:
case Evan.HEROS_WILL:
case Evan.ECHO_OF_HERO:
case Evan.MAGIC_BOOSTER:
case Evan.MAGIC_GUARD:
case Evan.ELEMENTAL_RESET:
case Evan.MAPLE_WARRIOR:
case Evan.MAGIC_RESISTANCE:
case Evan.MAGIC_SHIELD:
case Evan.SLOW:
isBuff = true;
break;
}
}
for (Data level : data.getChildByPath("level")) {
ret.addLevelEffect(StatEffect.loadSkillEffectFromData(level, id, isBuff));
}
ret.setAnimationTime(0);
if (effect != null) {
for (Data effectEntry : effect) {
ret.incAnimationTime(DataTool.getIntConvert("delay", effectEntry, 0));
}
}
return ret;
}
public static String getSkillName(int skillid) {
Data data = DataProviderFactory.getDataProvider(WZFiles.STRING).getData("Skill.img");
StringBuilder skill = new StringBuilder();
skill.append(skillid);
if (skill.length() == 4) {
skill.delete(0, 4);
skill.append("000").append(skillid);
}
if (data.getChildByPath(skill.toString()) != null) {
for (Data skilldata : data.getChildByPath(skill.toString()).getChildren()) {
if (skilldata.getName().equals("name")) {
return DataTool.getString(skilldata, null);
}
}
}
return null;
}
}

View File

@@ -0,0 +1,76 @@
/*
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 client;
public class SkillMacro {
private int skill1;
private int skill2;
private int skill3;
private final String name;
private final int shout;
private final int position;
public SkillMacro(int skill1, int skill2, int skill3, String name, int shout, int position) {
this.skill1 = skill1;
this.skill2 = skill2;
this.skill3 = skill3;
this.name = name;
this.shout = shout;
this.position = position;
}
public int getSkill1() {
return skill1;
}
public int getSkill2() {
return skill2;
}
public int getSkill3() {
return skill3;
}
public void setSkill1(int skill) {
skill1 = skill;
}
public void setSkill2(int skill) {
skill2 = skill;
}
public void setSkill3(int skill) {
skill3 = skill;
}
public String getName() {
return name;
}
public int getShout() {
return shout;
}
public int getPosition() {
return position;
}
}

View File

@@ -0,0 +1,52 @@
/*
This file is part of the OdinMS Maple Story Server
Copyright (C) 2008 Patrick Huy <patrick.huy@frz.cc>
Matthias Butz <matze@odinms.de>
Jan Christian Meyer <vimes@odinms.de>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation version 3 as published by
the Free Software Foundation. You may not use, modify or distribute
this program under any other version of the GNU Affero General Public
License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package client;
public enum SkinColor {
NORMAL(0),
DARK(1),
BLACK(2),
PALE(3),
BLUE(4),
GREEN(5),
WHITE(9),
PINK(10);
final int id;
SkinColor(int id) {
this.id = id;
}
public int getId() {
return id;
}
public static SkinColor getById(int id) {
for (SkinColor l : SkinColor.values()) {
if (l.getId() == id) {
return l;
}
}
return null;
}
}

View File

@@ -0,0 +1,86 @@
/*
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 client;
public enum Stat {
SKIN(0x1),
FACE(0x2),
HAIR(0x4),
LEVEL(0x10),
JOB(0x20),
STR(0x40),
DEX(0x80),
INT(0x100),
LUK(0x200),
HP(0x400),
MAXHP(0x800),
MP(0x1000),
MAXMP(0x2000),
AVAILABLEAP(0x4000),
AVAILABLESP(0x8000),
EXP(0x10000),
FAME(0x20000),
MESO(0x40000),
PET(0x180008),
GACHAEXP(0x200000);
private final int i;
Stat(int i) {
this.i = i;
}
public int getValue() {
return i;
}
public static Stat getByValue(int value) {
for (Stat stat : Stat.values()) {
if (stat.getValue() == value) {
return stat;
}
}
return null;
}
public static Stat getBy5ByteEncoding(int encoded) {
switch (encoded) {
case 64:
return STR;
case 128:
return DEX;
case 256:
return INT;
case 512:
return LUK;
}
return null;
}
public static Stat getByString(String type) {
for (Stat stat : Stat.values()) {
if (stat.name().equals(type)) {
return stat;
}
}
return null;
}
}

View File

@@ -0,0 +1,138 @@
/*
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 client.autoban;
import client.Character;
import config.YamlConfig;
import net.server.Server;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import tools.PacketCreator;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import static java.util.concurrent.TimeUnit.MINUTES;
import static java.util.concurrent.TimeUnit.SECONDS;
/**
* @author kevintjuh93
*/
public enum AutobanFactory {
MOB_COUNT,
GENERAL,
FIX_DAMAGE,
DAMAGE_HACK(15, MINUTES.toMillis(1)),
DISTANCE_HACK(10, MINUTES.toMillis(2)),
PORTAL_DISTANCE(5, SECONDS.toMillis(30)),
PACKET_EDIT,
ACC_HACK,
CREATION_GENERATOR,
HIGH_HP_HEALING,
FAST_HP_HEALING(15),
FAST_MP_HEALING(20, SECONDS.toMillis(30)),
GACHA_EXP,
TUBI(20, SECONDS.toMillis(15)),
SHORT_ITEM_VAC,
ITEM_VAC,
FAST_ITEM_PICKUP(5, SECONDS.toMillis(30)),
FAST_ATTACK(10, SECONDS.toMillis(30)),
MPCON(25, SECONDS.toMillis(30));
private static final Logger log = LoggerFactory.getLogger(AutobanFactory.class);
private static final Set<Integer> ignoredChrIds = new HashSet<>();
private final int points;
private final long expiretime;
AutobanFactory() {
this(1, -1);
}
AutobanFactory(int points) {
this.points = points;
this.expiretime = -1;
}
AutobanFactory(int points, long expire) {
this.points = points;
this.expiretime = expire;
}
public int getMaximum() {
return points;
}
public long getExpire() {
return expiretime;
}
public void addPoint(AutobanManager ban, String reason) {
ban.addPoint(this, reason);
}
public void alert(Character chr, String reason) {
if (YamlConfig.config.server.USE_AUTOBAN) {
if (chr != null && isIgnored(chr.getId())) {
return;
}
Server.getInstance().broadcastGMMessage((chr != null ? chr.getWorld() : 0), PacketCreator.sendYellowTip((chr != null ? Character.makeMapleReadable(chr.getName()) : "") + " caused " + this.name() + " " + reason));
}
if (YamlConfig.config.server.USE_AUTOBAN_LOG) {
final String chrName = chr != null ? Character.makeMapleReadable(chr.getName()) : "";
log.info("Autoban alert - chr {} caused {}-{}", chrName, this.name(), reason);
}
}
public void autoban(Character chr, String value) {
if (YamlConfig.config.server.USE_AUTOBAN) {
chr.autoban("Autobanned for (" + this.name() + ": " + value + ")");
//chr.sendPolice("You will be disconnected for (" + this.name() + ": " + value + ")");
}
}
/**
* Toggle ignored status for a character id.
* An ignored character will not trigger GM alerts.
*
* @return new status. true if the chrId is now ignored, otherwise false.
*/
public static boolean toggleIgnored(int chrId) {
if (ignoredChrIds.contains(chrId)) {
ignoredChrIds.remove(chrId);
return false;
} else {
ignoredChrIds.add(chrId);
return true;
}
}
private static boolean isIgnored(int chrId) {
return ignoredChrIds.contains(chrId);
}
public static Collection<Integer> getIgnoredChrIds() {
return ignoredChrIds;
}
}

View File

@@ -0,0 +1,132 @@
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package client.autoban;
import client.Character;
import config.YamlConfig;
import net.server.Server;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.HashMap;
import java.util.Map;
/**
* @author kevintjuh93
*/
public class AutobanManager {
private static final Logger log = LoggerFactory.getLogger(AutobanManager.class);
private final Character chr;
private final Map<AutobanFactory, Integer> points = new HashMap<>();
private final Map<AutobanFactory, Long> lastTime = new HashMap<>();
private int misses = 0;
private int lastmisses = 0;
private int samemisscount = 0;
private final long[] spam = new long[20];
private final int[] timestamp = new int[20];
private final byte[] timestampcounter = new byte[20];
public AutobanManager(Character chr) {
this.chr = chr;
}
public void addPoint(AutobanFactory fac, String reason) {
if (YamlConfig.config.server.USE_AUTOBAN) {
if (chr.isGM() || chr.isBanned()) {
return;
}
if (lastTime.containsKey(fac)) {
if (lastTime.get(fac) < (Server.getInstance().getCurrentTime() - fac.getExpire())) {
points.put(fac, points.get(fac) / 2); //So the points are not completely gone.
}
}
if (fac.getExpire() != -1) {
lastTime.put(fac, Server.getInstance().getCurrentTime());
}
if (points.containsKey(fac)) {
points.put(fac, points.get(fac) + 1);
} else {
points.put(fac, 1);
}
if (points.get(fac) >= fac.getMaximum()) {
chr.autoban(reason);
}
}
if (YamlConfig.config.server.USE_AUTOBAN_LOG) {
// Lets log every single point too.
log.info("Autoban - chr {} caused {} {}", Character.makeMapleReadable(chr.getName()), fac.name(), reason);
}
}
public void addMiss() {
this.misses++;
}
public void resetMisses() {
if (lastmisses == misses && misses > 6) {
samemisscount++;
}
if (samemisscount > 4) {
chr.sendPolice("You will be disconnected for miss godmode.");
}
//chr.autoban("Autobanned for : " + misses + " Miss godmode", 1);
else if (samemisscount > 0) {
this.lastmisses = misses;
}
this.misses = 0;
}
//Don't use the same type for more than 1 thing
public void spam(int type) {
this.spam[type] = Server.getInstance().getCurrentTime();
}
public void spam(int type, int timestamp) {
this.spam[type] = timestamp;
}
public long getLastSpam(int type) {
return spam[type];
}
/**
* Timestamp checker
*
* <code>type</code>:<br>
* 1: Pet Food<br>
* 2: InventoryMerge<br>
* 3: InventorySort<br>
* 4: SpecialMove<br>
* 5: UseCatchItem<br>
* 6: Item Drop<br>
* 7: Chat<br>
* 8: HealOverTimeHP<br>
* 9: HealOverTimeMP<br>
*
* @param type type
* @return Timestamp checker
*/
public void setTimestamp(int type, int time, int times) {
if (this.timestamp[type] == time) {
this.timestampcounter[type]++;
if (this.timestampcounter[type] >= times) {
if (YamlConfig.config.server.USE_AUTOBAN) {
chr.getClient().disconnect(false, false);
}
log.info("Autoban - Chr {} was caught spamming TYPE {} and has been disconnected", chr, type);
}
} else {
this.timestamp[type] = time;
this.timestampcounter[type] = 0;
}
}
}

View File

@@ -0,0 +1,62 @@
/*
This file is part of the HeavenMS MapleStory Server, commands OdinMS-based
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/>.
*/
/*
@Author: Arthur L - Refactored command content into modules
*/
package client.command;
import client.Client;
public abstract class Command {
protected int rank;
protected String description;
public abstract void execute(Client client, String[] params);
public String getDescription() {
return description;
}
protected void setDescription(String description) {
this.description = description;
}
public int getRank() {
return rank;
}
public void setRank(int rank) {
this.rank = rank;
}
protected String joinStringFrom(String[] arr, int start) {
StringBuilder builder = new StringBuilder();
for (int i = start; i < arr.length; i++) {
builder.append(arr[i]);
if (i != arr.length - 1) {
builder.append(" ");
}
}
return builder.toString();
}
}

View File

@@ -0,0 +1,398 @@
/*
This file is part of the HeavenMS MapleStory Server, commands OdinMS-based
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/>.
*/
/*
@Author: Arthur L - Refactored command content into modules
*/
package client.command;
import client.Client;
import client.command.commands.gm0.*;
import client.command.commands.gm1.*;
import client.command.commands.gm2.*;
import client.command.commands.gm3.*;
import client.command.commands.gm4.*;
import client.command.commands.gm5.*;
import client.command.commands.gm6.*;
import constants.id.MapId;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import tools.Pair;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
public class CommandsExecutor {
private static final Logger log = LoggerFactory.getLogger(CommandsExecutor.class);
private static final CommandsExecutor instance = new CommandsExecutor();
private static final char USER_HEADING = '@';
private static final char GM_HEADING = '!';
private final HashMap<String, Command> registeredCommands = new HashMap<>();
private final List<Pair<List<String>, List<String>>> commandsNameDesc = new ArrayList<>();
private Pair<List<String>, List<String>> levelCommandsCursor;
public static CommandsExecutor getInstance() {
return instance;
}
public static boolean isCommand(Client client, String content) {
char heading = content.charAt(0);
if (client.getPlayer().isGM()) {
return heading == USER_HEADING || heading == GM_HEADING;
}
return heading == USER_HEADING;
}
private CommandsExecutor() {
registerLv0Commands();
registerLv1Commands();
registerLv2Commands();
registerLv3Commands();
registerLv4Commands();
registerLv5Commands();
registerLv6Commands();
}
public List<Pair<List<String>, List<String>>> getGmCommands() {
return commandsNameDesc;
}
public void handle(Client client, String message) {
if (client.tryacquireClient()) {
try {
handleInternal(client, message);
} finally {
client.releaseClient();
}
} else {
client.getPlayer().dropMessage(5, "Try again in a while... Latest commands are currently being processed.");
}
}
private void handleInternal(Client client, String message) {
if (client.getPlayer().getMapId() == MapId.JAIL) {
client.getPlayer().yellowMessage("You do not have permission to use commands while in jail.");
return;
}
final String splitRegex = "[ ]";
String[] splitedMessage = message.substring(1).split(splitRegex, 2);
if (splitedMessage.length < 2) {
splitedMessage = new String[]{splitedMessage[0], ""};
}
client.getPlayer().setLastCommandMessage(splitedMessage[1]); // thanks Tochi & Nulliphite for noticing string messages being marshalled lowercase
final String commandName = splitedMessage[0].toLowerCase();
final String[] lowercaseParams = splitedMessage[1].toLowerCase().split(splitRegex);
final Command command = registeredCommands.get(commandName);
if (command == null) {
client.getPlayer().yellowMessage("Command '" + commandName + "' is not available. See @commands for a list of available commands.");
return;
}
if (client.getPlayer().gmLevel() < command.getRank()) {
client.getPlayer().yellowMessage("You do not have permission to use this command.");
return;
}
String[] params;
if (lowercaseParams.length > 0 && !lowercaseParams[0].isEmpty()) {
params = Arrays.copyOfRange(lowercaseParams, 0, lowercaseParams.length);
} else {
params = new String[]{};
}
command.execute(client, params);
log.info("Chr {} used command {}", client.getPlayer().getName(), command.getClass().getSimpleName());
}
private void addCommandInfo(String name, Class<? extends Command> commandClass) {
try {
levelCommandsCursor.getRight().add(commandClass.getDeclaredConstructor().newInstance().getDescription());
levelCommandsCursor.getLeft().add(name);
} catch (Exception e) {
e.printStackTrace();
}
}
private void addCommand(String[] syntaxs, Class<? extends Command> commandClass) {
for (String syntax : syntaxs) {
addCommand(syntax, 0, commandClass);
}
}
private void addCommand(String syntax, Class<? extends Command> commandClass) {
//for (String syntax : syntaxs){
addCommand(syntax, 0, commandClass);
//}
}
private void addCommand(String[] surtaxes, int rank, Class<? extends Command> commandClass) {
for (String syntax : surtaxes) {
addCommand(syntax, rank, commandClass);
}
}
private void addCommand(String syntax, int rank, Class<? extends Command> commandClass) {
if (registeredCommands.containsKey(syntax.toLowerCase())) {
log.warn("Error on register command with name: {}. Already exists.", syntax);
return;
}
String commandName = syntax.toLowerCase();
addCommandInfo(commandName, commandClass);
try {
Command commandInstance = commandClass.getDeclaredConstructor().newInstance(); // thanks Halcyon for noticing commands getting reinstanced every call
commandInstance.setRank(rank);
registeredCommands.put(commandName, commandInstance);
} catch (Exception e) {
log.warn("Failed to create command instance", e);
}
}
private void registerLv0Commands() {
levelCommandsCursor = new Pair<>(new ArrayList<String>(), new ArrayList<String>());
addCommand(new String[]{"help", "commands"}, HelpCommand.class);
addCommand("droplimit", DropLimitCommand.class);
addCommand("time", TimeCommand.class);
addCommand("credits", StaffCommand.class);
addCommand("buyback", BuyBackCommand.class);
addCommand("uptime", UptimeCommand.class);
addCommand("gacha", GachaCommand.class);
addCommand("dispose", DisposeCommand.class);
addCommand("changel", ChangeLanguageCommand.class);
addCommand("equiplv", EquipLvCommand.class);
addCommand("showrates", ShowRatesCommand.class);
addCommand("rates", RatesCommand.class);
addCommand("online", OnlineCommand.class);
addCommand("gm", GmCommand.class);
addCommand("reportbug", ReportBugCommand.class);
addCommand("points", ReadPointsCommand.class);
addCommand("joinevent", JoinEventCommand.class);
addCommand("leaveevent", LeaveEventCommand.class);
addCommand("ranks", RanksCommand.class);
addCommand("str", StatStrCommand.class);
addCommand("dex", StatDexCommand.class);
addCommand("int", StatIntCommand.class);
addCommand("luk", StatLukCommand.class);
addCommand("enableauth", EnableAuthCommand.class);
addCommand("toggleexp", ToggleExpCommand.class);
addCommand("mylawn", MapOwnerClaimCommand.class);
addCommand("bosshp", BossHpCommand.class);
addCommand("mobhp", MobHpCommand.class);
commandsNameDesc.add(levelCommandsCursor);
}
private void registerLv1Commands() {
levelCommandsCursor = new Pair<>(new ArrayList<String>(), new ArrayList<String>());
addCommand("whatdropsfrom", 1, WhatDropsFromCommand.class);
addCommand("whodrops", 1, WhoDropsCommand.class);
addCommand("buffme", 1, BuffMeCommand.class);
addCommand("goto", 1, GotoCommand.class);
commandsNameDesc.add(levelCommandsCursor);
}
private void registerLv2Commands() {
levelCommandsCursor = new Pair<>(new ArrayList<String>(), new ArrayList<String>());
addCommand("recharge", 2, RechargeCommand.class);
addCommand("whereami", 2, WhereaMiCommand.class);
addCommand("hide", 2, HideCommand.class);
addCommand("unhide", 2, UnHideCommand.class);
addCommand("sp", 2, SpCommand.class);
addCommand("ap", 2, ApCommand.class);
addCommand("empowerme", 2, EmpowerMeCommand.class);
addCommand("buffmap", 2, BuffMapCommand.class);
addCommand("buff", 2, BuffCommand.class);
addCommand("bomb", 2, BombCommand.class);
addCommand("dc", 2, DcCommand.class);
addCommand("cleardrops", 2, ClearDropsCommand.class);
addCommand("clearslot", 2, ClearSlotCommand.class);
addCommand("clearsavelocs", 2, ClearSavedLocationsCommand.class);
addCommand("warp", 2, WarpCommand.class);
addCommand(new String[]{"warphere", "summon"}, 2, SummonCommand.class);
addCommand(new String[]{"warpto", "reach", "follow"}, 2, ReachCommand.class);
addCommand("gmshop", 2, GmShopCommand.class);
addCommand("heal", 2, HealCommand.class);
addCommand("item", 2, ItemCommand.class);
addCommand("drop", 2, ItemDropCommand.class);
addCommand("level", 2, LevelCommand.class);
addCommand("levelpro", 2, LevelProCommand.class);
addCommand("setslot", 2, SetSlotCommand.class);
addCommand("setstat", 2, SetStatCommand.class);
addCommand("maxstat", 2, MaxStatCommand.class);
addCommand("maxskill", 2, MaxSkillCommand.class);
addCommand("resetskill", 2, ResetSkillCommand.class);
addCommand("search", 2, SearchCommand.class);
addCommand("jail", 2, JailCommand.class);
addCommand("unjail", 2, UnJailCommand.class);
addCommand("job", 2, JobCommand.class);
addCommand("unbug", 2, UnBugCommand.class);
addCommand("id", 2, IdCommand.class);
addCommand("gachalist", GachaListCommand.class);
addCommand("loot", LootCommand.class);
addCommand("mobskill", MobSkillCommand.class);
commandsNameDesc.add(levelCommandsCursor);
}
private void registerLv3Commands() {
levelCommandsCursor = new Pair<>(new ArrayList<String>(), new ArrayList<String>());
addCommand("debuff", 3, DebuffCommand.class);
addCommand("fly", 3, FlyCommand.class);
addCommand("spawn", 3, SpawnCommand.class);
addCommand("mutemap", 3, MuteMapCommand.class);
addCommand("checkdmg", 3, CheckDmgCommand.class);
addCommand("inmap", 3, InMapCommand.class);
addCommand("reloadevents", 3, ReloadEventsCommand.class);
addCommand("reloaddrops", 3, ReloadDropsCommand.class);
addCommand("reloadportals", 3, ReloadPortalsCommand.class);
addCommand("reloadmap", 3, ReloadMapCommand.class);
addCommand("reloadshops", 3, ReloadShopsCommand.class);
addCommand("hpmp", 3, HpMpCommand.class);
addCommand("maxhpmp", 3, MaxHpMpCommand.class);
addCommand("music", 3, MusicCommand.class);
addCommand("monitor", 3, MonitorCommand.class);
addCommand("monitors", 3, MonitorsCommand.class);
addCommand("ignore", 3, IgnoreCommand.class);
addCommand("ignored", 3, IgnoredCommand.class);
addCommand("pos", 3, PosCommand.class);
addCommand("togglecoupon", 3, ToggleCouponCommand.class);
addCommand("togglewhitechat", 3, ChatCommand.class);
addCommand("fame", 3, FameCommand.class);
addCommand("givenx", 3, GiveNxCommand.class);
addCommand("givevp", 3, GiveVpCommand.class);
addCommand("givems", 3, GiveMesosCommand.class);
addCommand("giverp", 3, GiveRpCommand.class);
addCommand("expeds", 3, ExpedsCommand.class);
addCommand("kill", 3, KillCommand.class);
addCommand("seed", 3, SeedCommand.class);
addCommand("maxenergy", 3, MaxEnergyCommand.class);
addCommand("killall", 3, KillAllCommand.class);
addCommand("notice", 3, NoticeCommand.class);
addCommand("rip", 3, RipCommand.class);
addCommand("openportal", 3, OpenPortalCommand.class);
addCommand("closeportal", 3, ClosePortalCommand.class);
addCommand("pe", 3, PeCommand.class);
addCommand("startevent", 3, StartEventCommand.class);
addCommand("endevent", 3, EndEventCommand.class);
addCommand("startmapevent", 3, StartMapEventCommand.class);
addCommand("stopmapevent", 3, StopMapEventCommand.class);
addCommand("online2", 3, OnlineTwoCommand.class);
addCommand("ban", 3, BanCommand.class);
addCommand("unban", 3, UnBanCommand.class);
addCommand("healmap", 3, HealMapCommand.class);
addCommand("healperson", 3, HealPersonCommand.class);
addCommand("hurt", 3, HurtCommand.class);
addCommand("killmap", 3, KillMapCommand.class);
addCommand("night", 3, NightCommand.class);
addCommand("npc", 3, NpcCommand.class);
addCommand("face", 3, FaceCommand.class);
addCommand("hair", 3, HairCommand.class);
addCommand("startquest", 3, QuestStartCommand.class);
addCommand("completequest", 3, QuestCompleteCommand.class);
addCommand("resetquest", 3, QuestResetCommand.class);
addCommand("timer", 3, TimerCommand.class);
addCommand("timermap", 3, TimerMapCommand.class);
addCommand("timerall", 3, TimerAllCommand.class);
addCommand("warpmap", 3, WarpMapCommand.class);
addCommand("warparea", 3, WarpAreaCommand.class);
commandsNameDesc.add(levelCommandsCursor);
}
private void registerLv4Commands() {
levelCommandsCursor = new Pair<>(new ArrayList<String>(), new ArrayList<String>());
addCommand("servermessage", 4, ServerMessageCommand.class);
addCommand("proitem", 4, ProItemCommand.class);
addCommand("seteqstat", 4, SetEqStatCommand.class);
addCommand("exprate", 4, ExpRateCommand.class);
addCommand("mesorate", 4, MesoRateCommand.class);
addCommand("droprate", 4, DropRateCommand.class);
addCommand("bossdroprate", 4, BossDropRateCommand.class);
addCommand("questrate", 4, QuestRateCommand.class);
addCommand("travelrate", 4, TravelRateCommand.class);
addCommand("fishrate", 4, FishingRateCommand.class);
addCommand("itemvac", 4, ItemVacCommand.class);
addCommand("forcevac", 4, ForceVacCommand.class);
addCommand("zakum", 4, ZakumCommand.class);
addCommand("horntail", 4, HorntailCommand.class);
addCommand("pinkbean", 4, PinkbeanCommand.class);
addCommand("pap", 4, PapCommand.class);
addCommand("pianus", 4, PianusCommand.class);
addCommand("cake", 4, CakeCommand.class);
addCommand("playernpc", 4, PlayerNpcCommand.class);
addCommand("playernpcremove", 4, PlayerNpcRemoveCommand.class);
addCommand("pnpc", 4, PnpcCommand.class);
addCommand("pnpcremove", 4, PnpcRemoveCommand.class);
addCommand("pmob", 4, PmobCommand.class);
addCommand("pmobremove", 4, PmobRemoveCommand.class);
commandsNameDesc.add(levelCommandsCursor);
}
private void registerLv5Commands() {
levelCommandsCursor = new Pair<>(new ArrayList<String>(), new ArrayList<String>());
addCommand("debug", 5, DebugCommand.class);
addCommand("set", 5, SetCommand.class);
addCommand("showpackets", 5, ShowPacketsCommand.class);
addCommand("showmovelife", 5, ShowMoveLifeCommand.class);
addCommand("showsessions", 5, ShowSessionsCommand.class);
addCommand("iplist", 5, IpListCommand.class);
commandsNameDesc.add(levelCommandsCursor);
}
private void registerLv6Commands() {
levelCommandsCursor = new Pair<>(new ArrayList<String>(), new ArrayList<String>());
addCommand("setgmlevel", 6, SetGmLevelCommand.class);
addCommand("warpworld", 6, WarpWorldCommand.class);
addCommand("saveall", 6, SaveAllCommand.class);
addCommand("dcall", 6, DCAllCommand.class);
addCommand("mapplayers", 6, MapPlayersCommand.class);
addCommand("getacc", 6, GetAccCommand.class);
addCommand("shutdown", 6, ShutdownCommand.class);
addCommand("clearquestcache", 6, ClearQuestCacheCommand.class);
addCommand("clearquest", 6, ClearQuestCommand.class);
addCommand("supplyratecoupon", 6, SupplyRateCouponCommand.class);
addCommand("spawnallpnpcs", 6, SpawnAllPNpcsCommand.class);
addCommand("eraseallpnpcs", 6, EraseAllPNpcsCommand.class);
addCommand("addchannel", 6, ServerAddChannelCommand.class);
addCommand("addworld", 6, ServerAddWorldCommand.class);
addCommand("removechannel", 6, ServerRemoveChannelCommand.class);
addCommand("removeworld", 6, ServerRemoveWorldCommand.class);
commandsNameDesc.add(levelCommandsCursor);
}
}

View File

@@ -0,0 +1,48 @@
/*
This file is part of the HeavenMS MapleStory Server, commands OdinMS-based
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/>.
*/
/*
@Author: Arthur L - Refactored command content into modules
*/
package client.command.commands.gm0;
import client.Client;
import client.command.Command;
import client.processor.action.BuybackProcessor;
public class BuyBackCommand extends Command {
{
setDescription("Revive yourself after a death.");
}
@Override
public void execute(Client c, String[] params) {
if (params.length < 1) {
c.getPlayer().yellowMessage("Syntax: @buyback <info|now>");
return;
}
if (params[0].contentEquals("now")) {
BuybackProcessor.processBuyback(c);
} else {
c.getPlayer().showBuybackInfo();
}
}
}

View File

@@ -0,0 +1,42 @@
/*
This file is part of the HeavenMS MapleStory Server, commands OdinMS-based
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/>.
*/
/*
@Author: Arthur L - Refactored command content into modules
*/
package client.command.commands.gm0;
import client.Client;
import client.command.Command;
public class ChangeLanguageCommand extends Command {
{
setDescription("Change language settings.");
}
@Override
public void execute(Client c, String[] params) {
if (params.length < 1) {
c.getPlayer().yellowMessage("Syntax: !changel <0=ptb, 1=esp, 2=eng>");
return;
}
c.setLanguage(Integer.parseInt(params[0]));
}
}

View File

@@ -0,0 +1,45 @@
/*
This file is part of the HeavenMS MapleStory Server, commands OdinMS-based
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/>.
*/
/*
@Author: Arthur L - Refactored command content into modules
*/
package client.command.commands.gm0;
import client.Client;
import client.command.Command;
import scripting.npc.NPCScriptManager;
import scripting.quest.QuestScriptManager;
import tools.PacketCreator;
public class DisposeCommand extends Command {
{
setDescription("Dispose to fix NPC chat.");
}
@Override
public void execute(Client c, String[] params) {
NPCScriptManager.getInstance().dispose(c);
QuestScriptManager.getInstance().dispose(c);
c.sendPacket(PacketCreator.enableActions());
c.removeClickedNPC();
c.getPlayer().message("You've been disposed.");
}
}

View File

@@ -0,0 +1,45 @@
/*
This file is part of the HeavenMS MapleStory Server, commands OdinMS-based
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/>.
*/
/*
@Author: Arthur L - Refactored command content into modules
*/
package client.command.commands.gm0;
import client.Client;
import client.command.Command;
import config.YamlConfig;
public class DropLimitCommand extends Command {
{
setDescription("Check drop limit of current map.");
}
@Override
public void execute(Client c, String[] params) {
int dropCount = c.getPlayer().getMap().getDroppedItemCount();
if (((float) dropCount) / YamlConfig.config.server.ITEM_LIMIT_ON_MAP < 0.75f) {
c.getPlayer().showHint("Current drop count: #b" + dropCount + "#k / #e" + YamlConfig.config.server.ITEM_LIMIT_ON_MAP + "#n", 300);
} else {
c.getPlayer().showHint("Current drop count: #r" + dropCount + "#k / #e" + YamlConfig.config.server.ITEM_LIMIT_ON_MAP + "#n", 300);
}
}
}

View File

@@ -0,0 +1,45 @@
/*
This file is part of the HeavenMS MapleStory Server, commands OdinMS-based
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/>.
*/
/*
@Author: Arthur L - Refactored command content into modules
*/
package client.command.commands.gm0;
import client.Client;
import client.command.Command;
import net.server.coordinator.login.LoginBypassCoordinator;
public class EnableAuthCommand extends Command {
{
setDescription("Enable PIC code by resetting the cooldown.");
}
@Override
public void execute(Client c, String[] params) {
if (c.tryacquireClient()) {
try {
LoginBypassCoordinator.getInstance().unregisterLoginBypassEntry(c.getHwid(), c.getAccID());
} finally {
c.releaseClient();
}
}
}
}

View File

@@ -0,0 +1,38 @@
/*
This file is part of the HeavenMS MapleStory Server, commands OdinMS-based
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/>.
*/
/*
@Author: Arthur L - Refactored command content into modules
*/
package client.command.commands.gm0;
import client.Client;
import client.command.Command;
public class EquipLvCommand extends Command {
{
setDescription("Show levels of all equipped items.");
}
@Override
public void execute(Client c, String[] params) {
c.getPlayer().showAllEquipFeatures();
}
}

View File

@@ -0,0 +1,69 @@
/*
This file is part of the HeavenMS MapleStory Server, commands OdinMS-based
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/>.
*/
/*
@Author: Arthur L - Refactored command content into modules
*/
package client.command.commands.gm0;
import client.Client;
import client.command.Command;
import constants.id.NpcId;
import server.ItemInformationProvider;
import server.gachapon.Gachapon;
public class GachaCommand extends Command {
{
setDescription("Show gachapon rewards.");
}
@Override
public void execute(Client c, String[] params) {
Gachapon.GachaponType gacha = null;
String search = c.getPlayer().getLastCommandMessage();
String gachaName = "";
String[] names = {"Henesys", "Ellinia", "Perion", "Kerning City", "Sleepywood", "Mushroom Shrine", "Showa Spa Male", "Showa Spa Female", "New Leaf City", "Nautilus Harbor"};
int[] ids = {NpcId.GACHAPON_HENESYS, NpcId.GACHAPON_ELLINIA, NpcId.GACHAPON_PERION, NpcId.GACHAPON_KERNING,
NpcId.GACHAPON_SLEEPYWOOD, NpcId.GACHAPON_MUSHROOM_SHRINE, NpcId.GACHAPON_SHOWA_MALE,
NpcId.GACHAPON_SHOWA_FEMALE, NpcId.GACHAPON_NLC, NpcId.GACHAPON_NAUTILUS};
for (int i = 0; i < names.length; i++) {
if (search.equalsIgnoreCase(names[i])) {
gachaName = names[i];
gacha = Gachapon.GachaponType.getByNpcId(ids[i]);
}
}
if (gacha == null) {
c.getPlayer().yellowMessage("Please use @gacha <name> where name corresponds to one of the below:");
for (String name : names) {
c.getPlayer().yellowMessage(name);
}
return;
}
String talkStr = "The #b" + gachaName + "#k Gachapon contains the following items.\r\n\r\n";
for (int i = 0; i < 2; i++) {
for (int id : gacha.getItems(i)) {
talkStr += "-" + ItemInformationProvider.getInstance().getName(id) + "\r\n";
}
}
talkStr += "\r\nPlease keep in mind that there are items that are in all gachapons and are not listed here.";
c.getAbstractPlayerInteraction().npcTalk(NpcId.MAPLE_ADMINISTRATOR, talkStr);
}
}

View File

@@ -0,0 +1,63 @@
/*
This file is part of the HeavenMS MapleStory Server, commands OdinMS-based
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/>.
*/
/*
@Author: Arthur L - Refactored command content into modules
*/
package client.command.commands.gm0;
import client.Character;
import client.Client;
import client.command.Command;
import net.server.Server;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import tools.PacketCreator;
import tools.Randomizer;
public class GmCommand extends Command {
{
setDescription("Send a message to the game masters.");
}
private static final Logger log = LoggerFactory.getLogger(GmCommand.class);
@Override
public void execute(Client c, String[] params) {
String[] tips = {
"Please only use @gm in emergencies or to report somebody.",
"To report a bug or make a suggestion, use the forum.",
"Please do not use @gm to ask if a GM is online.",
"Do not ask if you can receive help, just state your issue.",
"Do not say 'I have a bug to report', just state it.",
};
Character player = c.getPlayer();
if (params.length < 1 || params[0].length() < 3) { // #goodbye 'hi'
player.dropMessage(5, "Your message was too short. Please provide as much detail as possible.");
return;
}
String message = player.getLastCommandMessage();
Server.getInstance().broadcastGMMessage(c.getWorld(), PacketCreator.sendYellowTip("[GM Message]:" + Character.makeMapleReadable(player.getName()) + ": " + message));
Server.getInstance().broadcastGMMessage(c.getWorld(), PacketCreator.serverNotice(1, message));
log.info("{}: {}", Character.makeMapleReadable(player.getName()), message);
player.dropMessage(5, "Your message '" + message + "' was sent to GMs.");
player.dropMessage(5, tips[Randomizer.nextInt(tips.length)]);
}
}

View File

@@ -0,0 +1,39 @@
/*
This file is part of the HeavenMS MapleStory Server, commands OdinMS-based
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/>.
*/
/*
@Author: Arthur L - Refactored command content into modules
*/
package client.command.commands.gm0;
import client.Client;
import client.command.Command;
import constants.id.NpcId;
public class HelpCommand extends Command {
{
setDescription("Show available commands.");
}
@Override
public void execute(Client client, String[] params) {
client.getAbstractPlayerInteraction().openNpc(NpcId.STEWARD, "commands");
}
}

View File

@@ -0,0 +1,69 @@
/*
This file is part of the HeavenMS MapleStory Server, commands OdinMS-based
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/>.
*/
/*
@Author: Arthur L - Refactored command content into modules
*/
package client.command.commands.gm0;
import client.Character;
import client.Client;
import client.command.Command;
import constants.id.MapId;
import server.events.gm.Event;
import server.maps.FieldLimit;
public class JoinEventCommand extends Command {
{
setDescription("Join active event.");
}
@Override
public void execute(Client c, String[] params) {
Character player = c.getPlayer();
if (!FieldLimit.CANNOTMIGRATE.check(player.getMap().getFieldLimit())) {
Event event = c.getChannelServer().getEvent();
if (event != null) {
if (event.getMapId() != player.getMapId()) {
if (event.getLimit() > 0) {
player.saveLocation("EVENT");
if (event.getMapId() == MapId.EVENT_COCONUT_HARVEST || event.getMapId() == MapId.EVENT_SNOWBALL_ENTRANCE) {
player.setTeam(event.getLimit() % 2);
}
event.minusLimit();
player.saveLocationOnWarp();
player.changeMap(event.getMapId());
} else {
player.dropMessage(5, "The limit of players for the event has already been reached.");
}
} else {
player.dropMessage(5, "You are already in the event.");
}
} else {
player.dropMessage(5, "There is currently no event in progress.");
}
} else {
player.dropMessage(5, "You are currently in a map where you can't join an event.");
}
}
}

View File

@@ -0,0 +1,59 @@
/*
This file is part of the HeavenMS MapleStory Server, commands OdinMS-based
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/>.
*/
/*
@Author: Arthur L - Refactored command content into modules
*/
package client.command.commands.gm0;
import client.Character;
import client.Client;
import client.command.Command;
public class LeaveEventCommand extends Command {
{
setDescription("Leave active event.");
}
@Override
public void execute(Client c, String[] params) {
Character player = c.getPlayer();
int returnMap = player.getSavedLocation("EVENT");
if (returnMap != -1) {
if (player.getOla() != null) {
player.getOla().resetTimes();
player.setOla(null);
}
if (player.getFitness() != null) {
player.getFitness().resetTimes();
player.setFitness(null);
}
player.saveLocationOnWarp();
player.changeMap(returnMap);
if (c.getChannelServer().getEvent() != null) {
c.getChannelServer().getEvent().addLimit();
}
} else {
player.dropMessage(5, "You are not currently in an event.");
}
}
}

View File

@@ -0,0 +1,76 @@
/*
This file is part of the HeavenMS MapleStory Server, commands OdinMS-based
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/>.
*/
/*
@Author: Ronan
*/
package client.command.commands.gm0;
import client.Character;
import client.Client;
import client.command.Command;
import config.YamlConfig;
import server.maps.MapleMap;
public class MapOwnerClaimCommand extends Command {
{
setDescription("Claim ownership of the current map.");
}
@Override
public void execute(Client c, String[] params) {
if (c.tryacquireClient()) {
try {
Character chr = c.getPlayer();
if (YamlConfig.config.server.USE_MAP_OWNERSHIP_SYSTEM) {
if (chr.getEventInstance() == null) {
MapleMap map = chr.getMap();
if (map.countBosses() == 0) { // thanks Conrad for suggesting bosses prevent map leasing
MapleMap ownedMap = chr.getOwnedMap(); // thanks Conrad for suggesting not unlease a map as soon as player exits it
if (ownedMap != null) {
ownedMap.unclaimOwnership(chr);
if (map == ownedMap) {
chr.dropMessage(5, "This lawn is now free real estate.");
return;
}
}
if (map.claimOwnership(chr)) {
chr.dropMessage(5, "You have leased this lawn for a while, until you leave here or after 1 minute of inactivity.");
} else {
chr.dropMessage(5, "This lawn has already been leased by a player.");
}
} else {
chr.dropMessage(5, "This lawn is currently under a boss siege.");
}
} else {
chr.dropMessage(5, "This lawn cannot be leased.");
}
} else {
chr.dropMessage(5, "Feature unavailable.");
}
} finally {
c.releaseClient();
}
}
}
}

View File

@@ -0,0 +1,49 @@
/*
This file is part of the HeavenMS MapleStory Server, commands OdinMS-based
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/>.
*/
/*
@Author: Arthur L - Refactored command content into modules
*/
package client.command.commands.gm0;
import client.Character;
import client.Client;
import client.command.Command;
import net.server.Server;
import net.server.channel.Channel;
public class OnlineCommand extends Command {
{
setDescription("Show all online players.");
}
@Override
public void execute(Client c, String[] params) {
Character player = c.getPlayer();
for (Channel ch : Server.getInstance().getChannelsFromWorld(player.getWorld())) {
player.yellowMessage("Players in Channel " + ch.getId() + ":");
for (Character chr : ch.getPlayerStorage().getAllCharacters()) {
if (!chr.isGM()) {
player.message(" >> " + Character.makeMapleReadable(chr.getName()) + " is at " + chr.getMap().getMapName() + ".");
}
}
}
}
}

View File

@@ -0,0 +1,48 @@
/*
This file is part of the HeavenMS MapleStory Server, commands OdinMS-based
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/>.
*/
/*
@Author: Arthur L - Refactored command content into modules
*/
package client.command.commands.gm0;
import client.Character;
import client.Client;
import client.command.Command;
import constants.id.NpcId;
import net.server.Server;
import net.server.guild.GuildPackets;
import tools.Pair;
import java.util.List;
public class RanksCommand extends Command {
{
setDescription("Show player rankings.");
}
@Override
public void execute(Client c, String[] params) {
Character player = c.getPlayer();
List<Pair<String, Integer>> worldRanking = Server.getInstance().getWorldPlayerRanking(player.getWorld());
player.sendPacket(GuildPackets.showPlayerRanks(NpcId.MAPLE_ADMINISTRATOR, worldRanking));
}
}

View File

@@ -0,0 +1,52 @@
/*
This file is part of the HeavenMS MapleStory Server, commands OdinMS-based
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/>.
*/
/*
@Author: Arthur L - Refactored command content into modules
*/
package client.command.commands.gm0;
import client.Character;
import client.Client;
import client.command.Command;
import config.YamlConfig;
public class RatesCommand extends Command {
{
setDescription("Show your rates.");
}
@Override
public void execute(Client c, String[] params) {
Character player = c.getPlayer();
// travel rates not applicable since it's intrinsically a server/environment rate rather than a character rate
String showMsg_ = "#eCHARACTER RATES#n" + "\r\n\r\n";
showMsg_ += "EXP Rate: #e#b" + player.getExpRate() + "x#k#n" + (player.hasNoviceExpRate() ? " - novice rate" : "") + "\r\n";
showMsg_ += "MESO Rate: #e#b" + player.getMesoRate() + "x#k#n" + "\r\n";
showMsg_ += "DROP Rate: #e#b" + player.getDropRate() + "x#k#n" + "\r\n";
showMsg_ += "BOSS DROP Rate: #e#b" + player.getBossDropRate() + "x#k#n" + "\r\n";
if (YamlConfig.config.server.USE_QUEST_RATE) {
showMsg_ += "QUEST Rate: #e#b" + c.getWorldServer().getQuestRate() + "x#k#n" + "\r\n";
}
player.showHint(showMsg_, 300);
}
}

View File

@@ -0,0 +1,38 @@
package client.command.commands.gm0;
import client.Character;
import client.Client;
import client.command.Command;
public class ReadPointsCommand extends Command {
{
setDescription("Show point total.");
}
@Override
public void execute(Client client, String[] params) {
Character player = client.getPlayer();
if (params.length > 2) {
player.yellowMessage("Syntax: @points (rp|vp|all)");
return;
} else if (params.length == 0) {
player.yellowMessage("RewardPoints: " + player.getRewardPoints() + " | "
+ "VotePoints: " + player.getClient().getVotePoints());
return;
}
switch (params[0]) {
case "rp":
player.yellowMessage("RewardPoints: " + player.getRewardPoints());
break;
case "vp":
player.yellowMessage("VotePoints: " + player.getClient().getVotePoints());
break;
default:
player.yellowMessage("RewardPoints: " + player.getRewardPoints() + " | "
+ "VotePoints: " + player.getClient().getVotePoints());
break;
}
}
}

View File

@@ -0,0 +1,56 @@
/*
This file is part of the HeavenMS MapleStory Server, commands OdinMS-based
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/>.
*/
/*
@Author: Arthur L - Refactored command content into modules
*/
package client.command.commands.gm0;
import client.Character;
import client.Client;
import client.command.Command;
import net.server.Server;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import tools.PacketCreator;
public class ReportBugCommand extends Command {
{
setDescription("Send in a bug report.");
}
private static final Logger log = LoggerFactory.getLogger(ReportBugCommand.class);
@Override
public void execute(Client c, String[] params) {
Character player = c.getPlayer();
if (params.length < 1) {
player.dropMessage(5, "Message too short and not sent. Please do @bug <bug>");
return;
}
String message = player.getLastCommandMessage();
Server.getInstance().broadcastGMMessage(c.getWorld(), PacketCreator.sendYellowTip("[Bug]:" + Character.makeMapleReadable(player.getName()) + ": " + message));
Server.getInstance().broadcastGMMessage(c.getWorld(), PacketCreator.serverNotice(1, message));
log.info("{}: {}", Character.makeMapleReadable(player.getName()), message);
player.dropMessage(5, "Your bug '" + message + "' was submitted successfully to our developers. Thank you!");
}
}

View File

@@ -0,0 +1,81 @@
/*
This file is part of the HeavenMS MapleStory Server, commands OdinMS-based
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/>.
*/
/*
@Author: Arthur L - Refactored command content into modules
*/
package client.command.commands.gm0;
import client.Character;
import client.Client;
import client.command.Command;
import config.YamlConfig;
public class ShowRatesCommand extends Command {
{
setDescription("Show all world/character rates.");
}
@Override
public void execute(Client c, String[] params) {
Character player = c.getPlayer();
String showMsg = "#eEXP RATE#n" + "\r\n";
showMsg += "World EXP Rate: #k" + c.getWorldServer().getExpRate() + "x#k" + "\r\n";
showMsg += "Player EXP Rate: #k" + player.getRawExpRate() + "x#k" + "\r\n";
if (player.getCouponExpRate() != 1) {
showMsg += "Coupon EXP Rate: #k" + player.getCouponExpRate() + "x#k" + "\r\n";
}
showMsg += "EXP Rate: #e#b" + player.getExpRate() + "x#k#n" + (player.hasNoviceExpRate() ? " - novice rate" : "") + "\r\n";
showMsg += "\r\n" + "#eMESO RATE#n" + "\r\n";
showMsg += "World MESO Rate: #k" + c.getWorldServer().getMesoRate() + "x#k" + "\r\n";
showMsg += "Player MESO Rate: #k" + player.getRawMesoRate() + "x#k" + "\r\n";
if (player.getCouponMesoRate() != 1) {
showMsg += "Coupon MESO Rate: #k" + player.getCouponMesoRate() + "x#k" + "\r\n";
}
showMsg += "MESO Rate: #e#b" + player.getMesoRate() + "x#k#n" + "\r\n";
showMsg += "\r\n" + "#eDROP RATE#n" + "\r\n";
showMsg += "World DROP Rate: #k" + c.getWorldServer().getDropRate() + "x#k" + "\r\n";
showMsg += "Player DROP Rate: #k" + player.getRawDropRate() + "x#k" + "\r\n";
if (player.getCouponDropRate() != 1) {
showMsg += "Coupon DROP Rate: #k" + player.getCouponDropRate() + "x#k" + "\r\n";
}
showMsg += "DROP Rate: #e#b" + player.getDropRate() + "x#k#n" + "\r\n";
showMsg += "\r\n" + "#eBOSS DROP RATE#n" + "\r\n";
showMsg += "World BOSS DROP Rate: #k" + c.getWorldServer().getBossDropRate() + "x#k" + "\r\n";
showMsg += "Player DROP Rate: #k" + player.getRawDropRate() + "x#k" + "\r\n";
if (player.getCouponDropRate() != 1) {
showMsg += "Coupon DROP Rate: #k" + player.getCouponDropRate() + "x#k" + "\r\n";
}
showMsg += "BOSS DROP Rate: #e#b" + player.getBossDropRate() + "x#k#n" + "\r\n";
if (YamlConfig.config.server.USE_QUEST_RATE) {
showMsg += "\r\n" + "#eQUEST RATE#n" + "\r\n";
showMsg += "World QUEST Rate: #e#b" + c.getWorldServer().getQuestRate() + "x#k#n" + "\r\n";
}
showMsg += "\r\n";
showMsg += "World TRAVEL Rate: #e#b" + c.getWorldServer().getTravelRate() + "x#k#n" + "\r\n";
player.showHint(showMsg, 300);
}
}

View File

@@ -0,0 +1,39 @@
/*
This file is part of the HeavenMS MapleStory Server, commands OdinMS-based
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/>.
*/
/*
@Author: Arthur L - Refactored command content into modules
*/
package client.command.commands.gm0;
import client.Client;
import client.command.Command;
import constants.id.NpcId;
public class StaffCommand extends Command {
{
setDescription("Show credits. These people made the server possible.");
}
@Override
public void execute(Client c, String[] params) {
c.getAbstractPlayerInteraction().openNpc(NpcId.HERACLE, "credits");
}
}

View File

@@ -0,0 +1,56 @@
/*
This file is part of the HeavenMS MapleStory Server, commands OdinMS-based
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/>.
*/
/*
@Author: Arthur L - Refactored command content into modules
*/
package client.command.commands.gm0;
import client.Character;
import client.Client;
import client.command.Command;
import config.YamlConfig;
public class StatDexCommand extends Command {
{
setDescription("Assign AP into DEX.");
}
@Override
public void execute(Client c, String[] params) {
Character player = c.getPlayer();
int remainingAp = player.getRemainingAp();
int amount;
if (params.length > 0) {
try {
amount = Math.min(Integer.parseInt(params[0]), remainingAp);
} catch (NumberFormatException e) {
player.dropMessage("That is not a valid number!");
return;
}
} else {
amount = Math.min(remainingAp, YamlConfig.config.server.MAX_AP - player.getDex());
}
if (!player.assignDex(Math.max(amount, 0))) {
player.dropMessage("Please make sure your AP is not over " + YamlConfig.config.server.MAX_AP + " and you have enough to distribute.");
}
}
}

View File

@@ -0,0 +1,56 @@
/*
This file is part of the HeavenMS MapleStory Server, commands OdinMS-based
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/>.
*/
/*
@Author: Arthur L - Refactored command content into modules
*/
package client.command.commands.gm0;
import client.Character;
import client.Client;
import client.command.Command;
import config.YamlConfig;
public class StatIntCommand extends Command {
{
setDescription("Assign AP into INT.");
}
@Override
public void execute(Client c, String[] params) {
Character player = c.getPlayer();
int remainingAp = player.getRemainingAp();
int amount;
if (params.length > 0) {
try {
amount = Math.min(Integer.parseInt(params[0]), remainingAp);
} catch (NumberFormatException e) {
player.dropMessage("That is not a valid number!");
return;
}
} else {
amount = Math.min(remainingAp, YamlConfig.config.server.MAX_AP - player.getInt());
}
if (!player.assignInt(Math.max(amount, 0))) {
player.dropMessage("Please make sure your AP is not over " + YamlConfig.config.server.MAX_AP + " and you have enough to distribute.");
}
}
}

View File

@@ -0,0 +1,56 @@
/*
This file is part of the HeavenMS MapleStory Server, commands OdinMS-based
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/>.
*/
/*
@Author: Arthur L - Refactored command content into modules
*/
package client.command.commands.gm0;
import client.Character;
import client.Client;
import client.command.Command;
import config.YamlConfig;
public class StatLukCommand extends Command {
{
setDescription("Assign AP into LUK.");
}
@Override
public void execute(Client c, String[] params) {
Character player = c.getPlayer();
int remainingAp = player.getRemainingAp();
int amount;
if (params.length > 0) {
try {
amount = Math.min(Integer.parseInt(params[0]), remainingAp);
} catch (NumberFormatException e) {
player.dropMessage("That is not a valid number!");
return;
}
} else {
amount = Math.min(remainingAp, YamlConfig.config.server.MAX_AP - player.getLuk());
}
if (!player.assignLuk(Math.max(amount, 0))) {
player.dropMessage("Please make sure your AP is not over " + YamlConfig.config.server.MAX_AP + " and you have enough to distribute.");
}
}
}

View File

@@ -0,0 +1,56 @@
/*
This file is part of the HeavenMS MapleStory Server, commands OdinMS-based
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/>.
*/
/*
@Author: Arthur L - Refactored command content into modules
*/
package client.command.commands.gm0;
import client.Character;
import client.Client;
import client.command.Command;
import config.YamlConfig;
public class StatStrCommand extends Command {
{
setDescription("Assign AP into STR.");
}
@Override
public void execute(Client c, String[] params) {
Character player = c.getPlayer();
int remainingAp = player.getRemainingAp();
int amount;
if (params.length > 0) {
try {
amount = Math.min(Integer.parseInt(params[0]), remainingAp);
} catch (NumberFormatException e) {
player.dropMessage("That is not a valid number!");
return;
}
} else {
amount = Math.min(remainingAp, YamlConfig.config.server.MAX_AP - player.getStr());
}
if (!player.assignStr(Math.max(amount, 0))) {
player.dropMessage("Please make sure your AP is not over " + YamlConfig.config.server.MAX_AP + " and you have enough to distribute.");
}
}
}

View File

@@ -0,0 +1,45 @@
/*
This file is part of the HeavenMS MapleStory Server, commands OdinMS-based
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/>.
*/
/*
@Author: Arthur L - Refactored command content into modules
*/
package client.command.commands.gm0;
import client.Client;
import client.command.Command;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimeZone;
public class TimeCommand extends Command {
{
setDescription("Show current server time.");
}
@Override
public void execute(Client client, String[] params) {
DateFormat dateFormat = new SimpleDateFormat("HH:mm:ss");
dateFormat.setTimeZone(TimeZone.getDefault());
client.getPlayer().yellowMessage("Cosmic Server Time: " + dateFormat.format(new Date()));
}
}

View File

@@ -0,0 +1,44 @@
/*
This file is part of the HeavenMS MapleStory Server, commands OdinMS-based
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/>.
*/
/*
@Author: Ronan
*/
package client.command.commands.gm0;
import client.Client;
import client.command.Command;
public class ToggleExpCommand extends Command {
{
setDescription("Toggle enable/disable all exp gain.");
}
@Override
public void execute(Client c, String[] params) {
if (c.tryacquireClient()) {
try {
c.getPlayer().toggleExpGain(); // Vcoc's idea
} finally {
c.releaseClient();
}
}
}
}

View File

@@ -0,0 +1,46 @@
/*
This file is part of the HeavenMS MapleStory Server, commands OdinMS-based
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/>.
*/
/*
@Author: Arthur L - Refactored command content into modules
*/
package client.command.commands.gm0;
import client.Client;
import client.command.Command;
import net.server.Server;
import static java.util.concurrent.TimeUnit.*;
public class UptimeCommand extends Command {
{
setDescription("Show server online time.");
}
@Override
public void execute(Client c, String[] params) {
long milliseconds = System.currentTimeMillis() - Server.uptime;
int seconds = (int) (milliseconds / SECONDS.toMillis(1)) % 60;
int minutes = (int) ((milliseconds / MINUTES.toMillis(1)) % 60);
int hours = (int) ((milliseconds / HOURS.toMillis(1)) % 24);
int days = (int) ((milliseconds / DAYS.toMillis(1)));
c.getPlayer().yellowMessage("Server has been online for " + days + " days " + hours + " hours " + minutes + " minutes and " + seconds + " seconds.");
}
}

View File

@@ -0,0 +1,52 @@
/*
This file is part of the HeavenMS MapleStory Server, commands OdinMS-based
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/>.
*/
/*
@Author: Arthur L - Refactored command content into modules
*/
package client.command.commands.gm1;
import client.Character;
import client.Client;
import client.command.Command;
import server.life.Monster;
public class BossHpCommand extends Command {
{
setDescription("Show HP of bosses on current map.");
}
@Override
public void execute(Client c, String[] params) {
Character player = c.getPlayer();
for (Monster monster : player.getMap().getAllMonsters()) {
if (monster != null && monster.isBoss() && monster.getHp() > 0) {
long percent = monster.getHp() * 100L / monster.getMaxHp();
String bar = "[";
for (int i = 0; i < 100; i++) {
bar += i < percent ? "|" : ".";
}
bar += "]";
player.yellowMessage(monster.getName() + " (" + monster.getId() + ") has " + percent + "% HP left.");
player.yellowMessage("HP: " + bar);
}
}
}
}

View File

@@ -0,0 +1,46 @@
/*
This file is part of the HeavenMS MapleStory Server, commands OdinMS-based
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/>.
*/
/*
@Author: Arthur L - Refactored command content into modules
*/
package client.command.commands.gm1;
import client.Character;
import client.Client;
import client.SkillFactory;
import client.command.Command;
public class BuffMeCommand extends Command {
{
setDescription("Activate GM buffs on self.");
}
@Override
public void execute(Client c, String[] params) {
Character player = c.getPlayer();
SkillFactory.getSkill(4101004).getEffect(SkillFactory.getSkill(4101004).getMaxLevel()).applyTo(player);
SkillFactory.getSkill(2311003).getEffect(SkillFactory.getSkill(2311003).getMaxLevel()).applyTo(player);
SkillFactory.getSkill(1301007).getEffect(SkillFactory.getSkill(1301007).getMaxLevel()).applyTo(player);
SkillFactory.getSkill(2301004).getEffect(SkillFactory.getSkill(2301004).getMaxLevel()).applyTo(player);
SkillFactory.getSkill(1005).getEffect(SkillFactory.getSkill(1005).getMaxLevel()).applyTo(player);
player.healHpMp();
}
}

View File

@@ -0,0 +1,125 @@
/*
This file is part of the HeavenMS MapleStory Server, commands OdinMS-based
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/>.
*/
/*
@Author: Arthur L - Refactored command content into modules
*/
package client.command.commands.gm1;
import client.Character;
import client.Client;
import client.command.Command;
import constants.game.GameConstants;
import constants.id.NpcId;
import server.maps.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
public class GotoCommand extends Command {
{
setDescription("Warp to a predefined map.");
List<Entry<String, Integer>> towns = new ArrayList<>(GameConstants.GOTO_TOWNS.entrySet());
sortGotoEntries(towns);
try {
// thanks shavit for noticing goto areas getting loaded from wz needlessly only for the name retrieval
for (Map.Entry<String, Integer> e : towns) {
GOTO_TOWNS_INFO += ("'" + e.getKey() + "' - #b" + (MapFactory.loadPlaceName(e.getValue())) + "#k\r\n");
}
List<Entry<String, Integer>> areas = new ArrayList<>(GameConstants.GOTO_AREAS.entrySet());
sortGotoEntries(areas);
for (Map.Entry<String, Integer> e : areas) {
GOTO_AREAS_INFO += ("'" + e.getKey() + "' - #b" + (MapFactory.loadPlaceName(e.getValue())) + "#k\r\n");
}
} catch (Exception e) {
e.printStackTrace();
GOTO_TOWNS_INFO = "(none)";
GOTO_AREAS_INFO = "(none)";
}
}
public static String GOTO_TOWNS_INFO = "";
public static String GOTO_AREAS_INFO = "";
private static void sortGotoEntries(List<Entry<String, Integer>> listEntries) {
listEntries.sort((e1, e2) -> e1.getValue().compareTo(e2.getValue()));
}
@Override
public void execute(Client c, String[] params) {
Character player = c.getPlayer();
if (params.length < 1) {
String sendStr = "Syntax: #b@goto <map name>#k. Available areas:\r\n\r\n#rTowns:#k\r\n" + GOTO_TOWNS_INFO;
if (player.isGM()) {
sendStr += ("\r\n#rAreas:#k\r\n" + GOTO_AREAS_INFO);
}
player.getAbstractPlayerInteraction().npcTalk(NpcId.SPINEL, sendStr);
return;
}
if (!player.isAlive()) {
player.dropMessage(1, "This command cannot be used when you're dead.");
return;
}
if (!player.isGM()) {
if (player.getEventInstance() != null || MiniDungeonInfo.isDungeonMap(player.getMapId()) || FieldLimit.CANNOTMIGRATE.check(player.getMap().getFieldLimit())) {
player.dropMessage(1, "This command can not be used in this map.");
return;
}
}
Map<String, Integer> gotomaps;
if (player.isGM()) {
gotomaps = new HashMap<>(GameConstants.GOTO_AREAS); // distinct map registry for GM/users suggested thanks to Vcoc
gotomaps.putAll(GameConstants.GOTO_TOWNS); // thanks Halcyon (UltimateMors) for pointing out duplicates on listed entries functionality
} else {
gotomaps = GameConstants.GOTO_TOWNS;
}
if (gotomaps.containsKey(params[0])) {
MapleMap target = c.getChannelServer().getMapFactory().getMap(gotomaps.get(params[0]));
// expedition issue with this command detected thanks to Masterrulax
Portal targetPortal = target.getRandomPlayerSpawnpoint();
player.saveLocationOnWarp();
player.changeMap(target, targetPortal);
} else {
// detailed info on goto available areas suggested thanks to Vcoc
String sendStr = "Area '#r" + params[0] + "#k' is not available. Available areas:\r\n\r\n#rTowns:#k" + GOTO_TOWNS_INFO;
if (player.isGM()) {
sendStr += ("\r\n#rAreas:#k\r\n" + GOTO_AREAS_INFO);
}
player.getAbstractPlayerInteraction().npcTalk(NpcId.SPINEL, sendStr);
}
}
}

View File

@@ -0,0 +1,46 @@
/*
This file is part of the HeavenMS MapleStory Server, commands OdinMS-based
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/>.
*/
/*
@Author: Arthur L - Refactored command content into modules
*/
package client.command.commands.gm1;
import client.Character;
import client.Client;
import client.command.Command;
import server.life.Monster;
public class MobHpCommand extends Command {
{
setDescription("Show HP of mobs on current map.");
}
@Override
public void execute(Client c, String[] params) {
Character player = c.getPlayer();
for (Monster monster : player.getMap().getAllMonsters()) {
if (monster != null && monster.getHp() > 0) {
player.yellowMessage(monster.getName() + " (" + monster.getId() + ") has " + monster.getHp() + " / " + monster.getMaxHp() + " HP.");
}
}
}
}

View File

@@ -0,0 +1,78 @@
/*
This file is part of the HeavenMS MapleStory Server, commands OdinMS-based
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/>.
*/
/*
@Author: Arthur L - Refactored command content into modules
*/
package client.command.commands.gm1;
import client.Character;
import client.Client;
import client.command.Command;
import constants.id.NpcId;
import server.ItemInformationProvider;
import server.life.MonsterDropEntry;
import server.life.MonsterInformationProvider;
import tools.Pair;
import java.util.Iterator;
public class WhatDropsFromCommand extends Command {
{
setDescription("Show what items drop from a mob.");
}
@Override
public void execute(Client c, String[] params) {
Character player = c.getPlayer();
if (params.length < 1) {
player.dropMessage(5, "Please do @whatdropsfrom <monster name>");
return;
}
String monsterName = player.getLastCommandMessage();
String output = "";
int limit = 3;
Iterator<Pair<Integer, String>> listIterator = MonsterInformationProvider.getMobsIDsFromName(monsterName).iterator();
for (int i = 0; i < limit; i++) {
if (listIterator.hasNext()) {
Pair<Integer, String> data = listIterator.next();
int mobId = data.getLeft();
String mobName = data.getRight();
output += mobName + " drops the following items:\r\n\r\n";
for (MonsterDropEntry drop : MonsterInformationProvider.getInstance().retrieveDrop(mobId)) {
try {
String name = ItemInformationProvider.getInstance().getName(drop.itemId);
if (name == null || name.equals("null") || drop.chance == 0) {
continue;
}
float chance = Math.max(1000000 / drop.chance / (!MonsterInformationProvider.getInstance().isBoss(mobId) ? player.getDropRate() : player.getBossDropRate()), 1);
output += "- " + name + " (1/" + (int) chance + ")\r\n";
} catch (Exception ex) {
ex.printStackTrace();
continue;
}
}
output += "\r\n";
}
}
c.getAbstractPlayerInteraction().npcTalk(NpcId.MAPLE_ADMINISTRATOR, output);
}
}

View File

@@ -0,0 +1,96 @@
/*
This file is part of the HeavenMS MapleStory Server, commands OdinMS-based
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/>.
*/
/*
@Author: Arthur L - Refactored command content into modules
*/
package client.command.commands.gm1;
import client.Character;
import client.Client;
import client.command.Command;
import constants.id.NpcId;
import server.ItemInformationProvider;
import server.life.MonsterInformationProvider;
import tools.DatabaseConnection;
import tools.Pair;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.Iterator;
public class WhoDropsCommand extends Command {
{
setDescription("Show what drops an item.");
}
@Override
public void execute(Client c, String[] params) {
Character player = c.getPlayer();
if (params.length < 1) {
player.dropMessage(5, "Please do @whodrops <item name>");
return;
}
if (c.tryacquireClient()) {
try {
String searchString = player.getLastCommandMessage();
String output = "";
Iterator<Pair<Integer, String>> listIterator = ItemInformationProvider.getInstance().getItemDataByName(searchString).iterator();
if (listIterator.hasNext()) {
int count = 1;
while (listIterator.hasNext() && count <= 3) {
Pair<Integer, String> data = listIterator.next();
output += "#b" + data.getRight() + "#k is dropped by:\r\n";
try (Connection con = DatabaseConnection.getConnection();
PreparedStatement ps = con.prepareStatement("SELECT dropperid FROM drop_data WHERE itemid = ? LIMIT 50")) {
ps.setInt(1, data.getLeft());
try (ResultSet rs = ps.executeQuery()) {
while (rs.next()) {
String resultName = MonsterInformationProvider.getInstance().getMobNameFromId(rs.getInt("dropperid"));
if (resultName != null) {
output += resultName + ", ";
}
}
}
} catch (Exception e) {
player.dropMessage(6, "There was a problem retrieving the required data. Please try again.");
e.printStackTrace();
return;
}
output += "\r\n\r\n";
count++;
}
} else {
player.dropMessage(5, "The item you searched for doesn't exist.");
return;
}
c.getAbstractPlayerInteraction().npcTalk(NpcId.MAPLE_ADMINISTRATOR, output);
} finally {
c.releaseClient();
}
} else {
player.dropMessage(5, "Please wait a while for your request to be processed.");
}
}
}

View File

@@ -0,0 +1,69 @@
/*
This file is part of the HeavenMS MapleStory Server, commands OdinMS-based
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/>.
*/
/*
@Author: Arthur L - Refactored command content into modules
*/
package client.command.commands.gm2;
import client.Character;
import client.Client;
import client.command.Command;
import config.YamlConfig;
public class ApCommand extends Command {
{
setDescription("Set available AP.");
}
@Override
public void execute(Client c, String[] params) {
Character player = c.getPlayer();
if (params.length < 1) {
player.yellowMessage("Syntax: !ap [<playername>] <newap>");
return;
}
if (params.length < 2) {
int newAp = Integer.parseInt(params[0]);
if (newAp < 0) {
newAp = 0;
} else if (newAp > YamlConfig.config.server.MAX_AP) {
newAp = YamlConfig.config.server.MAX_AP;
}
player.changeRemainingAp(newAp, false);
} else {
Character victim = c.getWorldServer().getPlayerStorage().getCharacterByName(params[0]);
if (victim != null) {
int newAp = Integer.parseInt(params[1]);
if (newAp < 0) {
newAp = 0;
} else if (newAp > YamlConfig.config.server.MAX_AP) {
newAp = YamlConfig.config.server.MAX_AP;
}
victim.changeRemainingAp(newAp, false);
} else {
player.message("Player '" + params[0] + "' could not be found.");
}
}
}
}

View File

@@ -0,0 +1,54 @@
/*
This file is part of the HeavenMS MapleStory Server, commands OdinMS-based
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/>.
*/
/*
@Author: Arthur L - Refactored command content into modules
*/
package client.command.commands.gm2;
import client.Character;
import client.Client;
import client.command.Command;
import constants.id.MobId;
import net.server.Server;
import server.life.LifeFactory;
import tools.PacketCreator;
public class BombCommand extends Command {
{
setDescription("Bomb a player, dealing damage.");
}
@Override
public void execute(Client c, String[] params) {
Character player = c.getPlayer();
if (params.length > 0) {
Character victim = c.getWorldServer().getPlayerStorage().getCharacterByName(params[0]);
if (victim != null) {
victim.getMap().spawnMonsterOnGroundBelow(LifeFactory.getMonster(MobId.ARPQ_BOMB), victim.getPosition());
Server.getInstance().broadcastGMMessage(c.getWorld(), PacketCreator.serverNotice(5, player.getName() + " used !bomb on " + victim.getName()));
} else {
player.message("Player '" + params[0] + "' could not be found on this world.");
}
} else {
player.getMap().spawnMonsterOnGroundBelow(LifeFactory.getMonster(MobId.ARPQ_BOMB), player.getPosition());
}
}
}

View File

@@ -0,0 +1,51 @@
/*
This file is part of the HeavenMS MapleStory Server, commands OdinMS-based
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/>.
*/
/*
@Author: Arthur L - Refactored command content into modules
*/
package client.command.commands.gm2;
import client.Character;
import client.Client;
import client.Skill;
import client.SkillFactory;
import client.command.Command;
public class BuffCommand extends Command {
{
setDescription("Activate a buff.");
}
@Override
public void execute(Client c, String[] params) {
Character player = c.getPlayer();
if (params.length < 1) {
player.yellowMessage("Syntax: !buff <buffid>");
return;
}
int skillid = Integer.parseInt(params[0]);
Skill skill = SkillFactory.getSkill(skillid);
if (skill != null) {
skill.getEffect(skill.getMaxLevel()).applyTo(player);
}
}
}

View File

@@ -0,0 +1,46 @@
/*
This file is part of the HeavenMS MapleStory Server, commands OdinMS-based
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/>.
*/
/*
@Author: Arthur L - Refactored command content into modules
*/
package client.command.commands.gm2;
import client.Character;
import client.Client;
import client.SkillFactory;
import client.command.Command;
public class BuffMapCommand extends Command {
{
setDescription("Give GM buffs to the whole map.");
}
@Override
public void execute(Client c, String[] params) {
Character player = c.getPlayer();
SkillFactory.getSkill(9101001).getEffect(SkillFactory.getSkill(9101001).getMaxLevel()).applyTo(player, true);
SkillFactory.getSkill(9101002).getEffect(SkillFactory.getSkill(9101002).getMaxLevel()).applyTo(player, true);
SkillFactory.getSkill(9101003).getEffect(SkillFactory.getSkill(9101003).getMaxLevel()).applyTo(player, true);
SkillFactory.getSkill(9101008).getEffect(SkillFactory.getSkill(9101008).getMaxLevel()).applyTo(player, true);
SkillFactory.getSkill(1005).getEffect(SkillFactory.getSkill(1005).getMaxLevel()).applyTo(player, true);
}
}

View File

@@ -0,0 +1,41 @@
/*
This file is part of the HeavenMS MapleStory Server, commands OdinMS-based
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/>.
*/
/*
@Author: Arthur L - Refactored command content into modules
*/
package client.command.commands.gm2;
import client.Character;
import client.Client;
import client.command.Command;
public class ClearDropsCommand extends Command {
{
setDescription("Clear drops by player.");
}
@Override
public void execute(Client c, String[] params) {
Character player = c.getPlayer();
player.getMap().clearDrops(player);
player.dropMessage(5, "Cleared dropped items");
}
}

View File

@@ -0,0 +1,56 @@
/*
This file is part of the HeavenMS MapleStory Server, commands OdinMS-based
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/>.
*/
/*
@Author: Arthur L - Refactored command content into modules
*/
package client.command.commands.gm2;
import client.Character;
import client.Client;
import client.command.Command;
import server.maps.SavedLocationType;
public class ClearSavedLocationsCommand extends Command {
{
setDescription("Clear saved locations for a player.");
}
@Override
public void execute(Client c, String[] params) {
Character player = c.getPlayer(), victim;
if (params.length > 0) {
victim = c.getWorldServer().getPlayerStorage().getCharacterByName(params[0]);
if (victim == null) {
player.message("Player '" + params[0] + "' could not be found.");
return;
}
} else {
victim = c.getPlayer();
}
for (SavedLocationType type : SavedLocationType.values()) {
victim.clearSavedLocation(type);
}
player.message("Cleared " + params[0] + "'s saved locations.");
}
}

View File

@@ -0,0 +1,140 @@
/*
This file is part of the HeavenMS MapleStory Server, commands OdinMS-based
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/>.
*/
/*
@Author: Arthur L - Refactored command content into modules
*/
package client.command.commands.gm2;
import client.Character;
import client.Client;
import client.command.Command;
import client.inventory.InventoryType;
import client.inventory.Item;
import client.inventory.manipulator.InventoryManipulator;
public class ClearSlotCommand extends Command {
{
setDescription("Clear all items in an inventory tab.");
}
@Override
public void execute(Client c, String[] params) {
Character player = c.getPlayer();
if (params.length < 1) {
player.yellowMessage("Syntax: !clearslot <all, equip, use, setup, etc or cash.>");
return;
}
String type = params[0];
switch (type) {
case "all":
for (int i = 0; i < 101; i++) {
Item tempItem = c.getPlayer().getInventory(InventoryType.EQUIP).getItem((byte) i);
if (tempItem == null) {
continue;
}
InventoryManipulator.removeFromSlot(c, InventoryType.EQUIP, (byte) i, tempItem.getQuantity(), false, false);
}
for (int i = 0; i < 101; i++) {
Item tempItem = c.getPlayer().getInventory(InventoryType.USE).getItem((byte) i);
if (tempItem == null) {
continue;
}
InventoryManipulator.removeFromSlot(c, InventoryType.USE, (byte) i, tempItem.getQuantity(), false, false);
}
for (int i = 0; i < 101; i++) {
Item tempItem = c.getPlayer().getInventory(InventoryType.ETC).getItem((byte) i);
if (tempItem == null) {
continue;
}
InventoryManipulator.removeFromSlot(c, InventoryType.ETC, (byte) i, tempItem.getQuantity(), false, false);
}
for (int i = 0; i < 101; i++) {
Item tempItem = c.getPlayer().getInventory(InventoryType.SETUP).getItem((byte) i);
if (tempItem == null) {
continue;
}
InventoryManipulator.removeFromSlot(c, InventoryType.SETUP, (byte) i, tempItem.getQuantity(), false, false);
}
for (int i = 0; i < 101; i++) {
Item tempItem = c.getPlayer().getInventory(InventoryType.CASH).getItem((byte) i);
if (tempItem == null) {
continue;
}
InventoryManipulator.removeFromSlot(c, InventoryType.CASH, (byte) i, tempItem.getQuantity(), false, false);
}
player.yellowMessage("All Slots Cleared.");
break;
case "equip":
for (int i = 0; i < 101; i++) {
Item tempItem = c.getPlayer().getInventory(InventoryType.EQUIP).getItem((byte) i);
if (tempItem == null) {
continue;
}
InventoryManipulator.removeFromSlot(c, InventoryType.EQUIP, (byte) i, tempItem.getQuantity(), false, false);
}
player.yellowMessage("Equipment Slot Cleared.");
break;
case "use":
for (int i = 0; i < 101; i++) {
Item tempItem = c.getPlayer().getInventory(InventoryType.USE).getItem((byte) i);
if (tempItem == null) {
continue;
}
InventoryManipulator.removeFromSlot(c, InventoryType.USE, (byte) i, tempItem.getQuantity(), false, false);
}
player.yellowMessage("Use Slot Cleared.");
break;
case "setup":
for (int i = 0; i < 101; i++) {
Item tempItem = c.getPlayer().getInventory(InventoryType.SETUP).getItem((byte) i);
if (tempItem == null) {
continue;
}
InventoryManipulator.removeFromSlot(c, InventoryType.SETUP, (byte) i, tempItem.getQuantity(), false, false);
}
player.yellowMessage("Set-Up Slot Cleared.");
break;
case "etc":
for (int i = 0; i < 101; i++) {
Item tempItem = c.getPlayer().getInventory(InventoryType.ETC).getItem((byte) i);
if (tempItem == null) {
continue;
}
InventoryManipulator.removeFromSlot(c, InventoryType.ETC, (byte) i, tempItem.getQuantity(), false, false);
}
player.yellowMessage("ETC Slot Cleared.");
break;
case "cash":
for (int i = 0; i < 101; i++) {
Item tempItem = c.getPlayer().getInventory(InventoryType.CASH).getItem((byte) i);
if (tempItem == null) {
continue;
}
InventoryManipulator.removeFromSlot(c, InventoryType.CASH, (byte) i, tempItem.getQuantity(), false, false);
}
player.yellowMessage("Cash Slot Cleared.");
break;
default:
player.yellowMessage("Slot" + type + " does not exist!");
break;
}
}
}

View File

@@ -0,0 +1,65 @@
/*
This file is part of the HeavenMS MapleStory Server, commands OdinMS-based
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/>.
*/
/*
@Author: Arthur L - Refactored command content into modules
*/
package client.command.commands.gm2;
import client.Character;
import client.Client;
import client.command.Command;
public class DcCommand extends Command {
{
setDescription("Disconnect a player.");
}
@Override
public void execute(Client c, String[] params) {
Character player = c.getPlayer();
if (params.length < 1) {
player.yellowMessage("Syntax: !dc <playername>");
return;
}
Character victim = c.getWorldServer().getPlayerStorage().getCharacterByName(params[0]);
if (victim == null) {
victim = c.getChannelServer().getPlayerStorage().getCharacterByName(params[0]);
if (victim == null) {
victim = player.getMap().getCharacterByName(params[0]);
if (victim != null) {
try {//sometimes bugged because the map = null
victim.getClient().disconnect(true, false);
player.getMap().removePlayer(victim);
} catch (Exception e) {
e.printStackTrace();
}
} else {
return;
}
}
}
if (player.gmLevel() < victim.gmLevel()) {
victim = player;
}
victim.getClient().disconnect(false, false);
}
}

View File

@@ -0,0 +1,44 @@
/*
This file is part of the HeavenMS MapleStory Server, commands OdinMS-based
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/>.
*/
/*
@Author: Arthur L - Refactored command content into modules
*/
package client.command.commands.gm2;
import client.Character;
import client.Client;
import client.SkillFactory;
import client.command.Command;
public class EmpowerMeCommand extends Command {
{
setDescription("Activate all useful buffs.");
}
@Override
public void execute(Client c, String[] params) {
Character player = c.getPlayer();
final int[] array = {2311003, 2301004, 1301007, 4101004, 2001002, 1101007, 1005, 2301003, 5121009, 1111002, 4111001, 4111002, 4211003, 4211005, 1321000, 2321004, 3121002};
for (int i : array) {
SkillFactory.getSkill(i).getEffect(SkillFactory.getSkill(i).getMaxLevel()).applyTo(player);
}
}
}

View File

@@ -0,0 +1,37 @@
/*
This file is part of the HeavenMS MapleStory Server, commands OdinMS-based
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 client.command.commands.gm2;
import client.Client;
import client.command.Command;
/**
* @author Ronan
*/
public class GachaListCommand extends Command {
{
setDescription("Show gachapon rewards.");
}
@Override
public void execute(Client c, String[] params) {
c.getAbstractPlayerInteraction().openNpc(10000, "gachaponInfo");
}
}

View File

@@ -0,0 +1,39 @@
/*
This file is part of the HeavenMS MapleStory Server, commands OdinMS-based
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/>.
*/
/*
@Author: Arthur L - Refactored command content into modules
*/
package client.command.commands.gm2;
import client.Client;
import client.command.Command;
import server.ShopFactory;
public class GmShopCommand extends Command {
{
setDescription("Open the GM shop.");
}
@Override
public void execute(Client c, String[] params) {
ShopFactory.getInstance().getShop(1337).sendShop(c);
}
}

View File

@@ -0,0 +1,41 @@
/*
This file is part of the HeavenMS MapleStory Server, commands OdinMS-based
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/>.
*/
/*
@Author: Arthur L - Refactored command content into modules
*/
package client.command.commands.gm2;
import client.Character;
import client.Client;
import client.command.Command;
public class HealCommand extends Command {
{
setDescription("Fully heal your HP/MP.");
}
@Override
public void execute(Client c, String[] params) {
Character player = c.getPlayer();
player.healHpMp();
}
}

View File

@@ -0,0 +1,42 @@
/*
This file is part of the HeavenMS MapleStory Server, commands OdinMS-based
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/>.
*/
/*
@Author: Arthur L - Refactored command content into modules
*/
package client.command.commands.gm2;
import client.Character;
import client.Client;
import client.SkillFactory;
import client.command.Command;
public class HideCommand extends Command {
{
setDescription("Hide from players.");
}
@Override
public void execute(Client c, String[] params) {
Character player = c.getPlayer();
SkillFactory.getSkill(9101004).getEffect(SkillFactory.getSkill(9101004).getMaxLevel()).applyTo(player);
}
}

View File

@@ -0,0 +1,139 @@
package client.command.commands.gm2;
import client.Character;
import client.Client;
import client.command.Command;
import constants.game.NpcChat;
import constants.id.NpcId;
import server.ThreadManager;
import tools.exceptions.IdTypeNotSupportedException;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Predicate;
import java.util.stream.Collectors;
public class IdCommand extends Command {
{
setDescription("Search in handbook.");
}
private final static int MAX_SEARCH_HITS = 100;
private final Map<String, String> handbookDirectory = typeFilePaths();
private final Map<String, HandbookFileItems> typeItems = new ConcurrentHashMap<>();
private Map<String, String> typeFilePaths() {
return Map.ofEntries(
Map.entry("map", "handbook/Map.txt"),
Map.entry("etc", "handbook/Etc.txt"),
Map.entry("npc", "handbook/NPC.txt"),
Map.entry("use", "handbook/Use.txt"),
Map.entry("weapon", "handbook/Equip/Weapon.txt") // TODO add more into this
);
}
private static class HandbookFileItems {
private final List<HandbookItem> items;
public HandbookFileItems(List<String> fileLines) {
this.items = fileLines.stream()
.map(this::parseLine)
.filter(Predicate.not(Objects::isNull))
.toList();
}
private HandbookItem parseLine(String line) {
if (line == null) {
return null;
}
String[] splitLine = line.split(" - ", 2);
if (splitLine.length < 2 || splitLine[1].isBlank()) {
return null;
}
return new HandbookItem(splitLine[0], splitLine[1]);
}
public List<HandbookItem> search(String query) {
if (query == null || query.isBlank()) {
return Collections.emptyList();
}
return items.stream()
.filter(item -> item.matches(query))
.toList();
}
}
private record HandbookItem(String id, String name) {
public HandbookItem {
Objects.requireNonNull(id);
Objects.requireNonNull(name);
}
public boolean matches(String query) {
if (query == null) {
return false;
}
return this.name.toLowerCase().contains(query.toLowerCase());
}
}
@Override
public void execute(Client client, final String[] params) {
final Character chr = client.getPlayer();
if (params.length < 2) {
chr.yellowMessage("Syntax: !id <type> <query>");
return;
}
final String type = params[0].toLowerCase();
final String[] queryItems = Arrays.copyOfRange(params, 1, params.length);
final String query = String.join(" ", queryItems);
chr.yellowMessage("Querying for entry... May take some time... Please try to refine your search.");
Runnable queryRunnable = () -> {
try {
populateIdMap(type);
final HandbookFileItems handbookFileItems = typeItems.get(type);
if (handbookFileItems == null) {
return;
}
final List<HandbookItem> searchHits = handbookFileItems.search(query);
if (!searchHits.isEmpty()) {
String searchHitsText = searchHits.stream()
.limit(MAX_SEARCH_HITS)
.map(item -> "Id for %s is: #b%s#k".formatted(item.name, item.id))
.collect(Collectors.joining(NpcChat.NEW_LINE));
int hitsCount = Math.min(searchHits.size(), MAX_SEARCH_HITS);
String summaryText = "Results found: #r%d#k | Returned: #b%d#k/100 | Refine search query to improve time.".formatted(searchHits.size(), hitsCount);
String fullText = searchHitsText + NpcChat.NEW_LINE + summaryText;
chr.getAbstractPlayerInteraction().npcTalk(NpcId.MAPLE_ADMINISTRATOR, fullText);
} else {
chr.yellowMessage(String.format("Id not found for item: %s, of type: %s.", query, type));
}
} catch (IdTypeNotSupportedException e) {
chr.yellowMessage("Your query type is not supported.");
} catch (IOException e) {
chr.yellowMessage("Error reading file, please contact your administrator.");
}
};
ThreadManager.getInstance().newTask(queryRunnable);
}
private void populateIdMap(String type) throws IdTypeNotSupportedException, IOException {
final String filePath = handbookDirectory.get(type);
if (filePath == null) {
throw new IdTypeNotSupportedException();
}
if (typeItems.containsKey(type)) {
return;
}
final List<String> fileLines = Files.readAllLines(Path.of(filePath));
typeItems.put(type, new HandbookFileItems(fileLines));
}
}

View File

@@ -0,0 +1,92 @@
/*
This file is part of the HeavenMS MapleStory Server, commands OdinMS-based
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/>.
*/
/*
@Author: Arthur L - Refactored command content into modules
*/
package client.command.commands.gm2;
import client.Character;
import client.Client;
import client.command.Command;
import client.inventory.Pet;
import client.inventory.manipulator.InventoryManipulator;
import config.YamlConfig;
import constants.inventory.ItemConstants;
import server.ItemInformationProvider;
import static java.util.concurrent.TimeUnit.DAYS;
public class ItemCommand extends Command {
{
setDescription("Spawn an item into your inventory.");
}
@Override
public void execute(Client c, String[] params) {
Character player = c.getPlayer();
if (params.length < 1) {
player.yellowMessage("Syntax: !item <itemid> <quantity>");
return;
}
int itemId = Integer.parseInt(params[0]);
ItemInformationProvider ii = ItemInformationProvider.getInstance();
if (ii.getName(itemId) == null) {
player.yellowMessage("Item id '" + params[0] + "' does not exist.");
return;
}
short quantity = 1;
if (params.length >= 2) {
quantity = Short.parseShort(params[1]);
}
if (YamlConfig.config.server.BLOCK_GENERATE_CASH_ITEM && ii.isCash(itemId)) {
player.yellowMessage("You cannot create a cash item with this command.");
return;
}
if (ItemConstants.isPet(itemId)) {
if (params.length >= 2) { // thanks to istreety & TacoBell
quantity = 1;
long days = Math.max(1, Integer.parseInt(params[1]));
long expiration = System.currentTimeMillis() + DAYS.toMillis(days);
int petid = Pet.createPet(itemId);
InventoryManipulator.addById(c, itemId, quantity, player.getName(), petid, expiration);
return;
} else {
player.yellowMessage("Pet Syntax: !item <itemid> <expiration>");
return;
}
}
short flag = 0;
if (player.gmLevel() < 3) {
flag |= ItemConstants.ACCOUNT_SHARING;
flag |= ItemConstants.UNTRADEABLE;
}
InventoryManipulator.addById(c, itemId, quantity, player.getName(), -1, flag, -1);
}
}

View File

@@ -0,0 +1,120 @@
/*
This file is part of the HeavenMS MapleStory Server, commands OdinMS-based
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/>.
*/
/*
@Author: Arthur L - Refactored command content into modules
*/
package client.command.commands.gm2;
import client.Character;
import client.Client;
import client.command.Command;
import client.inventory.InventoryType;
import client.inventory.Item;
import client.inventory.Pet;
import config.YamlConfig;
import constants.inventory.ItemConstants;
import server.ItemInformationProvider;
import static java.util.concurrent.TimeUnit.DAYS;
public class ItemDropCommand extends Command {
{
setDescription("Spawn an item onto the ground.");
}
@Override
public void execute(Client c, String[] params) {
Character player = c.getPlayer();
if (params.length < 1) {
player.yellowMessage("Syntax: !drop <itemid> <quantity>");
return;
}
int itemId = Integer.parseInt(params[0]);
ItemInformationProvider ii = ItemInformationProvider.getInstance();
if (ii.getName(itemId) == null) {
player.yellowMessage("Item id '" + params[0] + "' does not exist.");
return;
}
short quantity = 1;
if (params.length >= 2) {
quantity = Short.parseShort(params[1]);
}
if (YamlConfig.config.server.BLOCK_GENERATE_CASH_ITEM && ii.isCash(itemId)) {
player.yellowMessage("You cannot create a cash item with this command.");
return;
}
if (ItemConstants.isPet(itemId)) {
if (params.length >= 2) { // thanks to istreety & TacoBell
quantity = 1;
long days = Math.max(1, Integer.parseInt(params[1]));
long expiration = System.currentTimeMillis() + DAYS.toMillis(days);
int petid = Pet.createPet(itemId);
Item toDrop = new Item(itemId, (short) 0, quantity, petid);
toDrop.setExpiration(expiration);
toDrop.setOwner("");
if (player.gmLevel() < 3) {
short f = toDrop.getFlag();
f |= ItemConstants.ACCOUNT_SHARING;
f |= ItemConstants.UNTRADEABLE;
f |= ItemConstants.SANDBOX;
toDrop.setFlag(f);
toDrop.setOwner("TRIAL-MODE");
}
c.getPlayer().getMap().spawnItemDrop(c.getPlayer(), c.getPlayer(), toDrop, c.getPlayer().getPosition(), true, true);
return;
} else {
player.yellowMessage("Pet Syntax: !drop <itemid> <expiration>");
return;
}
}
Item toDrop;
if (ItemConstants.getInventoryType(itemId) == InventoryType.EQUIP) {
toDrop = ii.getEquipById(itemId);
} else {
toDrop = new Item(itemId, (short) 0, quantity);
}
toDrop.setOwner(player.getName());
if (player.gmLevel() < 3) {
short f = toDrop.getFlag();
f |= ItemConstants.ACCOUNT_SHARING;
f |= ItemConstants.UNTRADEABLE;
f |= ItemConstants.SANDBOX;
toDrop.setFlag(f);
toDrop.setOwner("TRIAL-MODE");
}
c.getPlayer().getMap().spawnItemDrop(c.getPlayer(), c.getPlayer(), toDrop, c.getPlayer().getPosition(), true, true);
}
}

View File

@@ -0,0 +1,75 @@
/*
This file is part of the HeavenMS MapleStory Server, commands OdinMS-based
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/>.
*/
/*
@Author: Arthur L - Refactored command content into modules
*/
package client.command.commands.gm2;
import client.Character;
import client.Client;
import client.command.Command;
import constants.id.MapId;
import server.maps.MapleMap;
import server.maps.Portal;
import static java.util.concurrent.TimeUnit.MINUTES;
public class JailCommand extends Command {
{
setDescription("Move a player to the jail.");
}
@Override
public void execute(Client c, String[] params) {
Character player = c.getPlayer();
if (params.length < 1) {
player.yellowMessage("Syntax: !jail <playername> [<minutes>]");
return;
}
int minutesJailed = 5;
if (params.length >= 2) {
minutesJailed = Integer.parseInt(params[1]);
if (minutesJailed <= 0) {
player.yellowMessage("Syntax: !jail <playername> [<minutes>]");
return;
}
}
Character victim = c.getWorldServer().getPlayerStorage().getCharacterByName(params[0]);
if (victim != null) {
victim.addJailExpirationTime(MINUTES.toMillis(minutesJailed));
if (victim.getMapId() != MapId.JAIL) { // those gone to jail won't be changing map anyway
MapleMap target = c.getChannelServer().getMapFactory().getMap(MapId.JAIL);
Portal targetPortal = target.getPortal(0);
victim.saveLocationOnWarp();
victim.changeMap(target, targetPortal);
player.message(victim.getName() + " was jailed for " + minutesJailed + " minutes.");
} else {
player.message(victim.getName() + "'s time in jail has been extended for " + minutesJailed + " minutes.");
}
} else {
player.message("Player '" + params[0] + "' could not be found.");
}
}
}

View File

@@ -0,0 +1,67 @@
/*
This file is part of the HeavenMS MapleStory Server, commands OdinMS-based
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/>.
*/
/*
@Author: Arthur L - Refactored command content into modules
*/
package client.command.commands.gm2;
import client.Character;
import client.Client;
import client.Job;
import client.command.Command;
public class JobCommand extends Command {
{
setDescription("Change job of a player.");
}
@Override
public void execute(Client c, String[] params) {
Character player = c.getPlayer();
if (params.length == 1) {
int jobid = Integer.parseInt(params[0]);
if (jobid < 0 || jobid >= 2200) {
player.message("Jobid " + jobid + " is not available.");
return;
}
player.changeJob(Job.getById(jobid));
player.equipChanged();
} else if (params.length == 2) {
Character victim = c.getWorldServer().getPlayerStorage().getCharacterByName(params[0]);
if (victim != null) {
int jobid = Integer.parseInt(params[1]);
if (jobid < 0 || jobid >= 2200) {
player.message("Jobid " + jobid + " is not available.");
return;
}
victim.changeJob(Job.getById(jobid));
player.equipChanged();
} else {
player.message("Player '" + params[0] + "' could not be found.");
}
} else {
player.message("Syntax: !job <job id> <opt: IGN of another person>");
}
}
}

View File

@@ -0,0 +1,55 @@
/*
This file is part of the HeavenMS MapleStory Server, commands OdinMS-based
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/>.
*/
/*
@Author: Arthur L - Refactored command content into modules
*/
package client.command.commands.gm2;
import client.Character;
import client.Client;
import client.command.Command;
import config.YamlConfig;
public class LevelCommand extends Command {
{
setDescription("Set your level.");
}
@Override
public void execute(Client c, String[] params) {
Character player = c.getPlayer();
if (params.length < 1) {
player.yellowMessage("Syntax: !level <newlevel>");
return;
}
player.loseExp(player.getExp(), false, false);
player.setLevel(Math.min(Integer.parseInt(params[0]), player.getMaxClassLevel()) - 1);
player.resetPlayerRates();
if (YamlConfig.config.server.USE_ADD_RATES_BY_LEVEL) {
player.setPlayerRates();
}
player.setWorldRates();
player.levelUp(false);
}
}

View File

@@ -0,0 +1,46 @@
/*
This file is part of the HeavenMS MapleStory Server, commands OdinMS-based
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/>.
*/
/*
@Author: Arthur L - Refactored command content into modules
*/
package client.command.commands.gm2;
import client.Character;
import client.Client;
import client.command.Command;
public class LevelProCommand extends Command {
{
setDescription("Set your level, one by one.");
}
@Override
public void execute(Client c, String[] params) {
Character player = c.getPlayer();
if (params.length < 1) {
player.yellowMessage("Syntax: !levelpro <newlevel>");
return;
}
while (player.getLevel() < Math.min(player.getMaxClassLevel(), Integer.parseInt(params[0]))) {
player.levelUp(false);
}
}
}

View File

@@ -0,0 +1,52 @@
/*
This file is part of the HeavenMS MapleStory Server, commands OdinMS-based
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/>.
*/
/*
@Author: Resinate
*/
package client.command.commands.gm2;
import client.Client;
import client.command.Command;
import server.maps.MapItem;
import server.maps.MapObject;
import server.maps.MapObjectType;
import java.util.Arrays;
import java.util.List;
public class LootCommand extends Command {
{
setDescription("Loots all items that belong to you.");
}
@Override
public void execute(Client c, String[] params) {
List<MapObject> items = c.getPlayer().getMap().getMapObjectsInRange(c.getPlayer().getPosition(), Double.POSITIVE_INFINITY, Arrays.asList(MapObjectType.ITEM));
for (MapObject item : items) {
MapItem mapItem = (MapItem) item;
if (mapItem.getOwnerId() == c.getPlayer().getId() || mapItem.getOwnerId() == c.getPlayer().getPartyId()) {
c.getPlayer().pickupItem(mapItem);
}
}
}
}

View File

@@ -0,0 +1,62 @@
/*
This file is part of the HeavenMS MapleStory Server, commands OdinMS-based
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/>.
*/
/*
@Author: Arthur L - Refactored command content into modules
*/
package client.command.commands.gm2;
import client.Character;
import client.*;
import client.command.Command;
import provider.Data;
import provider.DataProviderFactory;
import provider.wz.WZFiles;
public class MaxSkillCommand extends Command {
{
setDescription("Max out all job skills.");
}
@Override
public void execute(Client c, String[] params) {
Character player = c.getPlayer();
for (Data skill_ : DataProviderFactory.getDataProvider(WZFiles.STRING).getData("Skill.img").getChildren()) {
try {
Skill skill = SkillFactory.getSkill(Integer.parseInt(skill_.getName()));
player.changeSkillLevel(skill, (byte) skill.getMaxLevel(), skill.getMaxLevel(), -1);
} catch (NumberFormatException nfe) {
nfe.printStackTrace();
break;
} catch (NullPointerException npe) {
}
}
if (player.getJob().isA(Job.ARAN1) || player.getJob().isA(Job.LEGEND)) {
Skill skill = SkillFactory.getSkill(5001005);
player.changeSkillLevel(skill, (byte) -1, -1, -1);
} else {
Skill skill = SkillFactory.getSkill(21001001);
player.changeSkillLevel(skill, (byte) -1, -1, -1);
}
player.yellowMessage("Skills maxed out.");
}
}

View File

@@ -0,0 +1,54 @@
/*
This file is part of the HeavenMS MapleStory Server, commands OdinMS-based
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/>.
*/
/*
@Author: Arthur L - Refactored command content into modules
*/
package client.command.commands.gm2;
import client.Character;
import client.Client;
import client.Stat;
import client.command.Command;
import config.YamlConfig;
public class MaxStatCommand extends Command {
{
setDescription("Max out all character stats.");
}
@Override
public void execute(Client c, String[] params) {
Character player = c.getPlayer();
player.loseExp(player.getExp(), false, false);
player.setLevel(255);
player.resetPlayerRates();
if (YamlConfig.config.server.USE_ADD_RATES_BY_LEVEL) {
player.setPlayerRates();
}
player.setWorldRates();
player.updateStrDexIntLuk(Short.MAX_VALUE);
player.setFame(13337);
player.updateMaxHpMaxMp(30000, 30000);
player.updateSingleStat(Stat.LEVEL, 255);
player.updateSingleStat(Stat.FAME, 13337);
player.yellowMessage("Stats maxed out.");
}
}

View File

@@ -0,0 +1,40 @@
package client.command.commands.gm2;
import client.Character;
import client.Client;
import client.command.Command;
import server.life.MobSkill;
import server.life.MobSkillFactory;
import server.life.MobSkillType;
import java.util.Collections;
import java.util.Optional;
public class MobSkillCommand extends Command {
{
setDescription("Apply a mob skill to all mobs on the map. Args: <mob skill id> <skill level>");
}
@Override
public void execute(Client client, String[] params) {
if (params.length < 2) {
throw new IllegalArgumentException("Mob skill command requires two args: mob skill id and level");
}
String skillId = params[0];
String skillLevel = params[1];
Optional<MobSkillType> possibleType = MobSkillType.from(Integer.parseInt(skillId));
Optional<MobSkill> possibleSkill = possibleType.map(
type -> MobSkillFactory.getMobSkillOrThrow(type, Integer.parseInt(skillLevel))
);
if (possibleSkill.isEmpty()) {
return;
}
Character chr = client.getPlayer();
MobSkill mobSkill = possibleSkill.get();
chr.getMap().getAllMonsters().forEach(
monster -> mobSkill.applyEffect(chr, monster, false, Collections.emptyList())
);
}
}

View File

@@ -0,0 +1,57 @@
/*
This file is part of the HeavenMS MapleStory Server, commands OdinMS-based
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/>.
*/
/*
@Author: Arthur L - Refactored command content into modules
*/
package client.command.commands.gm2;
import client.Character;
import client.Client;
import client.command.Command;
import server.maps.MapleMap;
public class ReachCommand extends Command {
{
setDescription("Warp to a player.");
}
@Override
public void execute(Client c, String[] params) {
Character player = c.getPlayer();
if (params.length < 1) {
player.yellowMessage("Syntax: !reach <playername>");
return;
}
Character victim = c.getWorldServer().getPlayerStorage().getCharacterByName(params[0]);
if (victim != null && victim.isLoggedin()) {
if (player.getClient().getChannel() != victim.getClient().getChannel()) {
player.dropMessage(5, "Player '" + victim.getName() + "' is at channel " + victim.getClient().getChannel() + ".");
} else {
MapleMap map = victim.getMap();
player.saveLocationOnWarp();
player.forceChangeMap(map, map.findClosestPortal(victim.getPosition()));
}
} else {
player.dropMessage(6, "Unknown player.");
}
}
}

View File

@@ -0,0 +1,60 @@
/*
This file is part of the HeavenMS MapleStory Server, commands OdinMS-based
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/>.
*/
/*
@Author: Arthur L - Refactored command content into modules
*/
package client.command.commands.gm2;
import client.Character;
import client.Client;
import client.command.Command;
import client.inventory.InventoryType;
import client.inventory.Item;
import constants.inventory.ItemConstants;
import server.ItemInformationProvider;
public class RechargeCommand extends Command {
{
setDescription("Recharge and refill all USE items.");
}
@Override
public void execute(Client c, String[] params) {
Character player = c.getPlayer();
ItemInformationProvider ii = ItemInformationProvider.getInstance();
for (Item torecharge : c.getPlayer().getInventory(InventoryType.USE).list()) {
if (ItemConstants.isThrowingStar(torecharge.getItemId())) {
torecharge.setQuantity(ii.getSlotMax(c, torecharge.getItemId()));
c.getPlayer().forceUpdateItem(torecharge);
} else if (ItemConstants.isArrow(torecharge.getItemId())) {
torecharge.setQuantity(ii.getSlotMax(c, torecharge.getItemId()));
c.getPlayer().forceUpdateItem(torecharge);
} else if (ItemConstants.isBullet(torecharge.getItemId())) {
torecharge.setQuantity(ii.getSlotMax(c, torecharge.getItemId()));
c.getPlayer().forceUpdateItem(torecharge);
} else if (ItemConstants.isConsumable(torecharge.getItemId())) {
torecharge.setQuantity(ii.getSlotMax(c, torecharge.getItemId()));
c.getPlayer().forceUpdateItem(torecharge);
}
}
player.dropMessage(5, "USE Recharged.");
}
}

View File

@@ -0,0 +1,62 @@
/*
This file is part of the HeavenMS MapleStory Server, commands OdinMS-based
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/>.
*/
/*
@Author: Arthur L - Refactored command content into modules
*/
package client.command.commands.gm2;
import client.Character;
import client.*;
import client.command.Command;
import provider.Data;
import provider.DataProviderFactory;
import provider.wz.WZFiles;
public class ResetSkillCommand extends Command {
{
setDescription("Set all skill levels to 0.");
}
@Override
public void execute(Client c, String[] params) {
Character player = c.getPlayer();
for (Data skill_ : DataProviderFactory.getDataProvider(WZFiles.STRING).getData("Skill.img").getChildren()) {
try {
Skill skill = SkillFactory.getSkill(Integer.parseInt(skill_.getName()));
player.changeSkillLevel(skill, (byte) 0, skill.getMaxLevel(), -1);
} catch (NumberFormatException nfe) {
nfe.printStackTrace();
break;
} catch (NullPointerException npe) {
}
}
if (player.getJob().isA(Job.ARAN1) || player.getJob().isA(Job.LEGEND)) {
Skill skill = SkillFactory.getSkill(5001005);
player.changeSkillLevel(skill, (byte) -1, -1, -1);
} else {
Skill skill = SkillFactory.getSkill(21001001);
player.changeSkillLevel(skill, (byte) -1, -1, -1);
}
player.yellowMessage("Skills reseted.");
}
}

View File

@@ -0,0 +1,139 @@
/*
This file is part of the HeavenMS MapleStory Server, commands OdinMS-based
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/>.
*/
/*
@Author: Arthur L - Refactored command content into modules
*/
package client.command.commands.gm2;
import client.Character;
import client.Client;
import client.command.Command;
import constants.id.NpcId;
import provider.Data;
import provider.DataProvider;
import provider.DataProviderFactory;
import provider.DataTool;
import provider.wz.WZFiles;
import server.ItemInformationProvider;
import server.quest.Quest;
import tools.Pair;
public class SearchCommand extends Command {
private static Data npcStringData;
private static Data mobStringData;
private static Data skillStringData;
private static Data mapStringData;
{
setDescription("Search String.wz.");
DataProvider dataProvider = DataProviderFactory.getDataProvider(WZFiles.STRING);
npcStringData = dataProvider.getData("Npc.img");
mobStringData = dataProvider.getData("Mob.img");
skillStringData = dataProvider.getData("Skill.img");
mapStringData = dataProvider.getData("Map.img");
}
@Override
public void execute(Client c, String[] params) {
Character player = c.getPlayer();
if (params.length < 2) {
player.yellowMessage("Syntax: !search <type> <name>");
return;
}
StringBuilder sb = new StringBuilder();
String search = joinStringFrom(params, 1);
long start = System.currentTimeMillis();//for the lulz
Data data = null;
if (!params[0].equalsIgnoreCase("ITEM")) {
int searchType = 0;
if (params[0].equalsIgnoreCase("NPC")) {
data = npcStringData;
} else if (params[0].equalsIgnoreCase("MOB") || params[0].equalsIgnoreCase("MONSTER")) {
data = mobStringData;
} else if (params[0].equalsIgnoreCase("SKILL")) {
data = skillStringData;
} else if (params[0].equalsIgnoreCase("MAP")) {
data = mapStringData;
searchType = 1;
} else if (params[0].equalsIgnoreCase("QUEST")) {
data = mapStringData;
searchType = 2;
} else {
sb.append("#bInvalid search.\r\nSyntax: '!search [type] [name]', where [type] is MAP, QUEST, NPC, ITEM, MOB, or SKILL.");
}
if (data != null) {
String name;
if (searchType == 0) {
for (Data searchData : data.getChildren()) {
name = DataTool.getString(searchData.getChildByPath("name"), "NO-NAME");
if (name.toLowerCase().contains(search.toLowerCase())) {
sb.append("#b").append(Integer.parseInt(searchData.getName())).append("#k - #r").append(name).append("\r\n");
}
}
} else if (searchType == 1) {
String mapName, streetName;
for (Data searchDataDir : data.getChildren()) {
for (Data searchData : searchDataDir.getChildren()) {
mapName = DataTool.getString(searchData.getChildByPath("mapName"), "NO-NAME");
streetName = DataTool.getString(searchData.getChildByPath("streetName"), "NO-NAME");
if (mapName.toLowerCase().contains(search.toLowerCase()) || streetName.toLowerCase().contains(search.toLowerCase())) {
sb.append("#b").append(Integer.parseInt(searchData.getName())).append("#k - #r").append(streetName).append(" - ").append(mapName).append("\r\n");
}
}
}
} else {
for (Quest mq : Quest.getMatchedQuests(search)) {
sb.append("#b").append(mq.getId()).append("#k - #r");
String parentName = mq.getParentName();
if (!parentName.isEmpty()) {
sb.append(parentName).append(" - ");
}
sb.append(mq.getName()).append("\r\n");
}
}
}
} else {
for (Pair<Integer, String> itemPair : ItemInformationProvider.getInstance().getAllItems()) {
if (sb.length() < 32654) {//ohlol
if (itemPair.getRight().toLowerCase().contains(search.toLowerCase())) {
sb.append("#b").append(itemPair.getLeft()).append("#k - #r").append(itemPair.getRight()).append("\r\n");
}
} else {
sb.append("#bCouldn't load all items, there are too many results.\r\n");
break;
}
}
}
if (sb.length() == 0) {
sb.append("#bNo ").append(params[0].toLowerCase()).append("s found.\r\n");
}
sb.append("\r\n#kLoaded within ").append((double) (System.currentTimeMillis() - start) / 1000).append(" seconds.");//because I can, and it's free
c.getAbstractPlayerInteraction().npcTalk(NpcId.MAPLE_ADMINISTRATOR, sb.toString());
}
}

View File

@@ -0,0 +1,55 @@
/*
This file is part of the HeavenMS MapleStory Server, commands OdinMS-based
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/>.
*/
/*
@Author: Ronan
*/
package client.command.commands.gm2;
import client.Character;
import client.Client;
import client.command.Command;
public class SetSlotCommand extends Command {
{
setDescription("Set amount of inventory slots in all tabs.");
}
@Override
public void execute(Client c, String[] params) {
Character player = c.getPlayer();
if (params.length < 1) {
player.yellowMessage("Syntax: !setslot <newlevel>");
return;
}
int slots = (Integer.parseInt(params[0]) / 4) * 4;
for (int i = 1; i < 5; i++) {
int curSlots = player.getSlots(i);
if (slots <= -curSlots) {
continue;
}
player.gainSlots(i, slots - curSlots, true);
}
player.yellowMessage("Slots updated.");
}
}

View File

@@ -0,0 +1,56 @@
/*
This file is part of the HeavenMS MapleStory Server, commands OdinMS-based
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/>.
*/
/*
@Author: Arthur L - Refactored command content into modules
*/
package client.command.commands.gm2;
import client.Character;
import client.Client;
import client.command.Command;
public class SetStatCommand extends Command {
{
setDescription("Set all primary stats to new value.");
}
@Override
public void execute(Client c, String[] params) {
Character player = c.getPlayer();
if (params.length < 1) {
player.yellowMessage("Syntax: !setstat <newstat>");
return;
}
try {
int x = Integer.parseInt(params[0]);
if (x > Short.MAX_VALUE) {
x = Short.MAX_VALUE;
} else if (x < 4) {
x = 4; // thanks Vcoc for pointing the minimal allowed stat value here
}
player.updateStrDexIntLuk(x);
} catch (NumberFormatException nfe) {
}
}
}

View File

@@ -0,0 +1,71 @@
/*
This file is part of the HeavenMS MapleStory Server, commands OdinMS-based
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/>.
*/
/*
@Author: Arthur L - Refactored command content into modules
*/
package client.command.commands.gm2;
import client.Character;
import client.Client;
import client.command.Command;
import config.YamlConfig;
public class SpCommand extends Command {
{
setDescription("Set available SP.");
}
@Override
public void execute(Client c, String[] params) {
Character player = c.getPlayer();
if (params.length < 1) {
player.yellowMessage("Syntax: !sp [<playername>] <newsp>");
return;
}
if (params.length == 1) {
int newSp = Integer.parseInt(params[0]);
if (newSp < 0) {
newSp = 0;
} else if (newSp > YamlConfig.config.server.MAX_AP) {
newSp = YamlConfig.config.server.MAX_AP;
}
player.updateRemainingSp(newSp);
} else {
Character victim = c.getWorldServer().getPlayerStorage().getCharacterByName(params[0]);
if (victim != null) {
int newSp = Integer.parseInt(params[1]);
if (newSp < 0) {
newSp = 0;
} else if (newSp > YamlConfig.config.server.MAX_AP) {
newSp = YamlConfig.config.server.MAX_AP;
}
victim.updateRemainingSp(newSp);
player.dropMessage(5, "SP given.");
} else {
player.message("Player '" + params[0] + "' could not be found.");
}
}
}
}

View File

@@ -0,0 +1,85 @@
/*
This file is part of the HeavenMS MapleStory Server, commands OdinMS-based
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/>.
*/
/*
@Author: Arthur L - Refactored command content into modules
*/
package client.command.commands.gm2;
import client.Character;
import client.Client;
import client.command.Command;
import net.server.Server;
import net.server.channel.Channel;
import server.maps.MapleMap;
public class SummonCommand extends Command {
{
setDescription("Move a player to your location.");
}
@Override
public void execute(Client c, String[] params) {
Character player = c.getPlayer();
if (params.length < 1) {
player.yellowMessage("Syntax: !warphere <playername>");
return;
}
Character victim = c.getChannelServer().getPlayerStorage().getCharacterByName(params[0]);
if (victim == null) {
//If victim isn't on current channel, loop all channels on current world.
for (Channel ch : Server.getInstance().getChannelsFromWorld(c.getWorld())) {
victim = ch.getPlayerStorage().getCharacterByName(params[0]);
if (victim != null) {
break;//We found the person, no need to continue the loop.
}
}
}
if (victim != null) {
if (!victim.isLoggedinWorld()) {
player.dropMessage(6, "Player currently not logged in or unreachable.");
return;
}
if (player.getClient().getChannel() != victim.getClient().getChannel()) {//And then change channel if needed.
victim.dropMessage("Changing channel, please wait a moment.");
victim.getClient().changeChannel(player.getClient().getChannel());
}
try {
for (int i = 0; i < 7; i++) { // poll for a while until the player reconnects
if (victim.isLoggedinWorld()) {
break;
}
Thread.sleep(1777);
}
} catch (InterruptedException e) {
}
MapleMap map = player.getMap();
victim.saveLocationOnWarp();
victim.forceChangeMap(map, map.findClosestPortal(player.getPosition()));
} else {
player.dropMessage(6, "Unknown player.");
}
}
}

View File

@@ -0,0 +1,39 @@
/*
This file is part of the HeavenMS MapleStory Server, commands OdinMS-based
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/>.
*/
/*
@Author: Arthur L - Refactored command content into modules
*/
package client.command.commands.gm2;
import client.Client;
import client.command.Command;
import tools.PacketCreator;
public class UnBugCommand extends Command {
{
setDescription("Unbug self.");
}
@Override
public void execute(Client c, String[] params) {
c.getPlayer().getMap().broadcastMessage(PacketCreator.enableActions());
}
}

View File

@@ -0,0 +1,42 @@
/*
This file is part of the HeavenMS MapleStory Server, commands OdinMS-based
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/>.
*/
/*
@Author: Arthur L - Refactored command content into modules
*/
package client.command.commands.gm2;
import client.Character;
import client.Client;
import client.SkillFactory;
import client.command.Command;
public class UnHideCommand extends Command {
{
setDescription("Toggle Hide.");
}
@Override
public void execute(Client c, String[] params) {
Character player = c.getPlayer();
SkillFactory.getSkill(9101004).getEffect(SkillFactory.getSkill(9101004).getMaxLevel()).applyTo(player);
}
}

View File

@@ -0,0 +1,56 @@
/*
This file is part of the HeavenMS MapleStory Server, commands OdinMS-based
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/>.
*/
/*
@Author: Arthur L - Refactored command content into modules
*/
package client.command.commands.gm2;
import client.Character;
import client.Client;
import client.command.Command;
public class UnJailCommand extends Command {
{
setDescription("Free a player from jail.");
}
@Override
public void execute(Client c, String[] params) {
Character player = c.getPlayer();
if (params.length < 1) {
player.yellowMessage("Syntax: !unjail <playername>");
return;
}
Character victim = c.getWorldServer().getPlayerStorage().getCharacterByName(params[0]);
if (victim != null) {
if (victim.getJailExpirationTimeLeft() <= 0) {
player.message("This player is already free.");
return;
}
victim.removeJailExpirationTime();
victim.message("By lack of concrete proof you are now unjailed. Enjoy freedom!");
player.message(victim.getName() + " was unjailed.");
} else {
player.message("Player '" + params[0] + "' could not be found.");
}
}
}

View File

@@ -0,0 +1,68 @@
/*
This file is part of the HeavenMS MapleStory Server, commands OdinMS-based
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/>.
*/
/*
@Author: MedicOP - Add warparea command
*/
package client.command.commands.gm2;
import client.Character;
import client.Client;
import client.command.Command;
import server.maps.MapleMap;
import java.awt.*;
import java.util.Collection;
public class WarpAreaCommand extends Command {
{
setDescription("Warp all nearby players to a new map.");
}
@Override
public void execute(Client c, String[] params) {
Character player = c.getPlayer();
if (params.length < 1) {
player.yellowMessage("Syntax: !warparea <mapid>");
return;
}
try {
MapleMap target = c.getChannelServer().getMapFactory().getMap(Integer.parseInt(params[0]));
if (target == null) {
player.yellowMessage("Map ID " + params[0] + " is invalid.");
return;
}
Point pos = player.getPosition();
Collection<Character> characters = player.getMap().getAllPlayers();
for (Character victim : characters) {
if (victim.getPosition().distanceSq(pos) <= 50000) {
victim.saveLocationOnWarp();
victim.changeMap(target, target.getRandomPlayerSpawnpoint());
}
}
} catch (Exception ex) {
player.yellowMessage("Map ID " + params[0] + " is invalid.");
}
}
}

View File

@@ -0,0 +1,72 @@
/*
This file is part of the HeavenMS MapleStory Server, commands OdinMS-based
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/>.
*/
/*
@Author: Arthur L - Refactored command content into modules
*/
package client.command.commands.gm2;
import client.Character;
import client.Client;
import client.command.Command;
import server.maps.FieldLimit;
import server.maps.MapleMap;
import server.maps.MiniDungeonInfo;
public class WarpCommand extends Command {
{
setDescription("Warp to a map.");
}
@Override
public void execute(Client c, String[] params) {
Character player = c.getPlayer();
if (params.length < 1) {
player.yellowMessage("Syntax: !warp <mapid>");
return;
}
try {
MapleMap target = c.getChannelServer().getMapFactory().getMap(Integer.parseInt(params[0]));
if (target == null) {
player.yellowMessage("Map ID " + params[0] + " is invalid.");
return;
}
if (!player.isAlive()) {
player.dropMessage(1, "This command cannot be used when you're dead.");
return;
}
if (!player.isGM()) {
if (player.getEventInstance() != null || MiniDungeonInfo.isDungeonMap(player.getMapId()) || FieldLimit.CANNOTMIGRATE.check(player.getMap().getFieldLimit())) {
player.dropMessage(1, "This command cannot be used in this map.");
return;
}
}
// expedition issue with this command detected thanks to Masterrulax
player.saveLocationOnWarp();
player.changeMap(target, target.getRandomPlayerSpawnpoint());
} catch (Exception ex) {
player.yellowMessage("Map ID " + params[0] + " is invalid.");
}
}
}

View File

@@ -0,0 +1,63 @@
/*
This file is part of the HeavenMS MapleStory Server, commands OdinMS-based
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/>.
*/
/*
@Author: MedicOP - Add warpmap command
*/
package client.command.commands.gm2;
import client.Character;
import client.Client;
import client.command.Command;
import server.maps.MapleMap;
import java.util.Collection;
public class WarpMapCommand extends Command {
{
setDescription("Warp all characters on current map to a new map.");
}
@Override
public void execute(Client c, String[] params) {
Character player = c.getPlayer();
if (params.length < 1) {
player.yellowMessage("Syntax: !warpmap <mapid>");
return;
}
try {
MapleMap target = c.getChannelServer().getMapFactory().getMap(Integer.parseInt(params[0]));
if (target == null) {
player.yellowMessage("Map ID " + params[0] + " is invalid.");
return;
}
Collection<Character> characters = player.getMap().getAllPlayers();
for (Character victim : characters) {
victim.saveLocationOnWarp();
victim.changeMap(target, target.getRandomPlayerSpawnpoint());
}
} catch (Exception ex) {
player.yellowMessage("Map ID " + params[0] + " is invalid.");
}
}
}

View File

@@ -0,0 +1,94 @@
/*
This file is part of the HeavenMS MapleStory Server, commands OdinMS-based
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/>.
*/
/*
@Author: Arthur L - Refactored command content into modules
*/
package client.command.commands.gm2;
import client.Character;
import client.Client;
import client.command.Command;
import server.life.Monster;
import server.life.NPC;
import server.life.PlayerNPC;
import server.maps.MapObject;
import java.util.HashSet;
public class WhereaMiCommand extends Command {
{
setDescription("Show info about objects on current map.");
}
@Override
public void execute(Client c, String[] params) {
Character player = c.getPlayer();
HashSet<Character> chars = new HashSet<>();
HashSet<NPC> npcs = new HashSet<>();
HashSet<PlayerNPC> playernpcs = new HashSet<>();
HashSet<Monster> mobs = new HashSet<>();
for (MapObject mmo : player.getMap().getMapObjects()) {
if (mmo instanceof NPC npc) {
npcs.add(npc);
} else if (mmo instanceof Character mc) {
chars.add(mc);
} else if (mmo instanceof Monster mob) {
if (mob.isAlive()) {
mobs.add(mob);
}
} else if (mmo instanceof PlayerNPC npc) {
playernpcs.add(npc);
}
}
player.yellowMessage("Map ID: " + player.getMap().getId());
player.yellowMessage("Players on this map:");
for (Character chr : chars) {
player.dropMessage(5, ">> " + chr.getName() + " - " + chr.getId() + " - Oid: " + chr.getObjectId());
}
if (!playernpcs.isEmpty()) {
player.yellowMessage("PlayerNPCs on this map:");
for (PlayerNPC pnpc : playernpcs) {
player.dropMessage(5, ">> " + pnpc.getName() + " - Scriptid: " + pnpc.getScriptId() + " - Oid: " + pnpc.getObjectId());
}
}
if (!npcs.isEmpty()) {
player.yellowMessage("NPCs on this map:");
for (NPC npc : npcs) {
player.dropMessage(5, ">> " + npc.getName() + " - " + npc.getId() + " - Oid: " + npc.getObjectId());
}
}
if (!mobs.isEmpty()) {
player.yellowMessage("Monsters on this map:");
for (Monster mob : mobs) {
if (mob.isAlive()) {
player.dropMessage(5, ">> " + mob.getName() + " - " + mob.getId() + " - Oid: " + mob.getObjectId());
}
}
}
}
}

View File

@@ -0,0 +1,87 @@
/*
This file is part of the HeavenMS MapleStory Server, commands OdinMS-based
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/>.
*/
/*
@Author: Arthur L - Refactored command content into modules
*/
package client.command.commands.gm3;
import client.Character;
import client.Client;
import client.command.Command;
import net.server.Server;
import server.TimerManager;
import tools.DatabaseConnection;
import tools.PacketCreator;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
public class BanCommand extends Command {
{
setDescription("Ban a player.");
}
@Override
public void execute(Client c, String[] params) {
Character player = c.getPlayer();
if (params.length < 2) {
player.yellowMessage("Syntax: !ban <IGN> <Reason> (Please be descriptive)");
return;
}
String ign = params[0];
String reason = joinStringFrom(params, 1);
Character target = c.getChannelServer().getPlayerStorage().getCharacterByName(ign);
if (target != null) {
String readableTargetName = Character.makeMapleReadable(target.getName());
String ip = target.getClient().getRemoteAddress();
//Ban ip
try (Connection con = DatabaseConnection.getConnection()) {
if (ip.matches("/[0-9]{1,3}\\..*")) {
try (PreparedStatement ps = con.prepareStatement("INSERT INTO ipbans VALUES (DEFAULT, ?, ?)")) {
ps.setString(1, ip);
ps.setString(2, String.valueOf(target.getClient().getAccID()));
ps.executeUpdate();
}
}
} catch (SQLException ex) {
ex.printStackTrace();
c.getPlayer().message("Error occured while banning IP address");
c.getPlayer().message(target.getName() + "'s IP was not banned: " + ip);
}
target.getClient().banMacs();
reason = c.getPlayer().getName() + " banned " + readableTargetName + " for " + reason + " (IP: " + ip + ") " + "(MAC: " + c.getMacs() + ")";
target.ban(reason);
target.yellowMessage("You have been banned by #b" + c.getPlayer().getName() + " #k.");
target.yellowMessage("Reason: " + reason);
c.sendPacket(PacketCreator.getGMEffect(4, (byte) 0));
final Character rip = target;
TimerManager.getInstance().schedule(() -> rip.getClient().disconnect(false, false), 5000); //5 Seconds
Server.getInstance().broadcastMessage(c.getWorld(), PacketCreator.serverNotice(6, "[RIP]: " + ign + " has been banned."));
} else if (Character.ban(ign, reason, false)) {
c.sendPacket(PacketCreator.getGMEffect(4, (byte) 0));
Server.getInstance().broadcastMessage(c.getWorld(), PacketCreator.serverNotice(6, "[RIP]: " + ign + " has been banned."));
} else {
c.sendPacket(PacketCreator.getGMEffect(6, (byte) 1));
}
}
}

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