Merge pull request #33 from wejrox/Custom-rebirth-npc

Custom rebirth npc ID
This commit is contained in:
Ponk
2021-05-31 21:13:29 +02:00
committed by GitHub
8 changed files with 131 additions and 93 deletions

View File

@@ -319,6 +319,7 @@ server:
NAME_CHANGE_COOLDOWN: 2592000000 # (30*24*60*60*1000) Cooldown for name changes, default (GMS) is 30 days.
WORLD_TRANSFER_COOLDOWN: 2592000000 # (30*24*60*60*1000) Cooldown for world tranfers, default is same as name change (30 days).
INSTANT_NAME_CHANGE: false #Whether or not to wait for server restart to apply name changes. Does on reconnect otherwise (requires queries on every login).
REBIRTH_NPC_ID: 9010021 #ID of the NPC that should be replaced with the rebirth mechanic, if enabled.
#Dangling Items/Locks Configuration
ITEM_EXPIRE_TIME: 180000 # (3 * 60 * 1000) Time before items start disappearing. Recommended to be set up to 3 minutes.
@@ -460,3 +461,7 @@ server:
#Event End Timestamp
EVENT_END_TIMESTAMP: 1428897600000
#Any NPC ids that should search for a js override script (useful if they already have wz entries since otherwise they're ignored).
NPCS_SCRIPTABLE:
#9200000: Talk to Cody # Cody
9001105: Rescue Gaga! # Grandpa moon bunny

View File

@@ -21,48 +21,9 @@
*/
/* 9010021 - Wolf Spirit Ryko
@author Ronan
*/
var status;
@author wejrox
*/
function start() {
status = -1;
const YamlConfig = Java.type('config.YamlConfig');
if (!YamlConfig.config.server.USE_REBIRTH_SYSTEM) {
cm.sendOk("... I came from distant planes to assist the fight against the #rBlack Magician#k. Right now I search my master, have you seen him?");
cm.dispose();
return;
}
action(1, 0, 0);
}
function action(mode, type, selection) {
if (mode == 1) {
status++;
} else {
cm.dispose();
return;
}
if (status == 0) {
cm.sendNext("Come to me when you want to be reborn again. You currently have a total of #r" + cm.getChar().getReborns() + " #krebirths.");
} else if (status == 1) {
cm.sendSimple("What do you want me to do today: \r\n \r\n #L0##bI want to be rebirthed#l \r\n #L1##bMaybe next time#k#l");
} else if (status == 2) {
if (selection == 0) {
if (cm.getChar().getLevel() == 200) {
cm.sendYesNo("Are you sure you want to be rebirthed?");
} else {
cm.sendOk("You are not level 200, please come back when you hit level 200.");
cm.dispose();
}
} else if (selection == 1) {
cm.sendOk("Ok Bye")
cm.dispose();
}
} else if (status == 3 && type == 1) {
cm.getChar().executeReborn();
cm.sendOk("You have now been reborn. That's a total of #r" + cm.getChar().getReborns() + "#k rebirths");
cm.dispose();
}
cm.sendOk("... I came from distant planes to assist the fight against the #rBlack Magician#k. Right now I search my master, have you seen him?");
cm.dispose();
}

67
scripts/npc/rebirth.js Normal file
View File

