Switch to Maven file structure

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

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,80 @@
/*
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 scripting;
import client.MapleClient;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import javax.script.*;
import constants.net.ServerConstants;
import jdk.nashorn.api.scripting.NashornScriptEngine;
import tools.FilePrinter;
/**
*
* @author Matze
*/
public abstract class AbstractScriptManager {
private ScriptEngineFactory sef;
protected AbstractScriptManager() {
sef = new ScriptEngineManager().getEngineByName("javascript").getFactory();
}
protected NashornScriptEngine getScriptEngine(String path) {
path = "scripts/" + path;
File scriptFile = new File(path);
if (!scriptFile.exists()) {
return null;
}
NashornScriptEngine engine = (NashornScriptEngine) sef.getScriptEngine();
try (FileReader fr = new FileReader(scriptFile)) {
if (ServerConstants.JAVA_8){
engine.eval("load('nashorn:mozilla_compat.js');" + System.lineSeparator());
}
engine.eval(fr);
} catch (final ScriptException | IOException t) {
FilePrinter.printError(FilePrinter.INVOCABLE + path.substring(12), t, path);
return null;
}
return engine;
}
protected NashornScriptEngine getScriptEngine(String path, MapleClient c) {
NashornScriptEngine engine = c.getScriptEngine("scripts/" + path);
if (engine == null) {
engine = getScriptEngine(path);
c.setScriptEngine(path, engine);
}
return engine;
}
protected void resetContext(String path, MapleClient c) {
c.removeScriptEngine("scripts/" + path);
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,984 @@
/*
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 scripting.event;
import config.YamlConfig;
import jdk.nashorn.api.scripting.ScriptObjectMirror;
import jdk.nashorn.api.scripting.ScriptUtils;
import tools.exceptions.EventInstanceInProgressException;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.script.ScriptException;
import constants.net.ServerConstants;
import constants.game.GameConstants;
import client.MapleCharacter;
import net.server.Server;
import net.server.world.World;
import net.server.channel.Channel;
import net.server.guild.MapleGuild;
import net.server.world.MapleParty;
import net.server.world.MaplePartyCharacter;
import scripting.event.scheduler.EventScriptScheduler;
import server.MapleMarriage;
import server.expeditions.MapleExpedition;
import server.maps.MapleMap;
import server.life.MapleMonster;
import server.life.MapleLifeFactory;
import server.quest.MapleQuest;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
import java.util.Set;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
import jdk.nashorn.api.scripting.NashornScriptEngine;
import net.server.audit.LockCollector;
import net.server.audit.locks.MonitoredLockType;
import net.server.audit.locks.MonitoredReentrantLock;
import net.server.audit.locks.factory.MonitoredReentrantLockFactory;
import server.ThreadManager;
//import jdk.nashorn.api.scripting.ScriptUtils;
/**
*
* @author Matze
* @author Ronan
*/
public class EventManager {
private NashornScriptEngine iv;
private Channel cserv;
private World wserv;
private Server server;
private EventScriptScheduler ess = new EventScriptScheduler();
private Map<String, EventInstanceManager> instances = new HashMap<String, EventInstanceManager>();
private Map<String, Integer> instanceLocks = new HashMap<String, Integer>();
private final Queue<Integer> queuedGuilds = new LinkedList<>();
private final Map<Integer, Integer> queuedGuildLeaders = new HashMap<>();
private List<Boolean> openedLobbys;
private List<EventInstanceManager> readyInstances = new LinkedList<>();
private Integer readyId = 0, onLoadInstances = 0;
private Properties props = new Properties();
private String name;
private MonitoredReentrantLock lobbyLock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.EM_LOBBY);
private MonitoredReentrantLock queueLock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.EM_QUEUE);
private MonitoredReentrantLock startLock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.EM_START);
private Set<Integer> playerPermit = new HashSet<>();
private Semaphore startSemaphore = new Semaphore(7);
private static final int maxLobbys = 8; // an event manager holds up to this amount of concurrent lobbys
public EventManager(Channel cserv, NashornScriptEngine iv, String name) {
this.server = Server.getInstance();
this.iv = iv;
this.cserv = cserv;
this.wserv = server.getWorld(cserv.getWorld());
this.name = name;
this.openedLobbys = new ArrayList<>();
for(int i = 0; i < maxLobbys; i++) this.openedLobbys.add(false);
}
private boolean isDisposed() {
return onLoadInstances <= -1000;
}
public void cancel() { // make sure to only call this when there are NO PLAYERS ONLINE to mess around with the event manager!
ess.dispose();
try {
iv.invokeFunction("cancelSchedule", (Object) null);
} catch (ScriptException | NoSuchMethodException ex) {
ex.printStackTrace();
}
Collection<EventInstanceManager> eimList;
synchronized(instances) {
eimList = getInstances();
instances.clear();
}
for(EventInstanceManager eim : eimList) {
eim.dispose(true);
}
List<EventInstanceManager> readyEims;
queueLock.lock();
try {
readyEims = new ArrayList<>(readyInstances);
readyInstances.clear();
onLoadInstances = Integer.MIN_VALUE / 2;
} finally {
queueLock.unlock();
}
for(EventInstanceManager eim : readyEims) {
eim.dispose(true);
}
props.clear();
cserv = null;
wserv = null;
server = null;
iv = null;
disposeLocks();
}
private void disposeLocks() {
LockCollector.getInstance().registerDisposeAction(new Runnable() {
@Override
public void run() {
emptyLocks();
}
});
}
private void emptyLocks() {
lobbyLock = lobbyLock.dispose();
queueLock = queueLock.dispose();
startLock = startLock.dispose();
}
private List<Integer> convertToIntegerArray(List<Object> list) {
List<Integer> intList = new ArrayList<>();
if (ServerConstants.JAVA_8) {
for (Object d: list) {
intList.add(((Integer) d).intValue());
}
} else {
for (Object d: list) {
intList.add(((Double) d).intValue());
}
}
return intList;
}
public long getLobbyDelay() {
return YamlConfig.config.server.EVENT_LOBBY_DELAY;
}
private List<Integer> getLobbyRange() {
try {
if (!ServerConstants.JAVA_8) {
return convertToIntegerArray((List<Object>)iv.invokeFunction("setLobbyRange", (Object) null));
} else { // java 8 support here thanks to MedicOP
ScriptObjectMirror object = (ScriptObjectMirror) iv.invokeFunction("setLobbyRange", (Object) null);
int[] to = object.to(int[].class);
List<Integer> list = new ArrayList<>();
for (int i : to) {
list.add(i);
}
return list;
}
} catch (ScriptException | NoSuchMethodException ex) { // they didn't define a lobby range
List<Integer> defaultRange = new ArrayList<>();
defaultRange.add(0);
defaultRange.add(maxLobbys);
return defaultRange;
}
}
public EventScheduledFuture schedule(String methodName, long delay) {
return schedule(methodName, null, delay);
}
public EventScheduledFuture schedule(final String methodName, final EventInstanceManager eim, long delay) {
Runnable r = new Runnable() {
@Override
public void run() {
try {
iv.invokeFunction(methodName, eim);
} catch (ScriptException | NoSuchMethodException ex) {
Logger.getLogger(EventManager.class.getName()).log(Level.SEVERE, null, ex);
}
}
};
ess.registerEntry(r, delay);
// hate to do that, but those schedules can still be cancelled, so well... Let GC do it's job
return new EventScheduledFuture(r, ess);
}
public EventScheduledFuture scheduleAtTimestamp(final String methodName, long timestamp) {
Runnable r = new Runnable() {
@Override
public void run() {
try {
iv.invokeFunction(methodName, (Object) null);
} catch (ScriptException | NoSuchMethodException ex) {
Logger.getLogger(EventManager.class.getName()).log(Level.SEVERE, null, ex);
}
}
};
ess.registerEntry(r, timestamp - server.getCurrentTime());
return new EventScheduledFuture(r, ess);
}
public World getWorldServer() {
return wserv;
}
public Channel getChannelServer() {
return cserv;
}
public NashornScriptEngine getIv() {
return iv;
}
public EventInstanceManager getInstance(String name) {
return instances.get(name);
}
public Collection<EventInstanceManager> getInstances() {
synchronized (instances) {
return new LinkedList<>(instances.values());
}
}
public EventInstanceManager newInstance(String name) throws EventInstanceInProgressException {
EventInstanceManager ret = getReadyInstance();
if(ret == null) {
ret = new EventInstanceManager(this, name);
} else {
ret.setName(name);
}
synchronized (instances) {
if (instances.containsKey(name)) {
throw new EventInstanceInProgressException(name, this.getName());
}
instances.put(name, ret);
}
return ret;
}
public MapleMarriage newMarriage(String name) throws EventInstanceInProgressException {
MapleMarriage ret = new MapleMarriage(this, name);
synchronized (instances) {
if (instances.containsKey(name)) {
throw new EventInstanceInProgressException(name, this.getName());
}
instances.put(name, ret);
}
return ret;
}
public void disposeInstance(final String name) {
ess.registerEntry(new Runnable() {
@Override
public void run() {
freeLobbyInstance(name);
synchronized (instances) {
instances.remove(name);
}
}
}, YamlConfig.config.server.EVENT_LOBBY_DELAY * 1000);
}
public void setProperty(String key, String value) {
props.setProperty(key, value);
}
public void setIntProperty(String key, int value) {
setProperty(key, value);
}
public void setProperty(String key, int value) {
props.setProperty(key, value + "");
}
public String getProperty(String key) {
return props.getProperty(key);
}
public int getIntProperty(String key) {
return Integer.parseInt(props.getProperty(key));
}
private void setLockLobby(int lobbyId, boolean lock) {
lobbyLock.lock();
try {
openedLobbys.set(lobbyId, lock);
} finally {
lobbyLock.unlock();
}
}
private boolean startLobbyInstance(int lobbyId) {
lobbyLock.lock();
try {
if (lobbyId < 0) {
lobbyId = 0;
} else if (lobbyId >= maxLobbys) {
lobbyId = maxLobbys - 1;
}
if(!openedLobbys.get(lobbyId)) {
openedLobbys.set(lobbyId, true);
return true;
}
return false;
} finally {
lobbyLock.unlock();
}
}
private void freeLobbyInstance(String lobbyName) {
Integer i = instanceLocks.get(lobbyName);
if(i == null) return;
instanceLocks.remove(lobbyName);
if(i > -1) setLockLobby(i, false);
}
public String getName() {
return name;
}
private int availableLobbyInstance() {
List<Integer> lr = getLobbyRange();
int lb = 0, hb = 0;
if(lr.size() >= 2) {
lb = Math.max(lr.get(0), 0);
hb = Math.min(lr.get(1), maxLobbys - 1);
}
for(int i = lb; i <= hb; i++) {
if(startLobbyInstance(i)) {
return i;
}
}
return -1;
}
private String getInternalScriptExceptionMessage(Throwable a) {
if (!(a instanceof ScriptException)) {
return null;
}
while(true) {
Throwable t = a;
a = a.getCause();
if (a == null) {
return t.getMessage();
}
}
}
private EventInstanceManager createInstance(String name, Object... args) throws ScriptException, NoSuchMethodException {
return (EventInstanceManager) iv.invokeFunction(name, args);
}
private void registerEventInstance(String eventName, int lobbyId) {
Integer oldLobby = instanceLocks.get(eventName);
if (oldLobby != null) {
setLockLobby(oldLobby, false);
}
instanceLocks.put(eventName, lobbyId);
}
public boolean startInstance(MapleExpedition exped) {
return startInstance(-1, exped);
}
public boolean startInstance(int lobbyId, MapleExpedition exped) {
return startInstance(lobbyId, exped, exped.getLeader());
}
//Expedition method: starts an expedition
public boolean startInstance(int lobbyId, MapleExpedition exped, MapleCharacter leader) {
if (this.isDisposed()) return false;
try {
if(!playerPermit.contains(leader.getId()) && startSemaphore.tryAcquire(7777, TimeUnit.MILLISECONDS)) {
playerPermit.add(leader.getId());
startLock.lock();
try {
try {
if(lobbyId == -1) {
lobbyId = availableLobbyInstance();
if(lobbyId == -1) return false;
}
else {
if(!startLobbyInstance(lobbyId)) return false;
}
EventInstanceManager eim;
try {
eim = createInstance("setup", leader.getClient().getChannel());
registerEventInstance(eim.getName(), lobbyId);
} catch (ScriptException | NullPointerException e) {
String message = getInternalScriptExceptionMessage(e);
if (message != null && !message.startsWith(EventInstanceInProgressException.EIIP_KEY)) {
throw e;
}
if(lobbyId > -1) {
setLockLobby(lobbyId, false);
}
return false;
}
eim.setLeader(leader);
exped.start();
eim.registerExpedition(exped);
eim.startEvent();
} catch (ScriptException | NoSuchMethodException ex) {
Logger.getLogger(EventManager.class.getName()).log(Level.SEVERE, null, ex);
}
return true;
} finally {
startLock.unlock();
playerPermit.remove(leader.getId());
startSemaphore.release();
}
}
} catch(InterruptedException ie) {
playerPermit.remove(leader.getId());
}
return false;
}
//Regular method: player
public boolean startInstance(MapleCharacter chr) {
return startInstance(-1, chr);
}
public boolean startInstance(int lobbyId, MapleCharacter leader) {
return startInstance(lobbyId, leader, leader, 1);
}
public boolean startInstance(int lobbyId, MapleCharacter chr, MapleCharacter leader, int difficulty) {
if (this.isDisposed()) return false;
try {
if(!playerPermit.contains(leader.getId()) && startSemaphore.tryAcquire(7777, TimeUnit.MILLISECONDS)) {
playerPermit.add(leader.getId());
startLock.lock();
try {
try {
if(lobbyId == -1) {
lobbyId = availableLobbyInstance();
if(lobbyId == -1) {
return false;
}
}
else {
if(!startLobbyInstance(lobbyId)) {
return false;
}
}
EventInstanceManager eim;
try {
eim = createInstance("setup", difficulty, (lobbyId > -1) ? lobbyId : leader.getId());
registerEventInstance(eim.getName(), lobbyId);
} catch (ScriptException | NullPointerException e) {
String message = getInternalScriptExceptionMessage(e);
if (message != null && !message.startsWith(EventInstanceInProgressException.EIIP_KEY)) {
throw e;
}
if(lobbyId > -1) {
setLockLobby(lobbyId, false);
}
return false;
}
eim.setLeader(leader);
if(chr != null) eim.registerPlayer(chr);
eim.startEvent();
} catch (ScriptException | NoSuchMethodException ex) {
Logger.getLogger(EventManager.class.getName()).log(Level.SEVERE, null, ex);
}
return true;
} finally {
startLock.unlock();
playerPermit.remove(leader.getId());
startSemaphore.release();
}
}
} catch(InterruptedException ie) {
playerPermit.remove(leader.getId());
}
return false;
}
//PQ method: starts a PQ
public boolean startInstance(MapleParty party, MapleMap map) {
return startInstance(-1, party, map);
}
public boolean startInstance(int lobbyId, MapleParty party, MapleMap map) {
return startInstance(lobbyId, party, map, party.getLeader().getPlayer());
}
public boolean startInstance(int lobbyId, MapleParty party, MapleMap map, MapleCharacter leader) {
if (this.isDisposed()) return false;
try {
if(!playerPermit.contains(leader.getId()) && startSemaphore.tryAcquire(7777, TimeUnit.MILLISECONDS)) {
playerPermit.add(leader.getId());
startLock.lock();
try {
try {
if(lobbyId == -1) {
lobbyId = availableLobbyInstance();
if(lobbyId == -1) return false;
}
else {
if(!startLobbyInstance(lobbyId)) return false;
}
EventInstanceManager eim;
try {
eim = createInstance("setup", (Object) null);
registerEventInstance(eim.getName(), lobbyId);
} catch (ScriptException | NullPointerException e) {
String message = getInternalScriptExceptionMessage(e);
if (message != null && !message.startsWith(EventInstanceInProgressException.EIIP_KEY)) {
throw e;
}
if(lobbyId > -1) {
setLockLobby(lobbyId, false);
}
return false;
}
eim.setLeader(leader);
eim.registerParty(party, map);
party.setEligibleMembers(null);
eim.startEvent();
} catch (ScriptException | NoSuchMethodException ex) {
Logger.getLogger(EventManager.class.getName()).log(Level.SEVERE, null, ex);
}
return true;
} finally {
startLock.unlock();
playerPermit.remove(leader.getId());
startSemaphore.release();
}
}
} catch(InterruptedException ie) {
playerPermit.remove(leader.getId());
}
return false;
}
//PQ method: starts a PQ with a difficulty level, requires function setup(difficulty, leaderid) instead of setup()
public boolean startInstance(MapleParty party, MapleMap map, int difficulty) {
return startInstance(-1, party, map, difficulty);
}
public boolean startInstance(int lobbyId, MapleParty party, MapleMap map, int difficulty) {
return startInstance(lobbyId, party, map, difficulty, party.getLeader().getPlayer());
}
public boolean startInstance(int lobbyId, MapleParty party, MapleMap map, int difficulty, MapleCharacter leader) {
if (this.isDisposed()) return false;
try {
if(!playerPermit.contains(leader.getId()) && startSemaphore.tryAcquire(7777, TimeUnit.MILLISECONDS)) {
playerPermit.add(leader.getId());
startLock.lock();
try {
try {
if(lobbyId == -1) {
lobbyId = availableLobbyInstance();
if(lobbyId == -1) return false;
}
else {
if(!startLobbyInstance(lobbyId)) return false;
}
EventInstanceManager eim;
try {
eim = createInstance("setup", difficulty, (lobbyId > -1) ? lobbyId : party.getLeaderId());
registerEventInstance(eim.getName(), lobbyId);
} catch (ScriptException | NullPointerException e) {
String message = getInternalScriptExceptionMessage(e);
if (message != null && !message.startsWith(EventInstanceInProgressException.EIIP_KEY)) {
throw e;
}
if(lobbyId > -1) {
setLockLobby(lobbyId, false);
}
return false;
}
eim.setLeader(leader);
eim.registerParty(party, map);
party.setEligibleMembers(null);
eim.startEvent();
} catch (ScriptException | NoSuchMethodException ex) {
Logger.getLogger(EventManager.class.getName()).log(Level.SEVERE, null, ex);
}
return true;
} finally {
startLock.unlock();
playerPermit.remove(leader.getId());
startSemaphore.release();
}
}
} catch(InterruptedException ie) {
playerPermit.remove(leader.getId());
}
return false;
}
//non-PQ method for starting instance
public boolean startInstance(EventInstanceManager eim, String ldr) {
return startInstance(-1, eim, ldr);
}
public boolean startInstance(EventInstanceManager eim, MapleCharacter ldr) {
return startInstance(-1, eim, ldr.getName(), ldr);
}
public boolean startInstance(int lobbyId, EventInstanceManager eim, String ldr) {
return startInstance(-1, eim, ldr, eim.getEm().getChannelServer().getPlayerStorage().getCharacterByName(ldr)); // things they make me do...
}
public boolean startInstance(int lobbyId, EventInstanceManager eim, String ldr, MapleCharacter leader) {
if (this.isDisposed()) return false;
try {
if(!playerPermit.contains(leader.getId()) && startSemaphore.tryAcquire(7777, TimeUnit.MILLISECONDS)) {
playerPermit.add(leader.getId());
startLock.lock();
try {
try {
if(lobbyId == -1) {
lobbyId = availableLobbyInstance();
if(lobbyId == -1) return false;
}
else {
if(!startLobbyInstance(lobbyId)) return false;
}
if(eim == null) {
if(lobbyId > -1) {
setLockLobby(lobbyId, false);
}
return false;
}
registerEventInstance(eim.getName(), lobbyId);
eim.setLeader(leader);
iv.invokeFunction("setup", eim);
eim.setProperty("leader", ldr);
eim.startEvent();
} catch (ScriptException | NoSuchMethodException ex) {
Logger.getLogger(EventManager.class.getName()).log(Level.SEVERE, null, ex);
}
return true;
} finally {
startLock.unlock();
playerPermit.remove(leader.getId());
startSemaphore.release();
}
}
} catch(InterruptedException ie) {
playerPermit.remove(leader.getId());
}
return false;
}
public List<MaplePartyCharacter> getEligibleParty(MapleParty party) {
if (party == null) {
return(new ArrayList<>());
}
try {
Object p = iv.invokeFunction("getEligibleParty", party.getPartyMembersOnline());
if(p != null) {
List<MaplePartyCharacter> lmpc;
if(ServerConstants.JAVA_8) {
lmpc = new ArrayList<>(((Map<String, MaplePartyCharacter>)(ScriptUtils.convert(p, Map.class))).values());
} else {
lmpc = new ArrayList<>((List<MaplePartyCharacter>) p);
}
party.setEligibleMembers(lmpc);
return lmpc;
}
} catch (ScriptException | NoSuchMethodException ex) {
ex.printStackTrace();
}
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);
} catch (ScriptException | NoSuchMethodException ex) {
Logger.getLogger(EventManager.class.getName()).log(Level.SEVERE, null, ex);
}
}
public MapleMonster getMonster(int mid) {
return(MapleLifeFactory.getMonster(mid));
}
private void exportReadyGuild(Integer guildId) {
MapleGuild mg = server.getGuild(guildId);
String callout = "[Guild Quest] Your guild has been registered to attend to the Sharenian Guild Quest at channel " + this.getChannelServer().getId()
+ " and HAS JUST STARTED THE STRATEGY PHASE. After 3 minutes, no more guild members will be allowed to join the effort."
+ " Check out Shuang at the excavation site in Perion for more info.";
mg.dropMessage(6, callout);
}
private void exportMovedQueueToGuild(Integer guildId, int place) {
MapleGuild mg = server.getGuild(guildId);
String callout = "[Guild Quest] Your guild has been registered to attend to the Sharenian Guild Quest at channel " + this.getChannelServer().getId()
+ " and is currently on the " + GameConstants.ordinal(place) + " place on the waiting queue.";
mg.dropMessage(6, callout);
}
private List<Integer> getNextGuildQueue() {
synchronized(queuedGuilds) {
Integer guildId = queuedGuilds.poll();
if(guildId == null) return null;
wserv.removeGuildQueued(guildId);
Integer leaderId = queuedGuildLeaders.remove(guildId);
int place = 1;
for(Integer i: queuedGuilds) {
exportMovedQueueToGuild(i, place);
place++;
}
List<Integer> list = new ArrayList<>(2);
list.add(guildId); list.add(leaderId);
return list;
}
}
public boolean isQueueFull() {
synchronized(queuedGuilds) {
return queuedGuilds.size() >= YamlConfig.config.server.EVENT_MAX_GUILD_QUEUE;
}
}
public int getQueueSize() {
synchronized(queuedGuilds) {
return queuedGuilds.size();
}
}
public byte addGuildToQueue(Integer guildId, Integer leaderId) {
if(wserv.isGuildQueued(guildId)) return -1;
if(!isQueueFull()) {
boolean canStartAhead;
synchronized(queuedGuilds) {
canStartAhead = queuedGuilds.isEmpty();
queuedGuilds.add(guildId);
wserv.putGuildQueued(guildId);
queuedGuildLeaders.put(guildId, leaderId);
int place = queuedGuilds.size();
exportMovedQueueToGuild(guildId, place);
}
if(canStartAhead) {
if(!attemptStartGuildInstance()) {
synchronized(queuedGuilds) {
queuedGuilds.add(guildId);
wserv.putGuildQueued(guildId);
queuedGuildLeaders.put(guildId, leaderId);
}
} else {
return 2;
}
}
return 1;
} else {
return 0;
}
}
public boolean attemptStartGuildInstance() {
MapleCharacter chr = null;
List<Integer> guildInstance = null;
while(chr == null) {
guildInstance = getNextGuildQueue();
if(guildInstance == null) {
return false;
}
chr = cserv.getPlayerStorage().getCharacterById(guildInstance.get(1));
}
if(startInstance(chr)) {
exportReadyGuild(guildInstance.get(0));
return true;
} else {
return false;
}
}
public void startQuest(MapleCharacter chr, int id, int npcid) {
try {
MapleQuest.getInstance(id).forceStart(chr, npcid);
} catch (NullPointerException ex) {
ex.printStackTrace();
}
}
public void completeQuest(MapleCharacter chr, int id, int npcid) {
try {
MapleQuest.getInstance(id).forceComplete(chr, npcid);
} catch (NullPointerException ex) {
ex.printStackTrace();
}
}
public int getTransportationTime(int travelTime) {
return this.getWorldServer().getTransportationTime(travelTime);
}
private void fillEimQueue() {
ThreadManager.getInstance().newTask(new EventManagerTask()); //call new thread to fill up readied instances queue
}
private EventInstanceManager getReadyInstance() {
queueLock.lock();
try {
if(readyInstances.isEmpty()) {
fillEimQueue();
return null;
}
EventInstanceManager eim = readyInstances.remove(0);
fillEimQueue();
return eim;
} finally {
queueLock.unlock();
}
}
private void instantiateQueuedInstance() {
int nextEventId;
queueLock.lock();
try {
if (this.isDisposed() || readyInstances.size() + onLoadInstances >= Math.ceil((double)maxLobbys / 3.0)) return;
onLoadInstances++;
nextEventId = readyId;
readyId++;
} finally {
queueLock.unlock();
}
EventInstanceManager eim = new EventInstanceManager(this, "sampleName" + nextEventId);
queueLock.lock();
try {
if (this.isDisposed()) { // EM already disposed
return;
}
readyInstances.add(eim);
onLoadInstances--;
} finally {
queueLock.unlock();
}
instantiateQueuedInstance(); // keep filling the queue until reach threshold.
}
private class EventManagerTask implements Runnable {
@Override
public void run() {
instantiateQueuedInstance();
}
}
}

