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

@@ -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();
}
}
}