Fixed quest rewarding + Lethal attacks in Dojo
Fixed quests not giving items in some cases, lethal damages rendering dojo uncompletable and added new scripts.
This commit is contained in:
@@ -132,3 +132,9 @@ Corre
|
||||
06 Abril 2017,
|
||||
Tentativa de correção em casos de falta de respawn em certas areas do jogo.
|
||||
Otimização de funções que lidam com popular ou despopular areas.
|
||||
|
||||
07 Abril 2017,
|
||||
Correção nos métodos que completam quests, que não atribuíam corretamente itens que dependem de jobs.
|
||||
Agora é possível variar atributos de mobs a serem spawnados (classes ChangeableStats, OverrideStats).
|
||||
Removido ataques letais (1HP/1MP) de bosses em Dojo, que tornava impossível a completude do mesmo.
|
||||
Adição de novos scripts de evento no jogo.
|
||||
@@ -2,16 +2,6 @@
|
||||
<project-private xmlns="http://www.netbeans.org/ns/project-private/1">
|
||||
<editor-bookmarks xmlns="http://www.netbeans.org/ns/editor-bookmarks/2" lastBookmarkId="0"/>
|
||||
<open-files xmlns="http://www.netbeans.org/ns/projectui-open-files/2">
|
||||
<group>
|
||||
<file>file:/C:/Nexon/MapleSolaxia/src/scripting/event/EventManager.java</file>
|
||||
<file>file:/C:/Nexon/MapleSolaxia/scripts/npc/world0/2012001.js</file>
|
||||
<file>file:/C:/Nexon/MapleSolaxia/src/net/SendOpcode.java</file>
|
||||
<file>file:/C:/Nexon/MapleSolaxia/src/server/life/SpawnPoint.java</file>
|
||||
<file>file:/C:/Nexon/MapleSolaxia/scripts/npc/world0/2012002.js</file>
|
||||
<file>file:/C:/Nexon/MapleSolaxia/src/server/maps/MapleMapFactory.java</file>
|
||||
<file>file:/C:/Nexon/MapleSolaxia/src/tools/MaplePacketCreator.java</file>
|
||||
<file>file:/C:/Nexon/MapleSolaxia/scripts/event/Boats.js</file>
|
||||
<file>file:/C:/Nexon/MapleSolaxia/src/server/maps/MapleMap.java</file>
|
||||
</group>
|
||||
<group/>
|
||||
</open-files>
|
||||
</project-private>
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
function init() {
|
||||
// After loading, ChannelServer
|
||||
}
|
||||
|
||||
function setup(eim, leaderid) {
|
||||
// Setup the instance when invoked, EG : start PQ
|
||||
}
|
||||
|
||||
function playerEntry(eim, player) {
|
||||
// Warp player in etc..
|
||||
}
|
||||
|
||||
function changedMap(eim, player, mapid) {
|
||||
// What to do when player've changed map, based on the mapid
|
||||
}
|
||||
|
||||
function scheduledTimeout(eim) {
|
||||
// When event timeout..
|
||||
|
||||
// restartEventTimer(long time)
|
||||
// stopEventTimer()
|
||||
// startEventTimer(long time)
|
||||
// isTimerStarted()
|
||||
}
|
||||
|
||||
function allMonstersDead(eim) {
|
||||
// When invoking unregisterMonster(MapleMonster mob) OR killed
|
||||
// Happens only when size = 0
|
||||
}
|
||||
|
||||
function playerDead(eim, player) {
|
||||
// Happens when player dies
|
||||
}
|
||||
|
||||
function playerRevive(eim, player) {
|
||||
// Happens when player's revived.
|
||||
// @Param : returns true/false
|
||||
}
|
||||
|
||||
function playerDisconnected(eim, player) {
|
||||
// return 0 - Deregister player normally + Dispose instance if there are zero player left
|
||||
// return x that is > 0 - Deregister player normally + Dispose instance if there x player or below
|
||||
// return x that is < 0 - Deregister player normally + Dispose instance if there x player or below, if it's leader = boot all
|
||||
}
|
||||
|
||||
function monsterValue(eim, mobid) {
|
||||
// Invoked when a monster that's registered has been killed
|
||||
// return x amount for this player - "Saved Points"
|
||||
}
|
||||
|
||||
function leftParty(eim, player) {
|
||||
// Happens when a player left the party
|
||||
}
|
||||
|
||||
function disbandParty(eim, player) {
|
||||
// Happens when the party is disbanded by the leader.
|
||||
}
|
||||
|
||||
function clearPQ(eim) {
|
||||
// Happens when the function EventInstanceManager.finishPQ() is invoked by NPC/Reactor script
|
||||
}
|
||||
|
||||
function removePlayer(eim, player) {
|
||||
// Happens when the funtion NPCConversationalManager.removePlayerFromInstance() is invoked
|
||||
}
|
||||
|
||||
function registerCarnivalParty(eim, carnivalparty) {
|
||||
// Happens when carnival PQ is started. - Unused for now.
|
||||
}
|
||||
|
||||
function onMapLoad(eim, player) {
|
||||
// Happens when player change map - Unused for now.
|
||||
}
|
||||
|
||||
function cancelSchedule() {
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* 4th Job Snipe / Concentration
|
||||
*/
|
||||
|
||||
function init() {
|
||||
em.setProperty("started", "false");
|
||||
}
|
||||
|
||||
function monsterValue(eim, mobId) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
function setup() {
|
||||
var eim = em.newInstance("s4aWorld");
|
||||
|
||||
eim.setInstanceMap(910500000).resetFully();
|
||||
eim.startEventTimer(1200000);
|
||||
|
||||
em.setProperty("started", "true");
|
||||
|
||||
return eim;
|
||||
}
|
||||
|
||||
function playerEntry(eim, player) {
|
||||
var map = eim.getMapFactory().getMap(910500000);
|
||||
player.changeMap(map, map.getPortal(0));
|
||||
}
|
||||
|
||||
function playerDead(eim, player) {
|
||||
}
|
||||
|
||||
function playerRevive(eim, player) {
|
||||
}
|
||||
|
||||
function scheduledTimeout(eim) {
|
||||
eim.disposeIfPlayerBelow(100, 105090200);
|
||||
|
||||
em.setProperty("started", "false");
|
||||
}
|
||||
|
||||
function changedMap(eim, player, mapid) {
|
||||
if (mapid != 910500000) {
|
||||
eim.unregisterPlayer(player);
|
||||
|
||||
if (eim.disposeIfPlayerBelow(0, 0)) {
|
||||
em.setProperty("started", "false");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function playerDisconnected(eim, player) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
function leftParty(eim, player) {
|
||||
// If only 2 players are left, uncompletable:
|
||||
playerExit(eim, player);
|
||||
}
|
||||
|
||||
function disbandParty(eim) {
|
||||
//boot whole party and end
|
||||
eim.disposeIfPlayerBelow(100, 105090200);
|
||||
|
||||
em.setProperty("started", "false");
|
||||
}
|
||||
|
||||
function playerExit(eim, player) {
|
||||
eim.unregisterPlayer(player);
|
||||
var map = eim.getMapFactory().getMap(105090200);
|
||||
player.changeMap(map, map.getPortal(0));
|
||||
}
|
||||
|
||||
function clearPQ(eim) {
|
||||
eim.disposeIfPlayerBelow(100, 105090200);
|
||||
|
||||
em.setProperty("started", "false");
|
||||
}
|
||||
|
||||
function allMonstersDead(eim) {
|
||||
//has nothing to do with monster killing
|
||||
}
|
||||
|
||||
function cancelSchedule() {
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
NPC Name: Insiginificant Being
|
||||
Map(s): Dungeon : Another Entrance
|
||||
Description: Takes you to another Dimension
|
||||
*/
|
||||
|
||||
function start() {
|
||||
if (cm.getQuestStatus(6108) == 1) {
|
||||
var ret = checkJob();
|
||||
if (ret == -1) {
|
||||
cm.sendOk("Please form a party and talk to me again.");
|
||||
} else if (ret == 0) {
|
||||
cm.sendOk("Please make sure that your party is a size of 2.");
|
||||
} else if (ret == 1) {
|
||||
cm.sendOk("One of your party member's job is not eligible for entering the other world.");
|
||||
} else if (ret == 2) {
|
||||
cm.sendOk("One of your party member's level is not eligible for entering the other world.");
|
||||
} else {
|
||||
var em = cm.getEventManager("s4aWorld");
|
||||
if (em == null) {
|
||||
cm.sendOk("You're not allowed to enter with unknown reason. Try again." );
|
||||
} else if (em.getProperty("started").equals("true")) {
|
||||
cm.sendOk("Someone else is already attempting to defeat the Jr.Balrog in another world." );
|
||||
} else {
|
||||
em.startInstance(cm.getParty(), cm.getMap());
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
cm.sendOk("You're not allowed to enter the other world with unknown reason.");
|
||||
}
|
||||
|
||||
cm.dispose();
|
||||
}
|
||||
|
||||
function action(mode, type, selection) {
|
||||
}
|
||||
|
||||
function checkJob() {
|
||||
var party = cm.getParty();
|
||||
|
||||
if (party == null) {
|
||||
return -1;
|
||||
}
|
||||
// if (party.getMembers().size() != 2) {
|
||||
// return 0;
|
||||
// }
|
||||
var it = party.getMembers().iterator();
|
||||
|
||||
while (it.hasNext()) {
|
||||
var cPlayer = it.next();
|
||||
|
||||
if (cPlayer.getJobId() == 312 || cPlayer.getJobId() == 322 || cPlayer.getJobId() == 900) {
|
||||
if (cPlayer.getLevel() < 120) {
|
||||
return 2;
|
||||
}
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 3;
|
||||
}
|
||||
+2
-2
@@ -12786,8 +12786,8 @@ CREATE TABLE IF NOT EXISTS `drop_data_global` (
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=latin1 ROW_FORMAT=DYNAMIC AUTO_INCREMENT=5 ;
|
||||
|
||||
INSERT INTO `drop_data_global` (`id`, `continent`, `dropType`, `itemid`, `minimum_quantity`, `maximum_quantity`, `questid`, `chance`, `comments`) VALUES
|
||||
(1, 0, 0, 4031865, 1, 1, 0, 150000, 'NX Card 100 PTS'),
|
||||
(2, 0, 0, 4031866, 1, 1, 0, 90000, 'NX Card 250 PTS'),
|
||||
(1, 0, 0, 4031865, 1, 1, 0, 125000, 'NX Card 100 PTS'),
|
||||
(2, 0, 0, 4031866, 1, 1, 0, 78000, 'NX Card 250 PTS'),
|
||||
(3, 0, 0, 4001126, 1, 2, 0, 10000, 'Maple Leaves'),
|
||||
(4, 0, 0, 2049100, 1, 1, 0, 1500, 'Chaos Scroll 60%'),
|
||||
(5, 0, 0, 4001006, 1, 1, 0, 12000, 'Flaming Feather');
|
||||
|
||||
+3
-3
@@ -18839,9 +18839,9 @@
|
||||
UPDATE drop_data SET questid=6191 WHERE itemid=4001107;
|
||||
UPDATE drop_data SET questid=28344 WHERE itemid=4032475;
|
||||
|
||||
UPDATE drop_data SET questid=77777 WHERE itemid=4001358; #id 77777 for ALL "quest items" with no v83 quest.
|
||||
UPDATE drop_data SET questid=77777 WHERE itemid=4001359;
|
||||
UPDATE drop_data SET questid=77777 WHERE itemid=4001342;
|
||||
UPDATE drop_data SET questid=7777 WHERE itemid=4001358; #id 7777 for ALL "quest items" with no v83 quest.
|
||||
UPDATE drop_data SET questid=7777 WHERE itemid=4001359;
|
||||
UPDATE drop_data SET questid=7777 WHERE itemid=4001342;
|
||||
UPDATE drop_data SET chance=0 WHERE itemid=2050099;
|
||||
UPDATE drop_data SET chance=40000 WHERE itemid=4031991;
|
||||
UPDATE drop_data SET questid=6191 WHERE itemid=4031477;
|
||||
|
||||
@@ -123,4 +123,17 @@ public enum MapleJob {
|
||||
public boolean isA(MapleJob basejob) {
|
||||
return getId() >= basejob.getId() && getId() / 100 == basejob.getId() / 100;
|
||||
}
|
||||
|
||||
public int getJobNiche() {
|
||||
return (jobid / 100) % 10;
|
||||
|
||||
/*
|
||||
case 0: BEGINNER;
|
||||
case 1: WARRIOR;
|
||||
case 2: MAGICIAN;
|
||||
case 3: BOWMAN;
|
||||
case 4: THIEF;
|
||||
case 5: PIRATE;
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,17 @@ import constants.skills.Aran;
|
||||
* @author kevintjuh93
|
||||
*/
|
||||
public class GameConstants {
|
||||
private static final int[] mobHpVal = {0, 15, 20, 25, 35, 50, 65, 80, 95, 110, 125, 150, 175, 200, 225, 250, 275, 300, 325, 350,
|
||||
375, 405, 435, 465, 495, 525, 580, 650, 720, 790, 900, 990, 1100, 1200, 1300, 1400, 1500, 1600, 1700, 1800,
|
||||
1900, 2000, 2100, 2200, 2300, 2400, 2520, 2640, 2760, 2880, 3000, 3200, 3400, 3600, 3800, 4000, 4300, 4600, 4900, 5200,
|
||||
5500, 5900, 6300, 6700, 7100, 7500, 8000, 8500, 9000, 9500, 10000, 11000, 12000, 13000, 14000, 15000, 17000, 19000, 21000, 23000,
|
||||
25000, 27000, 29000, 31000, 33000, 35000, 37000, 39000, 41000, 43000, 45000, 47000, 49000, 51000, 53000, 55000, 57000, 59000, 61000, 63000,
|
||||
65000, 67000, 69000, 71000, 73000, 75000, 77000, 79000, 81000, 83000, 85000, 89000, 91000, 93000, 95000, 97000, 99000, 101000, 103000,
|
||||
105000, 107000, 109000, 111000, 113000, 115000, 118000, 120000, 125000, 130000, 135000, 140000, 145000, 150000, 155000, 160000, 165000, 170000, 175000, 180000,
|
||||
185000, 190000, 195000, 200000, 205000, 210000, 215000, 220000, 225000, 230000, 235000, 240000, 250000, 260000, 270000, 280000, 290000, 300000, 310000, 320000,
|
||||
330000, 340000, 350000, 360000, 370000, 380000, 390000, 400000, 410000, 420000, 430000, 440000, 450000, 460000, 470000, 480000, 490000, 500000, 510000, 520000,
|
||||
530000, 550000, 570000, 590000, 610000, 630000, 650000, 670000, 690000, 710000, 730000, 750000, 770000, 790000, 810000, 830000, 850000, 870000, 890000, 910000};
|
||||
|
||||
|
||||
public static int getHiddenSkill(final int skill) {
|
||||
switch (skill) {
|
||||
@@ -96,4 +107,11 @@ public class GameConstants {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static int getMonsterHP(final int level) {
|
||||
if (level < 0 || level >= mobHpVal.length) {
|
||||
return Integer.MAX_VALUE;
|
||||
}
|
||||
return mobHpVal[level];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,6 +55,9 @@ public class ServerConstants {
|
||||
public static final double PET_AUTOHP_RATIO = 0.99; //will automatically consume potions until given ratio of the MaxHP/MaxMP is reached.
|
||||
public static final double PET_AUTOMP_RATIO = 0.99;
|
||||
|
||||
//Should bosses use 1HP,1MP attacks in dojo?
|
||||
public static final boolean USE_DEADLY_DOJO = false;
|
||||
|
||||
//Rates
|
||||
public static final int EXP_RATE = 10;
|
||||
public static final int MESO_RATE = 10;
|
||||
|
||||
@@ -274,7 +274,6 @@ public abstract class AbstractDealDamageHandler extends AbstractMaplePacketHandl
|
||||
int delay = 0;
|
||||
final int maxmeso = player.getBuffedValue(MapleBuffStat.PICKPOCKET).intValue();
|
||||
for (Integer eachd : onedList) {
|
||||
|
||||
eachd += Integer.MAX_VALUE;
|
||||
if (pickpocket.getEffect(player.getSkillLevel(pickpocket)).makeChanceResult()) {
|
||||
final Integer eachdf;
|
||||
|
||||
@@ -30,6 +30,7 @@ import client.inventory.Item;
|
||||
import client.inventory.MapleInventoryType;
|
||||
import client.status.MonsterStatus;
|
||||
import client.status.MonsterStatusEffect;
|
||||
import constants.ServerConstants;
|
||||
import constants.skills.Aran;
|
||||
import constants.skills.Corsair;
|
||||
|
||||
@@ -63,7 +64,7 @@ public final class TakeDamageHandler extends AbstractMaplePacketHandler {
|
||||
int damage = slea.readInt();
|
||||
int oid = 0, monsteridfrom = 0, pgmr = 0, direction = 0;
|
||||
int pos_x = 0, pos_y = 0, fake = 0;
|
||||
boolean is_pgmr = false, is_pg = true;
|
||||
boolean is_pgmr = false, is_pg = true, is_deadly = false;
|
||||
int mpattack = 0;
|
||||
MapleMonster attacker = null;
|
||||
final MapleMap map = player.getMap();
|
||||
@@ -111,6 +112,7 @@ public final class TakeDamageHandler extends AbstractMaplePacketHandler {
|
||||
if (attackInfo != null) {
|
||||
if (attackInfo.isDeadlyAttack()) {
|
||||
mpattack = player.getMp() - 1;
|
||||
is_deadly = true;
|
||||
}
|
||||
mpattack += attackInfo.getMpBurn();
|
||||
MobSkill skill = MobSkillFactory.getMobSkill(attackInfo.getDiseaseSkill(), attackInfo.getDiseaseLevel());
|
||||
@@ -142,6 +144,13 @@ public final class TakeDamageHandler extends AbstractMaplePacketHandler {
|
||||
if (damage == -1) {
|
||||
fake = 4020002 + (player.getJob().getId() / 10 - 40) * 100000;
|
||||
}
|
||||
|
||||
//in dojo player cannot use pot, so deadly attacks should be turned off as well
|
||||
if(is_deadly && player.getMap().isDojoMap() && !ServerConstants.USE_DEADLY_DOJO) {
|
||||
damage = 0;
|
||||
mpattack = 0;
|
||||
}
|
||||
|
||||
if (damage == 0) {
|
||||
player.getAutobanManager().addMiss();
|
||||
} else {
|
||||
|
||||
@@ -30,6 +30,8 @@ import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
|
||||
import javax.script.ScriptException;
|
||||
|
||||
@@ -61,6 +63,8 @@ public class EventInstanceManager {
|
||||
private MapleExpedition expedition = null;
|
||||
private List<Integer> mapIds = new LinkedList<Integer>();
|
||||
private List<Boolean> isInstanced = new LinkedList<Boolean>();
|
||||
private final ReentrantReadWriteLock mutex = new ReentrantReadWriteLock();
|
||||
private final Lock rL = mutex.readLock(), wL = mutex.writeLock();
|
||||
private boolean disposed = false;
|
||||
|
||||
public EventInstanceManager(EventManager em, String name) {
|
||||
@@ -78,8 +82,16 @@ public class EventInstanceManager {
|
||||
if (chr == null || !chr.isLoggedin()){
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
wL.lock();
|
||||
try {
|
||||
chars.add(chr);
|
||||
}
|
||||
finally {
|
||||
wL.unlock();
|
||||
}
|
||||
|
||||
chr.setEventInstance(this);
|
||||
em.getIv().invokeFunction("playerEntry", this, chr);
|
||||
} catch (ScriptException | NoSuchMethodException ex) {
|
||||
@@ -125,7 +137,13 @@ public class EventInstanceManager {
|
||||
}
|
||||
|
||||
public void unregisterPlayer(MapleCharacter chr) {
|
||||
wL.lock();
|
||||
try {
|
||||
chars.remove(chr);
|
||||
} finally {
|
||||
wL.unlock();
|
||||
}
|
||||
|
||||
chr.setEventInstance(null);
|
||||
}
|
||||
|
||||
@@ -346,4 +364,37 @@ public class EventInstanceManager {
|
||||
isInstanced.add(false);
|
||||
return this.getMapFactory().getMap(mapid);
|
||||
}
|
||||
|
||||
public final boolean disposeIfPlayerBelow(final byte size, final int towarp) {
|
||||
if (disposed) {
|
||||
return true;
|
||||
}
|
||||
MapleMap map = null;
|
||||
if (towarp > 0) {
|
||||
map = this.getMapFactory().getMap(towarp);
|
||||
}
|
||||
|
||||
wL.lock();
|
||||
try {
|
||||
if (chars != null && chars.size() <= size) {
|
||||
final List<MapleCharacter> chrs = new LinkedList<MapleCharacter>(chars);
|
||||
for (MapleCharacter chr : chrs) {
|
||||
if (chr == null) {
|
||||
continue;
|
||||
}
|
||||
unregisterPlayer(chr);
|
||||
if (towarp > 0) {
|
||||
chr.changeMap(map, map.getPortal(0));
|
||||
}
|
||||
}
|
||||
dispose();
|
||||
return true;
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
} finally {
|
||||
wL.unlock();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
This file is part of the OdinMS Maple Story Server
|
||||
Copyright (C) 2008 ~ 2010 Patrick Huy <[email protected]>
|
||||
Matthias Butz <[email protected]>
|
||||
Jan Christian Meyer <[email protected]>
|
||||
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 server.life;
|
||||
|
||||
import constants.GameConstants;
|
||||
|
||||
public class ChangeableStats extends OverrideMonsterStats {
|
||||
|
||||
public int watk, matk, wdef, mdef, level;
|
||||
|
||||
public ChangeableStats(MapleMonsterStats stats, OverrideMonsterStats ostats) {
|
||||
hp = ostats.getHp();
|
||||
exp = ostats.getExp();
|
||||
mp = ostats.getMp();
|
||||
watk = stats.getPADamage();
|
||||
matk = stats.getMADamage();
|
||||
wdef = stats.getPDDamage();
|
||||
mdef = stats.getMDDamage();
|
||||
level = stats.getLevel();
|
||||
}
|
||||
|
||||
public ChangeableStats(MapleMonsterStats stats, int newLevel, boolean pqMob) { // here we go i think
|
||||
final double mod = (double) newLevel / (double) stats.getLevel();
|
||||
final double hpRatio = (double) stats.getHp() / (double) stats.getExp();
|
||||
final double pqMod = (pqMob ? 1.5 : 1.0); // god damn
|
||||
hp = (int) Math.round((!stats.isBoss() ? GameConstants.getMonsterHP(newLevel) : (stats.getHp() * mod)) * pqMod); // right here lol
|
||||
exp = (int) Math.round((!stats.isBoss() ? (GameConstants.getMonsterHP(newLevel) / hpRatio) : (stats.getExp())) * pqMod);
|
||||
mp = (int) Math.round(stats.getMp() * mod * pqMod);
|
||||
watk = (int) Math.round(stats.getPADamage() * mod);
|
||||
matk = (int) Math.round(stats.getMADamage() * mod);
|
||||
wdef = Math.min(stats.isBoss() ? 30 : 20, (int) Math.round(stats.getPDDamage() * mod));
|
||||
mdef = Math.min(stats.isBoss() ? 30 : 20, (int) Math.round(stats.getMDDamage() * mod));
|
||||
level = newLevel;
|
||||
}
|
||||
}
|
||||
@@ -63,7 +63,7 @@ import tools.Pair;
|
||||
import tools.Randomizer;
|
||||
|
||||
public class MapleMonster extends AbstractLoadedMapleLife {
|
||||
|
||||
private ChangeableStats ostats = null; //unused, v83 WZs offers no support for changeable stats.
|
||||
private MapleMonsterStats stats;
|
||||
private int hp, mp;
|
||||
private WeakReference<MapleCharacter> controller = new WeakReference<>(null);
|
||||
@@ -957,4 +957,36 @@ public class MapleMonster extends AbstractLoadedMapleLife {
|
||||
public Map<MonsterStatus, MonsterStatusEffect> getStati() {
|
||||
return stati;
|
||||
}
|
||||
|
||||
// ---- one can always have fun trying these pieces of codes below in-game rofl ----
|
||||
|
||||
public final ChangeableStats getChangedStats() {
|
||||
return ostats;
|
||||
}
|
||||
|
||||
public final int getMobMaxHp() {
|
||||
if (ostats != null) {
|
||||
return ostats.hp;
|
||||
}
|
||||
return stats.getHp();
|
||||
}
|
||||
|
||||
public final void setOverrideStats(final OverrideMonsterStats ostats) {
|
||||
this.ostats = new ChangeableStats(stats, ostats);
|
||||
this.hp = ostats.getHp();
|
||||
this.mp = ostats.getMp();
|
||||
}
|
||||
|
||||
public final void changeLevel(final int newLevel) {
|
||||
changeLevel(newLevel, true);
|
||||
}
|
||||
|
||||
public final void changeLevel(final int newLevel, boolean pqMob) {
|
||||
if (!stats.isChangeable()) {
|
||||
return;
|
||||
}
|
||||
this.ostats = new ChangeableStats(stats, newLevel, pqMob);
|
||||
this.hp = ostats.getHp();
|
||||
this.mp = ostats.getMp();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,6 +36,7 @@ import tools.Pair;
|
||||
* @author Frz
|
||||
*/
|
||||
public class MapleMonsterStats {
|
||||
private boolean changeable;
|
||||
private int exp, hp, mp, level, PADamage, PDDamage, MADamage, MDDamage, dropPeriod, cp, buffToGive, removeAfter;
|
||||
private boolean boss, undead, ffaLoot, isExplosiveReward, firstAttack, removeOnMiss;
|
||||
private String name;
|
||||
@@ -50,6 +51,14 @@ public class MapleMonsterStats {
|
||||
private selfDestruction selfDestruction = null;
|
||||
private boolean friendly;
|
||||
|
||||
public void setChange(boolean change) {
|
||||
this.changeable = change;
|
||||
}
|
||||
|
||||
public boolean isChangeable() {
|
||||
return changeable;
|
||||
}
|
||||
|
||||
public int getExp() {
|
||||
return exp;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
This file is part of the OdinMS Maple Story Server
|
||||
Copyright (C) 2008 ~ 2010 Patrick Huy <[email protected]>
|
||||
Matthias Butz <[email protected]>
|
||||
Jan Christian Meyer <[email protected]>
|
||||
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 server.life;
|
||||
|
||||
public class OverrideMonsterStats {
|
||||
|
||||
public int hp;
|
||||
public int exp, mp;
|
||||
|
||||
public OverrideMonsterStats() {
|
||||
hp = 1;
|
||||
exp = 0;
|
||||
mp = 0;
|
||||
}
|
||||
|
||||
public OverrideMonsterStats(int hp, int mp, int exp, boolean change) {
|
||||
this.hp = /*change ? (hp * 3L / 2L) : */ hp;
|
||||
this.mp = mp;
|
||||
this.exp = exp;
|
||||
}
|
||||
|
||||
public OverrideMonsterStats(int hp, int mp, int exp) {
|
||||
this(hp, mp, exp, true);
|
||||
}
|
||||
|
||||
public int getExp() {
|
||||
return exp;
|
||||
}
|
||||
|
||||
public void setOExp(int exp) {
|
||||
this.exp = exp;
|
||||
}
|
||||
|
||||
public int getHp() {
|
||||
return hp;
|
||||
}
|
||||
|
||||
public void setOHp(int hp) {
|
||||
this.hp = hp;
|
||||
}
|
||||
|
||||
public int getMp() {
|
||||
return mp;
|
||||
}
|
||||
|
||||
public void setOMp(int mp) {
|
||||
this.mp = mp;
|
||||
}
|
||||
}
|
||||
@@ -368,14 +368,14 @@ public class MapleMap {
|
||||
final MapleItemInformationProvider ii = MapleItemInformationProvider.getInstance();
|
||||
final byte droptype = (byte) (mob.getStats().isExplosiveReward() ? 3 : mob.getStats().isFfaLoot() ? 2 : chr.getParty() != null ? 1 : 0);
|
||||
final int mobpos = mob.getPosition().x;
|
||||
int chServerrate = chr.getDropRate();
|
||||
int chRate = chr.getDropRate();
|
||||
Item idrop;
|
||||
byte d = 1;
|
||||
Point pos = new Point(0, mob.getPosition().y);
|
||||
|
||||
Map<MonsterStatus, MonsterStatusEffect> stati = mob.getStati();
|
||||
if (stati.containsKey(MonsterStatus.SHOWDOWN)) {
|
||||
chServerrate *= (stati.get(MonsterStatus.SHOWDOWN).getStati().get(MonsterStatus.SHOWDOWN).doubleValue() / 100.0 + 1.0);
|
||||
chRate *= (stati.get(MonsterStatus.SHOWDOWN).getStati().get(MonsterStatus.SHOWDOWN).doubleValue() / 100.0 + 1.0);
|
||||
}
|
||||
|
||||
final MapleMonsterInformationProvider mi = MapleMonsterInformationProvider.getInstance();
|
||||
@@ -383,7 +383,7 @@ public class MapleMap {
|
||||
|
||||
Collections.shuffle(dropEntry);
|
||||
for (final MonsterDropEntry de : dropEntry) {
|
||||
if (Randomizer.nextInt(999999) < de.chance * chServerrate) {
|
||||
if (Randomizer.nextInt(999999) < de.chance * chRate) {
|
||||
if (droptype == 3) {
|
||||
pos.x = (int) (mobpos + (d % 2 == 0 ? (40 * (d + 1) / 2) : -(40 * (d / 2))));
|
||||
} else {
|
||||
@@ -418,9 +418,7 @@ public class MapleMap {
|
||||
} else {
|
||||
pos.x = (int) (mobpos + ((d % 2 == 0) ? (25 * (d + 1) / 2) : -(25 * (d / 2))));
|
||||
}
|
||||
if (de.itemId == 0) {
|
||||
//chr.getCashShop().gainCash(1, 80);
|
||||
} else {
|
||||
if (de.itemId != 0) {
|
||||
if (ItemConstants.getInventoryType(de.itemId) == MapleInventoryType.EQUIP) {
|
||||
idrop = ii.randomizeStats((Equip) ii.getEquipById(de.itemId));
|
||||
} else {
|
||||
@@ -538,7 +536,6 @@ public class MapleMap {
|
||||
if (damage > 0) {
|
||||
monster.damage(chr, damage);
|
||||
if (!monster.isAlive()) { // monster just died
|
||||
//killMonster(monster, chr, true);
|
||||
killed = true;
|
||||
}
|
||||
} else if (monster.getId() >= 8810002 && monster.getId() <= 8810009) {
|
||||
@@ -2437,4 +2434,16 @@ public class MapleMap {
|
||||
public void broadcastShip(final boolean state) {
|
||||
broadcastMessage(MaplePacketCreator.boatPacket(state));
|
||||
}
|
||||
|
||||
public boolean isDojoMap() {
|
||||
return mapid >= 925020000 && mapid < 925040000;
|
||||
}
|
||||
|
||||
public final void resetFully() {
|
||||
resetFully(true);
|
||||
}
|
||||
|
||||
public final void resetFully(final boolean respawn) {
|
||||
resetMapObjects();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -222,6 +222,10 @@ public class MapleQuest {
|
||||
for (MapleQuestAction a : completeActs.values()) {
|
||||
a.run(c, selection);
|
||||
}
|
||||
|
||||
//dont seems to work...
|
||||
//c.getClient().getSession().write(MaplePacketCreator.showForeignEffect(12)); // Quest completion
|
||||
//c.getMap().broadcastMessage(c, MaplePacketCreator.showForeignEffect(c.getId(), 12), false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -179,13 +179,28 @@ public class ItemAction extends MapleQuestAction {
|
||||
return false;
|
||||
}
|
||||
|
||||
if(item.getJob() != -1) {
|
||||
if (item.getJob() != chr.getJob().getId()) {
|
||||
return false;
|
||||
} else if (MapleJob.getBy5ByteEncoding(item.getJob()).getId() / 100 != chr.getJob().getId() / 100) {
|
||||
return false;
|
||||
if (item.job > 0) {
|
||||
final List<Integer> code = getJobBy5ByteEncoding(item.getJob());
|
||||
boolean jobFound = false;
|
||||
for (int codec : code) {
|
||||
if (codec / 100 == chr.getJob().getId() / 100) {
|
||||
jobFound = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
/*
|
||||
if (!jobFound && item.jobEx > 0) {
|
||||
final List<Integer> codeEx = getJobBySimpleEncoding(item.jobEx);
|
||||
for (int codec : codeEx) {
|
||||
if ((codec / 100 % 10) == (chr.getJob().getId() / 100 % 10)) {
|
||||
jobFound = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
return jobFound;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -11,6 +11,9 @@ import provider.MapleData;
|
||||
import server.quest.MapleQuest;
|
||||
import server.quest.MapleQuestActionType;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Tyler (Twdtwd)
|
||||
@@ -36,4 +39,84 @@ public abstract class MapleQuestAction {
|
||||
public MapleQuestActionType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public static List<Integer> getJobBy5ByteEncoding(int encoded) {
|
||||
List<Integer> ret = new ArrayList<Integer>();
|
||||
if ((encoded & 0x1) != 0) {
|
||||
ret.add(0);
|
||||
}
|
||||
if ((encoded & 0x2) != 0) {
|
||||
ret.add(100);
|
||||
}
|
||||
if ((encoded & 0x4) != 0) {
|
||||
ret.add(200);
|
||||
}
|
||||
if ((encoded & 0x8) != 0) {
|
||||
ret.add(300);
|
||||
}
|
||||
if ((encoded & 0x10) != 0) {
|
||||
ret.add(400);
|
||||
}
|
||||
if ((encoded & 0x20) != 0) {
|
||||
ret.add(500);
|
||||
}
|
||||
if ((encoded & 0x400) != 0) {
|
||||
ret.add(1000);
|
||||
}
|
||||
if ((encoded & 0x800) != 0) {
|
||||
ret.add(1100);
|
||||
}
|
||||
if ((encoded & 0x1000) != 0) {
|
||||
ret.add(1200);
|
||||
}
|
||||
if ((encoded & 0x2000) != 0) {
|
||||
ret.add(1300);
|
||||
}
|
||||
if ((encoded & 0x4000) != 0) {
|
||||
ret.add(1400);
|
||||
}
|
||||
if ((encoded & 0x8000) != 0) {
|
||||
ret.add(1500);
|
||||
}
|
||||
if ((encoded & 0x20000) != 0) {
|
||||
ret.add(2001); //im not sure of this one
|
||||
ret.add(2200);
|
||||
}
|
||||
if ((encoded & 0x100000) != 0) {
|
||||
ret.add(2000);
|
||||
ret.add(2001); //?
|
||||
}
|
||||
if ((encoded & 0x200000) != 0) {
|
||||
ret.add(2100);
|
||||
}
|
||||
if ((encoded & 0x400000) != 0) {
|
||||
ret.add(2001); //?
|
||||
ret.add(2200);
|
||||
}
|
||||
|
||||
if ((encoded & 0x40000000) != 0) { //i haven't seen any higher than this o.o
|
||||
ret.add(3000);
|
||||
ret.add(3200);
|
||||
ret.add(3300);
|
||||
ret.add(3500);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static List<Integer> getJobBySimpleEncoding(int encoded) {
|
||||
List<Integer> ret = new ArrayList<Integer>();
|
||||
if ((encoded & 0x1) != 0) {
|
||||
ret.add(200);
|
||||
}
|
||||
if ((encoded & 0x2) != 0) {
|
||||
ret.add(300);
|
||||
}
|
||||
if ((encoded & 0x4) != 0) {
|
||||
ret.add(400);
|
||||
}
|
||||
if ((encoded & 0x8) != 0) {
|
||||
ret.add(500);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5682,6 +5682,10 @@ public class MaplePacketCreator {
|
||||
return mplew.getPacket();
|
||||
}
|
||||
|
||||
public static byte[] showForeignEffect(int effect) {
|
||||
return showForeignEffect(-1, effect);
|
||||
}
|
||||
|
||||
public static byte[] showForeignEffect(int cid, int effect) {
|
||||
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
||||
mplew.writeShort(SendOpcode.SHOW_FOREIGN_EFFECT.getValue());
|
||||
|
||||
Reference in New Issue
Block a user