Medal quest system tweak + Proximity check on quests + DB leak fix

Rebalanced the EXTREMELY low level section of the equipment level up system.
Added support code for quests on Kerning Square and Mushroom Castle.
Added quest scripts for many missing scripted quests.
Refactored medal quests, now using a default script system for uncoded medal questid's.
Fixed a DB leak regarding quest status and medal maps tables.
Added proximity check for NPCs to start/complete quests that doesn't use the lightbulb system.
Added "debuff" command, that debuffs people nearby.
This commit is contained in:
ronancpl
2018-04-27 11:14:45 -03:00
parent 7d448cce4f
commit 61292f5c9b
60 changed files with 965 additions and 981 deletions

View File

@@ -1,34 +0,0 @@
/*
This file is part of the OdinMS Maple Story Server
Copyright (C) 2008 ~ 2010 Patrick Huy <patrick.huy@frz.cc>
Matthias Butz <matze@odinms.de>
Jan Christian Meyer <vimes@odinms.de>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License version 3
as published by the Free Software Foundation. You may not use, modify
or distribute this program under any other version of the
GNU Affero General Public License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package client;
/**
*
* @author anybody can do this
*/
public class DiseaseValueHolder {
public long startTime, length;
public DiseaseValueHolder(long start, long length) {
this.startTime = start;
this.length = length;
}
}

View File

