Merge pull request #114 from P0nk/area-boss-debuffs

Make area bosses killable
This commit is contained in:
Ponk
2022-08-31 22:07:14 +02:00
committed by GitHub
31 changed files with 226 additions and 64 deletions

View File

@@ -46,8 +46,12 @@ function action(mode, type, selection) {
}
if (status == 0) {
cm.sendOk("A small focus of light lighting in the immersive darkness.");
cm.dispose();
cm.sendAcceptDecline("This is a small lamp with a switch. Would you like to turn it on?");
return;
} else if (status == 1) {
cm.weakenAreaBoss(5090000, "You have turned the lamp on. Shade's strength will rapidly weaken due to the light.");
}
cm.dispose();
}
}

View File

@@ -24,7 +24,34 @@
Control Device
*/
var status;
function start() {
cm.sendNext("This control device seems to be monitoring something...");
cm.dispose();
status = -1;
action(1, 0, 0);
}
function action(mode, type, selection) {
if (mode == -1) {
cm.dispose();
} else {
if (mode == 0 && status == 0) {
cm.dispose();
return;
}
if (mode == 1) {
status++;
} else {
status--;
}
if (status == 0) {
cm.sendAcceptDecline("You can operate the automated security system using the control unit. Would you like to deactivate the automated security system?");
return;
} else if (status == 1) {
cm.weakenAreaBoss(7090000, "The automated security system has been deactivated. The intruder alarm will shut down.");
}
cm.dispose();
}
}

View File

@@ -24,7 +24,34 @@
Incomplete Magic Square
*/
var status;
function start() {
cm.sendNext("This chalkboard has some hard-founded studies annotated on it...");
cm.dispose();
status = -1;
action(1, 0, 0);
}
function action(mode, type, selection) {
if (mode == -1) {
cm.dispose();
} else {
if (mode == 0 && status == 0) {
cm.dispose();
return;
}
if (mode == 1) {
status++;
} else {
status--;
}
if (status == 0) {
cm.sendAcceptDecline("This Magic Pentagram is incomplete. Would you like to finish off the drawing of the Magic Pentagram?");
return;
} else if (status == 1) {
cm.weakenAreaBoss(8090000, "The Magic Pentagram has been completed. The spell to eliminate Deet and Roi has been summoned.");
}
cm.dispose();
}
}

View File

@@ -26,4 +26,6 @@
function hit() {
var map = rm.getMap();
map.moveEnvironment("trap" + rm.getReactor().getName()[5], 1);
}
}
function act() {}

View File

@@ -19,8 +19,18 @@
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/>.
*/
/**
Tombstone in Forest of Dead Trees I
MSEA reference: http://mymapleland.blogspot.com/2009/09/kill-lich-at-forest-of-dead-trees-i-to.html
*/
function hit() {
rm.hitMonsterWithReactor(6090000, 14);
if (rm.getReactor().getState() !== 0) {
return
}
rm.weakenAreaBoss(6090000, "As the tombstone lit up and vanished, Lich lost all his magic abilities.")
}
function act() {}
function act() {
// If the chest is destroyed before Riche, killing him should yield no exp
}

View File

@@ -19,8 +19,18 @@
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/>.
*/
/**
Tombstone in Forest of Dead Trees II
MSEA reference: http://mymapleland.blogspot.com/2009/09/kill-lich-at-forest-of-dead-trees-i-to.html
*/
function hit() {
rm.hitMonsterWithReactor(6090000, 14);
if (rm.getReactor().getState() !== 0) {
return
}
rm.weakenAreaBoss(6090000, "As the tombstone lit up and vanished, Lich lost all his magic abilities.")
}
function act() {}
function act() {
// If the chest is destroyed before Riche, killing him should yield no exp
}

View File

@@ -19,8 +19,18 @@
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/>.
*/
/**
Tombstone in Forest of Dead Trees III
MSEA reference: http://mymapleland.blogspot.com/2009/09/kill-lich-at-forest-of-dead-trees-i-to.html
*/
function hit() {
rm.hitMonsterWithReactor(6090000, 14);
if (rm.getReactor().getState() !== 0) {
return
}
rm.weakenAreaBoss(6090000, "As the tombstone lit up and vanished, Lich lost all his magic abilities.")
}
function act() {}
function act() {
// If the chest is destroyed before Riche, killing him should yield no exp
}

View File

@@ -19,8 +19,18 @@
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/>.
*/
/**
Tombstone in Forest of Dead Trees IV
MSEA reference: http://mymapleland.blogspot.com/2009/09/kill-lich-at-forest-of-dead-trees-i-to.html
*/
function hit() {
rm.hitMonsterWithReactor(6090000, 14);
if (rm.getReactor().getState() !== 0) {
return
}
rm.weakenAreaBoss(6090000, "As the tombstone lit up and vanished, Lich lost all his magic abilities.")
}
function act() {}
function act() {
// If the chest is destroyed before Riche, killing him should yield no exp
}