@@ -0,0 +1,67 @@
/*
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/>.
*/
/* Rebirth NPC
@author Ronan
@author wejrox
*/
var status;
function start() {
status = -1;
const YamlConfig = Java.type('config.YamlConfig');
if (!YamlConfig.config.server.USE_REBIRTH_SYSTEM) {
cm.sendOk("Rebirths aren't enabled on this server, how did you get here?");
cm.dispose();
return;
}
action(1, 0, 0);
}
function action(mode, type, selection) {
if (mode === 1) {
status++;
} else {
cm.dispose();
return;
}
if (status === 0) {
cm.sendNext("Come to me when you want to be reborn again. You currently have a total of #r" + cm.getChar().getReborns() + " #krebirths.");
} else if (status === 1) {
cm.sendSimple("What do you want me to do today: \r\n \r\n #L0##bI want to be reborn!#l \r\n #L1##bNothing for now...#k#l");
} else if (status === 2) {
if (selection === 0) {
if (cm.getChar().getLevel() === 200) {
cm.sendYesNo("Are you sure you want to be reborn?");
} else {
cm.sendOk("You are not level 200, please come back when you hit level 200.");
cm.dispose();
}
} else if (selection === 1) {
cm.sendOk("See you soon!")
cm.dispose();
}
} else if (status === 3 && type === 1) {
cm.getChar().executeReborn();
cm.sendOk("You have now been reborn. That's a total of #r" + cm.getChar().getReborns() + "#k rebirths");
cm.dispose();
}
}

View File