View File

@@ -0,0 +1,40 @@
/*
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 scripting.event;
import scripting.event.scheduler.EventScriptScheduler;
/**
*
* @author Ronan
*/
public class EventScheduledFuture {
Runnable r;
EventScriptScheduler ess;
public EventScheduledFuture(Runnable r, EventScriptScheduler ess) {
this.r = r;
this.ess = ess;
}
public void cancel(boolean dummy) { // will always implement "non-interrupt if running" regardless of boolean value
ess.cancelEntry(r);
}
}

View File

@@ -0,0 +1,136 @@
/*
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 scripting.event;
import java.util.concurrent.ConcurrentHashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import jdk.nashorn.api.scripting.NashornScriptEngine;
import net.server.channel.Channel;
import scripting.AbstractScriptManager;
/**
*
* @author Matze
*/
public class EventScriptManager extends AbstractScriptManager {
private class EventEntry {
public EventEntry(NashornScriptEngine iv, EventManager em) {
this.iv = iv;
this.em = em;
}
public NashornScriptEngine iv;
public EventManager em;
}
private static EventEntry fallback;
private Map<String, EventEntry> events = new ConcurrentHashMap<>();
private boolean active = false;
public EventScriptManager(Channel cserv, String[] scripts) {
super();
for (String script : scripts) {
if (!script.equals("")) {
NashornScriptEngine iv = getScriptEngine("event/" + script + ".js");
events.put(script, new EventEntry(iv, new EventManager(cserv, iv, script)));
}
}
init();
fallback = events.remove("0_EXAMPLE");
}
public EventManager getEventManager(String event) {
EventEntry entry = events.get(event);
if (entry == null) {
return fallback.em;
}
return entry.em;
}
public boolean isActive() {
return active;
}
public final void init() {
for (EventEntry entry : events.values()) {
try {
entry.iv.put("em", entry.em);
entry.iv.invokeFunction("init", (Object) null);
} catch (Exception ex) {
Logger.getLogger(EventScriptManager.class.getName()).log(Level.SEVERE, null, ex);
System.out.println("Error on script: " + entry.em.getName());
}
}
active = events.size() > 1; // bootup loads only 1 script
}
private void reloadScripts() {
Set<Entry<String, EventEntry>> eventEntries = new HashSet<>(events.entrySet());
if (eventEntries.isEmpty()) {
return;
}
Channel cserv = eventEntries.iterator().next().getValue().em.getChannelServer();
for (Entry<String, EventEntry> entry : eventEntries) {
String script = entry.getKey();
NashornScriptEngine iv = getScriptEngine("event/" + script + ".js");
events.put(script, new EventEntry(iv, new EventManager(cserv, iv, script)));
}
}
public void reload() {
cancel();
reloadScripts();
init();
}
public void cancel() {
active = false;
for (EventEntry entry : events.values()) {
entry.em.cancel();
}
}
public void dispose() {
if (events.isEmpty()) {
return;
}
Set<EventEntry> eventEntries = new HashSet<>(events.values());
events.clear();
active = false;
for (EventEntry entry : eventEntries) {
entry.em.cancel();
}
}
}

