Player/NPC Shop patch + Fredrick/Duey patch + Loot w. time GMS-like

Reading approximated unitPrice value from WZ in such a fashion that the new double value can be represented in float point without losing too much data.
Fixed rechargeables with quantity 0 set on the playershop/hiredmerchant being handed back to the owner with quantity 1.
Solved many concurrecy issues related with items on the field and playershop/hiredmerchant.
Fixed anomalies with waiting time before picking up other players items, now acting GMS-like.
Added/patched copyleft claims in files that are from my own authorship. Please see backtrack_licenses/readme.txt for more info about this move.
Fixed issues with item retrieval when using bundles on playershop/hiredmerchant.
Fixed some exploits with playershop/hiredmerchant.
Fixed a glitch with npcshop when trying to recharge/buy items without having enough mesos.
Added portal sound effect for some scripted portals that still lacked it.
Fixed some exploits with NPCs Fredrick and Duey.
Fixed Body Pressure not displaying damage to other players.
Added a flag that permits town scrolls to act like a "banish" for players. This renders the antibanish scroll effect available.
This commit is contained in:
ronancpl
2018-05-10 13:09:57 -03:00
parent 727dfb2d62
commit 80b1776ad3
348 changed files with 3963 additions and 1597 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 505 KiB

View File

@@ -0,0 +1,3 @@
Change reason: New NPC files uploaded in with misleading header.
Committed 2017-09-01 (Reworked Autoassigner & Hero's Will & Trade + Visual NX + New commands)

View File

@@ -0,0 +1,5 @@
Change reason: New NPC files uploaded in with misleading/missing header.
9000017.js: Introduced before repository started, around 2015-08-05 (extracted from mychanges_ptbr.txt @ "source" commit)
9000036.js: Introduced before repository started, around 2015-07-25 (extracted from mychanges_ptbr.txt @ "source" commit)
9000041.js: Committed 2016-07-18 (Instant sell NPC + new features)

View File

@@ -0,0 +1,281 @@
/*
* 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 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/>.
*/
/**
* @author: Ronan
* @event: Sharenian Guild PQ
*/
var isPq = true;
var minPlayers = 1, maxPlayers = 30;
var minLevel = 1, maxLevel = 200;
var entryMap = 990000000;
var exitMap = 990001100;
var recruitMap = 101030104;
var clearMap = 990001101;
var minMapId = 990000000;
var maxMapId = 990001101;
var waitTime = 3;
var eventTime = 90; // 90 minutes
var lobbyRange = [0, 0];
function init() {
setEventRequirements();
}
function setLobbyRange() {
return lobbyRange;
}
function setEventRequirements() {
var reqStr = "";
reqStr += "\r\n Number of players: ";
if(maxPlayers - minPlayers >= 1) reqStr += minPlayers + " ~ " + maxPlayers;
else reqStr += minPlayers;
reqStr += "\r\n Level range: ";
if(maxLevel - minLevel >= 1) reqStr += minLevel + " ~ " + maxLevel;
else reqStr += minLevel;
reqStr += "\r\n Time limit: ";
reqStr += eventTime + " minutes";
em.setProperty("party", reqStr);
}
function setEventExclusives(eim) {
var itemSet = [1032033, 4001024, 4001025, 4001026, 4001027, 4001028, 4001029, 4001030, 4001031, 4001032, 4001033, 4001034, 4001035, 4001037];
eim.setExclusiveItems(itemSet);
}
function setEventRewards(eim) {
var itemSet, itemQty, evLevel, expStages;
evLevel = 1; //Rewards at clear PQ
itemSet = [];
itemQty = [];
eim.setEventRewards(evLevel, itemSet, itemQty);
expStages = []; //bonus exp given on CLEAR stage signal
eim.setEventClearStageExp(expStages);
}
function getEligibleParty(party) { //selects, from the given party, the team that is allowed to attempt this event
var eligible = [];
var hasLeader = false;
var guildId = 0;
if(party.size() > 0) {
var partyList = party.toArray();
for(var i = 0; i < party.size(); i++) {
var ch = partyList[i];
if(ch.isLeader()) {
guildId = ch.getGuildId();
break;
}
}
for(var i = 0; i < party.size(); i++) {
var ch = partyList[i];
if(ch.getMapId() == recruitMap && ch.getLevel() >= minLevel && ch.getLevel() <= maxLevel && ch.getGuildId() == guildId) {
if(ch.isLeader()) hasLeader = true;
eligible.push(ch);
}
}
}
if(!(hasLeader)) eligible = [];
return eligible;
}
function setup(level, lobbyid) {
var eim = em.newInstance("Guild" + lobbyid);
eim.setProperty("level", level);
eim.setProperty("guild", 0);
eim.setProperty("canJoin", 1);
eim.setProperty("statusStg1", -1);
eim.getInstanceMap(990000000).resetPQ(level);
eim.getInstanceMap(990000100).resetPQ(level);
eim.getInstanceMap(990000200).resetPQ(level);
eim.getInstanceMap(990000300).resetPQ(level);
eim.getInstanceMap(990000301).resetPQ(level);
eim.getInstanceMap(990000400).resetPQ(level);
eim.getInstanceMap(990000401).resetPQ(level);
eim.getInstanceMap(990000410).resetPQ(level);
eim.getInstanceMap(990000420).resetPQ(level);
eim.getInstanceMap(990000430).resetPQ(level);
eim.getInstanceMap(990000431).resetPQ(level);
eim.getInstanceMap(990000440).resetPQ(level);
eim.getInstanceMap(990000500).resetPQ(level);
eim.getInstanceMap(990000501).resetPQ(level);
eim.getInstanceMap(990000502).resetPQ(level);
eim.getInstanceMap(990000600).resetPQ(level);
eim.getInstanceMap(990000610).resetPQ(level);
eim.getInstanceMap(990000611).resetPQ(level);
eim.getInstanceMap(990000620).resetPQ(level);
eim.getInstanceMap(990000630).resetPQ(level);
eim.getInstanceMap(990000631).resetPQ(level);
eim.getInstanceMap(990000640).resetPQ(level);
eim.getInstanceMap(990000641).resetPQ(level);
eim.getInstanceMap(990000700).resetPQ(level);
eim.getInstanceMap(990000800).resetPQ(level);
eim.getInstanceMap(990000900).resetPQ(level);
eim.getInstanceMap(990001000).resetPQ(level);
eim.getInstanceMap(990001100).resetPQ(level);
eim.getInstanceMap(990001101).resetPQ(level);
respawnStages(eim);
var ts = Date.now();
ts += (60000 * waitTime);
eim.setProperty("entryTimestamp", "" + ts);
eim.startEventTimer(waitTime * 60000);
setEventRewards(eim);
setEventExclusives(eim);
return eim;
}
/*
function isTeamAllJobs(eim) {
var eventJobs = eim.getEventPlayersJobs();
var rangeJobs = parseInt('111110', 2);
return ((eventJobs & rangeJobs) == rangeJobs);
}
*/
function afterSetup(eim) {
eim.setProperty("guild", "" + eim.getLeader().getGuildId());
}
function respawnStages(eim) {}
function playerEntry(eim, player) {
var map = eim.getMapInstance(entryMap);
player.changeMap(map, map.getPortal(0));
var texttt = "So, here is the brief. You guys should be warned that, once out on the fortress outskirts, anyone that would not be equipping the #b#t1032033##k will die instantly due to the deteriorated state of the air around there. That being said, once your team move out to the next stage, make sure to #bhit the glowing rocks#k in that region and #bequip the dropped item#k before advancing stages. That will protect you thoroughly from the air sickness. Good luck!";
player.getClient().getSession().write(Packages.tools.MaplePacketCreator.getNPCTalk(9040000, /*(byte)*/ 0, texttt, "00 00", /*(byte)*/ 0));
}
function scheduledTimeout(eim) {
if(eim.getIntProperty("canJoin") == 1) {
eim.setProperty("canJoin", 0);
if(eim.checkEventTeamLacking(true, minPlayers)) {
end(eim);
} else {
eim.startEventTimer(eventTime * 60000);
}
} else {
end(eim);
}
}
function playerUnregistered(eim, player) {}
function playerExit(eim, player) {
eim.unregisterPlayer(player);
player.changeMap(exitMap, 0);
}
function changedMap(eim, player, mapid) {
if (mapid < minMapId || mapid > maxMapId) {
if (eim.isEventTeamLackingNow(true, minPlayers, player) && eim.getIntProperty("canJoin") == 0) {
eim.unregisterPlayer(player);
end(eim);
}
else
eim.unregisterPlayer(player);
}
}
function changedLeader(eim, leader) {}
function playerDead(eim, player) {}
function playerRevive(eim, player) { // player presses ok on the death pop up.
if (eim.isEventTeamLackingNow(true, minPlayers, player) && eim.getIntProperty("canJoin") == 0) {
eim.unregisterPlayer(player);
end(eim);
}
else
eim.unregisterPlayer(player);
}
function playerDisconnected(eim, player) {
if (eim.isEventTeamLackingNow(true, minPlayers, player) && eim.getIntProperty("canJoin") == 0) {
eim.unregisterPlayer(player);
end(eim);
}
else
eim.unregisterPlayer(player);
}
function leftParty(eim, player) {}
function disbandParty(eim) {
end(eim);
}
function monsterValue(eim, mobId) {
return 1;
}
function end(eim) {
var party = eim.getPlayers();
for (var i = 0; i < party.size(); i++) {
playerExit(eim, party.get(i));
}
eim.dispose();
}
function giveRandomEventReward(eim, player) {
eim.giveEventReward(player);
}
function clearPQ(eim) {
eim.stopEventTimer();
eim.setEventCleared();
}
function monsterKilled(mob, eim) {}
function allMonstersDead(eim) {}
function cancelSchedule() {}
function dispose(eim) {
em.schedule("reopenGuildQuest", em.getLobbyDelay() * 1.5 * 1000);
}
function reopenGuildQuest() {
em.attemptStartGuildInstance();
}

View File

@@ -0,0 +1,208 @@
/*
* 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 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/>.
*/
/*
* @Author Lerk
*
* Guild Quest
*/
var exitMap;
var waitingListCurrent = 0;
importPackage(Packages.world);
importPackage(Packages.client);
importPackage(Packages.server.maps);
importPackage(java.lang);
function init() {
em.setProperty("shuffleReactors","false");
em.setProperty("canEnter", "true");
em.setProperty("gpqOpen", "true");
}
function monsterValue(eim, mobId) { //should only trigger on ergoth
if (mobId == 9300028) { //but, just to be safe...
var rubian = new Packages.client.inventory.Item(4001024, 0, 1);
var map = eim.getMapInstance(990000900);
var reactor = map.getReactorByName("boss");
map.spawnItemDrop(reactor, eim.getPlayers().get(0), rubian, reactor.getPosition(), true, false);
}
return -1;
}
function setup(eim) {
exitMap = em.getChannelServer().getMapFactory().getMap(990001100); //returning path
//shuffle reactors in two maps for stage 3
eim.getMapInstance(990000501).shuffleReactors();
eim.getMapInstance(990000502).shuffleReactors();
//force no-respawn on certain map reactors
eim.getMapInstance(990000611).getReactorByName("").setDelay(-1);
eim.getMapInstance(990000620).getReactorByName("").setDelay(-1);
eim.getMapInstance(990000631).getReactorByName("").setDelay(-1);
eim.getMapInstance(990000641).getReactorByName("").setDelay(-1);
//activate three minutes after start
eim.setProperty("entryTimestamp", Packages.java.lang.System.currentTimeMillis());
eim.setProperty("canEnter","true");
eim.schedule("begin", 60000);
eim.startEventTimer(60000);
}
function begin(eim) {
eim.setProperty("canEnter","false");
var party = eim.getPlayers();
//if (party.size() < 6) { //not enough to start
// end(eim,"There are no longer enough players to continue, and those remaining shall be warped out.");
//} else {
var iter = party.iterator();
while (iter.hasNext()) {
iter.next().dropMessage(6,"The quest has begun.");
}
eim.startEventTimer(1000 * 60 * 90);
eim.schedule("timeOut", 1000 * 60 * 90);
//}
}
function timeOut(eim) {
end(eim, "Your allotted time to finish the quest has passed.");
}
function playerEntry(eim, player) {
var map = eim.getMapInstance(990000000);
player.changeMap(map, map.getPortal(0));
}
function playerRevive(eim, player) {
var returnMap = 990000200;
if (eim.getProperty("canEnter").equals("true")) {
returnMap = 990000000;
}
player.setHp(50);
player.setStance(0);
player.changeMap(eim.getMapInstance(returnMap), eim.getMapInstance(returnMap).getPortal(0));
return false;
}
function playerDead(eim, player) {
}
function playerDisconnected(eim, player) {
var party = eim.getPlayers();
if (player.getName().equals(eim.getProperty("leader"))) { //check for party leader
//boot all players and end
var iter = party.iterator();
while (iter.hasNext()) {
var pl = iter.next();
pl.dropMessage(6,"The leader of the instance has disconnected, and the remaining players shall be warped out.");
if (pl.equals(player)) {
removePlayer(eim, pl);
}
else {
eim.unregisterPlayer(pl);
pl.changeMap(exitMap, exitMap.getPortal(0));
}
}
eim.dispose();
}
else { //boot d/ced player and check if enough players left
removePlayer(eim, player);
if (party.size() < 6) { //five after player booted
end(eim,"There are no longer enough players to continue, and those remaining shall be warped out.");
}
}
}
function leftParty(eim, player) { //ignore for GQ
}
function disbandParty(eim) { //ignore for GQ
}
function playerExit(eim, player) {
eim.unregisterPlayer(player);
player.changeMap(exitMap, exitMap.getPortal(0));
var party = eim.getPlayers();
if (party.size() < 6) { //five after player booted
end(eim,"There are no longer enough players to continue, and those remaining shall be warped out.");
}
}
function end(eim, msg) {
var iter = eim.getPlayers().iterator();
while (iter.hasNext()) {
var player = iter.next();
player.dropMessage(6,msg);
eim.unregisterPlayer(player);
player.changeMap(exitMap, exitMap.getPortal(0));
}
eim.dispose();
}
//for offline players
function removePlayer(eim, player) {
eim.unregisterPlayer(player);
player.getMap().removePlayer(player);
player.setMap(exitMap);
}
function clearPQ(eim) {
var iter = eim.getPlayers().iterator();
var bonusMap = eim.getMapInstance(990001000);
eim.startEventTimer(40000);
while (iter.hasNext()) {
var player = iter.next();
player.changeMap(bonusMap, bonusMap.getPortal(0));
}
eim.schedule("finish", 40000)
}
function finish(eim) {
var iter = eim.getPlayers().iterator();
while (iter.hasNext()) {
var player = iter.next();
eim.unregisterPlayer(player);
player.changeMap(exitMap, exitMap.getPortal(0));
}
eim.dispose();
}
function allMonstersDead(eim) {
//do nothing; GQ has nothing to do with monster killing
}
function cancelSchedule() {
}
function dispose(eim) {
em.schedule("openGPQ", 5000);
}
function openGPQ() {
em.setProperty("gpqOpen", "true");
}
function timeOut() {
}

View File

@@ -0,0 +1,3 @@
Change reason: Rewrote script file as a whole, now using methods suitable for the server's improved EventManager (queue system and such).
Committed 2017-06-13 (GuildPQ Queue system + revamped Warp mechanic)

View File

@@ -0,0 +1,14 @@
[COMMIT 198]
Licenses for the following files are being changed due to misleading authorship:
- CafePQ NPCs: those NPC script files were not around on OdinMS server, neither before HeavenMS.
- GuildQuest.js: that event script file was completely rewritten to suit well the underlying EIM of HeavenMS.
- Custom NPCs 9000017, 9000036, 9000041: those NPC script files were not around on OdinMS server, neither on Solaxia.
Original dates are summarized on the subfolders, for steadfast conference.
Licenses for the following files are being added:
- Several PQs and boss battles: those event scripts are authored by myself, all following similar pattern and using
common functions introduced on this server (such as getEligibleParty, startEventTimer or isEventTeamLackingNow).
I am expecting no infringements from this action, should any issues arise contact me asap.

View File

@@ -1,8 +1,8 @@
#**HeavenMS _(MapleSolaxiaV2)_**
#**HeavenMS**
Credits:
Ronan - Developer
Ronan - Head Developer
Vcoc - Freelance Developer
@@ -51,6 +51,7 @@ Player Social Network:
* Beginners can create and join a "beginner-only" party (characters up to level 10).
* Enhanced synchronization on Player Shops and Hired Merchants. Transactions made are instantly informed to the owner.
* Game minirooms such as match cards and omok now has semi-functional password system.
* Item pickup cooldown on non-owned/non-partyowned items functional.
Cash & Items:
@@ -158,5 +159,7 @@ Localhost:
* Removed the 'n' problem within NPC dialog.
* Removed caps for MATK, WDEF, MDEF, ACC and AVOID.
* Removed "AP excess" popup and "Admin/MWLB" action block, original credits to kevintjuh93.
* Removed "You've gained a level!" popup, original credits to PrinceReborn.
---------------------------

View File

@@ -1,6 +1,6 @@
========== HeavenMS ==========
Credits:
Ronan - Freelance Developer
Ronan - Head Developer
Vcoc - Freelance Developer
---------------------------
@@ -8,18 +8,20 @@ Known issues:
- Everytime two people click on an npc at the same time, one of them dcs and the other needs to @dispose to talk to the npc.
- If multiple people hit boxes/reactors at the same time, they both dc with invalid pointer error.
- Passwords on minirooms are not encoded for players entering/logging into the map.
- Some criticals (e.g. from Aran skills) will not show up as crit for other players.
- Deadlocks may start appearing if the server stays online long enough with many players logged in.
---------------------------
---------------------------
Missing features list:
- Miniroom tooltips (such as number of players in store/host awaiting game) not showing up properly.
- Disease POISON appears MISSES to other players.
---------------------------
---------------------------
** Others **
- Marriage
- Family system
---------------------------
@@ -44,7 +46,7 @@ Missing features list:
---------------------------
** Skills **
Check autoban system
- Check autoban system
---------------------------

View File

@@ -919,4 +919,23 @@ Adicionado efeito visual relacionado ao map chair skill sendo usado por um jogad
Status de diseases agora são visíveis para outros jogadores, mesmo trocando de mapas.
Dano de poison agora é visível para outros jogadores.
Corrigido preço contabilizado incorretamente para itens recarregáveis.
Corrigido recarregáveis com quantidade zero não sendo vendidos pelo NPC shop.
Corrigido recarregáveis com quantidade zero não sendo vendidos pelo NPC shop.
03 - 07 Maio 2018,
Modificado unitPrice para aproximar o valor do WZ, de forma que possa ser representado num ponto flutuante sem perda de dados.
Corrigido rechargeables com quantidade 0 colocados no player shop/hired merchant retornando ao dono ou ao comprador com quantidade 1.
Resolvido vários problemas de acesso concorrente com itens no mapa.
Corrigido anomalias com tempo de espera para pegar drops de outros jogadores, agora atuando de forma mais parecida com o GMS-like.
Adicionado/corrigido direitos de copyleft em arquivos de PQs de minha própria autoria.
Revisto acesso concorrente com módulos de playershop/hiredmerchant.
Corrigido problemas com recuperação de itens quando usando bundles em playershop/hiredmerchant.
Corrigido alguns exploits com playershop/hiredmerchant.
Corrigido mensagem de falta de meso numa sessão de compra/venda com NPC travando novas transações naquela sessão.
Corrigido tempo de espera para pegar drops de outros jogadores sempre que se muda de mapa.
Adicionado efeito sonoro para alguns portais scriptados que ainda não o tinham implementado.
Corrigido alguns exploits envolvendo acesso em rajada com NPC Fredrick e Duey.
Corrigido Body Pressure não mostrando valor de dano para outros jogadores.
Adicionado flag que permite town scrolls atuarem como se fossem "player banishes", permitindo ativação do antibanish scroll.
09 Maio 2018,
Corrigido autopot handler consumindo mais pots que o necessário para pots com ganhos percentuais.