@@ -1850,25 +1850,7 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
}
}
try (PreparedStatement ps = con.prepareStatement("SELECT queststatusid FROM queststatus WHERE characterid = ?")) {
ps.setInt(1, cid);
try (ResultSet rs = ps.executeQuery()) {
while (rs.next()) {
int queststatusid = rs.getInt("queststatusid");
try (PreparedStatement ps2 = con.prepareStatement("DELETE FROM medalmaps WHERE queststatusid = ?")) {
ps2.setInt(1, queststatusid);
ps2.executeUpdate();
}
try (PreparedStatement ps2 = con.prepareStatement("DELETE FROM questprogress WHERE queststatusid = ?")) {
ps2.setInt(1, queststatusid);
ps2.executeUpdate();
}
}
}
}
deleteQuestProgressWhereCharacterId(con, cid);
try (PreparedStatement ps = con.prepareStatement("SELECT id FROM mts_cart WHERE cid = ?")) {
ps.setInt(1, cid);
@@ -1902,6 +1884,28 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
return false;
}
}
private static void deleteQuestProgressWhereCharacterId(Connection con, int cid) throws SQLException {
try (PreparedStatement ps = con.prepareStatement("SELECT queststatusid FROM queststatus WHERE characterid = ?")) {
ps.setInt(1, cid);
try (ResultSet rs = ps.executeQuery()) {
while (rs.next()) {
int queststatusid = rs.getInt("queststatusid");
try (PreparedStatement ps2 = con.prepareStatement("DELETE FROM medalmaps WHERE queststatusid = ?")) {
ps2.setInt(1, queststatusid);
ps2.executeUpdate();
}
try (PreparedStatement ps2 = con.prepareStatement("DELETE FROM questprogress WHERE queststatusid = ?")) {
ps2.setInt(1, queststatusid);
ps2.executeUpdate();
}
}
}
}
}
private void deleteWhereCharacterId(Connection con, String sql) throws SQLException {
try (PreparedStatement ps = con.prepareStatement(sql)) {
@@ -2744,6 +2748,17 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
}
}
public boolean hasBuffFromSourceid(int sourceid) {
effLock.lock();
chrLock.lock();
try {
return buffEffects.containsKey(sourceid);
} finally {
chrLock.unlock();
effLock.unlock();
}
}
private List<Pair<MapleBuffStat, Integer>> getActiveStatupsFromSourceid(int sourceid) { // already under effLock & chrLock
List<Pair<MapleBuffStat, Integer>> ret = new ArrayList<>();
@@ -5084,7 +5099,7 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
} else if (level == 25) {
yellowMessage("You seem to be improving, but you are still not ready to move on to the next step.");
} else if (level == 30) {
yellowMessage("You have finally reached level 30! Try job advancing, after that try the Mushroom Kingdom!");
yellowMessage("You have finally reached level 30! Try job advancing, after that try the Mushroom Castle!");
} else if (level == 35) {
yellowMessage("Hey did you hear about this mall that opened in Kerning? Try visiting the Kerning Mall.");
} else if (level == 40) {
@@ -6644,7 +6659,8 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
}
ps.executeBatch();
deleteWhereCharacterId(con, "DELETE FROM eventstats WHERE characterid = ?");
deleteWhereCharacterId(con, "DELETE FROM queststatus WHERE characterid = ?");
deleteQuestProgressWhereCharacterId(con, id);
ps = con.prepareStatement("INSERT INTO queststatus (`queststatusid`, `characterid`, `quest`, `status`, `time`, `expires`, `forfeited`) VALUES (DEFAULT, ?, ?, ?, ?, ?, ?)", Statement.RETURN_GENERATED_KEYS);
PreparedStatement psf;
try (PreparedStatement pse = con.prepareStatement("INSERT INTO questprogress VALUES (DEFAULT, ?, ?, ?)")) {
@@ -7556,7 +7572,7 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
announce(MaplePacketCreator.updateQuestInfo((short) quest.getQuest().getId(), quest.getNpc()));
} else if (quest.getStatus().equals(MapleQuestStatus.Status.COMPLETED)) {
short questid = quest.getQuest().getId();
if(questid != 3637) {
if(!MapleQuest.isExploitableQuest(questid)) {
quest_fame += 1;
if(ServerConstants.FAME_GAIN_BY_QUEST > 0)
fameGainByQuest();

View File

@@ -68,6 +68,8 @@ import server.life.MapleLifeFactory;
import server.life.MapleMonster;
import server.life.MapleMonsterInformationProvider;
import server.life.MapleNPC;
import server.life.MobSkill;
import server.life.MobSkillFactory;
import server.life.MonsterDropEntry;
import server.maps.MapleMap;
import server.maps.MapleMapItem;
@@ -89,6 +91,7 @@ import tools.data.output.MaplePacketLittleEndianWriter;
import client.MapleBuffStat;
import client.MapleCharacter;
import client.MapleClient;
import client.MapleDisease;
import client.MapleJob;
import client.MapleStat;
import client.Skill;
@@ -743,14 +746,9 @@ public class Commands {
break;
}
c.announce(MaplePacketCreator.getNPCTalk(9010000, (byte) 0, output, "00 00", (byte) 0));
break;
break;
case "buffme":
if(!player.isGM()) {
player.dropMessage(5, "You are already dead.");
break;
}
//GM Skills : Haste(Super) - Holy Symbol - Bless - Hyper Body - Echo of Hero
SkillFactory.getSkill(4101004).getEffect(SkillFactory.getSkill(4101004).getMaxLevel()).applyTo(player);
SkillFactory.getSkill(2311003).getEffect(SkillFactory.getSkill(2311003).getMaxLevel()).applyTo(player);
@@ -1572,6 +1570,81 @@ public class Commands {
MapleCharacter victim;
switch(sub[0]) {
case "debuff":
if (sub.length < 2) {
player.yellowMessage("Syntax: !debuff SLOW|SEDUCE|ZOMBIFY|CONFUSE|STUN|POISON|SEAL|DARKNESS|WEAKEN|CURSE");
break;
}
MapleDisease disease = null;
MobSkill skill = null;
switch(sub[1].toUpperCase()) {
case "SLOW":
disease = MapleDisease.SLOW;
skill = MobSkillFactory.getMobSkill(126, 7);
break;
case "SEDUCE":
disease = MapleDisease.SEDUCE;
skill = MobSkillFactory.getMobSkill(128, 7);
break;
case "ZOMBIFY":
disease = MapleDisease.ZOMBIFY;
skill = MobSkillFactory.getMobSkill(133, 1);
break;
case "CONFUSE":
disease = MapleDisease.CONFUSE;
skill = MobSkillFactory.getMobSkill(132, 2);
break;
case "STUN":
disease = MapleDisease.STUN;
skill = MobSkillFactory.getMobSkill(123, 7);
break;
case "POISON":
disease = MapleDisease.POISON;
skill = MobSkillFactory.getMobSkill(125, 5);
break;
case "SEAL":
disease = MapleDisease.SEAL;
skill = MobSkillFactory.getMobSkill(120, 1);
break;
case "DARKNESS":
disease = MapleDisease.DARKNESS;
skill = MobSkillFactory.getMobSkill(121, 1);
break;
case "WEAKEN":
disease = MapleDisease.WEAKEN;
skill = MobSkillFactory.getMobSkill(122, 1);
break;
case "CURSE":
disease = MapleDisease.CURSE;
skill = MobSkillFactory.getMobSkill(124, 1);
break;
}
if(disease == null) {
player.yellowMessage("Syntax: !debuff SLOW|SEDUCE|ZOMBIFY|CONFUSE|STUN|POISON|SEAL|DARKNESS|WEAKEN|CURSE");
break;
}
for (MapleMapObject mmo : player.getMap().getMapObjectsInRange(player.getPosition(), 1000.0, Arrays.asList(MapleMapObjectType.PLAYER))) {
MapleCharacter chr = (MapleCharacter) mmo;
if(chr.getId() != player.getId()) {
chr.giveDebuff(disease, skill);
}
}
break;
case "fly":
if (sub.length < 2) {
player.yellowMessage("Syntax: !fly <on/off>");

View File

@@ -486,7 +486,9 @@ public class Equip extends Item {
// Conversion factor between mob exp and equip exp gain. Through many calculations, the expected for equipment levelup
// from level 1 to 2 is killing about 100~200 mobs of the same level range, on a 1x EXP rate scenario.
if(reqLevel >= 78) {
if(reqLevel < 5) {
return 42;
} else if(reqLevel >= 78) {
return Math.max((10413.648 * Math.exp(reqLevel * 0.03275)), 15);
} else if(reqLevel >= 38) {
return Math.max(( 4985.818 * Math.exp(reqLevel * 0.02007)), 15);

View File

@@ -210,6 +210,10 @@ public class GameConstants {
return skillId > 1111002 && skillId < 1111007 || skillId == 11111002 || skillId == 11111003;
}
public static boolean isMedalQuest(short questid) {
return questid / 100 == 299;
}
public static boolean hasSPTable(MapleJob job) {
switch (job) {
case EVAN:

View File

@@ -21,11 +21,13 @@
*/
package net.server.channel.handlers;
import java.awt.Point;
import client.MapleCharacter;
import client.MapleClient;
import net.AbstractMaplePacketHandler;
import scripting.quest.QuestScriptManager;
import server.quest.MapleQuest;
import server.life.MapleNPC;
import tools.data.input.SeekableLittleEndianAccessor;
/**
@@ -33,6 +35,31 @@ import tools.data.input.SeekableLittleEndianAccessor;
* @author Matze
*/
public final class QuestActionHandler extends AbstractMaplePacketHandler {
// credits to gabriel.sin
private static boolean isNpcNearby(SeekableLittleEndianAccessor slea, MapleCharacter player, MapleQuest quest, int npcId) {
Point playerP = null;
if(slea.available() >= 4) {
playerP = new Point(slea.readShort(), slea.readShort());
}
if (playerP != null && !quest.isAutoStart() && !quest.isAutoComplete()) {
MapleNPC npc = player.getMap().getNPCById(npcId);
if(npc == null) {
return false;
}
Point npcP = npc.getPosition();
if (Math.abs(npcP.getX() - playerP.getX()) > 1200 || Math.abs(npcP.getY() - playerP.getY()) > 800) {
player.dropMessage(5, "Approach the NPC to fulfill this quest operation.");
return false;
}
}
return true;
}
@Override
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
byte action = slea.readByte();
@@ -41,8 +68,8 @@ public final class QuestActionHandler extends AbstractMaplePacketHandler {
MapleQuest quest = MapleQuest.getInstance(questid);
if (action == 1) { //Start Quest
int npc = slea.readInt();
if (slea.available() >= 4) {
slea.readInt();
if(!isNpcNearby(slea, player, quest, npc)) {
return;
}
if(quest.canStart(player, npc)) {
@@ -50,7 +77,9 @@ public final class QuestActionHandler extends AbstractMaplePacketHandler {
}
} else if (action == 2) { // Complete Quest
int npc = slea.readInt();
slea.readInt();
if(!isNpcNearby(slea, player, quest, npc)) {
return;
}
if(quest.canComplete(player, npc)) {
if (slea.available() >= 2) {
@@ -64,14 +93,18 @@ public final class QuestActionHandler extends AbstractMaplePacketHandler {
quest.forfeit(player);
} else if (action == 4) { // scripted start quest
int npc = slea.readInt();
slea.readInt();
if(!isNpcNearby(slea, player, quest, npc)) {
return;
}
if(quest.canStart(player, npc)) {
QuestScriptManager.getInstance().start(c, questid, npc);
}
} else if (action == 5) { // scripted end quests
//System.out.println(slea.toString());
int npc = slea.readInt();
slea.readInt();
if(!isNpcNearby(slea, player, quest, npc)) {
return;
}
if(quest.canComplete(player, npc)) {
QuestScriptManager.getInstance().end(c, questid, npc);

View File

@@ -23,6 +23,7 @@ package scripting.quest;
import client.MapleClient;
import scripting.npc.NPCConversationManager;
import server.MapleItemInformationProvider;
import server.quest.MapleQuest;
/**
@@ -69,4 +70,9 @@ public class QuestActionManager extends NPCConversationManager {
public void completeQuest() {
forceCompleteQuest();
}
public String getMedalName() { // usable only for medal quests (id 299XX)
MapleQuest q = MapleQuest.getInstance(quest);
return MapleItemInformationProvider.getInstance().getName(q.getMedalRequirement());
}
}

View File

@@ -30,6 +30,7 @@ import javax.script.Invocable;
import scripting.AbstractScriptManager;
import server.quest.MapleQuest;
import tools.FilePrinter;
import constants.GameConstants;
import client.MapleClient;
import client.MapleQuestStatus;
@@ -45,40 +46,44 @@ public class QuestScriptManager extends AbstractScriptManager {
public synchronized static QuestScriptManager getInstance() {
return instance;
}
public void start(MapleClient c, short questid, int npc) {
MapleQuest quest = MapleQuest.getInstance(questid);
if (!c.getPlayer().getQuest(quest).getStatus().equals(MapleQuestStatus.Status.NOT_STARTED)) {
dispose(c);
return;
}
try {
QuestActionManager qm = new QuestActionManager(c, questid, npc, true);
if (qms.containsKey(c)) {
return;
}
if(c.canClickNPC()) {
qms.put(c, qm);
Invocable iv = getInvocable("quest/" + questid + ".js", c);
if (iv == null) {
FilePrinter.printError(FilePrinter.QUEST_UNCODED, "START Quest " + questid + " is uncoded.\r\n");
}
if (iv == null || QuestScriptManager.getInstance() == null) {
qm.dispose();
return;
}
engine.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);
}
MapleQuest quest = MapleQuest.getInstance(questid);
if (!quest.canStartWithoutRequirements(c.getPlayer())) {
dispose(c);
return;
}
try {
QuestActionManager qm = new QuestActionManager(c, questid, npc, true);
if (qms.containsKey(c)) {
return;
}
if(c.canClickNPC()) {
qms.put(c, qm);
Invocable iv = getInvocable("quest/" + questid + ".js", c);
if (iv == null) {
if(GameConstants.isMedalQuest(questid)) { // start generic medal quest
iv = getInvocable("quest/medalQuest.js", c);
} else {
FilePrinter.printError(FilePrinter.QUEST_UNCODED, "START Quest " + questid + " is uncoded.\r\n");
}
}
if (iv == null || QuestScriptManager.getInstance() == null) {
qm.dispose();
return;
}
engine.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) {
@@ -96,7 +101,7 @@ public class QuestScriptManager extends AbstractScriptManager {
}
}
}
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)) {
@@ -112,9 +117,13 @@ public class QuestScriptManager extends AbstractScriptManager {
qms.put(c, qm);
Invocable iv = getInvocable("quest/" + questid + ".js", c);
if (iv == null) {
FilePrinter.printError(FilePrinter.QUEST_UNCODED, "END Quest " + questid + " is uncoded.\r\n");
qm.dispose();
return;
if(GameConstants.isMedalQuest(questid)) { // start generic medal quest
iv = getInvocable("quest/medalQuest.js", c);
} else {
FilePrinter.printError(FilePrinter.QUEST_UNCODED, "END Quest " + questid + " is uncoded.\r\n");
qm.dispose();
return;
}
}
engine.put("qm", qm);
scripts.put(c, iv);

View File

@@ -955,14 +955,14 @@ public class MapleStatEffect {
MapleMonster monster = (MapleMonster) mo;
if (isDispel()) {
monster.debuffMob(skill_.getId());
} else {
if (makeChanceResult()) {
monster.applyStatus(applyfrom, new MonsterStatusEffect(getMonsterStati(), skill_, null, false), isPoison(), getDuration());
if (isCrash()) {
monster.debuffMob(skill_.getId());
}
}
}
} else {
if (makeChanceResult()) {
monster.applyStatus(applyfrom, new MonsterStatusEffect(getMonsterStati(), skill_, null, false), isPoison(), getDuration());
if (isCrash()) {
monster.debuffMob(skill_.getId());
}
}
}
i++;
if (i >= mobCount) {
break;

View File

@@ -1446,6 +1446,19 @@ public class MapleMap {
}
}
public MapleNPC getNPCById(int id) {
for (MapleMapObject obj : getMapObjects()) {
if (obj.getType() == MapleMapObjectType.NPC) {
MapleNPC npc = (MapleNPC) obj;
if (npc.getId() == id) {
return npc;
}
}
}
return null;
}
public boolean containsNPC(int npcid) {
if (npcid == 9000066) {
return true;

View File

@@ -23,6 +23,7 @@ package server.quest;
import java.io.File;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
@@ -30,6 +31,7 @@ import client.MapleCharacter;
import client.MapleQuestStatus;
import client.MapleQuestStatus.Status;
import java.util.EnumMap;
import java.util.Set;
import provider.MapleData;
import provider.MapleDataProvider;
import provider.MapleDataProviderFactory;
@@ -41,10 +43,21 @@ import tools.MaplePacketCreator;
/**
*
* @author Matze
* @author Ronan (support for medal quests)
*/
public class MapleQuest {
private static Map<Integer, MapleQuest> quests = new HashMap<>();
private static Map<Short, Integer> medals = new HashMap<>();
private static final Set<Short> exploitableQuests = new HashSet<>();
static {
exploitableQuests.add((short) 2338);
exploitableQuests.add((short) 3637);
exploitableQuests.add((short) 3714);
exploitableQuests.add((short) 21752);
}
protected short infoNumber, id;
protected int timeLimit, timeLimit2;
protected String infoex;
@@ -77,6 +90,9 @@ public class MapleQuest {
autoStart = MapleDataTool.getInt("autoStart", reqInfo, 0) == 1;
autoPreComplete = MapleDataTool.getInt("autoPreComplete", reqInfo, 0) == 1;
autoComplete = MapleDataTool.getInt("autoComplete", reqInfo, 0) == 1;
int medalid = MapleDataTool.getInt("viewMedalItem", reqInfo, 0);
if(medalid != 0) medals.put(this.id, medalid);
} else {
System.out.println("no data " + id);
}
@@ -209,8 +225,13 @@ public class MapleQuest {
return str.toString();
}
public boolean canStartWithoutRequirements(MapleCharacter c) {
MapleQuestStatus mqs = c.getQuest(this);
return !(mqs.getStatus() != Status.NOT_STARTED && !(mqs.getStatus() == Status.COMPLETED && repeatable));
}
public boolean canStart(MapleCharacter c, int npcid) {
if (c.getQuest(this).getStatus() != Status.NOT_STARTED && !(c.getQuest(this).getStatus() == Status.COMPLETED && repeatable)) {
if (!canStartWithoutRequirements(c)) {
return false;
}
for (MapleQuestRequirement r : startReqs.values()) {
@@ -229,7 +250,9 @@ public class MapleQuest {
return false;
}
for (MapleQuestRequirement r : completeReqs.values()) {
if (r == null || !r.check(c, npcid)) {
if (r == null) {
return false;
} else if(!r.check(c, npcid)) {
if(r.getType() == MapleQuestRequirementType.MESO) { // TODO: find a way to tell the client about the new MESO requirement type.
c.dropMessage(5, "You don't have enough mesos to complete this quest.");
}
@@ -263,10 +286,6 @@ public class MapleQuest {
}
}
if (timeLimit > 0) {
c.announce(MaplePacketCreator.removeQuestTimeLimit(id));
}
forceComplete(c, npc);
for (MapleQuestAction a : completeActs.values()) {
a.run(c, selection);
@@ -308,6 +327,10 @@ public class MapleQuest {
}
public boolean forceComplete(MapleCharacter c, int npc) {
if (timeLimit > 0) {
c.announce(MaplePacketCreator.removeQuestTimeLimit(id));
}
MapleQuestStatus newStatus = new MapleQuestStatus(this, MapleQuestStatus.Status.COMPLETED, npc);
newStatus.setForfeited(c.getQuest(this).getForfeited());
newStatus.setCompletionTime(System.currentTimeMillis());
@@ -431,6 +454,12 @@ public class MapleQuest {
case PET:
ret = new PetRequirement(this, data);
break;
case BUFF:
ret = new BuffRequirement(this, data);
break;
case EXCEPT_BUFF:
ret = new BuffExceptRequirement(this, data);
break;
case SCRIPT:
case NORMAL_AUTO_START:
case START:
@@ -480,7 +509,16 @@ public class MapleQuest {
}
return ret;
}
public static boolean isExploitableQuest(short questid) {
return exploitableQuests.contains(questid);
}
public int getMedalRequirement() {
Integer medalid = medals.get(id);
return medalid != null ? medalid : -1;
}
public static void loadAllQuest() {
questInfo = questData.getData("QuestInfo.img");
questReq = questData.getData("Check.img");

View File

@@ -26,7 +26,7 @@ package server.quest;
* @author Matze
*/
public enum MapleQuestRequirementType {
UNDEFINED(-1), JOB(0), ITEM(1), QUEST(2), MIN_LEVEL(3), MAX_LEVEL(4), END_DATE(5), MOB(6), NPC(7), FIELD_ENTER(8), INTERVAL(9), SCRIPT(10), PET(11), MIN_PET_TAMENESS(12), MONSTER_BOOK(13), NORMAL_AUTO_START(14), INFO_NUMBER(15), INFO_EX(16), COMPLETED_QUEST(17), START(18), END(19), DAY_BY_DAY(20), MESO(21);
UNDEFINED(-1), JOB(0), ITEM(1), QUEST(2), MIN_LEVEL(3), MAX_LEVEL(4), END_DATE(5), MOB(6), NPC(7), FIELD_ENTER(8), INTERVAL(9), SCRIPT(10), PET(11), MIN_PET_TAMENESS(12), MONSTER_BOOK(13), NORMAL_AUTO_START(14), INFO_NUMBER(15), INFO_EX(16), COMPLETED_QUEST(17), START(18), END(19), DAY_BY_DAY(20), MESO(21), BUFF(22), EXCEPT_BUFF(23);
final byte type;
private MapleQuestRequirementType(int type) {
@@ -77,13 +77,17 @@ public enum MapleQuestRequirementType {
} else if (name.equals("questComplete")) {
return COMPLETED_QUEST;
} else if(name.equals("start")) {
return START;
return START;
} else if(name.equals("end")) {
return END;
return END;
} else if(name.equals("daybyday")) {
return DAY_BY_DAY;
return DAY_BY_DAY;
} else if (name.equals("money")) {
return MESO;
} else if (name.equals("buff")) {
return BUFF;
} else if (name.equals("exceptbuff")) {
return EXCEPT_BUFF;
} else {
return UNDEFINED;
}

View File

@@ -39,7 +39,11 @@ public class BuffAction extends MapleQuestAction {
super(MapleQuestActionType.BUFF, quest);
processData(data);
}
@Override
public boolean check(MapleCharacter chr, Integer extSelection) {
return true;
}
@Override
public void processData(MapleData data) {

View File

@@ -0,0 +1,50 @@
/*
This file is part of the HeavenMS (MapleSolaxiaV2) MapleStory Server
Copyleft (L) 2017 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 server.quest.requirements;
import client.MapleCharacter;
import provider.MapleData;
import provider.MapleDataTool;
import server.quest.MapleQuest;
import server.quest.MapleQuestRequirementType;
/**
*
* @author Ronan
*/
public class BuffExceptRequirement extends MapleQuestRequirement {
private int buffId = -1;
public BuffExceptRequirement(MapleQuest quest, MapleData data) {
super(MapleQuestRequirementType.BUFF);
processData(data);
}
@Override
public void processData(MapleData data) {
// item buffs are negative
buffId = -1 * Integer.valueOf(MapleDataTool.getString(data));
}
@Override
public boolean check(MapleCharacter chr, Integer npcid) {
return !chr.hasBuffFromSourceid(buffId);
}
}

View File

@@ -0,0 +1,50 @@
/*
This file is part of the HeavenMS (MapleSolaxiaV2) MapleStory Server
Copyleft (L) 2017 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 server.quest.requirements;
import client.MapleCharacter;
import provider.MapleData;
import provider.MapleDataTool;
import server.quest.MapleQuest;
import server.quest.MapleQuestRequirementType;
/**
*
* @author Ronan
*/
public class BuffRequirement extends MapleQuestRequirement {
private int buffId = 1;
public BuffRequirement(MapleQuest quest, MapleData data) {
super(MapleQuestRequirementType.BUFF);
processData(data);
}
@Override
public void processData(MapleData data) {
// item buffs are negative
buffId = -1 * Integer.valueOf(MapleDataTool.getString(data));
}
@Override
public boolean check(MapleCharacter chr, Integer npcid) {
return chr.hasBuffFromSourceid(buffId);
}
}

View File

@@ -1458,7 +1458,7 @@ public class MaplePacketCreator {
* 14: Angry ^
* 15: Orb animation thing, ??
* 16: ??
* 19: Mushroom kingdom boss thing
* 19: Mushroom castle boss thing
*/
if (life.getParentMobOid() != 0) {