View File

@@ -0,0 +1,182 @@
/*
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 scripting.event.scheduler;
import config.YamlConfig;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.ScheduledFuture;
import server.TimerManager;
import net.server.Server;
import net.server.audit.LockCollector;
import net.server.audit.locks.MonitoredLockType;
import net.server.audit.locks.MonitoredReentrantLock;
import net.server.audit.locks.factory.MonitoredReentrantLockFactory;
import server.ThreadManager;
/**
*
* @author Ronan
*/
public class EventScriptScheduler {
private boolean disposed = false;
private int idleProcs = 0;
private Map<Runnable, Long> registeredEntries = new HashMap<>();
private ScheduledFuture<?> schedulerTask = null;
private MonitoredReentrantLock schedulerLock;
private Runnable monitorTask = new Runnable() {
@Override
public void run() {
runBaseSchedule();
}
};
public EventScriptScheduler() {
schedulerLock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.EM_SCHDL, true);
}
private void runBaseSchedule() {
List<Runnable> toRemove;
Map<Runnable, Long> registeredEntriesCopy;
schedulerLock.lock();
try {
if (registeredEntries.isEmpty()) {
idleProcs++;
if (idleProcs >= YamlConfig.config.server.MOB_STATUS_MONITOR_LIFE) {
if (schedulerTask != null) {
schedulerTask.cancel(false);
schedulerTask = null;
}
}
return;
}
idleProcs = 0;
registeredEntriesCopy = new HashMap<>(registeredEntries);
} finally {
schedulerLock.unlock();
}
long timeNow = Server.getInstance().getCurrentTime();
toRemove = new LinkedList<>();
for (Entry<Runnable, Long> rmd : registeredEntriesCopy.entrySet()) {
if (rmd.getValue() < timeNow) {
Runnable r = rmd.getKey();
r.run(); // runs the scheduled action
toRemove.add(r);
}
}
if (!toRemove.isEmpty()) {
schedulerLock.lock();
try {
for (Runnable r : toRemove) {
registeredEntries.remove(r);
}
} finally {
schedulerLock.unlock();
}
}
}
public void registerEntry(final Runnable scheduledAction, final long duration) {
ThreadManager.getInstance().newTask(new Runnable() {
@Override
public void run() {
schedulerLock.lock();
try {
idleProcs = 0;
if (schedulerTask == null) {
if (disposed) {
return;
}
schedulerTask = TimerManager.getInstance().register(monitorTask, YamlConfig.config.server.MOB_STATUS_MONITOR_PROC, YamlConfig.config.server.MOB_STATUS_MONITOR_PROC);
}
registeredEntries.put(scheduledAction, Server.getInstance().getCurrentTime() + duration);
} finally {
schedulerLock.unlock();
}
}
});
}
public void cancelEntry(final Runnable scheduledAction) {
ThreadManager.getInstance().newTask(new Runnable() {
@Override
public void run() {
schedulerLock.lock();
try {
registeredEntries.remove(scheduledAction);
} finally {
schedulerLock.unlock();
}
}
});
}
public void dispose() {
ThreadManager.getInstance().newTask(new Runnable() {
@Override
public void run() {
schedulerLock.lock();
try {
if (schedulerTask != null) {
schedulerTask.cancel(false);
schedulerTask = null;
}
registeredEntries.clear();
disposed = true;
} finally {
schedulerLock.unlock();
}
disposeLocks();
}
});
}
private void disposeLocks() {
LockCollector.getInstance().registerDisposeAction(new Runnable() {
@Override
public void run() {
emptyLocks();
}
});
}
private void emptyLocks() {
schedulerLock = schedulerLock.dispose();
}
}