@@ -1,5 +1,7 @@
package config;
import java.util.*;
public class ServerConfig {
//Thread Tracker Configuration
public boolean USE_THREAD_TRACKER;
@@ -163,6 +165,7 @@ public class ServerConfig {
public long NAME_CHANGE_COOLDOWN;
public long WORLD_TRANSFER_COOLDOWN=NAME_CHANGE_COOLDOWN;//Cooldown for world tranfers, default is same as name change (30 days).
public boolean INSTANT_NAME_CHANGE;
public int REBIRTH_NPC_ID;
//Dangling Items/Locks Configuration
public int ITEM_EXPIRE_TIME ;
@@ -304,4 +307,6 @@ public class ServerConfig {
//Event End Timestamp
public long EVENT_END_TIMESTAMP;
//Custom NPC overrides. List of NPC IDs.
public Map<String, String> NPCS_SCRIPTABLE = new HashMap<>();
}

View File

@@ -1,24 +0,0 @@
package constants.game;
/**
* @brief ScriptableNPCConstants
* @author GabrielSin <gabrielsin@playellin.net>
* @date 16/09/2018
*
* Adaptations to use Pair and Set, in order to suit a one-packet marshall.
* Adapted by Ronan
*/
import java.util.HashSet;
import java.util.Set;
import tools.Pair;
public class ScriptableNPCConstants {
public static final Set<Pair<Integer, String>> SCRIPTABLE_NPCS = new HashSet<Pair<Integer, String>>(){{
//add(new Pair<>(9200000, "Cody"));
add(new Pair<>(9001105, "Grandpa Moon Bunny"));
}};
}

View File

@@ -65,6 +65,8 @@ public final class NPCTalkHandler extends AbstractMaplePacketHandler {
NPCScriptManager.getInstance().start(c, npc.getId(), "gachapon", null);
} else if (npc.getName().endsWith("Maple TV")) {
NPCScriptManager.getInstance().start(c, npc.getId(), "mapleTV", null);
} else if (YamlConfig.config.server.USE_REBIRTH_SYSTEM && npc.getId() == YamlConfig.config.server.REBIRTH_NPC_ID) {
NPCScriptManager.getInstance().start(c, npc.getId(), "rebirth", null);
} else {
boolean hasNpcScript = NPCScriptManager.getInstance().start(c, npc.getId(), oid, null);
if (!hasNpcScript) {

View File

@@ -26,7 +26,6 @@ import client.inventory.*;
import client.keybind.MapleKeyBinding;
import config.YamlConfig;
import constants.game.GameConstants;
import constants.game.ScriptableNPCConstants;
import net.AbstractMaplePacketHandler;
import net.server.PlayerBuffValueHolder;
import net.server.Server;
@@ -55,6 +54,7 @@ import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.*;
import java.util.Map.Entry;
import java.util.stream.Collectors;
public final class PlayerLoggedinHandler extends AbstractMaplePacketHandler {
@@ -407,9 +407,23 @@ public final class PlayerLoggedinHandler extends AbstractMaplePacketHandler {
eim.registerPlayer(player);
}
}
// Tell the client to use the custom scripts available for the NPCs provided, instead of the WZ entries.
if (YamlConfig.config.server.USE_NPCS_SCRIPTABLE) {
c.announce(MaplePacketCreator.setNPCScriptable(ScriptableNPCConstants.SCRIPTABLE_NPCS));
// Create a copy to prevent always adding entries to the server's list.
Map<Integer, String> npcsIds = YamlConfig.config.server.NPCS_SCRIPTABLE
.entrySet().stream().collect(Collectors.toMap(
entry -> Integer.parseInt(entry.getKey()),
Entry::getValue
));
// Any npc be specified as the rebirth npc. Allow the npc to use custom scripts explicitly.
if (YamlConfig.config.server.USE_REBIRTH_SYSTEM) {
npcsIds.put(YamlConfig.config.server.REBIRTH_NPC_ID, "Rebirth");
}
c.announce(MaplePacketCreator.setNPCScriptable(npcsIds));
}
if(newcomer) player.setLoginTime(System.currentTimeMillis());

View File

@@ -8327,17 +8327,25 @@ public class MaplePacketCreator {
mplew.writeInt(transition);
return mplew.getPacket();
}
public static byte[] setNPCScriptable(Set<Pair<Integer, String>> scriptNpcDescriptions) { // thanks to GabrielSin
/**
* Makes the NPCs provided set as scriptable, informing the client to search for js scripts for these NPCs even
* if they already have entries within the wz files.
*
* @param scriptableNpcIds Ids of npcs to enable scripts for.
* @return a packet which makes the npc's provided scriptable.
*/
public static byte[] setNPCScriptable(Map<Integer, String> scriptableNpcIds) { // thanks to GabrielSin
MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
mplew.writeShort(SendOpcode.SET_NPC_SCRIPTABLE.getValue());
mplew.write(scriptNpcDescriptions.size());
for (Pair<Integer, String> p : scriptNpcDescriptions) {
mplew.writeInt(p.getLeft());
mplew.writeMapleAsciiString(p.getRight());
mplew.write(scriptableNpcIds.size());
scriptableNpcIds.forEach((id, name) -> {
mplew.writeInt(id);
// The client needs a name for the npc conversation, which is displayed under etc when the npc has a quest available.
mplew.writeMapleAsciiString(name);
mplew.writeInt(0); // start time
mplew.writeInt(Integer.MAX_VALUE); // end time
}
});
return mplew.getPacket();
}
@@ -8383,17 +8391,17 @@ public class MaplePacketCreator {
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
mplew.writeShort(SendOpcode.TOURNAMENT_SET_PRIZE.getValue());
//0 = "You have failed the set the prize. Please check the item number again."
//1 = "You have successfully set the prize."
mplew.write(bSetPrize);
mplew.write(bHasPrize);
if(bHasPrize != 0)
{
mplew.writeInt(nItemID1);
mplew.writeInt(nItemID2);
}
//0 = "You have failed the set the prize. Please check the item number again."
//1 = "You have successfully set the prize."
mplew.write(bSetPrize);
mplew.write(bHasPrize);
if(bHasPrize != 0)
{
mplew.writeInt(nItemID1);
mplew.writeInt(nItemID2);
}
return mplew.getPacket();
}
@@ -8402,11 +8410,11 @@ public class MaplePacketCreator {
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
mplew.writeShort(SendOpcode.TOURNAMENT_UEW.getValue());
//Is this a bitflag o.o ?
//2 = "You have reached the finals by default."
//4 = "You have reached the semifinals by default."
//8 or 16 = "You have reached the round of %n by default." | Encodes nState as %n ?!
mplew.write(nState);
//Is this a bitflag o.o ?
//2 = "You have reached the finals by default."
//4 = "You have reached the semifinals by default."
//8 or 16 = "You have reached the round of %n by default." | Encodes nState as %n ?!
mplew.write(nState);
return mplew.getPacket();
}