View File

@@ -19,7 +19,6 @@
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/>.
*/
function hit() {
rm.hitMonsterWithReactor(6090001, 4);
rm.getReactor().setEventState(Math.floor(Math.random() * 3));
function act() {
rm.weakenAreaBoss(6090001, "The light at the altar appeases the hatred of the Snow Witch. The force of the Witch has weakened.");
}

View File

@@ -19,7 +19,6 @@
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/>.
*/
function hit() {
rm.hitMonsterWithReactor(6090001, 4);
rm.getReactor().setEventState(Math.floor(Math.random() * 3));
function act() {
rm.weakenAreaBoss(6090001, "The light at the altar appeases the hatred of the Snow Witch. The force of the Witch has weakened.");
}

View File

@@ -19,7 +19,6 @@
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/>.
*/
function hit() {
rm.hitMonsterWithReactor(6090001, 4);
rm.getReactor().setEventState(Math.floor(Math.random() * 3));
function act() {
rm.weakenAreaBoss(6090001, "The light at the altar appeases the hatred of the Snow Witch. The force of the Witch has weakened.");
}

View File

@@ -19,6 +19,6 @@
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/>.
*/
function hit() {
rm.hitMonsterWithReactor(6090003, 1);
function act() {
rm.weakenAreaBoss(6090003, "The grieving Scholar Ghost has been slightly appeased. You may be able to defeat the Scholar Ghost.");
}

View File

@@ -25,6 +25,6 @@
* Neo City Trash Can
*/
function hit() {
function act() {
rm.dropItems(true, 2, 5, 10, 1);
}

View File

@@ -25,6 +25,6 @@
* Neo City Trash Can
*/
function hit() {
function act() {
rm.dropItems(true, 2, 5, 10, 1);
}

View File

@@ -26,4 +26,6 @@
function hit() {
rm.sprayItems();
}
}
function act() {}

View File

@@ -2,8 +2,6 @@
Yulete's Lab: Making the Reagent
*/
function hit() {
if (rm.getReactor().getState() == 4) {
rm.dropItems();
}
function act() {
rm.dropItems();
}

View File

@@ -40,4 +40,6 @@ function hit() {
rm.getMap().getReactorByName(reactname).hitReactor(rm.getClient());
}
}
}
}
function act() {}

View File

@@ -20,11 +20,11 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/*2618000.js - MagatiaPQ Beaker
/*2618001.js - MagatiaPQ Door
*@author Ronan
*/
function hit() {
function act() {
var eim = rm.getEventInstance();
var isAlcadno = eim.getIntProperty("isAlcadno");

View File

@@ -20,11 +20,11 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/*2618000.js - MagatiaPQ Beaker
/*2618002.js - MagatiaPQ Door
*@author Ronan
*/
function hit() {
function act() {
var eim = rm.getEventInstance();
var isAlcadno = eim.getIntProperty("isAlcadno");

View File

@@ -26,4 +26,9 @@
function hit() {
rm.dropItems();
}
function act() {
// There's a timeout of 3 seconds to revert back from state 1 to 0.
// Reactor is destroyed (state 2) and triggers this if dropping two Magic Devices at once, which shouldn't really happen.
}

View File

@@ -0,0 +1,3 @@
function act() {
rm.weakenAreaBoss(6090004, "Rurumo has been poisoned. It may finally be defeatable!");
}

View File

@@ -0,0 +1,3 @@
function act() {
rm.weakenAreaBoss(6090004, "Rurumo has been poisoned. It may finally be defeatable!");
}

View File

@@ -0,0 +1,3 @@
function act() {
rm.weakenAreaBoss(6090004, "Rurumo has been poisoned. It may finally be defeatable!");
}

View File

@@ -39,4 +39,6 @@ function hit() {
//spawnJrBoss(mapObj.getMonsterById(8820023));
mapObj.killMonster(8820000);
}
}
function act() {}

View File

@@ -257,6 +257,7 @@ public class CommandsExecutor {
addCommand("id", 2, IdCommand.class);
addCommand("gachalist", GachaListCommand.class);
addCommand("loot", LootCommand.class);
addCommand("mobskill", MobSkillCommand.class);
commandsNameDesc.add(levelCommandsCursor);
}

View File

@@ -0,0 +1,32 @@
package client.command.commands.gm2;
import client.Character;
import client.Client;
import client.command.Command;
import server.life.MobSkill;
import server.life.MobSkillFactory;
import java.util.Collections;
public class MobSkillCommand extends Command {
{
setDescription("Apply a mob skill to all mobs on the map. Args: <mob skill id> <skill level>");
}
@Override
public void execute(Client client, String[] params) {
if (params.length < 2) {
throw new IllegalArgumentException("Mob skill command requires two args: mob skill id and level");
}
String skillId = params[0];
String skillLevel = params[1];
MobSkill mobSkill = MobSkillFactory.getMobSkill(Integer.parseInt(skillId), Integer.parseInt(skillLevel));
if (mobSkill == null) {
throw new IllegalArgumentException("Mob skill not found. Id: %s, level: %s".formatted(skillId, skillLevel));
}
Character chr = client.getPlayer();
chr.getMap().getAllMonsters().forEach(monster -> mobSkill.applyEffect(chr, monster, false, Collections.emptyList()));
}
}

View File

@@ -1185,4 +1185,30 @@ public class AbstractPlayerInteraction {
public long getCurrentTime() {
return Server.getInstance().getCurrentTime();
}
public void weakenAreaBoss(int monsterId, String message) {
MapleMap map = c.getPlayer().getMap();
Monster monster = map.getMonsterById(monsterId);
if (monster == null) {
return;
}
applySealSkill(monster);
applyReduceAvoid(monster);
sendBlueNotice(map, message);
}
private void applySealSkill(Monster monster) {
MobSkill sealSkill = MobSkillFactory.getMobSkill(157, 1);
sealSkill.applyEffect(monster);
}
private void applyReduceAvoid(Monster monster) {
MobSkill reduceAvoidSkill = MobSkillFactory.getMobSkill(155, 2);
reduceAvoidSkill.applyEffect(monster);
}
private void sendBlueNotice(MapleMap map, String message) {
map.dropMessage(6, message);
}
}

View File

@@ -26,7 +26,6 @@ import client.Client;
import client.inventory.Equip;
import client.inventory.InventoryType;
import client.inventory.Item;
import config.YamlConfig;
import constants.inventory.ItemConstants;
import scripting.AbstractPlayerInteraction;
import server.ItemInformationProvider;
@@ -34,12 +33,10 @@ import server.TimerManager;
import server.life.LifeFactory;
import server.life.Monster;
import server.maps.MapMonitor;
import server.maps.MapleMap;
import server.maps.Reactor;
import server.maps.ReactorDropEntry;
import server.partyquest.CarnivalFactory;
import server.partyquest.CarnivalFactory.MCSkill;
import tools.PacketCreator;
import javax.script.Invocable;
import java.awt.*;
@@ -284,25 +281,6 @@ public class ReactorActionManager extends AbstractPlayerInteraction {
spawnNpc(npcId, pos, reactor.getMap());
}
public void hitMonsterWithReactor(int id, int hitsToKill) { // until someone comes with a better solution, why not?
int customTime = YamlConfig.config.server.MOB_REACTOR_REFRESH_TIME;
if (customTime > 0) {
reactor.setDelay(customTime);
}
MapleMap map = reactor.getMap();
Monster mm = map.getMonsterById(id);
if (mm != null) {
int damage = (int) Math.ceil(mm.getMaxHp() / hitsToKill);
Character chr = this.getPlayer();
if (chr != null) {
map.damageMonster(chr, mm, damage);
map.broadcastMessage(PacketCreator.damageMonster(mm.getObjectId(), damage));
}
}
}
public Reactor getReactor() {
return reactor;
}

View File

@@ -122,6 +122,10 @@ public class MobSkill {
service.registerOverallAction(monster.getMap().getId(), toRun, animationTime);
}
public void applyEffect(Monster monster) {
applyEffect(null, monster, false, Collections.emptyList());
}
public void applyEffect(Character player, Monster monster, boolean skill, List<Character> banishPlayers) {
Disease disease = null;
Map<MonsterStatus, Integer> stats = new ArrayMap<>();
@@ -243,6 +247,9 @@ public class MobSkill {
case 156:
stats.put(MonsterStatus.SPEED, x);
break;
case 157:
stats.put(MonsterStatus.SEAL_SKILL, x);
break;
case 200: // summon
int skillLimit = this.getLimit();
MapleMap map = monster.getMap();

View File

@@ -1448,7 +1448,7 @@ public class Monster extends AbstractLoadedLife {
}
public boolean canUseSkill(MobSkill toUse, boolean apply) {
if (toUse == null) {
if (toUse == null || isBuffed(MonsterStatus.SEAL_SKILL)) {
return false;
}

View File

@@ -270,8 +270,11 @@ public class Reactor extends AbstractMapObject {
continue;
}
}
state = stats.getNextState(state, b);
if (stats.getNextState(state, b) == -1) {//end of reactor
this.state = stats.getNextState(state, b);
byte nextState = stats.getNextState(state, b);
boolean isInEndState = nextState < this.state;
if (isInEndState) {//end of reactor
if (reactorType < 100) {//reactor broken
if (delay > 0) {
map.destroyReactor(getObjectId());