View File

@@ -0,0 +1,39 @@
/*
This file is part of the OdinMS Maple Story Server
Copyright (C) 2008 Patrick Huy <patrick.huy@frz.cc>
Matthias Butz <matze@odinms.de>
Jan Christian Meyer <vimes@odinms.de>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation version 3 as published by
the Free Software Foundation. You may not use, modify or distribute
this program under any other version of the GNU Affero General Public
License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package scripting.item;
import client.MapleClient;
import scripting.npc.NPCScriptManager;
import server.MapleItemInformationProvider.ScriptedItem;
public class ItemScriptManager {
private static ItemScriptManager instance = new ItemScriptManager();
public static ItemScriptManager getInstance() {
return instance;
}
public void runItemScript(MapleClient c, ScriptedItem scriptItem) {
NPCScriptManager.getInstance().start(c, scriptItem, null);
}
}

View File

@@ -0,0 +1,35 @@
/*
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 scripting.item;
import client.MapleClient;
import scripting.AbstractPlayerInteraction;
/**
*
* @author kevintjuh93
*/
public class ItemScriptMethods extends AbstractPlayerInteraction {
public ItemScriptMethods(MapleClient c) {
super(c);
}
}

View File

@@ -0,0 +1,94 @@
/*
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 scripting.map;
import client.MapleCharacter;
import client.MapleClient;
import java.lang.reflect.UndeclaredThrowableException;
import java.util.HashMap;
import java.util.Map;
import javax.script.ScriptEngineFactory;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import jdk.nashorn.api.scripting.NashornScriptEngine;
import scripting.AbstractScriptManager;
import tools.FilePrinter;
public class MapScriptManager extends AbstractScriptManager {
private static MapScriptManager instance = new MapScriptManager();
public static MapScriptManager getInstance() {
return instance;
}
private Map<String, NashornScriptEngine> scripts = new HashMap<>();
private ScriptEngineFactory sef;
private MapScriptManager() {
ScriptEngineManager sem = new ScriptEngineManager();
sef = sem.getEngineByName("javascript").getFactory();
}
public void reloadScripts() {
scripts.clear();
}
public boolean runMapScript(MapleClient c, String mapScriptPath, boolean firstUser) {
if (firstUser) {
MapleCharacter chr = c.getPlayer();
int mapid = chr.getMapId();
if (chr.hasEntered(mapScriptPath, mapid)) {
return false;
} else {
chr.enteredScript(mapScriptPath, mapid);
}
}
NashornScriptEngine iv = scripts.get(mapScriptPath);
if (iv != null) {
try {
iv.invokeFunction("start", new MapScriptMethods(c));
return true;
} catch (final ScriptException | NoSuchMethodException e) {
e.printStackTrace();
}
}
try {
iv = getScriptEngine("map/" + mapScriptPath + ".js");
if (iv == null) {
return false;
}
scripts.put(mapScriptPath, iv);
iv.invokeFunction("start", new MapScriptMethods(c));
return true;
} catch (final UndeclaredThrowableException | ScriptException ute) {
FilePrinter.printError(FilePrinter.MAP_SCRIPT + mapScriptPath + ".txt", ute);
} catch (final Exception e) {
FilePrinter.printError(FilePrinter.MAP_SCRIPT + mapScriptPath + ".txt", e);
}
return false;
}
}

View File

@@ -0,0 +1,169 @@
/*
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 scripting.map;
import client.MapleCharacter.DelayedQuestUpdate;
import client.MapleClient;
import client.MapleQuestStatus;
import scripting.AbstractPlayerInteraction;
import server.quest.MapleQuest;
import tools.MaplePacketCreator;
public class MapScriptMethods extends AbstractPlayerInteraction {
private String rewardstring = " title has been rewarded. Please see NPC Dalair to receive your Medal.";
public MapScriptMethods(MapleClient c) {
super(c);
}
public void displayCygnusIntro() {
switch (c.getPlayer().getMapId()) {
case 913040100:
lockUI();
c.announce(MaplePacketCreator.showIntro("Effect/Direction.img/cygnusJobTutorial/Scene0"));
break;
case 913040101:
c.announce(MaplePacketCreator.showIntro("Effect/Direction.img/cygnusJobTutorial/Scene1"));
break;
case 913040102:
c.announce(MaplePacketCreator.showIntro("Effect/Direction.img/cygnusJobTutorial/Scene2"));
break;
case 913040103:
c.announce(MaplePacketCreator.showIntro("Effect/Direction.img/cygnusJobTutorial/Scene3"));
break;
case 913040104:
c.announce(MaplePacketCreator.showIntro("Effect/Direction.img/cygnusJobTutorial/Scene4"));
break;
case 913040105:
c.announce(MaplePacketCreator.showIntro("Effect/Direction.img/cygnusJobTutorial/Scene5"));
break;
case 913040106:
lockUI();
c.announce(MaplePacketCreator.showIntro("Effect/Direction.img/cygnusJobTutorial/Scene6"));
break;
}
}
public void displayAranIntro() {
switch (c.getPlayer().getMapId()) {
case 914090010:
lockUI();
c.announce(MaplePacketCreator.showIntro("Effect/Direction1.img/aranTutorial/Scene0"));
break;
case 914090011:
c.announce(MaplePacketCreator.showIntro("Effect/Direction1.img/aranTutorial/Scene1" + c.getPlayer().getGender()));
break;
case 914090012:
c.announce(MaplePacketCreator.showIntro("Effect/Direction1.img/aranTutorial/Scene2" + c.getPlayer().getGender()));
break;
case 914090013:
c.announce(MaplePacketCreator.showIntro("Effect/Direction1.img/aranTutorial/Scene3"));
break;
case 914090100:
lockUI();
c.announce(MaplePacketCreator.showIntro("Effect/Direction1.img/aranTutorial/HandedPoleArm" + c.getPlayer().getGender()));
break;
}
}
public void startExplorerExperience() {
if (c.getPlayer().getMapId() == 1020100) //Swordman
{
c.announce(MaplePacketCreator.showIntro("Effect/Direction3.img/swordman/Scene" + c.getPlayer().getGender()));
} else if (c.getPlayer().getMapId() == 1020200) //Magician
{
c.announce(MaplePacketCreator.showIntro("Effect/Direction3.img/magician/Scene" + c.getPlayer().getGender()));
} else if (c.getPlayer().getMapId() == 1020300) //Archer
{
c.announce(MaplePacketCreator.showIntro("Effect/Direction3.img/archer/Scene" + c.getPlayer().getGender()));
} else if (c.getPlayer().getMapId() == 1020400) //Rogue
{
c.announce(MaplePacketCreator.showIntro("Effect/Direction3.img/rogue/Scene" + c.getPlayer().getGender()));
} else if (c.getPlayer().getMapId() == 1020500) //Pirate
{
c.announce(MaplePacketCreator.showIntro("Effect/Direction3.img/pirate/Scene" + c.getPlayer().getGender()));
}
}
public void goAdventure() {
lockUI();
c.announce(MaplePacketCreator.showIntro("Effect/Direction3.img/goAdventure/Scene" + c.getPlayer().getGender()));
}
public void goLith() {
lockUI();
c.announce(MaplePacketCreator.showIntro("Effect/Direction3.img/goLith/Scene" + c.getPlayer().getGender()));
}
public void explorerQuest(short questid, String questName) {
MapleQuest quest = MapleQuest.getInstance(questid);
if (!isQuestStarted(questid)) {
if (!quest.forceStart(getPlayer(), 9000066)) {
return;
}
}
MapleQuestStatus qs = getPlayer().getQuest(quest);
if (!qs.addMedalMap(getPlayer().getMapId())) {
return;
}
String status = Integer.toString(qs.getMedalProgress());
String infoex = qs.getInfoEx(0);
getPlayer().announceUpdateQuest(DelayedQuestUpdate.UPDATE, qs, true);
StringBuilder smp = new StringBuilder();
StringBuilder etm = new StringBuilder();
if (status.equals(infoex)) {
etm.append("Earned the ").append(questName).append(" title!");
smp.append("You have earned the <").append(questName).append(">").append(rewardstring);
getPlayer().announce(MaplePacketCreator.getShowQuestCompletion(quest.getId()));
} else {
getPlayer().announce(MaplePacketCreator.earnTitleMessage(status + "/" + infoex + " regions explored."));
etm.append("Trying for the ").append(questName).append(" title.");
smp.append("You made progress on the ").append(questName).append(" title. ").append(status).append("/").append(infoex);
}
getPlayer().announce(MaplePacketCreator.earnTitleMessage(etm.toString()));
showInfoText(smp.toString());
}
public void touchTheSky() { //29004
MapleQuest quest = MapleQuest.getInstance(29004);
if (!isQuestStarted(29004)) {
if (!quest.forceStart(getPlayer(), 9000066)) {
return;
}
}
MapleQuestStatus qs = getPlayer().getQuest(quest);
if (!qs.addMedalMap(getPlayer().getMapId())) {
return;
}
String status = Integer.toString(qs.getMedalProgress());
getPlayer().announceUpdateQuest(DelayedQuestUpdate.UPDATE, qs, true);
getPlayer().announce(MaplePacketCreator.earnTitleMessage(status + "/5 Completed"));
getPlayer().announce(MaplePacketCreator.earnTitleMessage("The One Who's Touched the Sky title in progress."));
if (Integer.toString(qs.getMedalProgress()).equals(qs.getInfoEx(0))) {
showInfoText("The One Who's Touched the Sky" + rewardstring);
getPlayer().announce(MaplePacketCreator.getShowQuestCompletion(quest.getId()));
} else {
showInfoText("The One Who's Touched the Sky title in progress. " + status + "/5 Completed");
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,216 @@
/*
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 scripting.npc;
import client.MapleCharacter;
import client.MapleClient;
import java.lang.reflect.UndeclaredThrowableException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.script.ScriptException;
import jdk.nashorn.api.scripting.NashornScriptEngine;
import net.server.world.MaplePartyCharacter;
import scripting.AbstractScriptManager;
import server.MapleItemInformationProvider.ScriptedItem;
import tools.FilePrinter;
import tools.MaplePacketCreator;
/**
*
* @author Matze
*/
public class NPCScriptManager extends AbstractScriptManager {
private static NPCScriptManager instance = new NPCScriptManager();
public static NPCScriptManager getInstance() {
return instance;
}
private Map<MapleClient, NPCConversationManager> cms = new HashMap<>();
private Map<MapleClient, NashornScriptEngine> scripts = new HashMap<>();
public boolean isNpcScriptAvailable(MapleClient c, String fileName) {
NashornScriptEngine iv = null;
if (fileName != null) {
iv = getScriptEngine("npc/" + fileName + ".js", c);
}
return iv != null;
}
public boolean start(MapleClient c, int npc, MapleCharacter chr) {
return start(c, npc, -1, chr);
}
public boolean start(MapleClient c, int npc, int oid, MapleCharacter chr) {
return start(c, npc, oid, null, chr);
}
public boolean start(MapleClient c, int npc, String fileName, MapleCharacter chr) {
return start(c, npc, -1, fileName, chr);
}
public boolean start(MapleClient c, int npc, int oid, String fileName, MapleCharacter chr) {
return start(c, npc, oid, fileName, chr, false, "cm");
}
public boolean start(MapleClient c, ScriptedItem scriptItem, MapleCharacter chr) {
return start(c, scriptItem.getNpc(), -1, scriptItem.getScript(), chr, true, "im");
}
public void start(String filename, MapleClient c, int npc, List<MaplePartyCharacter> chrs) {
try {
NPCConversationManager cm = new NPCConversationManager(c, npc, chrs, true);
cm.dispose();
if (cms.containsKey(c)) {
return;
}
cms.put(c, cm);
NashornScriptEngine iv = getScriptEngine("npc/" + filename + ".js", c);
if (iv == null) {
c.getPlayer().dropMessage(1, "NPC " + npc + " is uncoded.");
cm.dispose();
return;
}
iv.put("cm", cm);
scripts.put(c, iv);
try {
iv.invokeFunction("start", chrs);
} catch (final NoSuchMethodException nsme) {
nsme.printStackTrace();
}
} catch (final UndeclaredThrowableException ute) {
FilePrinter.printError(FilePrinter.NPC + npc + ".txt", ute);
dispose(c);
} catch (final Exception e) {
FilePrinter.printError(FilePrinter.NPC + npc + ".txt", e);
dispose(c);
}
}
private boolean start(MapleClient c, int npc, int oid, String fileName, MapleCharacter chr, boolean itemScript, String engineName) {
try {
NPCConversationManager cm = new NPCConversationManager(c, npc, oid, fileName, itemScript);
if (cms.containsKey(c)) {
dispose(c);
}
if (c.canClickNPC()) {
cms.put(c, cm);
NashornScriptEngine iv = null;
if (!itemScript) {
if (fileName != null) {
iv = getScriptEngine("npc/" + fileName + ".js", c);
}
} else {
if (fileName != null) { // thanks MiLin for drafting NPC-based item scripts
iv = getScriptEngine("item/" + fileName + ".js", c);
}
}
if (iv == null) {
iv = getScriptEngine("npc/" + npc + ".js", c);
cm.resetItemScript();
}
if (iv == null) {
dispose(c);
return false;
}
iv.put(engineName, cm);
scripts.put(c, iv);
c.setClickedNPC();
try {
iv.invokeFunction("start");
} catch (final NoSuchMethodException nsme) {
try {
iv.invokeFunction("start", chr);
} catch (final NoSuchMethodException nsma) {
nsma.printStackTrace();
}
}
} else {
c.announce(MaplePacketCreator.enableActions());
}
return true;
} catch (final UndeclaredThrowableException | ScriptException ute) {
FilePrinter.printError(FilePrinter.NPC + npc + ".txt", ute);
dispose(c);
return false;
} catch (final Exception e) {
FilePrinter.printError(FilePrinter.NPC + npc + ".txt", e);
dispose(c);
return false;
}
}
public void action(MapleClient c, byte mode, byte type, int selection) {
NashornScriptEngine iv = scripts.get(c);
if (iv != null) {
try {
c.setClickedNPC();
iv.invokeFunction("action", mode, type, selection);
} catch (ScriptException | NoSuchMethodException t) {
if (getCM(c) != null) {
FilePrinter.printError(FilePrinter.NPC + getCM(c).getNpc() + ".txt", t);
}
dispose(c);
}
}
}
public void dispose(NPCConversationManager cm) {
MapleClient c = cm.getClient();
c.getPlayer().setCS(false);
c.getPlayer().setNpcCooldown(System.currentTimeMillis());
cms.remove(c);
scripts.remove(c);
String scriptFolder = (cm.isItemScript() ? "item" : "npc");
if (cm.getScriptName() != null) {
resetContext(scriptFolder + "/" + cm.getScriptName() + ".js", c);
} else {
resetContext(scriptFolder + "/" + cm.getNpc() + ".js", c);
}
c.getPlayer().flushDelayedUpdateQuests();
}
public void dispose(MapleClient c) {
NPCConversationManager cm = cms.get(c);
if (cm != null) {
dispose(cm);
}
}
public NPCConversationManager getCM(MapleClient c) {
return cms.get(c);
}
}

