mirror of
https://gitlab.com/2009scape/2009scape.git
synced 2025-12-10 10:20:41 -07:00
Abyss Improvements
Implemented random Abyss teleport, with corresponding rotation for the obstacles Added visuals for passing through abyss obstacles Teleport location is now uniformly distributed - any angle around the outer ring has equal chance Fixed bug where abyss obstacles would send you to the wrong locations in the inner ring Fixed inferno adze not working on tendrils
This commit is contained in:
parent
75a81f0df6
commit
c65632263e
1 changed files with 294 additions and 397 deletions
|
|
@ -1,6 +1,7 @@
|
|||
package core.game.node.entity.skill.runecrafting.abyss
|
||||
|
||||
import api.*
|
||||
import core.game.node.Node
|
||||
import rs09.plugin.ClassScanner.definePlugin
|
||||
import rs09.tools.stringtools.colorize
|
||||
import rs09.game.system.SystemLogger.logInfo
|
||||
|
|
@ -13,25 +14,31 @@ import core.game.node.entity.skill.gather.SkillingTool
|
|||
import core.game.node.entity.skill.runecrafting.Altar
|
||||
import core.game.system.task.Pulse
|
||||
import core.game.world.map.Location
|
||||
import core.game.world.map.RegionManager
|
||||
import core.game.world.update.flag.context.Animation
|
||||
import core.game.world.update.flag.context.Graphics
|
||||
import core.plugin.Initializable
|
||||
import core.tools.RandomFunction
|
||||
import org.rs09.consts.Items
|
||||
import org.rs09.consts.NPCs
|
||||
import org.rs09.consts.Vars
|
||||
import org.rs09.consts.Animations
|
||||
import org.rs09.consts.Graphics as Gfx
|
||||
import org.rs09.consts.Scenery as Sceneries
|
||||
import rs09.game.interaction.InteractionListener
|
||||
import rs09.game.world.GameWorld
|
||||
import kotlin.math.cos
|
||||
import kotlin.math.sin
|
||||
import kotlin.random.Random
|
||||
|
||||
/**
|
||||
* A plugin used to handle the abyss.
|
||||
* @author lila
|
||||
* @author cfunny
|
||||
*/
|
||||
@Initializable
|
||||
class AbyssPlugin : InteractionListener {
|
||||
|
||||
val OBSTACLE = AbbysalObstacle.values().filter { it != AbbysalObstacle.MINE && it != AbbysalObstacle.SQUEEZE && it != AbbysalObstacle.PASSAGE && it != AbbysalObstacle.CHOP }.map { it.option }.toTypedArray()
|
||||
val miningObstacle = 7158
|
||||
val agilityObstacle = 7164
|
||||
val passage = 7154
|
||||
val chopObstacle = 7161
|
||||
|
||||
override fun defineListeners() {
|
||||
definePlugin(AbyssalNPC())
|
||||
definePlugin(DarkMageDialogue())
|
||||
|
|
@ -49,422 +56,312 @@ class AbyssPlugin : InteractionListener {
|
|||
altar?.enterRift(player)
|
||||
return@on true
|
||||
}
|
||||
on(SCENERY, *OBSTACLE){ player, node ->
|
||||
val obstacle = AbbysalObstacle.forObject(node as Scenery)
|
||||
obstacle!!.handle(player, node as Scenery)
|
||||
on(Sceneries.PASSAGE_7154, SCENERY, "go-through",){ player, node ->
|
||||
player.properties.teleportLocation = innerRing(node)
|
||||
return@on true
|
||||
}
|
||||
on(miningObstacle, SCENERY, "mine"){ player, node ->
|
||||
val obstacle = AbbysalObstacle.forObject(node as Scenery)
|
||||
obstacle!!.handle(player, node as Scenery)
|
||||
return@on true
|
||||
on(Sceneries.ROCK_7158, SCENERY, "mine"){ player, node ->
|
||||
val tool: SkillingTool? = getTool(player, true)
|
||||
if (tool == null) {
|
||||
sendMessage(player, "You need a pickaxe in order to do that.")
|
||||
return@on true
|
||||
}
|
||||
return@on handleObstacle(
|
||||
node,
|
||||
player,
|
||||
Skills.MINING,
|
||||
MINE_PROGRESS,
|
||||
tool.animation,
|
||||
arrayOf(
|
||||
"You attempt to mine your way through...",
|
||||
"...and manage to break through the rock.",
|
||||
"...but fail to break-up the rock."
|
||||
)
|
||||
)
|
||||
}
|
||||
on(agilityObstacle, SCENERY, "squeeze-through"){ player, node ->
|
||||
val obstacle = AbbysalObstacle.forObject(node as Scenery)
|
||||
obstacle!!.handle(player, node as Scenery)
|
||||
return@on true
|
||||
on(Sceneries.TENDRILS_7161, SCENERY, "chop"){ player, node ->
|
||||
val tool: SkillingTool? = getTool(player, false)
|
||||
if (tool == null) {
|
||||
sendMessage(player, "You need an axe in order to do that.")
|
||||
return@on true
|
||||
}
|
||||
return@on handleObstacle(
|
||||
node,
|
||||
player,
|
||||
Skills.WOODCUTTING,
|
||||
CHOP_PROGRESS,
|
||||
tool.animation,
|
||||
arrayOf(
|
||||
"You attempt to chop your way through...",
|
||||
"...and manage to chop down the tendrils.",
|
||||
"...but fail to cut through the tendrils."
|
||||
)
|
||||
)
|
||||
}
|
||||
on(passage, SCENERY, "go-through",){ player, node ->
|
||||
val obstacle = AbbysalObstacle.forObject(node as Scenery)
|
||||
obstacle!!.handle(player, node as Scenery)
|
||||
return@on true
|
||||
on(Sceneries.BOIL_7165, SCENERY, "burn-down"){ player, node ->
|
||||
if (!inInventory(player, Items.TINDERBOX_590)) {
|
||||
sendMessage(player, "You don't have a tinderbox to burn it.")
|
||||
return@on true
|
||||
}
|
||||
// TODO: i vaguely remember there being burn graphics for the boil. find if this is indeed true, and if so, find gfx id
|
||||
return@on handleObstacle(
|
||||
node,
|
||||
player,
|
||||
Skills.FIREMAKING,
|
||||
BURN_PROGRESS,
|
||||
// Animation(Animations.HUMAN_LIGHT_FIRE_WITH_TINDERBOX_733),
|
||||
Animation(733),
|
||||
arrayOf(
|
||||
"You attempt to burn your way through...",
|
||||
"...and manage to burn it down and get past.",
|
||||
"...but fail to set it on fire."
|
||||
)
|
||||
)
|
||||
}
|
||||
on(chopObstacle, SCENERY, "chop"){ player, node ->
|
||||
val obstacle = AbbysalObstacle.forObject(node as Scenery)
|
||||
obstacle!!.handle(player, node as Scenery)
|
||||
return@on true
|
||||
on(Sceneries.EYES_7168, SCENERY, "distract"){ player, node ->
|
||||
val distractEmote = Animation(distractEmotes[RandomFunction.random(0,distractEmotes.size)])
|
||||
return@on handleObstacle(
|
||||
node,
|
||||
player,
|
||||
Skills.THIEVING,
|
||||
DISTRACT_PROGRESS,
|
||||
distractEmote,
|
||||
arrayOf(
|
||||
"You use your thieving skills to misdirect the eyes...",
|
||||
"...and sneak past while they're not looking.",
|
||||
"...but fail to distract the eyes."
|
||||
)
|
||||
)
|
||||
}
|
||||
on(Sceneries.GAP_7164, SCENERY, "squeeze-through"){ player, node ->
|
||||
return@on handleObstacle(
|
||||
node,
|
||||
player,
|
||||
Skills.AGILITY,
|
||||
null,
|
||||
// Animation(Animations.HUMAN_SQUEEZE_INTO_GAP_1331),
|
||||
Animation(1331),
|
||||
arrayOf(
|
||||
"You attempt to squeeze through the narrow gap...",
|
||||
"...and you manage to crawl through.",
|
||||
"...but fail to crawl through."
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents an obstacle in an abbsyal.
|
||||
* @author cfunny
|
||||
* @date 02/11/2013
|
||||
* emotes used for the eyes obstacle
|
||||
*/
|
||||
enum class AbbysalObstacle(
|
||||
/**
|
||||
* Represents the option.
|
||||
*/
|
||||
val option: String,
|
||||
/**
|
||||
* Represents the corssing location.
|
||||
*/
|
||||
val locations: Array<Location>,
|
||||
/**
|
||||
* Represents the object id.
|
||||
*/
|
||||
vararg val objects: Int
|
||||
) {
|
||||
BOIL("burn-down", arrayOf(Location.create(3024, 4833, 0), Location.create(3053, 4830, 0)), 7165) {
|
||||
override fun handle(player: Player, `object`: Scenery?) {
|
||||
`object` ?: return
|
||||
if (!inInventory(player, 590, 1)) {
|
||||
sendMessage(player, "You don't have a tinderbox to burn it.")
|
||||
return
|
||||
}
|
||||
player.animate(Animation(733))
|
||||
player.lock()
|
||||
GameWorld.Pulser.submit(object : Pulse(1, player) {
|
||||
var count = 0
|
||||
override fun pulse(): Boolean {
|
||||
when (count) {
|
||||
1 -> sendMessage(player, "You attempt to burn your way through..")
|
||||
4 -> return if (RandomFunction.random(100) < getStatLevel(
|
||||
player,
|
||||
Skills.FIREMAKING
|
||||
)
|
||||
) {
|
||||
sendMessage(
|
||||
player,
|
||||
colorize("%G...and manage to burn it down and get past.")
|
||||
)
|
||||
player.properties.teleportLocation = locations[getIndex(`object`)]
|
||||
player.unlock()
|
||||
true
|
||||
} else {
|
||||
sendMessage(player, colorize("%RYou fail to set it on fire."))
|
||||
player.unlock()
|
||||
true
|
||||
}
|
||||
}
|
||||
count++
|
||||
return false
|
||||
}
|
||||
|
||||
override fun stop() {
|
||||
super.stop()
|
||||
player.animate(Animation(-1, Animator.Priority.HIGH))
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
MINE("mine", arrayOf(Location.create(3030, 4821, 0), Location.create(3048, 4822, 0)), 7158, 7153) {
|
||||
override fun handle(player: Player, `object`: Scenery?) {
|
||||
`object` ?: return
|
||||
logInfo("handled abyss mine")
|
||||
val tool: SkillingTool = getTool(player, true) ?: return
|
||||
if (tool == null) {
|
||||
sendMessage(player, "You need a pickaxe in order to do that.")
|
||||
return
|
||||
}
|
||||
player.animate(tool.getAnimation())
|
||||
player.lock()
|
||||
GameWorld.Pulser.submit(object : Pulse(1, player) {
|
||||
var count = 0
|
||||
override fun pulse(): Boolean {
|
||||
when (count) {
|
||||
1 -> sendMessage(player, "You attempt to mine your way through..")
|
||||
4 -> return if (RandomFunction.random(100) < getStatLevel(
|
||||
player,
|
||||
Skills.MINING
|
||||
)
|
||||
) {
|
||||
sendMessage(player, colorize("%G...and manage to break through the rock."))
|
||||
player.properties.teleportLocation = locations[getIndex(`object`)]
|
||||
player.unlock()
|
||||
true
|
||||
} else {
|
||||
sendMessage(player, colorize("%R...but fail to break-up the rock."))
|
||||
player.unlock()
|
||||
true
|
||||
}
|
||||
}
|
||||
count++
|
||||
return false
|
||||
}
|
||||
|
||||
override fun stop() {
|
||||
super.stop()
|
||||
player.animate(Animation(-1, Animator.Priority.HIGH))
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
CHOP("chop", arrayOf(Location.create(3050, 4824, 0), Location.create(3028, 4824, 0)), 7161, 7144) {
|
||||
override fun handle(player: Player, `object`: Scenery?) {
|
||||
`object` ?: return
|
||||
val tool: SkillingTool? = setTool(false, player)
|
||||
if (tool == null) {
|
||||
player.packetDispatch.sendMessage("You need an axe in order to do that.")
|
||||
return
|
||||
}
|
||||
player.animate(tool.getAnimation())
|
||||
player.lock()
|
||||
GameWorld.Pulser.submit(object : Pulse(1, player) {
|
||||
var count = 0
|
||||
override fun pulse(): Boolean {
|
||||
when (count) {
|
||||
1 -> sendMessage(player, "You attempt to chop your way through...")
|
||||
4 -> return if (RandomFunction.random(100) < getStatLevel(
|
||||
player,
|
||||
Skills.WOODCUTTING
|
||||
)
|
||||
) {
|
||||
sendMessage(player, colorize("%G...and manage to chop down the tendrils."))
|
||||
player.properties.teleportLocation = locations[getIndex(`object`)]
|
||||
player.unlock()
|
||||
true
|
||||
} else {
|
||||
sendMessage(player, colorize("%RYou fail to cut through the tendrils."))
|
||||
player.unlock()
|
||||
true
|
||||
}
|
||||
}
|
||||
count++
|
||||
return false
|
||||
}
|
||||
|
||||
override fun stop() {
|
||||
super.stop()
|
||||
player.animate(Animation(-1, Animator.Priority.HIGH))
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
SQUEEZE(
|
||||
"squeeze-through",
|
||||
arrayOf(Location.create(3048, 4842, 0), Location.create(3031, 4842, 0)),
|
||||
7164,
|
||||
7147
|
||||
) {
|
||||
override fun handle(player: Player, `object`: Scenery?) {
|
||||
`object` ?: return
|
||||
player.animate(Animation(1331))
|
||||
player.lock()
|
||||
GameWorld.Pulser.submit(object : Pulse(1, player) {
|
||||
var count = 0
|
||||
override fun pulse(): Boolean {
|
||||
when (count) {
|
||||
1 -> sendMessage(player, "You attempt to squeeze through the narrow gap...")
|
||||
4 -> return if (RandomFunction.random(100) < getStatLevel(
|
||||
player,
|
||||
Skills.AGILITY
|
||||
)
|
||||
) {
|
||||
sendMessage(player, colorize("%G...and you manage to crawl through."))
|
||||
player.properties.teleportLocation = locations[getIndex(`object`)]
|
||||
player.unlock()
|
||||
true
|
||||
} else {
|
||||
sendMessage(player, colorize("%RYou fail to squeeze through the narrow gap"))
|
||||
player.unlock()
|
||||
true
|
||||
}
|
||||
}
|
||||
count++
|
||||
return false
|
||||
}
|
||||
|
||||
override fun stop() {
|
||||
super.stop()
|
||||
player.animate(Animation(-1, Animator.Priority.HIGH))
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
DISTRACT("distract", arrayOf(Location.create(3029, 4841, 0), Location.create(3051, 4838, 0)), 7168, 7150) {
|
||||
override fun handle(player: Player, `object`: Scenery?) {
|
||||
`object` ?: return
|
||||
val emotes = intArrayOf(
|
||||
855,
|
||||
856,
|
||||
857,
|
||||
858,
|
||||
859,
|
||||
860,
|
||||
861,
|
||||
862,
|
||||
863,
|
||||
864,
|
||||
865,
|
||||
866,
|
||||
2113,
|
||||
2109,
|
||||
2111,
|
||||
2106,
|
||||
2107,
|
||||
2108,
|
||||
0x558,
|
||||
2105,
|
||||
2110,
|
||||
2112,
|
||||
0x84F,
|
||||
0x850,
|
||||
1131,
|
||||
1130,
|
||||
1129,
|
||||
1128,
|
||||
1745,
|
||||
3544,
|
||||
3543,
|
||||
2836
|
||||
)
|
||||
val index: Int = RandomFunction.random(emotes.size)
|
||||
player.animate(Animation(emotes[index]))
|
||||
player.lock()
|
||||
GameWorld.Pulser.submit(object : Pulse(1, player) {
|
||||
var count = 0
|
||||
override fun pulse(): Boolean {
|
||||
when (count) {
|
||||
1 -> sendMessage(player, "You use your thieving skills to misdirect the eyes...")
|
||||
4 -> return if (RandomFunction.random(100) < getStatLevel(
|
||||
player,
|
||||
Skills.THIEVING
|
||||
)
|
||||
) {
|
||||
sendMessage(
|
||||
player,
|
||||
colorize("%G...and sneak past while they're not looking.")
|
||||
)
|
||||
player.properties.teleportLocation = locations[getIndex(`object`)]
|
||||
player.unlock()
|
||||
true
|
||||
} else {
|
||||
sendMessage(player, colorize("%RYou fail to distract the eyes."))
|
||||
player.unlock()
|
||||
true
|
||||
}
|
||||
}
|
||||
count++
|
||||
return false
|
||||
}
|
||||
|
||||
override fun stop() {
|
||||
super.stop()
|
||||
player.animate(Animation(-1, Animator.Priority.HIGH))
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
PASSAGE("go-through", arrayOf(Location.create(3040, 4844, 0)), 7154) {
|
||||
override fun handle(player: Player, `object`: Scenery?) {
|
||||
player.properties.teleportLocation = locations[0]
|
||||
}
|
||||
};
|
||||
/**
|
||||
* Gets the option.
|
||||
* @return The option.
|
||||
*/
|
||||
/**
|
||||
* Gets the locations.
|
||||
* @return The locations.
|
||||
*/
|
||||
/**
|
||||
* Gets the objects.
|
||||
* @return The objects.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Method used to get the index.
|
||||
* @param object the object.
|
||||
* @return the index.
|
||||
*/
|
||||
fun getIndex(`object`: Scenery): Int {
|
||||
for (i in objects.indices) {
|
||||
if (objects[i] == `object`.getId()) {
|
||||
return i
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
/**
|
||||
* Method used to handle the obstacle.
|
||||
* @param player the player.
|
||||
* @param object the object.
|
||||
*/
|
||||
open fun handle(player: Player, `object`: Scenery?) {}
|
||||
|
||||
companion object {
|
||||
/**
|
||||
* Method used to get the abbysal obstacle.
|
||||
* @param object the object.
|
||||
* @return the `AbbysalObstacle` or `Null`.
|
||||
*/
|
||||
fun forObject(`object`: Scenery): AbbysalObstacle? {
|
||||
for (obstacle in values()) {
|
||||
for (i in obstacle.objects) {
|
||||
if (i == `object`.getId()) {
|
||||
return obstacle
|
||||
}
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the tool used.
|
||||
*/
|
||||
private fun setTool(mining: Boolean, player: Player): SkillingTool? {
|
||||
var tool: SkillingTool? = null
|
||||
if (!mining) {
|
||||
if (checkTool(player, SkillingTool.DRAGON_AXE)) {
|
||||
tool = SkillingTool.DRAGON_AXE
|
||||
} else if (checkTool(player, SkillingTool.RUNE_AXE)) {
|
||||
tool = SkillingTool.RUNE_AXE
|
||||
} else if (checkTool(player, SkillingTool.ADAMANT_AXE)) {
|
||||
tool = SkillingTool.ADAMANT_AXE
|
||||
} else if (checkTool(player, SkillingTool.MITHRIL_AXE)) {
|
||||
tool = SkillingTool.MITHRIL_AXE
|
||||
} else if (checkTool(player, SkillingTool.BLACK_AXE)) {
|
||||
tool = SkillingTool.BLACK_AXE
|
||||
} else if (checkTool(player, SkillingTool.STEEL_AXE)) {
|
||||
tool = SkillingTool.STEEL_AXE
|
||||
} else if (checkTool(player, SkillingTool.IRON_AXE)) {
|
||||
tool = SkillingTool.IRON_AXE
|
||||
} else if (checkTool(player, SkillingTool.BRONZE_AXE)) {
|
||||
tool = SkillingTool.BRONZE_AXE
|
||||
}
|
||||
} else {
|
||||
if (checkTool(player, SkillingTool.RUNE_PICKAXE)) {
|
||||
tool = SkillingTool.RUNE_PICKAXE
|
||||
} else if (checkTool(player, SkillingTool.ADAMANT_PICKAXE)) {
|
||||
tool = SkillingTool.ADAMANT_PICKAXE
|
||||
} else if (checkTool(player, SkillingTool.MITHRIL_PICKAXE)) {
|
||||
tool = SkillingTool.MITHRIL_PICKAXE
|
||||
} else if (checkTool(player, SkillingTool.STEEL_PICKAXE)) {
|
||||
tool = SkillingTool.STEEL_PICKAXE
|
||||
} else if (checkTool(player, SkillingTool.IRON_PICKAXE)) {
|
||||
tool = SkillingTool.IRON_PICKAXE
|
||||
} else if (checkTool(player, SkillingTool.BRONZE_PICKAXE)) {
|
||||
tool = SkillingTool.BRONZE_PICKAXE
|
||||
}
|
||||
}
|
||||
return tool
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the player has a tool and if he can use it.
|
||||
* @param tool The tool.
|
||||
* @return `True` if the tool is usable.
|
||||
*/
|
||||
private fun checkTool(player: Player, tool: SkillingTool): Boolean {
|
||||
return if (player.equipment.contains(tool.getId(), 1)) {
|
||||
true
|
||||
} else player.inventory.contains(tool.getId(), 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
private val distractEmotes = intArrayOf(
|
||||
855,
|
||||
856,
|
||||
857,
|
||||
858,
|
||||
859,
|
||||
860,
|
||||
861,
|
||||
862,
|
||||
863,
|
||||
864,
|
||||
865,
|
||||
866,
|
||||
2113,
|
||||
2109,
|
||||
2111,
|
||||
2106,
|
||||
2107,
|
||||
2108,
|
||||
0x558,
|
||||
2105,
|
||||
2110,
|
||||
2112,
|
||||
0x84F,
|
||||
0x850,
|
||||
1131,
|
||||
1130,
|
||||
1129,
|
||||
1128,
|
||||
1745,
|
||||
3544,
|
||||
3543,
|
||||
2836
|
||||
)
|
||||
|
||||
companion object {
|
||||
|
||||
/**
|
||||
* Represents the teleporting to the abyss.
|
||||
* @param player the player.
|
||||
* varp bit offset for the abyss obstacles varbits
|
||||
*/
|
||||
const val ABYSS_OBSTACLES = 18
|
||||
// varp value, until the constant is defined in consntlib
|
||||
const val VARP_SCENERY_ABYSS = 491
|
||||
|
||||
/**
|
||||
* Represents teleporting to the abyss,
|
||||
* including randomized location and rotating obstacles accordingly
|
||||
*/
|
||||
fun teleport(player: Player, npc: NPC) {
|
||||
|
||||
var teleportLoc = AbyssLoc.randomLoc()
|
||||
while(!teleportLoc.isValid()) {
|
||||
teleportLoc = teleportLoc.attract()
|
||||
}
|
||||
|
||||
player.lock(3)
|
||||
// npc.visualize(Animation(Animations.MAGE_OF_ZAMORAK_TELEOTHER_1979), Graphics(Gfx.TELEOTHER_PURPLE_BEAMS_4))
|
||||
npc.visualize(Animation(1979), Graphics(4))
|
||||
npc.sendChat("Veniens! Sallakar! Rinnesset!")
|
||||
player.skills.decrementPrayerPoints(100.0)
|
||||
player.skullManager.checkSkull(player)
|
||||
GameWorld.Pulser.submit(object : Pulse(2, player) {
|
||||
override fun pulse(): Boolean {
|
||||
player.properties.teleportLocation = Location.create(3021, 4847, 0)
|
||||
rotateObstacles(player,teleportLoc)
|
||||
player.properties.teleportLocation = teleportLoc.toAbs()
|
||||
npc.updateMasks.reset()
|
||||
return true
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents getting the inner ring location corresponding to a node in the outer ring.
|
||||
* Used to send a player to the inner ring when they pass an obstacle.
|
||||
*/
|
||||
fun innerRing(node: Node): Location {
|
||||
val obstacleLoc = AbyssLoc.fromAbs(node.location)
|
||||
var loc = obstacleLoc.attract(5)
|
||||
while (!loc.isValid()) {
|
||||
loc = loc.attract()
|
||||
}
|
||||
return loc.toAbs()
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Represents rotating the abyssal obstacles for the player.
|
||||
* Used to make sure the player lands by the blocked obstacle.
|
||||
*/
|
||||
fun rotateObstacles(player: Player, abyssLoc: AbyssLoc) {
|
||||
setVarbit(player,VARP_SCENERY_ABYSS,ABYSS_OBSTACLES,abyssLoc.getSegment(),true)
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles attempts at passing abyssal obstacles to get from outer ring to inner ring
|
||||
*/
|
||||
const val MINE_PROGRESS = 12
|
||||
const val CHOP_PROGRESS = 14
|
||||
const val BURN_PROGRESS = 16
|
||||
const val DISTRACT_PROGRESS = 18
|
||||
fun handleObstacle(obstacle: Node, player: Player, skill: Int, varbitVal: Int?, animation: Animation, messages: Array<String>): Boolean {
|
||||
logInfo("handled abyss ${obstacle.name}")
|
||||
player.lock()
|
||||
player.animate(animation)
|
||||
GameWorld.Pulser.submit(object : Pulse(1, player) {
|
||||
var count = 0
|
||||
override fun pulse(): Boolean {
|
||||
when (count++) {
|
||||
1 -> sendMessage(player, messages[0])
|
||||
3 -> return if (RandomFunction.random(100) < getStatLevel(player,skill)
|
||||
) {
|
||||
sendMessage(player, colorize("%G${messages[1]}"))
|
||||
if(varbitVal != null) { setVarbit(player,VARP_SCENERY_ABYSS,ABYSS_OBSTACLES,varbitVal) }
|
||||
false
|
||||
} else {
|
||||
sendMessage(player, colorize("%R${messages[2]}"))
|
||||
player.unlock()
|
||||
true
|
||||
}
|
||||
5 -> {
|
||||
if(varbitVal != null) { setVarbit(player,VARP_SCENERY_ABYSS,ABYSS_OBSTACLES,varbitVal or 1) }
|
||||
}
|
||||
7 -> {
|
||||
player.unlock()
|
||||
player.properties.teleportLocation = innerRing(obstacle)
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
override fun stop() {
|
||||
super.stop()
|
||||
player.animate(Animation(-1, Animator.Priority.HIGH))
|
||||
}
|
||||
})
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Polar coordinates class for abyss
|
||||
* @author lila
|
||||
*/
|
||||
class AbyssLoc(val radius: Double, val angle: Double) {
|
||||
|
||||
/**
|
||||
* Attract the location towards the center
|
||||
*/
|
||||
fun attract(steps: Int = 1): AbyssLoc {
|
||||
return AbyssLoc(radius-steps.toDouble(),angle)
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the segment of an abyssloc - its angle as an integer modulo 12, with south = 0 and positive = clockwise
|
||||
* this is used to determine which of the 12 evenly spaced obstacles around the outer ring the location is nearest to
|
||||
*/
|
||||
fun getSegment() : Int {
|
||||
val segments = 12
|
||||
val angleToCircle = angle * segments / ( 2 * Math.PI )
|
||||
val angleSegment = (angleToCircle + 0.5).toInt()
|
||||
// now 'normalize' the segment, so that 0 is the southernmost obstacle and 1 is clockwise from it
|
||||
val normalSegment = ( 9 - angleSegment ).mod(12)
|
||||
return normalSegment
|
||||
}
|
||||
|
||||
/**
|
||||
* Transform back to absolute coordinates
|
||||
*/
|
||||
fun toAbs() : Location {
|
||||
val x = (radius * cos(angle)).toInt()
|
||||
val y = (radius * sin(angle)).toInt()
|
||||
return origin.transform(x,y,0)
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if location is valid
|
||||
*/
|
||||
fun isValid() : Boolean {
|
||||
val abs = toAbs()
|
||||
return (RegionManager.isTeleportPermitted(abs) && RegionManager.getObject(abs) == null)
|
||||
}
|
||||
companion object {
|
||||
|
||||
/**
|
||||
* origin and outer radius values of the abyss itself
|
||||
*/
|
||||
// origin: the exact center of the abyss, inside that spinny ball thing
|
||||
val origin = Location(3039,4832,0)
|
||||
// the outer ring is generally at radius 24-26; testing shows that a minimum of 25.1 guarantees that players don't end up on an obstacle or inner wall
|
||||
const val outerRadius = 25.1
|
||||
|
||||
/**
|
||||
* turn an absolute location into an abyss location
|
||||
*/
|
||||
fun fromAbs(loc: Location) : AbyssLoc {
|
||||
val local = Location.getDelta(origin,loc)
|
||||
val radius = Math.sqrt((local.x * local.x + local.y * local.y).toDouble())
|
||||
val angle = Math.atan2(local.y.toDouble(),local.x.toDouble())
|
||||
return AbyssLoc(radius,angle)
|
||||
}
|
||||
|
||||
/**
|
||||
* get a random location around the abyss outer ring
|
||||
*/
|
||||
fun randomLoc() : AbyssLoc {
|
||||
val angle = Random.nextDouble() * 2 * Math.PI
|
||||
return AbyssLoc(outerRadius,angle)
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue