Water of Life + Fixed GPQ & Buff system
Added Water of Life. Fixed Shuang (GPQ) npc dc'ing the leader when first trying to enter the waiting area. Fixed some cases with the revamped buff system, that would not properly check for the best buffs in some scenarios, and would throw exceptions, caused by not properly protecting access to critical data.
This commit is contained in:
@@ -20,6 +20,11 @@ Server files: https://github.com/ronancpl/MapleSolaxiaV2
|
|||||||
|
|
||||||
Client files & general tools: https://drive.google.com/drive/folders/0BzDsHSr-0V4MYVJ0TWIxd05hYUk
|
Client files & general tools: https://drive.google.com/drive/folders/0BzDsHSr-0V4MYVJ0TWIxd05hYUk
|
||||||
|
|
||||||
|
---
|
||||||
|
### Donation
|
||||||
|
|
||||||
|
If you liked what you have seen on the project, donate a little something as a helping hand for my contributions towards Maple development. Paypal: https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=3K8KVTWRLFBQ4
|
||||||
|
|
||||||
---
|
---
|
||||||
### Preparing the ambient
|
### Preparing the ambient
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
#Fri, 22 Sep 2017 22:54:29 -0300
|
#Mon, 25 Sep 2017 01:46:09 -0300
|
||||||
|
|
||||||
|
|
||||||
C\:\\Nexon\\MapleSolaxia\\MapleSolaxiaV2=
|
C\:\\Nexon\\MapleSolaxia\\MapleSolaxiaV2=
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
dist/MapleSolaxia.jar
vendored
BIN
dist/MapleSolaxia.jar
vendored
Binary file not shown.
@@ -32,7 +32,7 @@ Quests:
|
|||||||
* Quests can now reward properly items when matching a reward item with the player's job.
|
* Quests can now reward properly items when matching a reward item with the player's job.
|
||||||
* Loads of quests have been patched.
|
* Loads of quests have been patched.
|
||||||
* Quest rewards according to jobs works properly.
|
* Quest rewards according to jobs works properly.
|
||||||
* Rewarding system now checks for stacking opportunities on the inventory before checking for new slots.
|
* Enchanced rewarding system: checks for stacking opportunities on the inventory before checking for new slots.
|
||||||
|
|
||||||
Player Social Network:
|
Player Social Network:
|
||||||
* Guild and Alliance system fully functional.
|
* Guild and Alliance system fully functional.
|
||||||
@@ -60,6 +60,7 @@ Server potentials:
|
|||||||
* Mastery book announcer displays droppers of needed books of a player, by reading underlying DB.
|
* Mastery book announcer displays droppers of needed books of a player, by reading underlying DB.
|
||||||
* Every skill/mastery book is now droppable by mobs.
|
* Every skill/mastery book is now droppable by mobs.
|
||||||
* Inventory auto-gather and auto-sorting feature.
|
* Inventory auto-gather and auto-sorting feature.
|
||||||
|
* Enhanced buff system: smartly checks for the best available buff effects to be active on the player.
|
||||||
* Enhanced AP auto-assigner: exactly matches AP with the needed for the player's current level, surplus assigned to the primary attribute.
|
* Enhanced AP auto-assigner: exactly matches AP with the needed for the player's current level, surplus assigned to the primary attribute.
|
||||||
* Added Boss HP Bar for dozens of bosses (needs provided custom wz).
|
* Added Boss HP Bar for dozens of bosses (needs provided custom wz).
|
||||||
* If multiple bosses are on the same area, client will prioritize Boss HP bar of the target of the player.
|
* If multiple bosses are on the same area, client will prioritize Boss HP bar of the target of the player.
|
||||||
|
|||||||
@@ -545,4 +545,8 @@ Completamente reestruturado sistema de buffs. Nova flag permite perman
|
|||||||
|
|
||||||
22 Setembro 2017,
|
22 Setembro 2017,
|
||||||
Adicionado buffs para GPQ.
|
Adicionado buffs para GPQ.
|
||||||
Consertado GPQ não iniciando devido a problemas com o script de evento.
|
Consertado GPQ não iniciando devido a problemas com o script de evento.
|
||||||
|
|
||||||
|
23 Setembro 2017,
|
||||||
|
Adicionado Water of Life.
|
||||||
|
Consertado bug com sistema novo de buffs ao entrar no cash shop e em outros cenários onde não se detectava o melhor buff corretamente.
|
||||||
@@ -2,14 +2,6 @@
|
|||||||
<project-private xmlns="http://www.netbeans.org/ns/project-private/1">
|
<project-private xmlns="http://www.netbeans.org/ns/project-private/1">
|
||||||
<editor-bookmarks xmlns="http://www.netbeans.org/ns/editor-bookmarks/2" lastBookmarkId="1"/>
|
<editor-bookmarks xmlns="http://www.netbeans.org/ns/editor-bookmarks/2" lastBookmarkId="1"/>
|
||||||
<open-files xmlns="http://www.netbeans.org/ns/projectui-open-files/2">
|
<open-files xmlns="http://www.netbeans.org/ns/projectui-open-files/2">
|
||||||
<group>
|
<group/>
|
||||||
<file>file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/scripts/event/GuildQuest.js</file>
|
|
||||||
<file>file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/scripts/npc/9040000.js</file>
|
|
||||||
<file>file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/scripting/event/EventInstanceManager.java</file>
|
|
||||||
<file>file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/client/MapleCharacter.java</file>
|
|
||||||
<file>file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/scripting/event/EventManager.java</file>
|
|
||||||
<file>file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/scripts/npc/1052013.js</file>
|
|
||||||
<file>file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/scripts/event/AmoriaPQ.js</file>
|
|
||||||
</group>
|
|
||||||
</open-files>
|
</open-files>
|
||||||
</project-private>
|
</project-private>
|
||||||
|
|||||||
@@ -25,7 +25,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
var isPq = true;
|
var isPq = true;
|
||||||
var minPlayers = 1, maxPlayers = 30;
|
var minPlayers = 6, maxPlayers = 30;
|
||||||
var minLevel = 1, maxLevel = 255;
|
var minLevel = 1, maxLevel = 255;
|
||||||
var entryMap = 990000000;
|
var entryMap = 990000000;
|
||||||
var exitMap = 990001100;
|
var exitMap = 990001100;
|
||||||
@@ -201,10 +201,10 @@ function scheduledTimeout(eim) {
|
|||||||
} else {
|
} else {
|
||||||
eim.startEventTimer(eventTime * 60000);
|
eim.startEventTimer(eventTime * 60000);
|
||||||
|
|
||||||
//if(isTeamAllJobs(eim)) {
|
if(isTeamAllJobs(eim)) {
|
||||||
var rnd = Math.floor(Math.random() * 4);
|
var rnd = Math.floor(Math.random() * 4);
|
||||||
eim.applyEventPlayersItemBuff(2023000 + rnd);
|
eim.applyEventPlayersItemBuff(2023000 + rnd);
|
||||||
//}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
end(eim);
|
end(eim);
|
||||||
|
|||||||
@@ -104,7 +104,7 @@ function action(mode, type, selection) {
|
|||||||
}
|
}
|
||||||
} else if (status == 2) {
|
} else if (status == 2) {
|
||||||
if (selection == 0) {
|
if (selection == 0) {
|
||||||
MapleInventoryManipulator.removeFromSlot(cm.getC(), MapleInventoryType.CASH, 1, 1, true);
|
MapleInventoryManipulator.removeFromSlot(cm.getClient(), MapleInventoryType.CASH, 1, 1, true);
|
||||||
cm.sendOk("Your cash first slot is removed.");
|
cm.sendOk("Your cash first slot is removed.");
|
||||||
} else if (selection == 1) {
|
} else if (selection == 1) {
|
||||||
if (cm.haveItem(5000029, 2)) {
|
if (cm.haveItem(5000029, 2)) {
|
||||||
|
|||||||
95
scripts/npc/waterOfLife.js
Normal file
95
scripts/npc/waterOfLife.js
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
/*
|
||||||
|
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/>.
|
||||||
|
*/
|
||||||
|
/* Mar the Fairy
|
||||||
|
Handles Water of Life
|
||||||
|
*/
|
||||||
|
|
||||||
|
importPackage(Packages.client.inventory);
|
||||||
|
importPackage(Packages.server);
|
||||||
|
|
||||||
|
var status;
|
||||||
|
var dList;
|
||||||
|
|
||||||
|
function start() {
|
||||||
|
status = -1;
|
||||||
|
dList = cm.getDriedPets();
|
||||||
|
if(dList.size() == 0) {
|
||||||
|
cm.playerMessage(5, "You currently do not own a pet that needs to be treated with Water of Life.");
|
||||||
|
cm.dispose();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
action(1, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
function action(mode, type, selection) {
|
||||||
|
if (mode == -1) {
|
||||||
|
cm.dispose();
|
||||||
|
} else {
|
||||||
|
if (mode == 0 && type > 0) {
|
||||||
|
cm.dispose();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (mode == 1)
|
||||||
|
status++;
|
||||||
|
else
|
||||||
|
status--;
|
||||||
|
|
||||||
|
if (status == 0) {
|
||||||
|
cm.sendYesNo("I am Mar the Fairy. You have the #bWater of Life#k... With this, I can bring a doll back to life with my magic. What do you think? Do you want to use this item and reawaken your pet ...?");
|
||||||
|
|
||||||
|
} else if (status == 1) {
|
||||||
|
var talkStr = "So which pet you want to reawaken? Please choose the pet you'd most like to reawaken...\r\n\r\n";
|
||||||
|
|
||||||
|
var listStr = "";
|
||||||
|
var i = 0;
|
||||||
|
|
||||||
|
var dIter = dList.iterator();
|
||||||
|
while (dIter.hasNext()){
|
||||||
|
var dPet = dIter.next();
|
||||||
|
|
||||||
|
listStr += "#b#L" + i + "# " + dPet.getName() + " #k - Lv " + dPet.getLevel() + " Closeness " + dPet.getCloseness();
|
||||||
|
listStr += "#l\r\n";
|
||||||
|
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
cm.sendSimple(talkStr + listStr);
|
||||||
|
} else if (status == 2) {
|
||||||
|
var sPet = dList.get(selection);
|
||||||
|
|
||||||
|
if(sPet != null) {
|
||||||
|
cm.sendNext("Your doll has now reawaken as your pet! However, my magic isn't perfect, so I can't promise an eternal life for your pet... Please take care of that pet before the Water of Life dries. Well then, good bye...");
|
||||||
|
|
||||||
|
var it = cm.getPlayer().getInventory(MapleInventoryType.CASH).getItem(sPet.getPosition());
|
||||||
|
it.setExpiration(Date.now() + (1000 * 60 * 60 * 24 * 90));
|
||||||
|
cm.getPlayer().forceUpdateItem(it);
|
||||||
|
|
||||||
|
cm.gainItem(5180000, -1);
|
||||||
|
} else {
|
||||||
|
cm.sendNext("Oh, well then. Good bye...");
|
||||||
|
}
|
||||||
|
|
||||||
|
cm.dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -92,7 +92,7 @@ function end(mode, type, selection) {
|
|||||||
name = MapleItemInformationProvider.getInstance().getName(after);
|
name = MapleItemInformationProvider.getInstance().getName(after);
|
||||||
} */
|
} */
|
||||||
|
|
||||||
//qm.unequipPet(qm.getC());
|
//qm.unequipPet(qm.getClient());
|
||||||
qm.gainItem(5380000, -1);
|
qm.gainItem(5380000, -1);
|
||||||
qm.gainMeso(-10000);
|
qm.gainMeso(-10000);
|
||||||
qm.evolvePet(i, after);
|
qm.evolvePet(i, after);
|
||||||
|
|||||||
@@ -19820,6 +19820,15 @@ USE `maplesolaxia`;
|
|||||||
(9420501, 1492005, 1, 1, 0, 2000),
|
(9420501, 1492005, 1, 1, 0, 2000),
|
||||||
(8820001, 2388043, 1, 1, 0, 24000);
|
(8820001, 2388043, 1, 1, 0, 24000);
|
||||||
|
|
||||||
|
# zhelms, pink bean customs
|
||||||
|
DELETE FROM temp_data WHERE itemid=1002357;
|
||||||
|
INSERT IGNORE INTO temp_data (`dropperid`, `itemid`, `minimum_quantity`, `maximum_quantity`, `questid`, `chance`) VALUES
|
||||||
|
(8800002, 1002357, 1, 1, 0, 300000),
|
||||||
|
(8800002, 1002390, 1, 1, 0, 80000),
|
||||||
|
(8800002, 1002430, 1, 1, 0, 40000),
|
||||||
|
(8820001, 1002971, 1, 1, 0, 80000),
|
||||||
|
(8820001, 1052202, 1, 1, 0, 80000);
|
||||||
|
|
||||||
# delete item drops from bosses in inactive form
|
# delete item drops from bosses in inactive form
|
||||||
DELETE FROM temp_data WHERE dropperid=4220001;
|
DELETE FROM temp_data WHERE dropperid=4220001;
|
||||||
DELETE FROM temp_data WHERE dropperid=5220001;
|
DELETE FROM temp_data WHERE dropperid=5220001;
|
||||||
|
|||||||
@@ -151,11 +151,12 @@ import scripting.item.ItemScriptManager;
|
|||||||
import server.maps.MapleMapItem;
|
import server.maps.MapleMapItem;
|
||||||
|
|
||||||
public class MapleCharacter extends AbstractAnimatedMapleMapObject {
|
public class MapleCharacter extends AbstractAnimatedMapleMapObject {
|
||||||
|
private static NumberFormat nf = new DecimalFormat("#,###,###,###");
|
||||||
private static final String LEVEL_200 = "[Congrats] %s has reached Level 200! Congratulate %s on such an amazing achievement!";
|
private static final String LEVEL_200 = "[Congrats] %s has reached Level 200! Congratulate %s on such an amazing achievement!";
|
||||||
|
|
||||||
private static final String[] BLOCKED_NAMES = {"admin", "owner", "moderator", "intern", "donor", "administrator", "help", "helper", "alert", "notice", "maplestory", "Solaxia", "fuck", "wizet", "fucking", "negro", "fuk", "fuc", "penis", "pussy", "asshole", "gay",
|
private static final String[] BLOCKED_NAMES = {"admin", "owner", "moderator", "intern", "donor", "administrator", "help", "helper", "alert", "notice", "maplestory", "Solaxia", "fuck", "wizet", "fucking", "negro", "fuk", "fuc", "penis", "pussy", "asshole", "gay",
|
||||||
"nigger", "homo", "suck", "cum", "shit", "shitty", "condom", "security", "official", "rape", "nigga", "sex", "tit", "boner", "orgy", "clit", "asshole", "fatass", "bitch", "support", "gamemaster", "cock", "gaay", "gm",
|
"nigger", "homo", "suck", "cum", "shit", "shitty", "condom", "security", "official", "rape", "nigga", "sex", "tit", "boner", "orgy", "clit", "asshole", "fatass", "bitch", "support", "gamemaster", "cock", "gaay", "gm",
|
||||||
"operate", "master", "sysop", "party", "GameMaster", "community", "message", "event", "test", "meso", "Scania", "renewal", "yata", "AsiaSoft", "henesys"};
|
"operate", "master", "sysop", "party", "GameMaster", "community", "message", "event", "test", "meso", "Scania", "renewal", "yata", "AsiaSoft", "henesys"};
|
||||||
|
|
||||||
private int world;
|
private int world;
|
||||||
private int accountid, id;
|
private int accountid, id;
|
||||||
private int rank, rankMove, jobRank, jobRankMove;
|
private int rank, rankMove, jobRank, jobRankMove;
|
||||||
@@ -260,7 +261,6 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
|
|||||||
private Lock chrLock = new ReentrantLock();
|
private Lock chrLock = new ReentrantLock();
|
||||||
private Lock effLock = new ReentrantLock();
|
private Lock effLock = new ReentrantLock();
|
||||||
private Lock petLock = new ReentrantLock();
|
private Lock petLock = new ReentrantLock();
|
||||||
private NumberFormat nf = new DecimalFormat("#,###,###,###");
|
|
||||||
private Map<Integer, Set<Integer>> excluded = new LinkedHashMap<>();
|
private Map<Integer, Set<Integer>> excluded = new LinkedHashMap<>();
|
||||||
private Set<Integer> excludedItems = new LinkedHashSet<>();
|
private Set<Integer> excludedItems = new LinkedHashSet<>();
|
||||||
private List<MapleRing> crushRings = new ArrayList<>();
|
private List<MapleRing> crushRings = new ArrayList<>();
|
||||||
@@ -2095,22 +2095,26 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
|
|||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
Set<Entry<Integer, Long>> es;
|
Set<Entry<Integer, Long>> es;
|
||||||
|
List<MapleBuffStatValueHolder> toCancel = new ArrayList<>();
|
||||||
|
|
||||||
effLock.lock();
|
effLock.lock();
|
||||||
chrLock.lock();
|
chrLock.lock();
|
||||||
try {
|
try {
|
||||||
es = new LinkedHashSet<>(buffExpires.entrySet());
|
es = new LinkedHashSet<>(buffExpires.entrySet());
|
||||||
|
|
||||||
|
long curTime = System.currentTimeMillis();
|
||||||
|
for(Entry<Integer, Long> bel : es) {
|
||||||
|
if(curTime >= bel.getValue()) {
|
||||||
|
toCancel.add(buffEffects.get(bel.getKey()).entrySet().iterator().next().getValue()); //rofl
|
||||||
|
}
|
||||||
|
}
|
||||||
} finally {
|
} finally {
|
||||||
chrLock.unlock();
|
chrLock.unlock();
|
||||||
effLock.unlock();
|
effLock.unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
long curTime = System.currentTimeMillis();
|
for(MapleBuffStatValueHolder mbsvh : toCancel) {
|
||||||
for(Entry<Integer, Long> bel : es) {
|
cancelEffect(mbsvh.effect, false, mbsvh.startTime);
|
||||||
if(curTime >= bel.getValue()) {
|
|
||||||
MapleBuffStatValueHolder mbsvh = buffEffects.get(bel.getKey()).entrySet().iterator().next().getValue(); // rofl
|
|
||||||
cancelEffect(mbsvh.effect, false, mbsvh.startTime);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, 1500);
|
}, 1500);
|
||||||
@@ -2181,6 +2185,7 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
|
|||||||
for (MapleInventory inv : inventory) {
|
for (MapleInventory inv : inventory) {
|
||||||
for (Item item : inv.list()) {
|
for (Item item : inv.list()) {
|
||||||
expiration = item.getExpiration();
|
expiration = item.getExpiration();
|
||||||
|
|
||||||
if (expiration != -1 && (expiration < currenttime) && ((item.getFlag() & ItemConstants.LOCK) == ItemConstants.LOCK)) {
|
if (expiration != -1 && (expiration < currenttime) && ((item.getFlag() & ItemConstants.LOCK) == ItemConstants.LOCK)) {
|
||||||
byte aids = item.getFlag();
|
byte aids = item.getFlag();
|
||||||
aids &= ~(ItemConstants.LOCK);
|
aids &= ~(ItemConstants.LOCK);
|
||||||
@@ -2188,10 +2193,15 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
|
|||||||
item.setExpiration(-1);
|
item.setExpiration(-1);
|
||||||
forceUpdateItem(item); //TEST :3
|
forceUpdateItem(item); //TEST :3
|
||||||
} else if (expiration != -1 && expiration < currenttime) {
|
} else if (expiration != -1 && expiration < currenttime) {
|
||||||
client.announce(MaplePacketCreator.itemExpired(item.getItemId()));
|
if(!ItemConstants.isPet(item.getItemId()) || ServerConstants.USE_ERASE_PET_ON_EXPIRATION) {
|
||||||
toberemove.add(item);
|
client.announce(MaplePacketCreator.itemExpired(item.getItemId()));
|
||||||
if(ItemConstants.isRateCoupon(item.getItemId())) {
|
toberemove.add(item);
|
||||||
deletedCoupon = true;
|
if(ItemConstants.isRateCoupon(item.getItemId())) {
|
||||||
|
deletedCoupon = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
item.setExpiration(-1);
|
||||||
|
forceUpdateItem(item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2472,7 +2482,7 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
|
|||||||
effLock.lock();
|
effLock.lock();
|
||||||
chrLock.lock();
|
chrLock.lock();
|
||||||
try {
|
try {
|
||||||
return buffEffects.keySet();
|
return new LinkedHashSet<>(buffEffects.keySet());
|
||||||
} finally {
|
} finally {
|
||||||
chrLock.unlock();
|
chrLock.unlock();
|
||||||
effLock.unlock();
|
effLock.unlock();
|
||||||
@@ -2500,12 +2510,14 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
|
|||||||
effLock.lock();
|
effLock.lock();
|
||||||
chrLock.lock();
|
chrLock.lock();
|
||||||
try {
|
try {
|
||||||
|
long curtime = System.currentTimeMillis();
|
||||||
|
|
||||||
Map<Integer, PlayerBuffValueHolder> ret = new LinkedHashMap<>();
|
Map<Integer, PlayerBuffValueHolder> ret = new LinkedHashMap<>();
|
||||||
for(Map<MapleBuffStat, MapleBuffStatValueHolder> bel : buffEffects.values()) {
|
for(Map<MapleBuffStat, MapleBuffStatValueHolder> bel : buffEffects.values()) {
|
||||||
for(MapleBuffStatValueHolder mbsvh : bel.values()) {
|
for(MapleBuffStatValueHolder mbsvh : bel.values()) {
|
||||||
int srcid = mbsvh.effect.getBuffSourceId();
|
int srcid = mbsvh.effect.getBuffSourceId();
|
||||||
if(!ret.containsKey(srcid)) {
|
if(!ret.containsKey(srcid)) {
|
||||||
ret.put(srcid, new PlayerBuffValueHolder(mbsvh.startTime, mbsvh.effect));
|
ret.put(srcid, new PlayerBuffValueHolder((int)(curtime - mbsvh.startTime), mbsvh.effect));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2826,16 +2838,32 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
|
|||||||
chrLock.lock();
|
chrLock.lock();
|
||||||
try {
|
try {
|
||||||
Map<Integer, Pair<MapleStatEffect, Long>> retrievedEffects = new LinkedHashMap<>();
|
Map<Integer, Pair<MapleStatEffect, Long>> retrievedEffects = new LinkedHashMap<>();
|
||||||
|
Map<MapleBuffStat, Pair<Integer, Integer>> maxStatups = new LinkedHashMap<>();
|
||||||
|
|
||||||
for(Entry<Integer, Map<MapleBuffStat, MapleBuffStatValueHolder>> bel : buffEffects.entrySet()) {
|
for(Entry<Integer, Map<MapleBuffStat, MapleBuffStatValueHolder>> bel : buffEffects.entrySet()) {
|
||||||
for(Entry<MapleBuffStat, MapleBuffStatValueHolder> belv : bel.getValue().entrySet()) {
|
for(Entry<MapleBuffStat, MapleBuffStatValueHolder> belv : bel.getValue().entrySet()) {
|
||||||
if(removedStats.contains(belv.getKey())) {
|
if(removedStats.contains(belv.getKey())) {
|
||||||
retrievedEffects.put(bel.getKey(), new Pair<>(belv.getValue().effect, belv.getValue().startTime));
|
if(!retrievedEffects.containsKey(bel.getKey())) {
|
||||||
|
retrievedEffects.put(bel.getKey(), new Pair<>(belv.getValue().effect, belv.getValue().startTime));
|
||||||
|
}
|
||||||
|
|
||||||
|
Pair<Integer, Integer> thisStat = maxStatups.get(belv.getKey());
|
||||||
|
if(thisStat == null || belv.getValue().value > thisStat.getRight()) {
|
||||||
|
maxStatups.put(belv.getKey(), new Pair<>(bel.getKey(), belv.getValue().value));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for(Entry<Integer, Pair<MapleStatEffect, Long>> lmse: retrievedEffects.entrySet()) {
|
Map<Integer, Pair<MapleStatEffect, Long>> bestEffects = new LinkedHashMap<>();
|
||||||
|
for(Entry<MapleBuffStat, Pair<Integer, Integer>> lmse: maxStatups.entrySet()) {
|
||||||
|
Integer srcid = lmse.getValue().getLeft();
|
||||||
|
if(!bestEffects.containsKey(srcid)) {
|
||||||
|
bestEffects.put(srcid, retrievedEffects.get(srcid));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for(Entry<Integer, Pair<MapleStatEffect, Long>> lmse: bestEffects.entrySet()) {
|
||||||
lmse.getValue().getLeft().updateBuffEffect(this, getActiveStatupsFromSourceid(lmse.getKey()), lmse.getValue().getRight());
|
lmse.getValue().getLeft().updateBuffEffect(this, getActiveStatupsFromSourceid(lmse.getKey()), lmse.getValue().getRight());
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
@@ -6933,9 +6961,10 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
|
|||||||
setHp(getHp(), true);
|
setHp(getHp(), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void silentGiveBuffs(List<PlayerBuffValueHolder> buffs) {
|
public void silentGiveBuffs(List<Pair<Long, PlayerBuffValueHolder>> buffs) {
|
||||||
for (PlayerBuffValueHolder mbsvh : buffs) {
|
for (Pair<Long, PlayerBuffValueHolder> mbsv : buffs) {
|
||||||
mbsvh.effect.silentApplyBuff(this, mbsvh.startTime);
|
PlayerBuffValueHolder mbsvh = mbsv.getRight();
|
||||||
|
mbsvh.effect.silentApplyBuff(this, mbsv.getLeft());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -49,6 +49,7 @@ public class ServerConstants {
|
|||||||
public static final boolean USE_REFRESH_RANK_MOVE = true;
|
public static final boolean USE_REFRESH_RANK_MOVE = true;
|
||||||
public static final boolean USE_ENFORCE_MDOOR_POSITION = true; //Forces mystic door to be spawned near spawnpoints. (since things bugs out other way, and this helps players to locate the door faster)
|
public static final boolean USE_ENFORCE_MDOOR_POSITION = true; //Forces mystic door to be spawned near spawnpoints. (since things bugs out other way, and this helps players to locate the door faster)
|
||||||
public static final boolean USE_ERASE_UNTRADEABLE_DROP = true; //Forces flagged untradeable items to disappear when dropped.
|
public static final boolean USE_ERASE_UNTRADEABLE_DROP = true; //Forces flagged untradeable items to disappear when dropped.
|
||||||
|
public static final boolean USE_ERASE_PET_ON_EXPIRATION = false;//Forces pets to be removed from inventory when expire time comes, rather than converting it to a doll.
|
||||||
public static final boolean USE_BUFF_MOST_SIGNIFICANT = true; //When applying buffs, the player will stick with the highest stat boost among the listed, rather than overwriting stats.
|
public static final boolean USE_BUFF_MOST_SIGNIFICANT = true; //When applying buffs, the player will stick with the highest stat boost among the listed, rather than overwriting stats.
|
||||||
|
|
||||||
//Server Rates And Experience
|
//Server Rates And Experience
|
||||||
|
|||||||
@@ -245,6 +245,7 @@ public final class PacketProcessor {
|
|||||||
registerHandler(RecvOpcode.MONSTER_CARNIVAL, new MonsterCarnivalHandler());
|
registerHandler(RecvOpcode.MONSTER_CARNIVAL, new MonsterCarnivalHandler());
|
||||||
registerHandler(RecvOpcode.REMOTE_STORE, new RemoteStoreHandler());
|
registerHandler(RecvOpcode.REMOTE_STORE, new RemoteStoreHandler());
|
||||||
registerHandler(RecvOpcode.WEDDING_ACTION, new WeddingHandler());
|
registerHandler(RecvOpcode.WEDDING_ACTION, new WeddingHandler());
|
||||||
|
registerHandler(RecvOpcode.WATER_OF_LIFE, new UseWaterOfLifeHandler());
|
||||||
registerHandler(RecvOpcode.ADMIN_CHAT, new AdminChatHandler());
|
registerHandler(RecvOpcode.ADMIN_CHAT, new AdminChatHandler());
|
||||||
registerHandler(RecvOpcode.MOVE_DRAGON, new MoveDragonHandler());
|
registerHandler(RecvOpcode.MOVE_DRAGON, new MoveDragonHandler());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -116,6 +116,7 @@ public enum RecvOpcode {
|
|||||||
USE_ITEM_REWARD(0x70),
|
USE_ITEM_REWARD(0x70),
|
||||||
MAKER_SKILL(0x71),
|
MAKER_SKILL(0x71),
|
||||||
USE_REMOTE(0x74),
|
USE_REMOTE(0x74),
|
||||||
|
WATER_OF_LIFE(0x75),
|
||||||
ADMIN_CHAT(0x76),
|
ADMIN_CHAT(0x76),
|
||||||
PARTYCHAT(0x77),
|
PARTYCHAT(0x77),
|
||||||
WHISPER(0x78),
|
WHISPER(0x78),
|
||||||
|
|||||||
@@ -28,11 +28,11 @@ import server.MapleStatEffect;
|
|||||||
* @author Danny
|
* @author Danny
|
||||||
*/
|
*/
|
||||||
public class PlayerBuffValueHolder {
|
public class PlayerBuffValueHolder {
|
||||||
public long startTime;
|
public int usedTime;
|
||||||
public MapleStatEffect effect;
|
public MapleStatEffect effect;
|
||||||
|
|
||||||
public PlayerBuffValueHolder(long startTime, MapleStatEffect effect) {
|
public PlayerBuffValueHolder(int usedTime, MapleStatEffect effect) {
|
||||||
this.startTime = startTime;
|
this.usedTime = usedTime;
|
||||||
this.effect = effect;
|
this.effect = effect;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,7 +41,6 @@ public final class CancelBuffHandler extends AbstractMaplePacketHandler implemen
|
|||||||
@Override
|
@Override
|
||||||
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
|
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
|
||||||
int sourceid = slea.readInt();
|
int sourceid = slea.readInt();
|
||||||
if(sourceid < 0) sourceid = -sourceid; //oh my...
|
|
||||||
|
|
||||||
switch (sourceid) {
|
switch (sourceid) {
|
||||||
case FPArchMage.BIG_BANG:
|
case FPArchMage.BIG_BANG:
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ import java.sql.Connection;
|
|||||||
import java.sql.PreparedStatement;
|
import java.sql.PreparedStatement;
|
||||||
import java.sql.ResultSet;
|
import java.sql.ResultSet;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import net.AbstractMaplePacketHandler;
|
import net.AbstractMaplePacketHandler;
|
||||||
@@ -39,9 +40,11 @@ import net.server.world.PartyOperation;
|
|||||||
import net.server.world.World;
|
import net.server.world.World;
|
||||||
import tools.DatabaseConnection;
|
import tools.DatabaseConnection;
|
||||||
import tools.MaplePacketCreator;
|
import tools.MaplePacketCreator;
|
||||||
|
import tools.Pair;
|
||||||
import tools.data.input.SeekableLittleEndianAccessor;
|
import tools.data.input.SeekableLittleEndianAccessor;
|
||||||
import client.BuddylistEntry;
|
import client.BuddylistEntry;
|
||||||
import client.CharacterNameAndId;
|
import client.CharacterNameAndId;
|
||||||
|
import client.MapleBuffStat;
|
||||||
import client.MapleCharacter;
|
import client.MapleCharacter;
|
||||||
import client.MapleClient;
|
import client.MapleClient;
|
||||||
import client.MapleFamily;
|
import client.MapleFamily;
|
||||||
@@ -50,6 +53,8 @@ import client.inventory.MapleInventoryType;
|
|||||||
import client.inventory.MaplePet;
|
import client.inventory.MaplePet;
|
||||||
import constants.GameConstants;
|
import constants.GameConstants;
|
||||||
import constants.ServerConstants;
|
import constants.ServerConstants;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Comparator;
|
||||||
|
|
||||||
public final class PlayerLoggedinHandler extends AbstractMaplePacketHandler {
|
public final class PlayerLoggedinHandler extends AbstractMaplePacketHandler {
|
||||||
|
|
||||||
@@ -107,7 +112,8 @@ public final class PlayerLoggedinHandler extends AbstractMaplePacketHandler {
|
|||||||
|
|
||||||
List<PlayerBuffValueHolder> buffs = server.getPlayerBuffStorage().getBuffsFromStorage(cid);
|
List<PlayerBuffValueHolder> buffs = server.getPlayerBuffStorage().getBuffsFromStorage(cid);
|
||||||
if (buffs != null) {
|
if (buffs != null) {
|
||||||
player.silentGiveBuffs(buffs);
|
List<Pair<Long, PlayerBuffValueHolder>> timedBuffs = getLocalStartTimes(buffs);
|
||||||
|
player.silentGiveBuffs(timedBuffs);
|
||||||
}
|
}
|
||||||
Connection con = null;
|
Connection con = null;
|
||||||
PreparedStatement ps = null;
|
PreparedStatement ps = null;
|
||||||
@@ -286,4 +292,22 @@ public final class PlayerLoggedinHandler extends AbstractMaplePacketHandler {
|
|||||||
|
|
||||||
player.receivePartyMemberHP();
|
player.receivePartyMemberHP();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private List<Pair<Long, PlayerBuffValueHolder>> getLocalStartTimes(List<PlayerBuffValueHolder> lpbvl) {
|
||||||
|
List<Pair<Long, PlayerBuffValueHolder>> timedBuffs = new ArrayList<>();
|
||||||
|
long curtime = System.currentTimeMillis();
|
||||||
|
|
||||||
|
for(PlayerBuffValueHolder pb : lpbvl) {
|
||||||
|
timedBuffs.add(new Pair<>(curtime - pb.usedTime, pb));
|
||||||
|
}
|
||||||
|
|
||||||
|
Collections.sort(timedBuffs, new Comparator<Pair<Long, PlayerBuffValueHolder>>() {
|
||||||
|
@Override
|
||||||
|
public int compare(Pair<Long, PlayerBuffValueHolder> p1, Pair<Long, PlayerBuffValueHolder> p2) {
|
||||||
|
return p1.getLeft().compareTo(p2.getLeft());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return timedBuffs;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
34
src/net/server/channel/handlers/UseWaterOfLifeHandler.java
Normal file
34
src/net/server/channel/handlers/UseWaterOfLifeHandler.java
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
/*
|
||||||
|
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 net.server.channel.handlers;
|
||||||
|
|
||||||
|
import client.MapleClient;
|
||||||
|
import net.AbstractMaplePacketHandler;
|
||||||
|
import tools.data.input.SeekableLittleEndianAccessor;
|
||||||
|
|
||||||
|
public final class UseWaterOfLifeHandler extends AbstractMaplePacketHandler {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
|
||||||
|
c.getAbstractPlayerInteraction().openNpc(1032102, "waterOfLife");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -901,4 +901,21 @@ public class AbstractPlayerInteraction {
|
|||||||
public long getJailTimeLeft() {
|
public long getJailTimeLeft() {
|
||||||
return getPlayer().getJailExpirationTimeLeft();
|
return getPlayer().getJailExpirationTimeLeft();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<MaplePet> getDriedPets() {
|
||||||
|
List<MaplePet> list = new LinkedList<>();
|
||||||
|
|
||||||
|
long curTime = System.currentTimeMillis();
|
||||||
|
for(Item it : getPlayer().getInventory(MapleInventoryType.CASH).list()) {
|
||||||
|
if(ItemConstants.isPet(it.getItemId()) && it.getExpiration() < curTime) {
|
||||||
|
MaplePet pet = it.getPet();
|
||||||
|
if (pet != null) {
|
||||||
|
list.add(pet);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -978,16 +978,14 @@ public class MapleStatEffect {
|
|||||||
Rectangle bounds = new Rectangle(mylt.x, mylt.y, myrb.x - mylt.x, myrb.y - mylt.y);
|
Rectangle bounds = new Rectangle(mylt.x, mylt.y, myrb.x - mylt.x, myrb.y - mylt.y);
|
||||||
return bounds;
|
return bounds;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void silentApplyBuff(MapleCharacter chr, long starttime) {
|
public void silentApplyBuff(MapleCharacter chr, long localStartTime) {
|
||||||
int localDuration = duration;
|
int localDuration = duration;
|
||||||
localDuration = alchemistModifyVal(chr, localDuration, false);
|
localDuration = alchemistModifyVal(chr, localDuration, false);
|
||||||
//CancelEffectAction cancelAction = new CancelEffectAction(chr, this, starttime);
|
//CancelEffectAction cancelAction = new CancelEffectAction(chr, this, starttime);
|
||||||
//ScheduledFuture<?> schedule = TimerManager.getInstance().schedule(cancelAction, ((starttime + localDuration) - System.currentTimeMillis()));
|
//ScheduledFuture<?> schedule = TimerManager.getInstance().schedule(cancelAction, ((starttime + localDuration) - System.currentTimeMillis()));
|
||||||
|
|
||||||
if(starttime + localDuration <= System.currentTimeMillis()) return;
|
chr.registerEffect(this, localStartTime, localStartTime + localDuration, true);
|
||||||
|
|
||||||
chr.registerEffect(this, starttime, (starttime + localDuration), true);
|
|
||||||
SummonMovementType summonMovementType = getSummonMovementType();
|
SummonMovementType summonMovementType = getSummonMovementType();
|
||||||
if (summonMovementType != null) {
|
if (summonMovementType != null) {
|
||||||
final MapleSummon tosummon = new MapleSummon(chr, sourceid, chr.getPosition(), summonMovementType);
|
final MapleSummon tosummon = new MapleSummon(chr, sourceid, chr.getPosition(), summonMovementType);
|
||||||
|
|||||||
@@ -83731,7 +83731,7 @@
|
|||||||
</imgdir>
|
</imgdir>
|
||||||
<imgdir name="8166">
|
<imgdir name="8166">
|
||||||
<int name="SN" value="60000002"/>
|
<int name="SN" value="60000002"/>
|
||||||
<int name="ItemId" value="5000014"/>
|
<int name="ItemId" value="5000015"/>
|
||||||
<int name="Count" value="1"/>
|
<int name="Count" value="1"/>
|
||||||
<int name="Price" value="6700"/>
|
<int name="Price" value="6700"/>
|
||||||
<int name="Period" value="0"/>
|
<int name="Period" value="0"/>
|
||||||
@@ -91605,6 +91605,16 @@
|
|||||||
<int name="Period" value="90"/>
|
<int name="Period" value="90"/>
|
||||||
<int name="OnSale" value="0"/>
|
<int name="OnSale" value="0"/>
|
||||||
</imgdir>
|
</imgdir>
|
||||||
|
<imgdir name="8941">
|
||||||
|
<int name="Count" value="1"/>
|
||||||
|
<int name="Gender" value="2"/>
|
||||||
|
<int name="ItemId" value="5000013"/>
|
||||||
|
<int name="OnSale" value="1"/>
|
||||||
|
<int name="Period" value="90"/>
|
||||||
|
<int name="Price" value="5900"/>
|
||||||
|
<int name="Priority" value="7"/>
|
||||||
|
<int name="SN" value="60001000"/>
|
||||||
|
</imgdir>
|
||||||
<imgdir name="8940">
|
<imgdir name="8940">
|
||||||
<int name="SN" value="92000020"/>
|
<int name="SN" value="92000020"/>
|
||||||
<int name="ItemId" value="5041000"/>
|
<int name="ItemId" value="5041000"/>
|
||||||
@@ -91612,4 +91622,53 @@
|
|||||||
<int name="Period" value="90"/>
|
<int name="Period" value="90"/>
|
||||||
<int name="OnSale" value="0"/>
|
<int name="OnSale" value="0"/>
|
||||||
</imgdir>
|
</imgdir>
|
||||||
|
<imgdir name="8946">
|
||||||
|
<int name="Count" value="1"/>
|
||||||
|
<int name="Gender" value="2"/>
|
||||||
|
<int name="ItemId" value="5000060"/>
|
||||||
|
<int name="OnSale" value="1"/>
|
||||||
|
<int name="Price" value="20000"/>
|
||||||
|
<int name="Priority" value="6"/>
|
||||||
|
<int name="SN" value="60001005"/>
|
||||||
|
</imgdir>
|
||||||
|
<imgdir name="8945">
|
||||||
|
<int name="Count" value="1"/>
|
||||||
|
<int name="Gender" value="2"/>
|
||||||
|
<int name="ItemId" value="5000034"/>
|
||||||
|
<int name="OnSale" value="1"/>
|
||||||
|
<int name="Period" value="90"/>
|
||||||
|
<int name="Price" value="5800"/>
|
||||||
|
<int name="Priority" value="7"/>
|
||||||
|
<int name="SN" value="60001004"/>
|
||||||
|
</imgdir>
|
||||||
|
<imgdir name="8944">
|
||||||
|
<int name="Count" value="1"/>
|
||||||
|
<int name="Gender" value="2"/>
|
||||||
|
<int name="ItemId" value="5000045"/>
|
||||||
|
<int name="OnSale" value="1"/>
|
||||||
|
<int name="Period" value="90"/>
|
||||||
|
<int name="Price" value="5600"/>
|
||||||
|
<int name="Priority" value="7"/>
|
||||||
|
<int name="SN" value="60001003"/>
|
||||||
|
</imgdir>
|
||||||
|
<imgdir name="8943">
|
||||||
|
<int name="Count" value="1"/>
|
||||||
|
<int name="Gender" value="2"/>
|
||||||
|
<int name="ItemId" value="5000044"/>
|
||||||
|
<int name="OnSale" value="1"/>
|
||||||
|
<int name="Period" value="90"/>
|
||||||
|
<int name="Price" value="6900"/>
|
||||||
|
<int name="Priority" value="7"/>
|
||||||
|
<int name="SN" value="60001002"/>
|
||||||
|
</imgdir>
|
||||||
|
<imgdir name="8942">
|
||||||
|
<int name="Count" value="1"/>
|
||||||
|
<int name="Gender" value="2"/>
|
||||||
|
<int name="ItemId" value="5000039"/>
|
||||||
|
<int name="OnSale" value="1"/>
|
||||||
|
<int name="Period" value="90"/>
|
||||||
|
<int name="Price" value="5800"/>
|
||||||
|
<int name="Priority" value="7"/>
|
||||||
|
<int name="SN" value="60001001"/>
|
||||||
|
</imgdir>
|
||||||
</imgdir>
|
</imgdir>
|
||||||
|
|||||||
Reference in New Issue
Block a user