View File

@@ -0,0 +1,101 @@
/*
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 scripting.portal;
import client.MapleClient;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import scripting.AbstractPlayerInteraction;
import scripting.map.MapScriptManager;
import server.maps.MaplePortal;
import tools.DatabaseConnection;
import tools.MaplePacketCreator;
public class PortalPlayerInteraction extends AbstractPlayerInteraction {
private MaplePortal portal;
public PortalPlayerInteraction(MapleClient c, MaplePortal portal) {
super(c);
this.portal = portal;
}
public MaplePortal getPortal() {
return portal;
}
public void runMapScript() {
MapScriptManager msm = MapScriptManager.getInstance();
msm.runMapScript(c, "onUserEnter/" + portal.getScriptName(), false);
}
public boolean hasLevel30Character() {
PreparedStatement ps = null;
ResultSet rs = null;
Connection con = null;
try {
con = DatabaseConnection.getConnection();
ps = con.prepareStatement("SELECT `level` FROM `characters` WHERE accountid = ?");
ps.setInt(1, getPlayer().getAccountID());
rs = ps.executeQuery();
while (rs.next()) {
if (rs.getInt("level") >= 30) {
ps.close();
rs.close();
return true;
}
}
} catch (SQLException sqle) {
sqle.printStackTrace();
} finally {
try {
if (ps != null && !ps.isClosed()) {
ps.close();
}
if (rs != null && !rs.isClosed()) {
rs.close();
}
if (con != null && !con.isClosed()) {
con.close();
}
} catch (SQLException ex) {
ex.printStackTrace();
}
}
return getPlayer().getLevel() >= 30;
}
public void blockPortal() {
c.getPlayer().blockPortal(getPortal().getScriptName());
}
public void unblockPortal() {
c.getPlayer().unblockPortal(getPortal().getScriptName());
}
public void playPortalSound() {
c.announce(MaplePacketCreator.playPortalSound());
}
}

View File

@@ -0,0 +1,26 @@
/*
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 scripting.portal;
public interface PortalScript {
public boolean enter(PortalPlayerInteraction ppi);
}

View File

@@ -0,0 +1,85 @@
/*
This file is part of the OdinMS Maple Story Server
Copyright (C) 2008 Patrick Huy <patrick.huy@frz.cc>
Matthias Butz <matze@odinms.de>
Jan Christian Meyer <vimes@odinms.de>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation version 3 as published by
the Free Software Foundation. You may not use, modify or distribute
this program under any other version of the GNU Affero General Public
License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package scripting.portal;
import client.MapleClient;
import java.lang.reflect.UndeclaredThrowableException;
import java.util.HashMap;
import java.util.Map;
import javax.script.ScriptEngineFactory;
import javax.script.ScriptEngineManager;
import jdk.nashorn.api.scripting.NashornScriptEngine;
import scripting.AbstractScriptManager;
import server.maps.MaplePortal;
import tools.FilePrinter;
public class PortalScriptManager extends AbstractScriptManager {
private static PortalScriptManager instance = new PortalScriptManager();
public static PortalScriptManager getInstance() {
return instance;
}
private Map<String, NashornScriptEngine> scripts = new HashMap<>();
private ScriptEngineFactory sef;
private PortalScriptManager() {
ScriptEngineManager sem = new ScriptEngineManager();
sef = sem.getEngineByName("javascript").getFactory();
}
private NashornScriptEngine getPortalScript(String scriptName) {
String scriptPath = "portal/" + scriptName + ".js";
NashornScriptEngine iv = scripts.get(scriptPath);
if (iv != null) {
return iv;
}
iv = getScriptEngine(scriptPath);
if (iv == null) {
return null;
}
scripts.put(scriptPath, iv);
return iv;
}
public boolean executePortalScript(MaplePortal portal, MapleClient c) {
try {
NashornScriptEngine iv = getPortalScript(portal.getScriptName());
if (iv != null) {
boolean couldWarp = (boolean) iv.invokeFunction("enter", new PortalPlayerInteraction(c, portal));
return couldWarp;
}
} catch (UndeclaredThrowableException ute) {
FilePrinter.printError(FilePrinter.PORTAL + portal.getScriptName() + ".txt", ute);
} catch (final Exception e) {
FilePrinter.printError(FilePrinter.PORTAL + portal.getScriptName() + ".txt", e);
}
return false;
}
public void reloadPortalScripts() {
scripts.clear();
}
}

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 scripting.quest;
import client.MapleClient;
import scripting.npc.NPCConversationManager;
import server.MapleItemInformationProvider;
import server.quest.MapleQuest;
import server.quest.actions.ExpAction;
import server.quest.actions.MesoAction;
/**
*
* @author RMZero213
*/
public class QuestActionManager extends NPCConversationManager {
private boolean start; // this is if the script in question is start or end
private int quest;
public QuestActionManager(MapleClient c, int quest, int npc, boolean start) {
super(c, npc, null);
this.quest = quest;
this.start = start;
}
public int getQuest() {
return quest;
}
public boolean isStart() {
return start;
}
@Override
public void dispose() {
QuestScriptManager.getInstance().dispose(this, getClient());
}
public boolean forceStartQuest() {
return forceStartQuest(quest);
}
public boolean forceCompleteQuest() {
return forceCompleteQuest(quest);
}
// For compatibility with some older scripts...
public void startQuest() {
forceStartQuest();
}
// For compatibility with some older scripts...
public void completeQuest() {
forceCompleteQuest();
}
@Override
public void gainExp(int gain) {
ExpAction.runAction(getPlayer(), gain);
}
@Override
public void gainMeso(int gain) {
MesoAction.runAction(getPlayer(), gain);
}
public String getMedalName() { // usable only for medal quests (id 299XX)
MapleQuest q = MapleQuest.getInstance(quest);
return MapleItemInformationProvider.getInstance().getName(q.getMedalRequirement());
}
}

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 scripting.quest;
import java.lang.reflect.UndeclaredThrowableException;
import java.util.HashMap;
import java.util.Map;
import jdk.nashorn.api.scripting.NashornScriptEngine;
import scripting.AbstractScriptManager;
import server.quest.MapleQuest;
import tools.FilePrinter;
import constants.game.GameConstants;
import client.MapleClient;
import client.MapleQuestStatus;
/**
*
* @author RMZero213
*/
public class QuestScriptManager extends AbstractScriptManager {
private static QuestScriptManager instance = new QuestScriptManager();
public static QuestScriptManager getInstance() {
return instance;
}
private Map<MapleClient, QuestActionManager> qms = new HashMap<>();
private Map<MapleClient, NashornScriptEngine> scripts = new HashMap<>();
private NashornScriptEngine getQuestScriptEngine(MapleClient c, short questid) {
NashornScriptEngine iv = getScriptEngine("quest/" + questid + ".js", c);
if (iv == null && GameConstants.isMedalQuest(questid)) {
iv = getScriptEngine("quest/medalQuest.js", c); // start generic medal quest
}
return iv;
}
public void start(MapleClient c, short questid, int npc) {
MapleQuest quest = MapleQuest.getInstance(questid);
try {
QuestActionManager qm = new QuestActionManager(c, questid, npc, true);
if (qms.containsKey(c)) {
return;
}
if(c.canClickNPC()) {
qms.put(c, qm);
if (!quest.hasScriptRequirement(false)) { // lack of scripted quest checks found thanks to Mali, Resinate
qm.dispose();
return;
}
NashornScriptEngine iv = getQuestScriptEngine(c, questid);
if (iv == null) {
FilePrinter.printError(FilePrinter.QUEST_UNCODED, "START Quest " + questid + " is uncoded.");
qm.dispose();
return;
}
iv.put("qm", qm);
scripts.put(c, iv);
c.setClickedNPC();
iv.invokeFunction("start", (byte) 1, (byte) 0, 0);
}
} catch (final UndeclaredThrowableException ute) {
FilePrinter.printError(FilePrinter.QUEST + questid + ".txt", ute);
dispose(c);
} catch (final Throwable t) {
FilePrinter.printError(FilePrinter.QUEST + getQM(c).getQuest() + ".txt", t);
dispose(c);
}
}
public void start(MapleClient c, byte mode, byte type, int selection) {
NashornScriptEngine iv = scripts.get(c);
if (iv != null) {
try {
c.setClickedNPC();
iv.invokeFunction("start", mode, type, selection);
} catch (final UndeclaredThrowableException ute) {
FilePrinter.printError(FilePrinter.QUEST + getQM(c).getQuest() + ".txt", ute);
dispose(c);
} catch (final Throwable t) {
FilePrinter.printError(FilePrinter.QUEST + getQM(c).getQuest() + ".txt", t);
dispose(c);
}
}
}
public void end(MapleClient c, short questid, int npc) {
MapleQuest quest = MapleQuest.getInstance(questid);
if (!c.getPlayer().getQuest(quest).getStatus().equals(MapleQuestStatus.Status.STARTED) || !c.getPlayer().getMap().containsNPC(npc)) {
dispose(c);
return;
}
try {
QuestActionManager qm = new QuestActionManager(c, questid, npc, false);
if (qms.containsKey(c)) {
return;
}
if(c.canClickNPC()){
qms.put(c, qm);
if (!quest.hasScriptRequirement(true)) {
qm.dispose();
return;
}
NashornScriptEngine iv = getQuestScriptEngine(c, questid);
if (iv == null) {
FilePrinter.printError(FilePrinter.QUEST_UNCODED, "END Quest " + questid + " is uncoded.");
qm.dispose();
return;
}
iv.put("qm", qm);
scripts.put(c, iv);
c.setClickedNPC();
iv.invokeFunction("end", (byte) 1, (byte) 0, 0);
}
} catch (final UndeclaredThrowableException ute) {
FilePrinter.printError(FilePrinter.QUEST + questid + ".txt", ute);
dispose(c);
} catch (final Throwable t) {
FilePrinter.printError(FilePrinter.QUEST + getQM(c).getQuest() + ".txt", t);
dispose(c);
}
}
public void end(MapleClient c, byte mode, byte type, int selection) {
NashornScriptEngine iv = scripts.get(c);
if (iv != null) {
try {
c.setClickedNPC();
iv.invokeFunction("end", mode, type, selection);
} catch (final UndeclaredThrowableException ute) {
FilePrinter.printError(FilePrinter.QUEST + getQM(c).getQuest() + ".txt", ute);
dispose(c);
} catch (final Throwable t) {
FilePrinter.printError(FilePrinter.QUEST + getQM(c).getQuest() + ".txt", t);
dispose(c);
}
}
}
public void raiseOpen(MapleClient c, short questid, int npc) {
try {
QuestActionManager qm = new QuestActionManager(c, questid, npc, true);
if (qms.containsKey(c)) {
return;
}
if(c.canClickNPC()) {
qms.put(c, qm);
NashornScriptEngine iv = getQuestScriptEngine(c, questid);
if (iv == null) {
//FilePrinter.printError(FilePrinter.QUEST_UNCODED, "RAISE Quest " + questid + " is uncoded.");
qm.dispose();
return;
}
iv.put("qm", qm);
scripts.put(c, iv);
c.setClickedNPC();
iv.invokeFunction("raiseOpen");
}
} catch (final UndeclaredThrowableException ute) {
FilePrinter.printError(FilePrinter.QUEST + questid + ".txt", ute);
dispose(c);
} catch (final Throwable t) {
FilePrinter.printError(FilePrinter.QUEST + getQM(c).getQuest() + ".txt", t);
dispose(c);
}
}
public void dispose(QuestActionManager qm, MapleClient c) {
qms.remove(c);
scripts.remove(c);
c.getPlayer().setNpcCooldown(System.currentTimeMillis());
resetContext("quest/" + qm.getQuest() + ".js", c);
c.getPlayer().flushDelayedUpdateQuests();
}
public void dispose(MapleClient c) {
QuestActionManager qm = qms.get(c);
if (qm != null) {
dispose(qm, c);
}
}
public QuestActionManager getQM(MapleClient c) {
return qms.get(c);
}
public void reloadQuestScripts() {
scripts.clear();
qms.clear();
}
}

