KerningPQ + some boosts on PQ/event scripting

Added cleaner mechanics for dealing with PQs and events (bonus Exp when
clearing a stage, for instance). Reimplemented KerningPQ.
This commit is contained in:
ronancpl
2017-05-05 00:55:36 -03:00
parent 03ab8be97d
commit da00345aec
45 changed files with 1260 additions and 1030 deletions

View File

@@ -151,9 +151,17 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
private static final int[] EXP_RATE_GAIN = {1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144}; //fibonacci :3
private static final String LEVEL_200 = "[Congrats] %s has reached Level 200! Congratulate %s on such an amazing achievement!";
// MapleStory default keyset
private static final int[] DEFAULT_KEY = {18, 65, 2, 23, 3, 4, 5, 6, 16, 17, 19, 25, 26, 27, 31, 34, 35, 37, 38, 40, 43, 44, 45, 46, 50, 56, 59, 60, 61, 62, 63, 64, 57, 48, 29, 7, 24, 33, 41, 39};
private static final int[] DEFAULT_TYPE = {4, 6, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 4, 4, 5, 6, 6, 6, 6, 6, 6, 5, 4, 5, 4, 4, 4, 4, 4};
private static final int[] DEFAULT_ACTION = {0, 106, 10, 1, 12, 13, 18, 24, 8, 5, 4, 19, 14, 15, 2, 17, 11, 3, 20, 16, 9, 50, 51, 6, 7, 53, 100, 101, 102, 103, 104, 105, 54, 22, 52, 21, 25, 26, 23, 27};
// MapleSolaxiaV2 custom keyset
private static final int[] CUSTOM_KEY = {2, 3, 4, 5, 31, 56, 59, 32, 42, 6, 17, 29, 30, 41, 50, 60, 61, 62, 63, 64, 65, 16, 7, 8};
private static final int[] CUSTOM_TYPE = {4, 4, 4, 4, 5, 5, 6, 5, 5, 4, 4, 4, 5, 4, 4, 6, 6, 6, 6, 6, 6, 4, 4, 4};
private static final int[] CUSTOM_ACTION = {1, 0, 3, 2, 53, 54, 100, 52, 51, 19, 5, 9, 50, 7, 22, 101, 102, 103, 104, 105, 106, 8, 17, 26};
private static final String[] BLOCKED_NAMES = {"admin", "owner", "moderator", "intern", "donor", "administrator", "help", "helper", "alert", "notice", "maplestory", "Solaxia", "fuck", "wizet", "fucking", "negro", "fuk", "fuc", "penis", "pussy", "asshole", "gay",
"nigger", "homo", "suck", "cum", "shit", "shitty", "condom", "security", "official", "rape", "nigga", "sex", "tit", "boner", "orgy", "clit", "asshole", "fatass", "bitch", "support", "gamemaster", "cock", "gaay", "gm",
"operate", "master", "sysop", "party", "GameMaster", "community", "message", "event", "test", "meso", "Scania", "renewal", "yata", "AsiaSoft", "henesys"};
@@ -354,9 +362,28 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
ret.getInventory(MapleInventoryType.USE).setSlotLimit(24);
ret.getInventory(MapleInventoryType.SETUP).setSlotLimit(24);
ret.getInventory(MapleInventoryType.ETC).setSlotLimit(24);
for (int i = 0; i < DEFAULT_KEY.length; i++) {
ret.keymap.put(DEFAULT_KEY[i], new MapleKeyBinding(DEFAULT_TYPE[i], DEFAULT_ACTION[i]));
// Select a keybinding method
int[] selectedKey;
int[] selectedType;
int[] selectedAction;
if(ServerConstants.USE_CUSTOM_KEYSET) {
selectedKey = CUSTOM_KEY;
selectedType = CUSTOM_TYPE;
selectedAction = CUSTOM_ACTION;
}
else {
selectedKey = DEFAULT_KEY;
selectedType = DEFAULT_TYPE;
selectedAction = DEFAULT_ACTION;
}
for (int i = 0; i < selectedKey.length; i++) {
ret.keymap.put(selectedKey[i], new MapleKeyBinding(selectedType[i], selectedAction[i]));
}
//to fix the map 0 lol
for (int i = 0; i < 5; i++) {
ret.trockmaps.add(999999999);
@@ -1206,6 +1233,11 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
newWarpMap = -1;
changeMap(temp);
}
// if this event map has a gate already opened, render it
if(getEventInstance() != null) {
getEventInstance().recoverOpenedGate(this, map.getId());
}
}
public void changePage(int page) {
@@ -1714,6 +1746,10 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
this.addFame(delta);
this.updateSingleStat(MapleStat.FAME, this.fame);
}
public void gainMeso(int gain) {
gainMeso(gain, true, false, true);
}
public void gainMeso(int gain, boolean show) {
gainMeso(gain, show, false, false);
@@ -3475,7 +3511,7 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
int lastQuestProcessed = 0;
try {
for (MapleQuestStatus q : quests.values()) {
lastQuestProcessed = q.getQuest().getId();
lastQuestProcessed = q.getQuest().getId();
if (q.getStatus() == MapleQuestStatus.Status.COMPLETED || q.getQuest().canComplete(this, null)) {
continue;
}
@@ -4037,12 +4073,28 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
return false;
}
// Select a keybinding method
int[] selectedKey;
int[] selectedType;
int[] selectedAction;
if(ServerConstants.USE_CUSTOM_KEYSET) {
selectedKey = CUSTOM_KEY;
selectedType = CUSTOM_TYPE;
selectedAction = CUSTOM_ACTION;
}
else {
selectedKey = DEFAULT_KEY;
selectedType = DEFAULT_TYPE;
selectedAction = DEFAULT_ACTION;
}
ps = con.prepareStatement("INSERT INTO keymap (characterid, `key`, `type`, `action`) VALUES (?, ?, ?, ?)");
ps.setInt(1, id);
for (int i = 0; i < DEFAULT_KEY.length; i++) {
ps.setInt(2, DEFAULT_KEY[i]);
ps.setInt(3, DEFAULT_TYPE[i]);
ps.setInt(4, DEFAULT_ACTION[i]);
for (int i = 0; i < selectedKey.length; i++) {
ps.setInt(2, selectedKey[i]);
ps.setInt(3, selectedType[i]);
ps.setInt(4, selectedAction[i]);
ps.execute();
}
ps.close();
@@ -4203,6 +4255,7 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
ps.addBatch();
}
ps.executeBatch();
deleteWhereCharacterId(con, "DELETE FROM skillmacros WHERE characterid = ?");
ps = con.prepareStatement("INSERT INTO skillmacros (characterid, skill1, skill2, skill3, name, shout, position) VALUES (?, ?, ?, ?, ?, ?, ?)");
ps.setInt(1, getId());

View File

@@ -24,6 +24,7 @@ public class ServerConstants {
public static boolean JAVA_8;
public static boolean SHUTDOWNHOOK;
//Gameplay Configurations
public static final boolean USE_CUSTOM_KEYSET = true;
public static final boolean USE_MAXRANGE = true; //will send and receive packets from all events of a map, rather than those of only view range.
public static final boolean USE_DEBUG = true; //will enable some text prints and new commands in the client oriented for debugging.
public static final boolean USE_MTS = false;

View File

@@ -35,28 +35,30 @@ import tools.data.input.SeekableLittleEndianAccessor;
public final class KeymapChangeHandler extends AbstractMaplePacketHandler {
@Override
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
if (slea.available() >= 8) {
if (slea.available() >= 8) {
int mode = slea.readInt();
if(mode == 0) {
int numChanges = slea.readInt();
for (int i = 0; i < numChanges; i++) {
int key = slea.readInt();
int type = slea.readByte();
int action = slea.readInt();
int action = slea.readInt();
Skill skill = SkillFactory.getSkill(action);
boolean isBanndedSkill = false;
if (skill != null) {
isBanndedSkill = GameConstants.bannedBindSkills(skill.getId());
isBanndedSkill = GameConstants.bannedBindSkills(skill.getId());
if (isBanndedSkill || (!c.getPlayer().isGM() && GameConstants.isGMSkills(skill.getId())) || (!GameConstants.isInJobTree(skill.getId(), c.getPlayer().getJob().getId()) && !c.getPlayer().isGM())) { //for those skills are are "technically" in the beginner tab, like bamboo rain in Dojo or skills you find in PYPQ
AutobanFactory.PACKET_EDIT.alert(c.getPlayer(), c.getPlayer().getName() + " tried to packet edit keymapping.");
FilePrinter.printError(FilePrinter.EXPLOITS + c.getPlayer().getName() + ".txt", c.getPlayer().getName() + " tried to use skill " + skill.getId() + "\r\n");
c.disconnect(true, false);
return;
}
if (c.getPlayer().getSkillLevel(skill) < 1) {
continue;
}
/* if (c.getPlayer().getSkillLevel(skill) < 1) { HOW WOULD A SKILL EVEN BE AVAILABLE TO KEYBINDING
continue; IF THERE IS NOT EVEN A SINGLE POINT USED INTO IT??
} */ //Nice to know some skills have the same ids as items, heh.
}
c.getPlayer().changeKeybinding(key, new MapleKeyBinding(type, action));
}
} else if(mode == 1) { // Auto HP Potion

View File

@@ -99,10 +99,10 @@ public final class PartyOperationHandler extends AbstractMaplePacketHandler {
String name = slea.readMapleAsciiString();
MapleCharacter invited = world.getPlayerStorage().getCharacterByName(name);
if (invited != null) {
if(invited.getLevel() < 10) { //min requirement is level 10
c.announce(MaplePacketCreator.serverNotice(5, "The player you have invited does not meet the requirements."));
return;
}
if(invited.getLevel() < 10) { //min requirement is level 10
c.announce(MaplePacketCreator.serverNotice(5, "The player you have invited does not meet the requirements."));
return;
}
if (invited.getParty() == null) {
if (player.getParty() == null) {
partyplayer = new MaplePartyCharacter(player);

View File

@@ -245,8 +245,8 @@ public final class PlayerLoggedinHandler extends AbstractMaplePacketHandler {
player.checkBerserk();
player.expirationTask();
//player.setRates();
if (GameConstants.hasSPTable(player.getJob()) && player.getJob().getId() != 2001) {
player.createDragon();
if (GameConstants.hasSPTable(player.getJob()) && player.getJob().getId() != 2001) {
player.createDragon();
}
if (newcomer){
/*

View File

@@ -59,18 +59,18 @@ public final class QuestActionHandler extends AbstractMaplePacketHandler {
} else if (action == 4) { // scripted start quest
int npc = slea.readInt();
slea.readInt();
if(quest.canStart(player, npc)) {
QuestScriptManager.getInstance().start(c, questid, npc);
}
if(quest.canStart(player, npc)) {
QuestScriptManager.getInstance().start(c, questid, npc);
}
} else if (action == 5) { // scripted end quests
//System.out.println(slea.toString());
int npc = slea.readInt();
slea.readInt();
if(quest.canComplete(player, npc)) {
QuestScriptManager.getInstance().end(c, questid, npc);
player.getClient().getSession().write(MaplePacketCreator.showSpecialEffect(9)); //show effect when completion
player.getMap().broadcastMessage(player, MaplePacketCreator.showForeignEffect(player.getId(), 9));//show effect around players I guess
QuestScriptManager.getInstance().end(c, questid, npc);
player.getClient().getSession().write(MaplePacketCreator.showSpecialEffect(9)); //show effect when completion
player.getMap().broadcastMessage(player, MaplePacketCreator.showForeignEffect(player.getId(), 9));//show effect around players I guess
}
}
}

View File

@@ -32,6 +32,7 @@ import net.server.channel.Channel;
import net.server.guild.MapleGuild;
import net.server.world.MapleParty;
import net.server.world.MaplePartyCharacter;
import scripting.event.EventInstanceManager;
import scripting.event.EventManager;
import scripting.npc.NPCScriptManager;
import server.MapleInventoryManipulator;
@@ -157,24 +158,19 @@ public class AbstractPlayerInteraction {
return getClient().getEventManager(event);
}
public void clearPQ(int toMap) {
clearPQ(getWarpMap(toMap));
}
public EventInstanceManager getEventInstance() {
return getPlayer().getEventInstance();
}
public void clearPQ(MapleMap toMap) {
if(getPlayer().getEventInstance() != null)
getPlayer().getEventInstance().getEm().clearPQ(getPlayer().getEventInstance(), toMap);
}
public MapleInventory getInventory(MapleInventoryType type) {
return getPlayer().getInventory(type);
}
public boolean hasItem(int itemid){
public boolean hasItem(int itemid) {
return haveItem(itemid, 1);
}
public boolean hasItem(int itemid, int quantity){
public boolean hasItem(int itemid, int quantity) {
return haveItem(itemid, quantity);
}

View File

@@ -25,10 +25,12 @@ import java.io.File;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.HashMap;
import java.util.Map;
import java.util.HashSet;
import java.util.Set;
import java.util.Properties;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock;
@@ -39,6 +41,7 @@ import javax.script.ScriptException;
import net.server.world.MapleParty;
import net.server.world.MaplePartyCharacter;
import provider.MapleDataProviderFactory;
import server.MaplePortal;
import server.TimerManager;
import server.expeditions.MapleExpedition;
import server.life.MapleMonster;
@@ -52,6 +55,7 @@ import java.util.concurrent.ScheduledFuture;
import java.util.logging.Level;
import java.util.logging.Logger;
import scripting.AbstractPlayerInteraction;
import tools.MaplePacketCreator;
/**
*
@@ -75,12 +79,23 @@ public class EventInstanceManager {
private final WriteLock wL = mutex.writeLock();
private ScheduledFuture<?> event_schedule = null;
private boolean disposed = false;
private boolean eventCleared = false;
// multi-leveled PQ rewards!
private Map<Integer, List<Integer>> collectionSet = new HashMap<>(ServerConstants.MAX_EVENT_LEVELS);
private Map<Integer, List<Integer>> collectionQty = new HashMap<>(ServerConstants.MAX_EVENT_LEVELS);
private Map<Integer, Integer> collectionExp = new HashMap<>(ServerConstants.MAX_EVENT_LEVELS);
// Exp/Meso rewards by CLEAR on a stage
private List<Integer> onMapClearExp = new ArrayList<>();
private List<Integer> onMapClearMeso = new ArrayList<>();
// registers player status on an event (null on this Map structure equals to 0)
private Map<Integer, Integer> playerGrid = new HashMap<>();
// registers all opened gates on the event. Will help late characters to encounter next stages gates already opened
private Set<Integer> openedGates = new HashSet<>();
public EventInstanceManager(EventManager em, String name) {
this.em = em;
this.name = name;
@@ -97,6 +112,8 @@ public class EventInstanceManager {
}
public void giveEventPlayersExp(int gain, int mapId) {
if(gain == 0) return;
rL.lock();
try {
if(mapId == -1) {
@@ -113,6 +130,30 @@ public class EventInstanceManager {
rL.unlock();
}
}
public void giveEventPlayersMeso(int gain) {
giveEventPlayersMeso(gain, -1);
}
public void giveEventPlayersMeso(int gain, int mapId) {
if(gain == 0) return;
rL.lock();
try {
if(mapId == -1) {
for(MapleCharacter mc: chars) {
mc.gainMeso(gain * mc.getMesoRate());
}
}
else {
for(MapleCharacter mc: chars) {
if(mc.getMapId() == mapId) mc.gainMeso(gain * mc.getMesoRate());
}
}
} finally {
rL.unlock();
}
}
public void registerPlayer(MapleCharacter chr) {
if (chr == null || !chr.isLoggedin()){
@@ -186,12 +227,19 @@ public class EventInstanceManager {
}
}
public void cancelEventTimer() {
if(event_schedule != null) event_schedule.cancel(false);
public void stopEventTimer() {
if(event_schedule != null) {
event_schedule.cancel(false);
event_schedule = null;
}
dismissEventTimer();
}
private void dismissEventTimer() {
for(MapleCharacter chr: getPlayers()) {
chr.getClient().getSession().write(MaplePacketCreator.removeClock());
}
event_schedule = null;
eventTime = 0;
timeStarted = 0;
@@ -220,9 +268,10 @@ public class EventInstanceManager {
public void unregisterPlayer(MapleCharacter chr) {
wL.lock();
try {
chars.remove(chr);
chars.remove(chr);
gridRemove(chr);
} finally {
wL.unlock();
wL.unlock();
}
chr.setEventInstance(null);
@@ -231,20 +280,20 @@ public class EventInstanceManager {
public int getPlayerCount() {
rL.lock();
try {
return chars.size();
return chars.size();
}
finally {
rL.unlock();
rL.unlock();
}
}
public List<MapleCharacter> getPlayers() {
rL.lock();
try {
return new ArrayList<>(chars);
return new ArrayList<>(chars);
}
finally {
rL.unlock();
rL.unlock();
}
}
@@ -340,37 +389,40 @@ public class EventInstanceManager {
public int getKillCount(MapleCharacter chr) {
Integer kc = killCount.get(chr);
if (kc == null) {
return 0;
} else {
return kc;
}
return (kc == null) ? 0 : kc;
}
public void cancelSchedule() {
if(event_schedule != null) {
event_schedule.cancel(false);
event_schedule = null;
}
}
public void dispose() {
try {
em.getIv().invokeFunction("dispose", this);
} catch (ScriptException | NoSuchMethodException ex) {
ex.printStackTrace();
}
try {
em.getIv().invokeFunction("dispose", this);
} catch (ScriptException | NoSuchMethodException ex) {
ex.printStackTrace();
}
wL.lock();
try {
chars.clear();
} finally {
wL.unlock();
}
if(event_schedule != null) event_schedule.cancel(false);
wL.lock();
try {
chars.clear();
} finally {
wL.unlock();
}
cancelSchedule();
mobs.clear();
killCount.clear();
mapFactory = null;
if (expedition != null) {
em.getChannelServer().getExpeditions().remove(expedition);
}
em.disposeInstance(name);
em = null;
mobs.clear();
killCount.clear();
mapFactory = null;
if (expedition != null) {
em.getChannelServer().getExpeditions().remove(expedition);
}
em.disposeInstance(name);
em = null;
}
public MapleMapFactory getMapFactory() {
@@ -381,6 +433,8 @@ public class EventInstanceManager {
TimerManager.getInstance().schedule(new Runnable() {
@Override
public void run() {
if(em == null) return;
try {
em.getIv().invokeFunction(methodName, EventInstanceManager.this);
} catch (ScriptException | NoSuchMethodException ex) {
@@ -431,8 +485,8 @@ public class EventInstanceManager {
return props.getProperty(key);
}
public Properties getProperties(){
return props;
public Properties getProperties() {
return props;
}
public void leftParty(MapleCharacter chr) {
@@ -451,7 +505,7 @@ public class EventInstanceManager {
}
}
public void finishPQ() {
public void clearPQ() {
try {
em.getIv().invokeFunction("clearPQ", this);
} catch (ScriptException | NoSuchMethodException ex) {
@@ -472,149 +526,315 @@ public class EventInstanceManager {
}
public final MapleMap setInstanceMap(final int mapid) { //gets instance map from the channelserv
if (disposed) {
if (disposed) {
return this.getMapFactory().getMap(mapid);
}
mapIds.add(mapid);
isInstanced.add(false);
return this.getMapFactory().getMap(mapid);
}
mapIds.add(mapid);
isInstanced.add(false);
return this.getMapFactory().getMap(mapid);
}
public final boolean disposeIfPlayerBelow(final byte size, final int towarp) {
if (disposed) {
return true;
}
MapleMap map = null;
if (towarp > 0) {
map = this.getMapFactory().getMap(towarp);
}
rL.lock();
try {
if (chars != null && chars.size() < size) {
for (MapleCharacter chr : chars) {
if (chr == null) {
continue;
}
unregisterPlayer(chr);
if (towarp > 0) {
chr.changeMap(map, map.getPortal(0));
}
}
dispose();
return true;
if (disposed) {
return true;
}
} catch (Exception ex) {
ex.printStackTrace();
} finally {
rL.unlock();
}
return false;
MapleMap map = null;
if (towarp > 0) {
map = this.getMapFactory().getMap(towarp);
}
rL.lock();
try {
if (chars != null && chars.size() < size) {
for (MapleCharacter chr : chars) {
if (chr == null) {
continue;
}
unregisterPlayer(chr);
if (towarp > 0) {
chr.changeMap(map, map.getPortal(0));
}
}
dispose();
return true;
}
} catch (Exception ex) {
ex.printStackTrace();
} finally {
rL.unlock();
}
return false;
}
private List<Integer> convertToIntegerArray(List<Double> list) {
List<Integer> intList = new ArrayList<>();
for(Double d: list) intList.add(d.intValue());
return intList;
List<Integer> intList = new ArrayList<>();
for(Double d: list) intList.add(d.intValue());
return intList;
}
public void setEventClearStageExp(List<Double> gain) {
onMapClearExp.clear();
onMapClearExp.addAll(convertToIntegerArray(gain));
}
public void setEventClearStageMeso(List<Double> gain) {
onMapClearMeso.clear();
onMapClearMeso.addAll(convertToIntegerArray(gain));
}
public Integer getClearStageExp(int stage) { //stage counts from ONE.
if(stage > onMapClearExp.size()) return 0;
return onMapClearExp.get(stage - 1);
}
public Integer getClearStageMeso(int stage) { //stage counts from ONE.
if(stage > onMapClearMeso.size()) return 0;
return onMapClearMeso.get(stage - 1);
}
public List<Integer> getClearStageBonus(int stage) {
List<Integer> list = new ArrayList<>();
list.add(getClearStageExp(stage));
list.add(getClearStageMeso(stage));
return list;
}
public final void setEventRewards(List<Double> rwds, List<Double> qtys, int expGiven) {
setEventRewards(1, rwds, qtys, expGiven);
setEventRewards(1, rwds, qtys, expGiven);
}
public final void setEventRewards(List<Double> rwds, List<Double> qtys) {
setEventRewards(1, rwds, qtys);
setEventRewards(1, rwds, qtys);
}
public final void setEventRewards(int eventLevel, List<Double> rwds, List<Double> qtys) {
setEventRewards(eventLevel, rwds, qtys, 0);
setEventRewards(eventLevel, rwds, qtys, 0);
}
public final void setEventRewards(int eventLevel, List<Double> rwds, List<Double> qtys, int expGiven) {
// fixed EXP will be rewarded at the same time the random item is given
if(eventLevel <= 0 || eventLevel > ServerConstants.MAX_EVENT_LEVELS) return;
eventLevel--; //event level starts from 1
List<Integer> rewardIds = convertToIntegerArray(rwds);
List<Integer> rewardQtys = convertToIntegerArray(qtys);
//rewardsSet and rewardsQty hold temporary values
collectionSet.put(eventLevel, rewardIds);
collectionQty.put(eventLevel, rewardQtys);
collectionExp.put(eventLevel, expGiven);
// fixed EXP will be rewarded at the same time the random item is given
if(eventLevel <= 0 || eventLevel > ServerConstants.MAX_EVENT_LEVELS) return;
eventLevel--; //event level starts from 1
List<Integer> rewardIds = convertToIntegerArray(rwds);
List<Integer> rewardQtys = convertToIntegerArray(qtys);
//rewardsSet and rewardsQty hold temporary values
wL.lock();
try {
collectionSet.put(eventLevel, rewardIds);
collectionQty.put(eventLevel, rewardQtys);
collectionExp.put(eventLevel, expGiven);
} finally {
wL.unlock();
}
}
private byte getRewardListRequirements(int level) {
if(level >= collectionSet.size()) return 0;
byte rewardTypes = 0;
List<Integer> list = collectionSet.get(level);
for (Integer itemId : list) {
rewardTypes |= (1 << ItemConstants.getInventoryType(itemId).getType());
}
return rewardTypes;
if(level >= collectionSet.size()) return 0;
byte rewardTypes = 0;
List<Integer> list = collectionSet.get(level);
for (Integer itemId : list) {
rewardTypes |= (1 << ItemConstants.getInventoryType(itemId).getType());
}
return rewardTypes;
}
private boolean hasRewardSlot(MapleCharacter player, int eventLevel) {
byte listReq = getRewardListRequirements(eventLevel); //gets all types of items present in the event reward list
//iterating over all valid inventory types
for(byte type = 1; type <= 5; type++) {
if((listReq >> type) % 2 == 1 && !player.hasEmptySlot(type))
return false;
}
return true;
byte listReq = getRewardListRequirements(eventLevel); //gets all types of items present in the event reward list
//iterating over all valid inventory types
for(byte type = 1; type <= 5; type++) {
if((listReq >> type) % 2 == 1 && !player.hasEmptySlot(type))
return false;
}
return true;
}
public final boolean giveEventReward(MapleCharacter player) {
return giveEventReward(player, 1);
return giveEventReward(player, 1);
}
//gives out EXP & a random item in a similar fashion of when clearing KPQ, LPQ, etc.
public final boolean giveEventReward(MapleCharacter player, int eventLevel) {
eventLevel--; //event level starts counting from 1
if(eventLevel >= collectionSet.size()) return true;
List<Integer> rewardsSet = collectionSet.get(eventLevel);
List<Integer> rewardsQty = collectionQty.get(eventLevel);
Integer rewardExp = collectionExp.get(eventLevel);
if(rewardExp == null) rewardExp = 0;
if(rewardsSet == null || rewardsSet.isEmpty()) {
if(rewardExp > 0) player.gainExp(rewardExp);
return true;
}
if(!hasRewardSlot(player, eventLevel)) return false;
rL.lock();
try {
eventLevel--; //event level starts counting from 1
if(eventLevel >= collectionSet.size()) return true;
AbstractPlayerInteraction api = new AbstractPlayerInteraction(player.getClient());
int rnd = (int)Math.floor(Math.random() * rewardsSet.size());
api.gainItem(rewardsSet.get(rnd), rewardsQty.get(rnd).shortValue());
if(rewardExp > 0) player.gainExp(rewardExp);
return true;
List<Integer> rewardsSet = collectionSet.get(eventLevel);
List<Integer> rewardsQty = collectionQty.get(eventLevel);
Integer rewardExp = collectionExp.get(eventLevel);
if(rewardExp == null) rewardExp = 0;
if(rewardsSet == null || rewardsSet.isEmpty()) {
if(rewardExp > 0) player.gainExp(rewardExp);
return true;
}
if(!hasRewardSlot(player, eventLevel)) return false;
AbstractPlayerInteraction api = new AbstractPlayerInteraction(player.getClient());
int rnd = (int)Math.floor(Math.random() * rewardsSet.size());
api.gainItem(rewardsSet.get(rnd), rewardsQty.get(rnd).shortValue());
if(rewardExp > 0) player.gainExp(rewardExp);
return true;
} finally {
rL.unlock();
}
}
public final void setEventCleared() {
eventCleared = true;
}
public final boolean isEventTeamLackingNow(boolean testLeader, int minPlayers, MapleCharacter quitter) {
if(eventCleared && getPlayerCount() > 1) return false;
if(!eventCleared && testLeader && getLeader().getId() == quitter.getId()) return true;
if(getPlayerCount() <= minPlayers) return true;
return false;
}
public final boolean isEventTeamTogether() {
if(chars.size() <= 1) return true;
int mapId = chars.get(0).getMapId();
for(int i = 1; i < chars.size(); i++) {
if(chars.get(i).getMapId() != mapId) return false;
}
return true;
rL.lock();
try {
if(chars.size() <= 1) return true;
int mapId = chars.get(0).getMapId();
for(int i = 1; i < chars.size(); i++) {
if(chars.get(i).getMapId() != mapId) return false;
}
return true;
} finally {
rL.unlock();
}
}
public final void warpEventTeam(int warpTo) {
for (MapleCharacter chr : chars) {
chr.changeMap(warpTo);
}
rL.lock();
try {
for (MapleCharacter chr : chars) {
chr.changeMap(warpTo);
}
} finally {
rL.unlock();
}
}
public final MapleCharacter getLeader() {
rL.lock();
try {
for (MapleCharacter chr : chars) {
if(chr.isPartyLeader()) return chr;
}
return null;
} finally {
rL.unlock();
}
}
public final void showWrongEffect() {
MapleMap map = getMapInstance(getLeader().getMapId());
map.broadcastMessage(MaplePacketCreator.showEffect("quest/party/wrong_kor"));
map.broadcastMessage(MaplePacketCreator.playSound("Party1/Failed"));
}
public final void showClearEffect() {
showClearEffect(false);
}
public final void showClearEffect(boolean hasGate) {
MapleMap map = getMapInstance(getLeader().getMapId());
map.broadcastMessage(MaplePacketCreator.showEffect("quest/party/clear"));
map.broadcastMessage(MaplePacketCreator.playSound("Party1/Clear"));
if(hasGate) {
map.broadcastMessage(MaplePacketCreator.environmentChange("gate", 2));
wL.lock();
try {
openedGates.add(map.getId());
} finally {
wL.unlock();
}
}
}
public final void recoverOpenedGate(MapleCharacter chr, int thisMapId) {
rL.lock();
try {
if(openedGates.contains(thisMapId)) {
chr.announce(MaplePacketCreator.environmentChange("gate", 2));
}
} finally {
rL.unlock();
}
}
public final void linkToNextStage(int thisStage, String eventFamily, int thisMapId) {
List<Integer> list = getClearStageBonus(thisStage); // will give bonus exp & mesos to everyone in the event
giveEventPlayersExp(list.get(0));
giveEventPlayersMeso(list.get(1));
thisStage--; //stages counts from ONE, scripts from ZERO
MapleMap nextStage = getMapInstance(thisMapId);
MaplePortal portal = nextStage.getPortal("next00");
if (portal != null) {
portal.setScriptName(eventFamily + thisStage);
}
}
// registers a player status in an event
public final void gridInsert(MapleCharacter chr, int newStatus) {
wL.lock();
try {
playerGrid.put(chr.getId(), newStatus);
} finally {
wL.unlock();
}
}
// unregisters a player status in an event
public final void gridRemove(MapleCharacter chr) {
wL.lock();
try {
playerGrid.remove(chr.getId());
} finally {
wL.unlock();
}
}
// checks a player status
public final int gridCheck(MapleCharacter chr) {
rL.lock();
try {
Integer i = playerGrid.get(chr.getId());
return (i != null) ? i : -1;
} finally {
rL.unlock();
}
}
public final void gridClear() {
wL.lock();
try {
playerGrid.clear();
} finally {
wL.unlock();
}
}
}

View File

@@ -154,56 +154,76 @@ public class EventManager {
}
//Expedition method: starts an expedition
public void startInstance(MapleExpedition exped) {
public boolean startInstance(MapleExpedition exped) {
try {
EventInstanceManager eim = (EventInstanceManager) (iv.invokeFunction("setup", (Object) null));
if(eim == null) return false;
eim.registerExpedition(exped);
exped.start();
} catch (ScriptException | NoSuchMethodException ex) {
Logger.getLogger(EventManager.class.getName()).log(Level.SEVERE, null, ex);
}
return true;
}
//Regular method: player
public void startInstance(MapleCharacter chr) {
public boolean startInstance(MapleCharacter chr) {
try {
EventInstanceManager eim = (EventInstanceManager) (iv.invokeFunction("setup", (Object) null));
if(eim == null) return false;
eim.registerPlayer(chr);
} catch (ScriptException | NoSuchMethodException ex) {
Logger.getLogger(EventManager.class.getName()).log(Level.SEVERE, null, ex);
}
return true;
}
//PQ method: starts a PQ
public void startInstance(MapleParty party, MapleMap map) {
public boolean startInstance(MapleParty party, MapleMap map) {
try {
EventInstanceManager eim = (EventInstanceManager) (iv.invokeFunction("setup", (Object) null));
if(eim == null) return false;
eim.registerParty(party, map);
party.setEligibleMembers(null);
} catch (ScriptException | NoSuchMethodException ex) {
Logger.getLogger(EventManager.class.getName()).log(Level.SEVERE, null, ex);
}
return true;
}
//PQ method: starts a PQ with a difficulty level, requires function setup(difficulty, leaderid) instead of setup()
public void startInstance(MapleParty party, MapleMap map, int difficulty) {
public boolean startInstance(MapleParty party, MapleMap map, int difficulty) {
try {
EventInstanceManager eim = (EventInstanceManager) (iv.invokeFunction("setup", difficulty, party.getLeader().getId()));
if(eim == null) return false;
eim.registerParty(party, map);
party.setEligibleMembers(null);
} catch (ScriptException | NoSuchMethodException ex) {
Logger.getLogger(EventManager.class.getName()).log(Level.SEVERE, null, ex);
}
return true;
}
//non-PQ method for starting instance
public void startInstance(EventInstanceManager eim, String leader) {
public boolean startInstance(EventInstanceManager eim, String leader) {
try {
if(eim == null) return false;
iv.invokeFunction("setup", eim);
eim.setProperty("leader", leader);
} catch (ScriptException | NoSuchMethodException ex) {
Logger.getLogger(EventManager.class.getName()).log(Level.SEVERE, null, ex);
}
return true;
}
public List<MaplePartyCharacter> getEligibleParty(MapleParty party) {
@@ -225,6 +245,14 @@ public class EventManager {
return(new ArrayList<>());
}
public void clearPQ(EventInstanceManager eim) {
try {
iv.invokeFunction("clearPQ", eim);
} catch (ScriptException | NoSuchMethodException ex) {
Logger.getLogger(EventManager.class.getName()).log(Level.SEVERE, null, ex);
}
}
public void clearPQ(EventInstanceManager eim, MapleMap toMap) {
try {
iv.invokeFunction("clearPQ", eim, toMap);

View File

@@ -227,7 +227,7 @@ public class NPCConversationManager extends AbstractPlayerInteraction {
if (gain > 0 && ServerConstants.USE_AUTOBAN == true) {
FilePrinter.printError(FilePrinter.EXPLOITS + c.getPlayer().getName() + ".txt", c.getPlayer().getName() + " gained " + gain + " mesos from NPC " + npc + "\r\n");
}
getPlayer().gainMeso(gain, true, false, true);
getPlayer().gainMeso(gain);
}
public void gainExp(int gain) {

View File

@@ -90,8 +90,8 @@ public class MapleQuest {
MapleQuestRequirement req = this.getRequirement(type, startReq);
if(req == null)
continue;
if(req == null)
continue;
if (type.equals(MapleQuestRequirementType.MOB)) {
for (MapleData mob : startReq.getChildren()) {
@@ -161,15 +161,46 @@ public class MapleQuest {
public static MapleQuest getInstance(int id) {
MapleQuest ret = quests.get(id);
if (ret == null) {
questInfo = questData.getData("QuestInfo.img");
questReq = questData.getData("Check.img");
questAct = questData.getData("Act.img");
questInfo = questData.getData("QuestInfo.img");
questReq = questData.getData("Check.img");
questAct = questData.getData("Act.img");
ret = new MapleQuest(id);
quests.put(id, ret);
}
return ret;
}
private String getIntervalTimeLeft(MapleCharacter c, IntervalRequirement r) {
StringBuilder str = new StringBuilder();
long futureTime = c.getQuest(MapleQuest.getInstance(getId())).getCompletionTime() + r.getInterval();
long leftTime = futureTime - System.currentTimeMillis();
byte mode = 0;
if(leftTime / (60*1000) > 0) {
mode++; //counts minutes
if(leftTime / (60*60*1000) > 0)
mode++; //counts hours
}
switch(mode) {
case 2:
int hours = (int) ((leftTime / (1000*60*60)));
str.append(hours + " hours, ");
case 1:
int minutes = (int) ((leftTime / (1000*60)) % 60);
str.append(minutes + " minutes, ");
default:
int seconds = (int) (leftTime / 1000) % 60 ;
str.append(seconds + " seconds");
}
return str.toString();
}
public boolean canStart(MapleCharacter c, int npcid) {
if (c.getQuest(this).getStatus() != Status.NOT_STARTED && !(c.getQuest(this).getStatus() == Status.COMPLETED && repeatable)) {
@@ -177,6 +208,9 @@ public class MapleQuest {
}
for (MapleQuestRequirement r : startReqs.values()) {
if (!r.check(c, npcid)) {
if(r.getType().getType() == MapleQuestRequirementType.INTERVAL.getType()) {
c.message("This quest will become available again in approximately " + getIntervalTimeLeft(c, (IntervalRequirement)r) + ".");
}
return false;
}
}
@@ -198,9 +232,9 @@ public class MapleQuest {
public void start(MapleCharacter c, int npc) {
if (autoStart || canStart(c, npc)) {
for (MapleQuestAction a : startActs.values()) {
if (!a.check(c, null)) { // would null be good ?
return;
}
if (!a.check(c, null)) { // would null be good ?
return;
}
a.run(c, null);
}
forceStart(c, npc);
@@ -212,20 +246,20 @@ public class MapleQuest {
}
public void complete(MapleCharacter c, int npc, Integer selection) {
if (autoPreComplete || canComplete(c, npc)) {
for (MapleQuestAction a : completeActs.values()) {
if (!a.check(c, selection)) {
return;
}
}
forceComplete(c, npc);
for (MapleQuestAction a : completeActs.values()) {
a.run(c, selection);
}
c.getClient().getSession().write(MaplePacketCreator.showSpecialEffect(9)); // Quest completion
c.getMap().broadcastMessage(c, MaplePacketCreator.showForeignEffect(c.getId(), 9), false); //use 9 instead of 12 for both
}
if (autoPreComplete || canComplete(c, npc)) {
for (MapleQuestAction a : completeActs.values()) {
if (!a.check(c, selection)) {
return;
}
}
forceComplete(c, npc);
for (MapleQuestAction a : completeActs.values()) {
a.run(c, selection);
}
c.getClient().getSession().write(MaplePacketCreator.showSpecialEffect(9)); // Quest completion
c.getMap().broadcastMessage(c, MaplePacketCreator.showForeignEffect(c.getId(), 9), false); //use 9 instead of 12 for both
}
}
public void reset(MapleCharacter c) {
@@ -314,9 +348,9 @@ public class MapleQuest {
return ret;
}
public int getTimeLimit() {
return timeLimit;
}
public int getTimeLimit() {
return timeLimit;
}
public static void clearCache(int quest) {
if(quests.containsKey(quest)){

View File

@@ -42,6 +42,9 @@ public class IntervalRequirement extends MapleQuestRequirement {
questID = quest.getId();
}
public int getInterval() {
return interval;
}
@Override
public void processData(MapleData data) {

View File

@@ -51,6 +51,6 @@ public abstract class MapleQuestRequirement {
public abstract void processData(MapleData data);
public MapleQuestRequirementType getType() {
return type;
}
return type;
}
}

View File

@@ -2508,6 +2508,7 @@ public class MaplePacketCreator {
* @param progress
* @return
*/
public static byte[] updateQuestInfo(short quest, int npc) {
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
mplew.writeShort(SendOpcode.UPDATE_QUEST_INFO.getValue());