/*
This file is part of the OdinMS Maple Story Server
Copyright (C) 2008 ~ 2010 Patrick Huy <patrick.huy@frz.cc>
Matthias Butz <matze@odinms.de>
Jan Christian Meyer <vimes@odinms.de>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License version 3
as published by the Free Software Foundation. You may not use, modify
or distribute this program under any other version of the
GNU Affero General Public License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package scripting;
import client.MapleClient;
import client.inventory.Equip;
import client.inventory.Item;
import client.inventory.MapleInventoryType;
import constants.GameConstants;
import handling.channel.ChannelServer;
import java.awt.Point;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import server.MapleCarnivalFactory;
import server.MapleCarnivalFactory.MCSkill;
import server.MapleItemInformationProvider;
import server.Randomizer;
import server.life.MapleLifeFactory;
import server.life.MapleMonster;
import server.maps.MapleReactor;
import server.maps.ReactorDropEntry;
import tools.packet.CField;
public class ReactorActionManager extends AbstractPlayerInteraction {
private final MapleReactor reactor;
public ReactorActionManager(MapleClient c, MapleReactor reactor) {
super(c, reactor.getReactorId(), c.getPlayer().getMapId(), null);
this.reactor = reactor;
}
// only used for meso = false, really. No minItems because meso is used to fill the gap
public void dropItems() {
dropItems(false, 0, 0, 0, 0);
}
public void dropItems(boolean meso, int mesoChance, int minMeso, int maxMeso) {
dropItems(meso, mesoChance, minMeso, maxMeso, 0);
}
public void dropItems(boolean meso, int mesoChance, int minMeso, int maxMeso, int minItems) {
final List<ReactorDropEntry> chances = ReactorScriptManager.getInstance().getDrops(reactor.getReactorId());
final List<ReactorDropEntry> items = new LinkedList<>();
if (meso) {
if (Math.random() < (1 / (double) mesoChance)) {
items.add(new ReactorDropEntry(0, mesoChance, -1));
}
}
int numItems = 0;
// narrow list down by chances
final Iterator<ReactorDropEntry> iter = chances.iterator();
// for (DropEntry d : chances){
while (iter.hasNext()) {
ReactorDropEntry d = (ReactorDropEntry) iter.next();
if (Math.random() < (1 / (double) d.chance) && (d.questid <= 0 || getPlayer().getQuestStatus(d.questid) == 1)) {
numItems++;
items.add(d);
}
}
// if a minimum number of drops is required, add meso
while (items.size() < minItems) {
items.add(new ReactorDropEntry(0, mesoChance, -1));
numItems++;
}
final Point dropPos = reactor.getPosition();
dropPos.x -= (12 * numItems);
int range, mesoDrop;
final MapleItemInformationProvider ii = MapleItemInformationProvider.getInstance();
for (final ReactorDropEntry d : items) {
if (d.itemId == 0) {
range = maxMeso - minMeso;
mesoDrop = Randomizer.nextInt(range) + minMeso * ChannelServer.getInstance(getClient().getChannel()).getMesoRate(getClient().getPlayer() != null ? getClient().getPlayer().getWorld() : 0);
reactor.getMap().spawnMesoDrop(mesoDrop, dropPos, reactor, getPlayer(), false, (byte) 0);
} else {
Item drop;
if (GameConstants.getInventoryType(d.itemId) != MapleInventoryType.EQUIP) {
drop = new Item(d.itemId, (byte) 0, (short) 1, (byte) 0);
} else {
drop = ii.randomizeStats((Equip) ii.getEquipById(d.itemId));
}
drop.setGMLog("Dropped from reactor " + reactor.getReactorId() + " on map " + getPlayer().getMapId());
reactor.getMap().spawnItemDrop(reactor, getPlayer(), drop, dropPos, false, false);
}
dropPos.x += 25;
}
}
public void dropSingleItem(int itemId) {
Item drop;
if (GameConstants.getInventoryType(itemId) != MapleInventoryType.EQUIP) {
drop = new Item(itemId, (byte) 0, (short) 1, (byte) 0);
} else {
drop = MapleItemInformationProvider.getInstance().randomizeStats((Equip) MapleItemInformationProvider.getInstance().getEquipById(itemId));
}
drop.setGMLog("Dropped from reactor " + reactor.getReactorId() + " on map " + getPlayer().getMapId());
reactor.getMap().spawnItemDrop(reactor, getPlayer(), drop, reactor.getPosition(), false, false);
}
@Override
public void spawnNpc(int npcId) {
spawnNpc(npcId, getPosition());
}
// returns slightly above the reactor's position for monster spawns
public Point getPosition() {
Point pos = reactor.getPosition();
pos.y -= 10;
return pos;
}
public MapleReactor getReactor() {
return reactor;
}
public int hitBigby() {
MapleReactor bigby = null;
for (MapleReactor r : getMap().getAllReactor()) {
if (r.getReactorId() == 1301000) {
bigby = r;
}
}
if (bigby != null) {
bigby.forceHitReactor((byte) (bigby.getState() + 1));
if (bigby.getState() == 10) {
return 2;
}
return 1;
}
return 0;
}
public void spawnZakum() {
reactor.getMap().spawnZakum(getPosition().x, getPosition().y);
}
public void spawnFakeMonster(int id) {
spawnFakeMonster(id, 1, getPosition());
}
// summon one monster, remote location
public void spawnFakeMonster(int id, int x, int y) {
spawnFakeMonster(id, 1, new Point(x, y));
}
// multiple monsters, reactor location
public void spawnFakeMonster(int id, int qty) {
spawnFakeMonster(id, qty, getPosition());
}
// multiple monsters, remote location
public void spawnFakeMonster(int id, int qty, int x, int y) {
spawnFakeMonster(id, qty, new Point(x, y));
}
// handler for all spawnFakeMonster
private void spawnFakeMonster(int id, int qty, Point pos) {
for (int i = 0; i < qty; i++) {
reactor.getMap().spawnFakeMonsterOnGroundBelow(MapleLifeFactory.getMonster(id), pos);
}
}
public void killAll() {
reactor.getMap().killAllMonsters(true);
}
public void killMonster(int monsId) {
reactor.getMap().killMonster(monsId);
}
public void killReactor(int reactId) {
reactor.getMap().getReactorById(reactId).delayedDestroyReactor(1);
}
// summon one monster on reactor location
@Override
public void spawnMonster(int id) {
spawnMonster(id, 1, getPosition());
}
// summon monsters on reactor location
@Override
public void spawnMonster(int id, int qty) {
spawnMonster(id, qty, getPosition());
}
public void dispelAllMonsters(final int num) { //dispels all mobs, cpq
final MCSkill skil = MapleCarnivalFactory.getInstance().getGuardian(num);
if (skil != null) {
for (MapleMonster mons : getMap().getAllMonstersThreadsafe()) {
mons.dispelSkill(skil.getSkill());
}
}
}
public void cancelHarvest(boolean succ) {
getPlayer().setFatigue((byte) (getPlayer().getFatigue() + 1));
getPlayer().getMap().broadcastMessage(getPlayer(), CField.showHarvesting(getPlayer().getId(), 0), false);
getPlayer().getMap().broadcastMessage(CField.harvestResult(getPlayer().getId(), succ));
}
public void doHarvest() { //TODO LEGEND
if (getPlayer().getFatigue() >= (GameConstants.GMS ? 200 : 100) || getPlayer().getStat().harvestingTool <= 0 || getReactor().getTruePosition().distanceSq(getPlayer().getTruePosition()) > 10000) {
return;
}
final int pID = getReactor().getReactorId() < 200000 ? 92000000 : 92010000;
final String pName = (getReactor().getReactorId() < 200000 ? "Herbalism" : "Mining");
final int he = getPlayer().getProfessionLevel(pID);
if (he <= 0) {
return;
}
final Item item = getInventory(1).getItem((short) getPlayer().getStat().harvestingTool);
if (item == null || ((item.getItemId() / 10000)) != (getReactor().getReactorId() < 200000 ? 150 : 151)) {
return;
}
int hm = getReactor().getReactorId() % 100;
int successChance = 90 + ((he - hm) * 10);
if (getReactor().getReactorId() % 100 == 10) {
hm = 1;
successChance = 100;
} else if (getReactor().getReactorId() % 100 == 11) {
hm = 10;
successChance -= 40;
}
getPlayer().getStat().checkEquipDurabilitys(getPlayer(), -1, true);
int masteryIncrease = (hm - he) * 2 + 20;
final boolean succ = randInt(100) < successChance;
if (!succ) {
masteryIncrease /= 10;
dropSingleItem(getReactor().getReactorId() < 200000 ? 4022023 : 4010010);
} else {
dropItems();
if (getReactor().getReactorId() < 200000) {
addTrait("sense", 5);
if (Randomizer.nextInt(10) == 0) {
dropSingleItem(2440000);
}
if (Randomizer.nextInt(100) == 0) {
dropSingleItem(4032933);
}
} else {
addTrait("insight", 5);
if (Randomizer.nextInt(10) == 0) {
dropSingleItem(2440001); //IMP
}
}
}
cancelHarvest(succ);
playerMessage(-5, pName + "'s Mastery increased. (+" + masteryIncrease + ")");
if (getPlayer().addProfessionExp(pID, masteryIncrease)) {
playerMessage(-5, pName + " has gained a level.");
}
}
}