View File

@@ -0,0 +1,362 @@
/*
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 scripting.reactor;
import client.MapleCharacter;
import client.MapleClient;
import client.inventory.Equip;
import client.inventory.Item;
import client.inventory.MapleInventoryType;
import config.YamlConfig;
import constants.inventory.ItemConstants;
import java.awt.Point;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.ScheduledFuture;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.script.ScriptException;
import jdk.nashorn.api.scripting.NashornScriptEngine;
import scripting.AbstractPlayerInteraction;
import scripting.event.EventInstanceManager;
import scripting.event.EventManager;
import server.MapleItemInformationProvider;
import server.TimerManager;
import server.life.MapleLifeFactory;
import server.life.MapleMonster;
import server.maps.MapMonitor;
import server.maps.MapleMap;
import server.maps.MapleReactor;
import server.maps.ReactorDropEntry;
import server.partyquest.MapleCarnivalFactory;
import server.partyquest.MapleCarnivalFactory.MCSkill;
import tools.MaplePacketCreator;
/**
* @author Lerk
* @author Ronan
*/
public class ReactorActionManager extends AbstractPlayerInteraction {
private MapleReactor reactor;
private NashornScriptEngine iv;
private ScheduledFuture<?> sprayTask = null;
public ReactorActionManager(MapleClient c, MapleReactor reactor, NashornScriptEngine iv) {
super(c);
this.reactor = reactor;
this.iv = iv;
}
public void hitReactor() {
reactor.hitReactor(c);
}
public void destroyNpc(int npcId) {
reactor.getMap().destroyNPC(npcId);
}
private static void sortDropEntries(List<ReactorDropEntry> from, List<ReactorDropEntry> item, List<ReactorDropEntry> visibleQuest, List<ReactorDropEntry> otherQuest, MapleCharacter chr) {
MapleItemInformationProvider ii = MapleItemInformationProvider.getInstance();
for(ReactorDropEntry mde : from) {
if(!ii.isQuestItem(mde.itemId)) {
item.add(mde);
} else {
if(chr.needQuestItem(mde.questid, mde.itemId)) {
visibleQuest.add(mde);
} else {
otherQuest.add(mde);
}
}
}
}
private static List<ReactorDropEntry> assembleReactorDropEntries(MapleCharacter chr, List<ReactorDropEntry> items) {
final List<ReactorDropEntry> dropEntry = new ArrayList<>();
final List<ReactorDropEntry> visibleQuestEntry = new ArrayList<>();
final List<ReactorDropEntry> otherQuestEntry = new ArrayList<>();
sortDropEntries(items, dropEntry, visibleQuestEntry, otherQuestEntry, chr);
Collections.shuffle(dropEntry);
Collections.shuffle(visibleQuestEntry);
Collections.shuffle(otherQuestEntry);
items.clear();
items.addAll(dropEntry);
items.addAll(visibleQuestEntry);
items.addAll(otherQuestEntry);
List<ReactorDropEntry> items1 = new ArrayList<>(items.size());
List<ReactorDropEntry> items2 = new ArrayList<>(items.size() / 2);
for (int i = 0; i < items.size(); i++) {
if (i % 2 == 0) {
items1.add(items.get(i));
} else {
items2.add(items.get(i));
}
}
Collections.reverse(items1);
items1.addAll(items2);
return items1;
}
public void sprayItems() {
sprayItems(false, 0, 0, 0, 0);
}
public void sprayItems(boolean meso, int mesoChance, int minMeso, int maxMeso) {
sprayItems(meso, mesoChance, minMeso, maxMeso, 0);
}
public void sprayItems(boolean meso, int mesoChance, int minMeso, int maxMeso, int minItems) {
sprayItems((int)reactor.getPosition().getX(), (int)reactor.getPosition().getY(), meso, mesoChance, minMeso, maxMeso, minItems);
}
public void sprayItems(int posX, int posY, boolean meso, int mesoChance, int minMeso, int maxMeso, int minItems) {
dropItems(true, posX, posY, meso, mesoChance, minMeso, maxMeso, minItems);
}
public void dropItems() {
dropItems(false, 0, 0, 0, 0);
}
public void dropItems(boolean meso, int mesoChance, int minMeso, int maxMeso) {
dropItems(meso, mesoChance, minMeso, maxMeso, 0);
}
public void dropItems(boolean meso, int mesoChance, int minMeso, int maxMeso, int minItems) {
dropItems((int)reactor.getPosition().getX(), (int)reactor.getPosition().getY(), meso, mesoChance, minMeso, maxMeso, minItems);
}
public void dropItems(int posX, int posY, boolean meso, int mesoChance, int minMeso, int maxMeso, int minItems) {
dropItems(true, posX, posY, meso, mesoChance, minMeso, maxMeso, minItems); // all reactors actually drop items sequentially... thanks inhyuk for pointing this out!
}
public void dropItems(boolean delayed, int posX, int posY, boolean meso, int mesoChance, final int minMeso, final int maxMeso, int minItems) {
MapleCharacter chr = c.getPlayer();
if(chr == null) return;
List<ReactorDropEntry> items = assembleReactorDropEntries(chr, generateDropList(getDropChances(), chr.getDropRate(), meso, mesoChance, minItems));
if(items.size() % 2 == 0) posX -= 12;
final Point dropPos = new Point(posX, posY);
if(!delayed) {
MapleItemInformationProvider ii = MapleItemInformationProvider.getInstance();
byte p = 1;
for (ReactorDropEntry d : items) {
dropPos.x = (int) (posX + ((p % 2 == 0) ? (25 * ((p + 1) / 2)) : -(25 * (p / 2))));
p++;
if (d.itemId == 0) {
int range = maxMeso - minMeso;
int displayDrop = (int) (Math.random() * range) + minMeso;
int mesoDrop = (displayDrop * c.getWorldServer().getMesoRate());
reactor.getMap().spawnMesoDrop(mesoDrop, reactor.getMap().calcDropPos(dropPos, reactor.getPosition()), reactor, c.getPlayer(), false, (byte) 2);
} else {
Item drop;
if (ItemConstants.getInventoryType(d.itemId) != MapleInventoryType.EQUIP) {
drop = new Item(d.itemId, (short) 0, (short) 1);
} else {
drop = ii.randomizeStats((Equip) ii.getEquipById(d.itemId));
}
reactor.getMap().dropFromReactor(getPlayer(), reactor, drop, dropPos, (short) d.questid);
}
}
} else {
final MapleReactor r = reactor;
final List<ReactorDropEntry> dropItems = items;
final int worldMesoRate = c.getWorldServer().getMesoRate();
dropPos.x -= (12 * items.size());
sprayTask = TimerManager.getInstance().register(new Runnable() {
@Override
public void run() {
if(dropItems.isEmpty()) {
sprayTask.cancel(false);
return;
}
ReactorDropEntry d = dropItems.remove(0);
if (d.itemId == 0) {
int range = maxMeso - minMeso;
int displayDrop = (int) (Math.random() * range) + minMeso;
int mesoDrop = (displayDrop * worldMesoRate);
r.getMap().spawnMesoDrop(mesoDrop, r.getMap().calcDropPos(dropPos, r.getPosition()), r, chr, false, (byte) 2);
} else {
Item drop;
if (ItemConstants.getInventoryType(d.itemId) != MapleInventoryType.EQUIP) {
drop = new Item(d.itemId, (short) 0, (short) 1);
} else {
MapleItemInformationProvider ii = MapleItemInformationProvider.getInstance();
drop = ii.randomizeStats((Equip) ii.getEquipById(d.itemId));
}
r.getMap().dropFromReactor(getPlayer(), r, drop, dropPos, (short) d.questid);
}
dropPos.x += 25;
}
}, 200);
}
}
private List<ReactorDropEntry> getDropChances() {
return ReactorScriptManager.getInstance().getDrops(reactor.getId());
}
private List<ReactorDropEntry> generateDropList(List<ReactorDropEntry> drops, int dropRate, boolean meso, int mesoChance, int minItems) {
List<ReactorDropEntry> items = new ArrayList<>();
if (meso && Math.random() < (1 / (double) mesoChance)) {
items.add(new ReactorDropEntry(0, mesoChance, -1));
}
for(ReactorDropEntry mde : drops) {
if (Math.random() < (dropRate / (double) mde.chance)) {
items.add(mde);
}
}
while (items.size() < minItems) {
items.add(new ReactorDropEntry(0, mesoChance, -1));
}
return items;
}
public void spawnMonster(int id) {
spawnMonster(id, 1, getPosition());
}
public void createMapMonitor(int mapId, String portal) {
new MapMonitor(c.getChannelServer().getMapFactory().getMap(mapId), portal);
}
public void spawnMonster(int id, int qty) {
spawnMonster(id, qty, getPosition());
}
public void spawnMonster(int id, int qty, int x, int y) {
spawnMonster(id, qty, new Point(x, y));
}
public void spawnMonster(int id, int qty, Point pos) {
for (int i = 0; i < qty; i++) {
reactor.getMap().spawnMonsterOnGroundBelow(MapleLifeFactory.getMonster(id), pos);
}
}
public Point getPosition() {
Point pos = reactor.getPosition();
pos.y -= 10;
return pos;
}
public void spawnNpc(int npcId) {
spawnNpc(npcId, getPosition());
}
public void spawnNpc(int npcId, Point pos) {
spawnNpc(npcId, pos, reactor.getMap());
}
public void hitMonsterWithReactor(int id, int hitsToKill) { // until someone comes with a better solution, why not?
int customTime = YamlConfig.config.server.MOB_REACTOR_REFRESH_TIME;
if(customTime > 0) {
reactor.setDelay(customTime);
}
MapleMap map = reactor.getMap();
MapleMonster mm = map.getMonsterById(id);
if(mm != null) {
int damage = (int)Math.ceil(mm.getMaxHp() / hitsToKill);
MapleCharacter chr = this.getPlayer();
if(chr != null) {
map.damageMonster(chr, mm, damage);
map.broadcastMessage(MaplePacketCreator.damageMonster(mm.getObjectId(), damage));
}
}
}
public MapleReactor getReactor() {
return reactor;
}
public void spawnFakeMonster(int id) {
reactor.getMap().spawnFakeMonsterOnGroundBelow(MapleLifeFactory.getMonster(id), getPosition());
}
public ScheduledFuture<?> schedule(String methodName, long delay) {
return schedule(methodName, null, delay);
}
public ScheduledFuture<?> schedule(final String methodName, final EventInstanceManager eim, long delay) {
return TimerManager.getInstance().schedule(new Runnable() {
@Override
public void run() {
try {
iv.invokeFunction(methodName, eim);
} catch (ScriptException | NoSuchMethodException ex) {
Logger.getLogger(EventManager.class.getName()).log(Level.SEVERE, null, ex);
}
}
}, delay);
}
public ScheduledFuture<?> scheduleAtTimestamp(final String methodName, long timestamp) {
return TimerManager.getInstance().scheduleAtTimestamp(new Runnable() {
@Override
public void run() {
try {
iv.invokeFunction(methodName, (Object) null);
} catch (ScriptException | NoSuchMethodException ex) {
Logger.getLogger(EventManager.class.getName()).log(Level.SEVERE, null, ex);
}
}
}, timestamp);
}
public void dispelAllMonsters(int num, int team) { //dispels all mobs, cpq
final MCSkill skil = MapleCarnivalFactory.getInstance().getGuardian(num);
if (skil != null) {
for (MapleMonster mons : getMap().getAllMonsters()) {
if(mons.getTeam() == team) {
mons.dispelSkill(skil.getSkill());
}
}
}
if (team == 0) {
getPlayer().getMap().getRedTeamBuffs().remove(skil);
} else {
getPlayer().getMap().getBlueTeamBuffs().remove(skil);
}
}
}

