I've had to develop this in ~20 hours of total time for a service, with the quality of code not being a matter (by preference of customer).
It's external instead of embedded, I didn't want to bother adapting to an already bad system, so I made it cycle based - it's working just fine, beside auto-retaliation (you can force that none the less, figure out on your own)
It has: All attacks (Ranged, Prayer deactivation, Poison, Magic, Dragonfire) - as well as the freezing with the small alien pet, the big dragon fire (one-shot) & acid splatters.
If you don't use this, at least recognize the approach on how I did the calculation for acid splatters landing AROUND the circle instead because all vorkaths I saw so far had half-assed acid splatters.
Lacking stuff:
The projectile height of the one-shot ball is a bit too low
The delays are off on the smaller dragon balls, yet walking/dodging works fine
The projectiles shoot from a tile instead of relative to vorkaths mouth/face
The code is utter trash - lets be for real
The delays obviously are not the same as OSRS
There is no defensive stance animation / vorkath
Death animation is lacking / Alien
If I forgot a method, let me know
link for the standalone classes https://www.mediafire.com/file/cnnav02szvbbi85/vorkath.zip/file
Yasin: Me on R-S
If I forget anything, I'll tweak it asap on here
Media: https://i.gyazo.com/b058a5f20630b9f00ad3a67faf210a03.mp4 https://i.gyazo.com/13731ecdd3dee54338810ecb3e0a2f4c.mp4
AttackType class
package osv.model.npcs.bosses.vorkath;
/**
* @author Yasin
*/
public enum AttackType {
MAGIC(7952, 1479, 1480),
RANGED(7952, 1477, 1478),
ONE_HIT(7960, 1491, 157),
PRAYER_SNIPE(7952, 1471, 1473),
POISON(7952, 1470, 1472),
DRAGON_FIRE(7952, 393, 157),
SPECIAL_1(7957, 1486, 1473), //acid
SPECIAL_2(7952, 395, 369); //jihad
private int animationId;
private int projectileId;
private int endGfx;
AttackType(int animationId, int projectileId, int endGfx) {
this.animationId = animationId;
this.projectileId = projectileId;
this.endGfx = endGfx;
}
public int getAnimationId() {
return animationId;
}
public int getProjectileId() {
return projectileId;
}
public int getEndGfx() {
return endGfx;
}
}
Vorkath class
package osv.model.npcs.bosses.vorkath;
import osv.Server;
import osv.event.CycleEvent;
import osv.event.CycleEventContainer;
import osv.event.CycleEventHandler;
import osv.event.DelayEvent;
import osv.model.content.instances.InstancedAreaManager;
import osv.model.content.instances.SingleInstancedArea;
import osv.model.content.instances.impl.SingleInstancedVorkath;
import osv.model.entity.HealthStatus;
import osv.model.npcs.NPC;
import osv.model.npcs.NPCDumbPathFinder;
import osv.model.npcs.NPCHandler;
import osv.model.npcs.bosses.vorkath.impl.DeathStage;
import osv.model.npcs.bosses.vorkath.impl.SpawnStage;
import osv.model.npcs.bosses.vorkath.impl.WakeUpStage;
import osv.model.players.Player;
import osv.model.players.Position;
import osv.model.players.combat.Hitmark;
import osv.util.Misc;
import osv.world.objects.GlobalObject;
import java.util.Arrays;
import java.util.Optional;
import java.util.stream.Collectors;
/**
* @author Yasin
*/
public class Vorkath {
private final Player player;
private AttackType specialAttackType;
private AttackType attackType;
private VorkathState vorkathState;
private final Object eventLock;
private int attacks;
private NPC vorkath;
private boolean zombieSpawned;
private boolean forceDeath;
private SingleInstancedVorkath vorkathInstance;
public Vorkath(Player player) {
this.player = player;
this.specialAttackType = Arrays.stream(AttackType.values()).filter(type -> type.name().toLowerCase().contains("special")).collect(Collectors.toList()).get(Misc.random(1));//only 0 or 1
this.vorkathState = VorkathState.SLEEPING;
this.eventLock = new Object();
}
public void start() {
if (vorkathInstance != null) {
disposeInstance();
//player.sendMessage("Vorkath instance is not null, fyi! Disposing..");
}
int height = InstancedAreaManager.getSingleton().getNextOpenHeight(VorkathConstants.VORKATH_BOUNDARY);
vorkathInstance = new SingleInstancedVorkath(player, VorkathConstants.VORKATH_BOUNDARY, height);
InstancedAreaManager.getSingleton().add(height, vorkathInstance);
if (vorkathInstance == null) {
player.getDH().sendStatement("Vorkath can't be fought right now.", "Please try again shortly.");
player.nextChat = -1;
return;
}
CycleEventHandler.getSingleton().addEvent(eventLock, new SpawnStage(this, player), 1);
}
public void disposeInstance() {
forceDeath = true;
if (vorkath != null) {
setVorkathState(VorkathState.SLEEPING);
Server.npcHandler.kill(vorkath.npcType, vorkathInstance.getHeight());
}
attacks = 0;
InstancedAreaManager.getSingleton().disposeOf(vorkathInstance);
Server.getGlobalObjects().remove(32000, vorkathInstance.getHeight());
vorkathInstance = null;
forceDeath = false;
}
public void resetCombat() {
if (vorkath == null) {
return;
}
player.getCombat().resetPlayerAttack();
vorkath.underAttack = false;
vorkath.face = 0;
if (vorkathState == VorkathState.RESTING) {
vorkath.attackTimer += 1;
}
vorkath.underAttackBy = 0;
}
public boolean canSpecial() {
return attacks % 7 == 0 && attacks > 0;
}
public void wakeUp() {
if(vorkathState == VorkathState.AWAKE) {
return;
}
if (vorkathState != VorkathState.RESTING) { //just to make sure
vorkathState = VorkathState.AWAKE;
CycleEventHandler.getSingleton().addEvent(eventLock, new WakeUpStage(this, player, false), 1);
}
if (vorkathState == VorkathState.RESTING) { //just to make sure
vorkathState = VorkathState.AWAKE;
CycleEventHandler.getSingleton().addEvent(eventLock, new WakeUpStage(this, player, true), 1);
}
}
public void handleAttack() {
if (player != null && vorkath != null && !vorkath.isDead && !player.isDead && !zombieSpawned) {
int distance = player.distanceToPoint(vorkath.getX(), vorkath.getY());
if (vorkath.actionTimer > 0) {
return;
}
if(distance >= 15) {
return;
}
if(distance <= 3) {
vorkath.actionTimer += 2;
}
vorkath.actionTimer += 5;
attacks += 1;
if (canSpecial()) { //Every 7 attacks
specialAttackType = specialAttackType == AttackType.SPECIAL_1 ? AttackType.SPECIAL_2 : AttackType.SPECIAL_1;
vorkath.startAnimation(specialAttackType.getAnimationId());
if (specialAttackType == AttackType.SPECIAL_1) { //acid
CycleEventHandler.getSingleton().addEvent(eventLock, handleAcidSpecial(), 1);
vorkath.actionTimer += 22;
} else if (specialAttackType == AttackType.SPECIAL_2) { //jihad
fireTargetedProjectile(specialAttackType.getProjectileId());
CycleEventHandler.getSingleton().addEvent(eventLock, handleJihadSpecial(), 1);
player.stopMovement();
vorkath.actionTimer += 7;
}
} else {
attackType = Arrays.stream(AttackType.values()).filter(type ->
!type.name().toLowerCase().contains("special")).
collect(Collectors.toList()).get(Misc.random(5));
vorkath.actionTimer += 1;
vorkath.startAnimation(attackType.getAnimationId());
if (attackType != AttackType.ONE_HIT) {
CycleEventHandler.getSingleton().addEvent(eventLock, handleAttackType(), 1);
fireTargetedProjectile(attackType.getProjectileId());
} else {
CycleEventHandler.getSingleton().addEvent(eventLock, handleOneHit(), 1);
fireOneshit(attackType.getProjectileId(), 110, player.getX(), player.getY(),
50, 50); //50 -> current angle, 50 -> current start height
}
}
}
}
public void jump() {
CycleEventHandler.getSingleton().addEvent(eventLock, new CycleEvent() {
boolean north;
@Override
public void execute(CycleEventContainer container) {
if (container.getOwner() == null || player == null || player.isDead || player.animationRequest != -1) {
container.stop();
return;
}
int cycle = container.getTotalTicks();
if (cycle == 1) {
if (player.getX() <= 2273 && player.getX() >= 2271 && player.getY() == 4052) {
north = true;
}
player.startAnimation(1115);
player.sendMessage("You jump over the ice bricks..");
}
if (cycle == 3) {
player.stopAnimation();
player.sendMessage("and reach the other side..");
if(north && vorkathInstance == null) {
start();
}
if(vorkathInstance == null) { //height will be set in spawnstage
player.getPA().movePlayer(player.getX(), north ? player.getY() + 2 : player.getY() - 2);
} else { //so the player can continue
player.getPA().movePlayer(player.getX(), north ? player.getY() + 2 : player.getY() - 2, vorkathInstance.getHeight());
}
container.stop();
}
}
}, 1);
}
private CycleEvent handleJihadSpecial() {
return new CycleEvent() {
int SPAWN_X;
int SPAWN_Y;
NPC spawn;
private void killSpawn(boolean explode) {
spawn.gfx0(542);
zombieSpawned = false;
spawn.needRespawn = false;
spawn.isDead = true;
if(explode) {
player.appendDamage(Misc.random(60) + 10, Hitmark.HIT);
}
player.freezeTimer = 0;
}
@Override
public void execute(CycleEventContainer container) {
if (container.getOwner() == null || vorkath == null || player == null || player.isDead || vorkathInstance == null) {
container.stop();
return;
}
int cycle = container.getTotalTicks();
if (cycle == 4) {
player.gfx0(specialAttackType.getEndGfx());
player.freezeTimer = 500;
player.sendMessage("You've been frozen.");
}
if (cycle == 5) {
SPAWN_X = vorkath.getX() + Misc.random(7) + 3;
SPAWN_Y = vorkath.getY() - 2;
player.sendMessage("The dragon throws a creature towards you..");
zombieSpawned = true;
fireProjectileToLocation(1484, 130, SPAWN_X, SPAWN_Y, 50);
}
if (cycle == 9) {
spawn = Server.npcHandler.spawnNpc(player, VorkathConstants.ZOMBIE_SPAWN, SPAWN_X, SPAWN_Y, vorkathInstance.getHeight(), 1, VorkathConstants.ZOMBIE_SPAWN_LIFE_POINTS, 1, 1, 1, false, false);
}
if (cycle >= 10) {
int distance = player.distanceToPoint(spawn.getX(), spawn.getY());
if(zombieSpawned && spawn.isDead) {
killSpawn(false);
container.stop();
}
if (distance <= 1 && zombieSpawned) {
killSpawn(true);
container.stop();
}
}
if (zombieSpawned && cycle >= 10) {
if (spawn.getX() != player.absX - 1 && spawn.getY() != player.absY - 1) {
NPCDumbPathFinder.walkTowards(spawn, player.getX(), player.getY());
}
}
if (!zombieSpawned && cycle >= 20) {
container.stop();
}
if (zombieSpawned && cycle >= 20 && player.distanceToPoint(spawn.getX(), spawn.getY()) >= 5) {
if (player.distanceToPoint(spawn.getX(), spawn.getY()) < 40) {
killSpawn(false);
player.sendMessage("The spawn lost its orientation and blew up..");
}
}
}
};
}
private CycleEvent handleAcidSpecial() {
return new CycleEvent() {
int x;
int y;
@Override
public void execute(CycleEventContainer container) {
if (container.getOwner() == null || vorkath == null || player == null || player.isDead || vorkathInstance == null) {
container.stop();
return;
}
int cycle = container.getTotalTicks();
if(Server.getGlobalObjects().exists(32000, player.getX(), player.getY(), player.getHeight())) {
int randomDamage = Misc.random(10) + 7;
vorkath.getHealth().increase(randomDamage);
vorkath.updateRequired = true;
player.appendDamage(randomDamage, Hitmark.HIT);
player.sendMessage("You step on the acid and take some damage");
}
if (cycle == 1) {
int minX = VorkathConstants.VORKATH_BOUNDARY.getMinimumX();
int maxX = VorkathConstants.VORKATH_BOUNDARY.getMaximumX();
int minY = 4054; //it's bugged in the boundaries
int maxY = VorkathConstants.VORKATH_BOUNDARY.getMaximumY();
for (int i = 0; i < 40; i++) {
int randomX = minX + Misc.random(maxX - minX);
int randomY = minY + Misc.random(maxY - minY);
if ((randomX <= 2276 && randomX >= 2268 && randomY <= 4069 && randomY >= 4061)) {
continue;
}
fireProjectileToLocation(1486, 100,
randomX,
randomY, 60);
Server.getEventHandler().submit(new DelayEvent(5) {
@Override
public void onExecute() {
Server.getGlobalObjects().add(new GlobalObject(32000, randomX, randomY, vorkathInstance.getHeight(), Misc.random(3) + 1, 10, -1, -1));
}
});
}
}
if (cycle >= 3 && cycle <= 25) {
if (cycle >= 5) {
if (x == player.getX() && y == player.getY()) {
player.appendDamage(30, Hitmark.HIT);
}
}
x = player.getX();
y = player.getY();
fireProjectileToLocation(1482, 95, x, y, 35);
player.getPA().stillGfx(131, x, y, 15, 95);
fireProjectileToLocation(1482, 70, x, y, 35);
player.getPA().stillGfx(131, x, y, 15, 70);
}
if (cycle == 30) {
Server.getGlobalObjects().remove(32000, vorkathInstance.getHeight());
container.stop();
}
}
};
}
private CycleEvent handleOneHit() {
return new CycleEvent() {
Position arrival;
@Override
public void execute(CycleEventContainer container) {
if (container.getOwner() == null || vorkath == null || player == null || player.isDead || vorkathInstance == null) {
container.stop();
return;
}
int cycle = container.getTotalTicks();
if (cycle == 0) {
arrival = new Position(player.getX(), player.getY());
}
if (cycle == 5) {
int arrivalX = arrival.getX();
int arrivalY = arrival.getY();
int playerX = player.getX();
int playerY = player.getY();
if (playerX == arrivalX && playerY == arrivalY) {
applyRandomDamage(player.getHealth().getMaximum());
player.getPA().stillGfx(attackType.getEndGfx(), arrival.getX(), arrival.getY(), 100, 0);
} if(playerX == (arrivalX + 1)
|| playerX == (arrivalX - 1)
|| playerY == (arrivalY + 1)
|| arrivalY == (arrivalY - 1)) {
applyRandomDamage(player.getHealth().getMaximum() / 2);
player.getPA().stillGfx(attackType.getEndGfx(), arrivalX, arrivalY, 100, 0);
} else {
player.getPA().stillGfx(attackType.getEndGfx(), arrivalX, arrivalY, 20, 0);
}
container.stop();
}
}
};
}
private void fireTargetedProjectile(int projectileId) {
int offY = (vorkath.getX() - player.getX()) * -1;
int offX = (vorkath.getY() - player.getY()) * -1;
int delay = 0;
player.getPA().createPlayersProjectile(vorkath.getX() + 3, vorkath.getY(), offX, offY, 50, 110, projectileId, 35, 31, -player.getIndex() - 1, 65, delay);
}
private void fireProjectileToLocation(int projectileId, int projectileSpeed, int targetX, int targetY, int startHeight) {
int offY = (vorkath.getX() - targetX) * -1;
int offX = (vorkath.getY() - targetY) * -1;
int delay = 0;
player.getPA().createPlayersProjectile(vorkath.getX() + 3, vorkath.getY(), offX, offY - 3, 50, projectileSpeed, projectileId, startHeight, 31, 0, 65, delay);
}
private void fireOneshit(int projectileId, int projectileSpeed, int targetX, int targetY, int angle, int startHeight) {
int offY = (vorkath.getX() - targetX) * -1;
int offX = (vorkath.getY() - targetY) * -1;
int delay = 0;
player.getPA().createPlayersProjectile(vorkath.getX() + 3, vorkath.getY(), offX, offY - 3, 50, projectileSpeed, projectileId, startHeight, 31, 0, 65, delay);
}
private CycleEvent handleAttackType() {
return new CycleEvent() {
@Override
public void execute(CycleEventContainer container) {
if (container.getOwner() == null || vorkath == null || player == null || player.isDead || vorkathInstance == null) {
container.stop();
return;
}
int cycle = container.getTotalTicks();
//player.getPA().stillGfx(attackType.getEndGfx(), player.getX(), player.getY(), 100, 110);
if (cycle == 4) {
handleEffect();
}
if (cycle == 5) {
player.getPA().stillGfx(attackType.getEndGfx(), player.getX(), player.getY(), 100, 0);
container.stop();
}
}
};
}
private void applyRandomDamage(int amount) {
player.appendDamage(Misc.random(amount) + 1, Hitmark.HIT);
}
private void handleEffect() {
switch (attackType) {
case MAGIC:
if (player.prayerActive[16]) {
player.appendDamage(0, Hitmark.MISS);
return;
} else {
applyRandomDamage(35);
}
break;
case POISON:
applyRandomDamage(3);
player.getHealth().proposeStatus(HealthStatus.POISON, Misc.random(12), Optional.of(vorkath));
break;
case RANGED:
if (player.prayerActive[17]) {
player.appendDamage(0, Hitmark.MISS);
return;
} else {
applyRandomDamage(30);
}
break;
case DRAGON_FIRE:
boolean isResistent =
player.getItems().isWearingItem(1540)
|| player.getItems().isWearingItem(11283)
|| player.getItems().isWearingItem(11284)
|| (System.currentTimeMillis() - player.lastAntifirePotion < player.antifireDelay);
if (isResistent) {
player.sendMessage("Your resistance reflects the dragons fire!");
player.appendDamage(0, Hitmark.MISS);
return;
} else {
applyRandomDamage(35);
player.sendMessage("You got horribly burned by the dragons fire.");
}
break;
case PRAYER_SNIPE:
for (int i = 0; i < player.prayerActive.length - 1; i++) {
if (!player.prayerActive[i])
continue;
player.prayerActive[i] = false;
player.getPA().sendFrame36(player.PRAYER_GLOW[i], 0);
}
player.headIcon = -1;
player.getPA().requestUpdates();
applyRandomDamage(3);
break;
default:
break;
}
}
public void handleDeath() {
vorkathState = VorkathState.RESTING;
CycleEventHandler.getSingleton().addEvent(eventLock, new DeathStage(this, player), 1);
}
public void setVorkathInstance(SingleInstancedVorkath vorkathInstance) {
this.vorkathInstance = vorkathInstance;
}
public AttackType getAttackType() {
return attackType;
}
public VorkathState getVorkathState() {
return vorkathState;
}
public SingleInstancedArea getVorkathInstance() {
return vorkathInstance;
}
public Object getEventLock() {
return eventLock;
}
public AttackType getSpecialAttackType() {
return specialAttackType;
}
public void setVorkathState(VorkathState vorkathState) {
this.vorkathState = vorkathState;
}
public NPC getNpc() {
return vorkath;
}
public void setVorkath(NPC vorkath) {
this.vorkath = vorkath;
}
public int getAttacks() {
return attacks;
}
public void setAttacks(int attacks) {
this.attacks = attacks;
}
public boolean isForceDeath() {
return forceDeath;
}
public void setForceDeath(boolean forceDeath) {
this.forceDeath = forceDeath;
} public boolean isZombieSpawned() {
return zombieSpawned;
}
}
VorkathConstants class
package osv.model.npcs.bosses.vorkath;
import osv.model.players.Boundary;
/**
* @author Yasin
*/
public class VorkathConstants {
public static final int SLEEPING_VORKATH_ID = 8059;
public static final int AWAKENED_VORKATH_ID = 8061;
public static final int ZOMBIE_SPAWN = 8063;
public static final int ZOMBIE_SPAWN_LIFE_POINTS = 38;
public static final int VORKATH_LIFE_POINTS = 769;
public static final int X_COORDINATE = 2269;
public static final int Y_COORDINATE = 4062;
public static final Boundary VORKATH_BOUNDARY = new Boundary(2262, 4061, 2282, 4072);
}
VorkathState class
package osv.model.npcs.bosses.vorkath;
/**
* @author Yasin
*/
public enum VorkathState {
SLEEPING(-1, -1),
RESTING(-1, -1),
AWAKE(-1, -1);
private int animation;
private int npcId;
VorkathState(int animation, int npcId) {
this.animation = animation;
this.npcId = npcId;
}
public int getAnimation() {
return animation;
}
public int getNpcId() {
return npcId;
}
}
impl/DeathStage
package osv.model.npcs.bosses.vorkath.impl;
import osv.Server;
import osv.event.CycleEventContainer;
import osv.event.CycleEventHandler;
import osv.model.npcs.NPCHandler;
import osv.model.npcs.bosses.vorkath.Vorkath;
import osv.model.npcs.bosses.vorkath.VorkathConstants;
import osv.model.npcs.bosses.vorkath.VorkathState;
import osv.model.players.Player;
/**
* @author Yasin
*/
public class DeathStage extends Stage {
public DeathStage(Vorkath vorkath, Player player) {
super(vorkath, player);
}
@Override
public void execute(CycleEventContainer container) {
if (container.getOwner() == null || vorkath == null || player == null || player.isDead || vorkath.getVorkathInstance() == null) {
container.stop();
return;
}
int cycle = container.getTotalTicks();
int height = vorkath.getVorkathInstance().getHeight();
//reset both combat until stage ends
vorkath.resetCombat();
player.getCombat().resetPlayerAttack();
// player.sendMessage("Death stage Cycle: " + cycle);
if (cycle == 1) {
vorkath.setVorkathState(VorkathState.RESTING);
vorkath.getNpc().isDead = false;
vorkath.getNpc().spawnedMinions = false;
player.sendMessage("The dragon died..");
vorkath.getNpc().startAnimation(7949);//death animation
vorkath.getNpc().requestTransform(8059);
vorkath.setVorkath(Server.npcHandler.getNpc(VorkathConstants.SLEEPING_VORKATH_ID, VorkathConstants.X_COORDINATE, VorkathConstants.Y_COORDINATE, height));
container.stop();
}
/*if (cycle == 10) {
CycleEventHandler.getSingleton().addEvent(vorkath.getEventLock(), new WakeUpStage(vorkath, player, true), 1);
container.stop();
}*/
}
}
impl/SpawnStage
package osv.model.npcs.bosses.vorkath.impl;
import osv.Server;
import osv.event.CycleEventContainer;
import osv.model.npcs.bosses.vorkath.Vorkath;
import osv.model.npcs.bosses.vorkath.VorkathConstants;
import osv.model.players.Player;
/**
* @author Yasin
*/
public class SpawnStage extends Stage {
public SpawnStage(Vorkath vorkath, Player player) {
super(vorkath, player);
}
@Override
public void execute(CycleEventContainer container) {
if (container.getOwner() == null || vorkath == null || player == null || player.isDead || player.disconnected || vorkath.getVorkathInstance() == null) {
container.stop();
return;
}
int cycle = container.getTotalTicks();
int height = vorkath.getVorkathInstance().getHeight();
if(cycle == 1) {
// player.sendMessage("Height before:" + player.heightLevel);
player.setHeight(height);
player.heightLevel = height;
Server.getGlobalObjects().remove(32000, height);
//player.sendMessage("Height after: " + player.getHeight());
vorkath.setVorkath(Server.npcHandler.spawnNpc(player, VorkathConstants.SLEEPING_VORKATH_ID, VorkathConstants.X_COORDINATE, VorkathConstants.Y_COORDINATE, height, -1, VorkathConstants.VORKATH_LIFE_POINTS, 1, 500, 500, false, false));
//player.sendMessage("On height: " + height);
}
if(cycle == 2) {
player.sendMessage("You find yourself in a cave, with a dragon sleeping..");
}
if(cycle >= 3) {
container.stop();
}
}
}
**Please move Stage outside of the impl package, hence Stage is not an implementation of itself..**
impl/Stage class
package osv.model.npcs.bosses.vorkath.impl;
import osv.event.CycleEvent;
import osv.event.CycleEventContainer;
import osv.model.npcs.bosses.vorkath.Vorkath;
import osv.model.players.Player;
/**
* @author Yasin
*/
public class Stage extends CycleEvent {
protected Vorkath vorkath;
protected Player player;
public Stage(Vorkath vorkath, Player player) {
this.vorkath = vorkath;
this.player = player;
}
@Override
public void execute(CycleEventContainer container) {
}
}
package osv.model.npcs.bosses.vorkath.impl;
import osv.Server;
import osv.event.CycleEventContainer;
import osv.model.npcs.NPCHandler;
import osv.model.npcs.bosses.vorkath.Vorkath;
import osv.model.npcs.bosses.vorkath.VorkathConstants;
import osv.model.npcs.bosses.vorkath.VorkathState;
import osv.model.players.Player;
/**
* @author Yasin
*/
public class WakeUpStage extends Stage {
private boolean alreadyAlive;
public WakeUpStage(Vorkath vorkath, Player player) {
super(vorkath, player);
}
public WakeUpStage(Vorkath vorkath, Player player, boolean alreadyAlive) {
super(vorkath, player);
this.alreadyAlive = alreadyAlive;
}
@Override
public void execute(CycleEventContainer container) {
if (container.getOwner() == null || vorkath == null || player == null || player.isDead) {
container.stop();
return;
}
int cycle = container.getTotalTicks();
//reset both combat until stage ends
if(vorkath != null) {
vorkath.resetCombat();
}
if(alreadyAlive) {
if(cycle == 3) {
vorkath.getNpc().getHealth().setAmount(VorkathConstants.VORKATH_LIFE_POINTS);
}
if(cycle == 6) {
vorkath.getNpc().startAnimation(7950);
}
if(cycle == 9) {
vorkath.setAttacks(0);
vorkath.getNpc().requestTransform(VorkathConstants.AWAKENED_VORKATH_ID);
vorkath.setVorkath(Server.npcHandler.getNpc(VorkathConstants.AWAKENED_VORKATH_ID, VorkathConstants.X_COORDINATE, VorkathConstants.Y_COORDINATE, player.getHeight()));
vorkath.setVorkathState(VorkathState.AWAKE);
}
if(cycle >= 12) {
container.stop();
}
} else {
if(cycle == 1) {
player.startAnimation(2292);
player.sendMessage("You poke the dragon..");
}
if(cycle == 2) {
vorkath.getNpc().startAnimation(7950);
player.turnPlayerTo(vorkath.getNpc().getX(), vorkath.getNpc().getY() - 3);
vorkath.getNpc().getHealth().setAmount(VorkathConstants.VORKATH_LIFE_POINTS);
}
if(cycle == 9) {
vorkath.getNpc().requestTransform(VorkathConstants.AWAKENED_VORKATH_ID);
vorkath.setVorkathState(VorkathState.AWAKE);
container.stop();
}
}
}
}
AttackAnimation class, handleEmote method
Under the switch case
case VorkathConstants.AWAKENED_VORKATH_ID:
case VorkathConstants.SLEEPING_VORKATH_ID:
Player player = PlayerHandler.players[Server.npcHandler.npcs[i].spawnedBy];
if (player == null || player.getVorkath() == null || player.getVorkath().getNpc() == null) {
return -1;
}
if (player.getVorkath().canSpecial()) {
return player.getVorkath().getSpecialAttackType().getAnimationId();
} else if (player.distanceToPoint(Server.npcHandler.npcs[i].getX(), Server.npcHandler.npcs[i].getY()) > 4) {
return player.getVorkath().getAttackType().getAnimationId(); //regular attacks (distance)
}
return 7951;
DeathAnimation class, handleEmote method
under the switch case
case VorkathConstants.ZOMBIE_SPAWN:
case VorkathConstants.AWAKENED_VORKATH_ID:
case VorkathConstants.SLEEPING_VORKATH_ID:
return 102;
NPCHandler class, getNpcDelay method
under the switch case
case VorkathConstants.AWAKENED_VORKATH_ID:
case VorkathConstants.SLEEPING_VORKATH_ID:
return 4;
NPCHandler class, process method
under
if (npcs[i].actionTimer == 0 && !npcs[i].applyDead && !npcs[i].needRespawn) {
add this
if(npcs[i].npcType == VorkathConstants.SLEEPING_VORKATH_ID) {
npcs[i].isDead = false;
//player.sendMessage("HELL NO");
continue;
}
if (npcs[i].npcType == VorkathConstants.AWAKENED_VORKATH_ID) {
if (player.getVorkath().isForceDeath()) { //if forced death (ie player logout)
npcs[i].isDead = true;
npcs[i].updateRequired = true;
} else {
//player.sendMessage("Applying death");
npcs[i].killedBy = player.getIndex();
dropItems(i);
player.getVorkath().resetCombat();
player.getVorkath().handleDeath();
}
continue;
}
under
if (c.respawnTimer <= 0) {
add this:
if(npcs[i].npcType == VorkathConstants.AWAKENED_VORKATH_ID) {
return;
}
NPCHandler class, followPlayer method
under the switch case
case VorkathConstants.AWAKENED_VORKATH_ID:
case VorkathConstants.SLEEPING_VORKATH_ID:
return false;
NPCHandler class, attackPlayer method
under
if (npcs[i].lastX != npcs[i].getX() || npcs[i].lastY != npcs[i].getY()) {
return;
}
add
if(npcs[i].npcType == VorkathConstants.SLEEPING_VORKATH_ID) {
return;
}
if (npcs[i].npcType == VorkathConstants.AWAKENED_VORKATH_ID) {
if (c.getVorkath() != null) {
c.getVorkath().handleAttack();
}
}
NPCHandler class, isAggressive (this should make vorkath aggressive]
case VorkathConstants.AWAKENED_VORKATH_ID:
return true;
NPCHandler class, dropItems method
if (npcs[i].npcType == VorkathConstants.AWAKENED_VORKATH_ID) {
dropX = 2267;
dropY = 4061;
if (player.getNpcDeathTracker().getTracker().get(npcs[i].getName()) != null) {
int kills = player.getNpcDeathTracker().getTracker().get(npcs[i].getName());
if (kills == 50) {
Server.itemHandler.createGroundItem(player, 21907, dropX, dropY, player.heightLevel, 1);
}
}
}
NPCHandler class, distanceRequired method
under switch case
case VorkathConstants.AWAKENED_VORKATH_ID:
return 35;
NPCHandler class, retaliates(
|| npcType == VorkathConstants.AWAKENED_VORKATH_ID
Config class, UNDEAD_IDS array, add this element:
VorkathConstants.ZOMBIE_SPAWN
Disposal of instance on logout:
Player class, logout method
if (vorkath.getVorkathInstance() != null) { //if logging out from vorkath or while in vorkath instance
getPA().movePlayer(2272, 4052, 0);
vorkath.disposeInstance();
}
[/code]
[/SPOILER]
Disposal of instance when out of reach
[SPOILER=Player, process]
if (vorkath != null) {
if (vorkath.getVorkathInstance() != null) {
if (vorkath.getNpc() != null) {
if (distanceToPoint(vorkath.getNpc().getX(), vorkath.getNpc().getY()) >= 40) {
vorkath.disposeInstance();
sendMessage("Vorkath seems to have despawned..");
}
}
}
}
at last:
Player class:
declare instance
private Vorkath vorkath = new Vorkath(this);
declare getters/setters
public Vorkath getVorkath() {
return vorkath;
}
public void setVorkath(Vorkath vorkath) {
this.vorkath = vorkath;
}
create class
SingleInstancedVorkath class
package osv.model.content.instances.impl;
import osv.model.content.instances.SingleInstancedArea;
import osv.model.npcs.bosses.vorkath.Vorkath;
import osv.model.players.Boundary;
import osv.model.players.Player;
/**
* @author Yasin
*/
public class SingleInstancedVorkath extends SingleInstancedArea {
public SingleInstancedVorkath(Boundary boundary, int height) {
super(boundary, height);
}
public SingleInstancedVorkath(Player player, Boundary boundary, int height) {
super(player, boundary, height);
}
@Override
public void onDispose() {
Vorkath vorkath = player.getVorkath();
if (vorkath != null) {
vorkath.disposeInstance();
}
}
}
ObjectOptionOne class, under handleOption1add to the objectType switch:
case 31990:
if(c.getVorkath().getVorkathInstance() == null) {
c.getVorkath().jump();
}
break;