View File

@@ -0,0 +1,134 @@
/*
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 scripting.reactor;
import client.MapleClient;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import javax.script.ScriptException;
import jdk.nashorn.api.scripting.NashornScriptEngine;
import scripting.AbstractScriptManager;
import server.maps.MapleReactor;
import server.maps.ReactorDropEntry;
import tools.DatabaseConnection;
import tools.FilePrinter;
/**
* @author Lerk
*/
public class ReactorScriptManager extends AbstractScriptManager {
private static ReactorScriptManager instance = new ReactorScriptManager();
public static ReactorScriptManager getInstance() {
return instance;
}
private Map<Integer, List<ReactorDropEntry>> drops = new HashMap<>();
public void onHit(MapleClient c, MapleReactor reactor) {
try {
NashornScriptEngine iv = getScriptEngine("reactor/" + reactor.getId() + ".js", c);
if (iv == null) return;
ReactorActionManager rm = new ReactorActionManager(c, reactor, iv);
iv.put("rm", rm);
iv.invokeFunction("hit");
} catch (final NoSuchMethodException e) {} //do nothing, hit is OPTIONAL
catch (final ScriptException | NullPointerException e) {
FilePrinter.printError(FilePrinter.REACTOR + reactor.getId() + ".txt", e);
}
}
public void act(MapleClient c, MapleReactor reactor) {
try {
NashornScriptEngine iv = getScriptEngine("reactor/" + reactor.getId() + ".js", c);
if (iv == null) return;
ReactorActionManager rm = new ReactorActionManager(c, reactor, iv);
iv.put("rm", rm);
iv.invokeFunction("act");
} catch (final ScriptException | NoSuchMethodException | NullPointerException e) {
FilePrinter.printError(FilePrinter.REACTOR + reactor.getId() + ".txt", e);
}
}
public List<ReactorDropEntry> getDrops(int rid) {
List<ReactorDropEntry> ret = drops.get(rid);
if (ret == null) {
ret = new LinkedList<>();
try {
Connection con = DatabaseConnection.getConnection();
try (PreparedStatement ps = con.prepareStatement("SELECT itemid, chance, questid FROM reactordrops WHERE reactorid = ? AND chance >= 0")) {
ps.setInt(1, rid);
try (ResultSet rs = ps.executeQuery()) {
while (rs.next()) {
ret.add(new ReactorDropEntry(rs.getInt("itemid"), rs.getInt("chance"), rs.getInt("questid")));
}
}
}
con.close();
} catch (Throwable e) {
FilePrinter.printError(FilePrinter.REACTOR + rid + ".txt", e);
}
drops.put(rid, ret);
}
return ret;
}
public void clearDrops() {
drops.clear();
}
public void touch(MapleClient c, MapleReactor reactor) {
touching(c, reactor, true);
}
public void untouch(MapleClient c, MapleReactor reactor) {
touching(c, reactor, false);
}
private void touching(MapleClient c, MapleReactor reactor, boolean touching) {
try {
NashornScriptEngine iv = getScriptEngine("reactor/" + reactor.getId() + ".js", c);
if (iv == null) return;
ReactorActionManager rm = new ReactorActionManager(c, reactor, iv);
iv.put("rm", rm);
if (touching) {
iv.invokeFunction("touch");
} else {
iv.invokeFunction("untouch");
}
} catch (final ScriptException | NoSuchMethodException | NullPointerException ute) {
FilePrinter.printError(FilePrinter.REACTOR + reactor.getId() + ".txt", ute);
}
}
}