mirror of
https://gitlab.com/2009scape/2009scape.git
synced 2026-08-28 05:45:10 -06:00
Merge branch 2009scape:master into master
This commit is contained in:
commit
1821f3879e
39 changed files with 654 additions and 314 deletions
|
|
@ -1264,12 +1264,12 @@
|
|||
},
|
||||
{
|
||||
"examine": "Like a mini man!",
|
||||
"melee_animation": "422",
|
||||
"range_animation": "422",
|
||||
"melee_animation": "190",
|
||||
"range_animation": "190",
|
||||
"magic_level": "1",
|
||||
"defence_animation": "404",
|
||||
"defence_animation": "193",
|
||||
"magic_animation": "422",
|
||||
"death_animation": "9055",
|
||||
"death_animation": "196",
|
||||
"name": "Gnome",
|
||||
"defence_level": "1",
|
||||
"safespot": null,
|
||||
|
|
@ -1281,12 +1281,12 @@
|
|||
},
|
||||
{
|
||||
"examine": "Like a mini man!",
|
||||
"melee_animation": "422",
|
||||
"range_animation": "422",
|
||||
"melee_animation": "190",
|
||||
"range_animation": "190",
|
||||
"magic_level": "1",
|
||||
"defence_animation": "404",
|
||||
"defence_animation": "193",
|
||||
"magic_animation": "422",
|
||||
"death_animation": "9055",
|
||||
"death_animation": "196",
|
||||
"name": "Gnome",
|
||||
"defence_level": "1",
|
||||
"safespot": null,
|
||||
|
|
@ -1298,12 +1298,12 @@
|
|||
},
|
||||
{
|
||||
"examine": "Like a mini man!",
|
||||
"melee_animation": "422",
|
||||
"range_animation": "422",
|
||||
"melee_animation": "190",
|
||||
"range_animation": "190",
|
||||
"magic_level": "1",
|
||||
"defence_animation": "404",
|
||||
"defence_animation": "193",
|
||||
"magic_animation": "422",
|
||||
"death_animation": "9055",
|
||||
"death_animation": "196",
|
||||
"name": "Gnome",
|
||||
"defence_level": "1",
|
||||
"safespot": null,
|
||||
|
|
@ -1907,17 +1907,17 @@
|
|||
},
|
||||
{
|
||||
"examine": "Eeek! A ghost!",
|
||||
"melee_animation": "5540",
|
||||
"melee_animation": "5532",
|
||||
"range_animation": "0",
|
||||
"combat_audio": "436,439,438",
|
||||
"attack_speed": "4",
|
||||
"magic_level": "1",
|
||||
"respawn_delay": "40",
|
||||
"defence_animation": "5541",
|
||||
"defence_animation": "5533",
|
||||
"weakness": "5",
|
||||
"slayer_exp": "25",
|
||||
"magic_animation": "0",
|
||||
"death_animation": "5542",
|
||||
"death_animation": "5534",
|
||||
"name": "Ghost",
|
||||
"defence_level": "18",
|
||||
"safespot": null,
|
||||
|
|
@ -2182,11 +2182,11 @@
|
|||
"attack_speed": "4",
|
||||
"magic_level": "1",
|
||||
"respawn_delay": "25",
|
||||
"defence_animation": "360",
|
||||
"defence_animation": "4651",
|
||||
"weakness": "8",
|
||||
"slayer_exp": "75",
|
||||
"magic_animation": "359",
|
||||
"death_animation": "361",
|
||||
"death_animation": "4653",
|
||||
"name": "Cyclops",
|
||||
"defence_level": "35",
|
||||
"safespot": null,
|
||||
|
|
@ -47350,12 +47350,15 @@
|
|||
"attack_level": "1"
|
||||
},
|
||||
{
|
||||
"combat_audio": "931,923,922",
|
||||
"melee_animation": "5578",
|
||||
"defence_animation": "5567",
|
||||
"slayer_exp": "30",
|
||||
"death_animation": "5569",
|
||||
"name": "Zombie",
|
||||
"defence_level": "1",
|
||||
"safespot": null,
|
||||
"lifepoints": "40",
|
||||
"combat_audio": "931,923,922",
|
||||
"strength_level": "1",
|
||||
"id": "5394",
|
||||
"range_level": "1",
|
||||
|
|
@ -76059,8 +76062,21 @@
|
|||
"id": "2239"
|
||||
},
|
||||
{
|
||||
"examine": "Like a mini man!",
|
||||
"combat_style": "1",
|
||||
"force_talk": "",
|
||||
"melee_animation": "190",
|
||||
"attack_speed": "4",
|
||||
"respawn_delay": "60",
|
||||
"defence_animation": "193",
|
||||
"death_animation": "196",
|
||||
"name": "Gnome",
|
||||
"id": "2251"
|
||||
"defence_level": "1",
|
||||
"lifepoints": "3",
|
||||
"strength_level": "1",
|
||||
"id": "2251",
|
||||
"range_level": "1",
|
||||
"attack_level": "1"
|
||||
},
|
||||
{
|
||||
"name": "Crow",
|
||||
|
|
|
|||
|
|
@ -1546,5 +1546,41 @@
|
|||
"animation": "426",
|
||||
"drop_ammo": "true",
|
||||
"ammunition": "14202,14203,14204,14205,14206"
|
||||
},
|
||||
{
|
||||
"itemId": "10149",
|
||||
"name": "Swamp lizard",
|
||||
"ammo_slot": "13",
|
||||
"weapon_type": "0",
|
||||
"animation": "5247",
|
||||
"drop_ammo": "false",
|
||||
"ammunition": "10142"
|
||||
},
|
||||
{
|
||||
"itemId": "10146",
|
||||
"name": "Orange salamander",
|
||||
"ammo_slot": "13",
|
||||
"weapon_type": "0",
|
||||
"animation": "5247",
|
||||
"drop_ammo": "false",
|
||||
"ammunition": "10143"
|
||||
},
|
||||
{
|
||||
"itemId": "10147",
|
||||
"name": "Red salamander",
|
||||
"ammo_slot": "13",
|
||||
"weapon_type": "0",
|
||||
"animation": "5247",
|
||||
"drop_ammo": "false",
|
||||
"ammunition": "10144"
|
||||
},
|
||||
{
|
||||
"itemId": "10148",
|
||||
"name": "Black salamander",
|
||||
"ammo_slot": "13",
|
||||
"weapon_type": "0",
|
||||
"animation": "5247",
|
||||
"drop_ammo": "false",
|
||||
"ammunition": "10145"
|
||||
}
|
||||
]
|
||||
|
|
|
|||
|
|
@ -9,15 +9,14 @@ import core.game.event.TeleportEvent
|
|||
import core.game.interaction.QueueStrength
|
||||
import core.game.node.entity.player.Player
|
||||
import core.game.node.entity.player.link.TeleportManager
|
||||
import core.game.node.entity.player.link.diary.DiaryType
|
||||
import core.game.node.item.Item
|
||||
import core.game.system.task.Pulse
|
||||
import core.game.world.GameWorld
|
||||
import core.game.world.map.Location
|
||||
import core.game.world.update.flag.context.Animation
|
||||
import core.game.world.update.flag.context.Graphics
|
||||
import org.rs09.consts.Items
|
||||
import core.game.world.GameWorld.Pulser
|
||||
import core.tools.Log
|
||||
import org.rs09.consts.Items
|
||||
import org.rs09.consts.Sounds
|
||||
import java.util.*
|
||||
|
||||
|
|
@ -258,6 +257,11 @@ enum class EnchantedJewellery(
|
|||
resetAnimator(player)
|
||||
unlock(player)
|
||||
player.dispatch(TeleportEvent(TeleportManager.TeleportType.NORMAL, TeleportMethod.JEWELRY, item, location))
|
||||
|
||||
if (DIGSITE_PENDANT.ids.contains(item.id)) {
|
||||
player.achievementDiaryManager.finishTask(player, DiaryType.VARROCK, 1, 10)
|
||||
}
|
||||
|
||||
if (!replace) {
|
||||
return@queueScript stopExecuting(player)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -317,6 +317,7 @@ public enum Consumables {
|
|||
TCHIKI_MONKEY_PASTE(new Food(new int[] {7575}, new HealingEffect(5), "You eat the Tchiki monkey nut paste. It sticks to the roof of your mouth.")),
|
||||
OOMLIE_WRAP(new Food(new int[] {Items.COOKED_OOMLIE_WRAP_2343}, new MultiEffect(new HealingEffect(14), new AchievementEffect(DiaryType.KARAMJA, 2, 2)))),
|
||||
ROE(new Food(new int[]{11324}, new HealingEffect(3))),
|
||||
CAVIAR(new Food(new int[]{11326}, new HealingEffect(5))),
|
||||
EQUA_LEAVES(new Food(new int[]{2128}, new HealingEffect(1))),
|
||||
CHOC_ICE(new Food(new int[]{6794}, new HealingEffect(7))),
|
||||
EDIBLE_SEAWEED(new Food(new int[] {403}, new HealingEffect(4))),
|
||||
|
|
|
|||
|
|
@ -1,8 +1,6 @@
|
|||
package content.global.activity.cchallange.npc
|
||||
|
||||
import core.api.*
|
||||
import core.game.container.impl.EquipmentContainer
|
||||
import core.game.global.action.EquipHandler
|
||||
import core.game.node.entity.Entity
|
||||
import core.game.node.entity.combat.BattleState
|
||||
import core.game.node.entity.npc.AbstractNPC
|
||||
|
|
@ -62,12 +60,11 @@ class LesserDemonChampionNPC(id: Int = 0, location: Location? = null) : Abstract
|
|||
super.checkImpact(state)
|
||||
val player = state.attacker
|
||||
if (player is Player) {
|
||||
if (!player.equipment[3].hasItemPlugin()) {
|
||||
if (player.equipment.isEmpty) {
|
||||
state.neutralizeHits()
|
||||
state.estimatedHit = state.maximumHit
|
||||
} else {
|
||||
EquipHandler.unequip(player, EquipmentContainer.SLOT_WEAPON, id)
|
||||
sendMessage(player, "You cannot use weapons in this challenge.")
|
||||
sendMessage(player, "You cannot wear any equipment in this challenge.")
|
||||
if (state.estimatedHit > -1) {
|
||||
state.estimatedHit = 0
|
||||
return
|
||||
|
|
|
|||
|
|
@ -63,8 +63,8 @@ class ZombieChampionNPC(id: Int = 0, location: Location? = null) : AbstractNPC(i
|
|||
val player = state.attacker
|
||||
if (player is Player) {
|
||||
if (state.style == CombatStyle.MELEE || state.style == CombatStyle.RANGE) {
|
||||
state.estimatedHit = state.maximumHit
|
||||
state.neutralizeHits()
|
||||
state.estimatedHit = state.maximumHit
|
||||
}
|
||||
if (state.style == CombatStyle.MAGIC) {
|
||||
sendMessage(player, "You cannot use spells in this challenge.")
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ class PenguinManager{
|
|||
return tagMapping[Penguin.forLocation(location)?.ordinal]?.contains(player.username.toLowerCase()) ?: false
|
||||
}
|
||||
|
||||
private fun updateStoreFile(){
|
||||
fun updateStoreFile(){
|
||||
val jsonTags = JSONArray()
|
||||
tagMapping.filter { it.value.isNotEmpty() }.forEach { (ordinal,taggers) ->
|
||||
log(this::class.java, Log.FINE, "$ordinal - ${taggers.first()}")
|
||||
|
|
|
|||
|
|
@ -44,18 +44,65 @@ enum class Penguin(val id: Int, val hint: String, val location: Location){
|
|||
BUSH_8(NPCs.BUSH_8105,"located in the kingdom of Asgarnia.",Location.create(2951, 3511, 0)),
|
||||
BUSH_9(NPCs.BUSH_8105,"located in the northern desert.",Location.create(3350, 3311, 0)),
|
||||
BUSH_10(NPCs.BUSH_8105,"located somewhere in the kingdom of Kandarin.",Location.create(2633, 3501, 0)),
|
||||
BUSH_11(NPCs.BUSH_8105,"located south of Ardougne.",Location.create(2440, 3206, 0)),
|
||||
BUSH_12(NPCs.BUSH_8105,"located where wizards study.",Location.create(3112, 3149, 0)),
|
||||
BUSH_11(NPCs.BUSH_8105,"located where wizards study.",Location.create(3112, 3149, 0)),
|
||||
ROCK_1(NPCs.ROCK_8109,"located where the Imperial Guard train.",Location.create(2852, 3578, 0)),
|
||||
ROCK_2(NPCs.ROCK_8109,"located in the kingdom of Misthalin.",Location.create(3356, 3416, 0)),
|
||||
ROCK_3(NPCs.ROCK_8109,"located near some ogres.",Location.create(2631, 2980, 0)),
|
||||
ROCK_3(NPCs.ROCK_8109,"located near some ogres.",Location.create(2631, 2980, 0)), //potentially incorrect location
|
||||
ROCK_4(NPCs.ROCK_8109,"located in the Kingdom of Asgarnia.",Location.create(3013, 3501, 0)),
|
||||
ROCK_5(NPCs.ROCK_8109,"located between Fremennik and barbarians.",Location.create(2532, 3630, 0)),
|
||||
CRATE_1(NPCs.CRATE_8108,"located in the kingdom of Misthalin.",Location.create(3112, 3332, 0)),
|
||||
CRATE_2(NPCs.CRATE_8108,"located in the Kingdom of Misthalin.",Location.create(3305, 3508, 0)),
|
||||
BARREL_1(NPCs.CRATE_8108,"located where no weapons may go.",Location.create(2806, 3383, 0)),
|
||||
CRATE_3(NPCs.CRATE_8108,"located south of Ardougne.",Location.create(2440, 3206, 0)),
|
||||
BARREL_1(NPCs.BARREL_8104,"located where no weapons may go.",Location.create(2806, 3383, 0)),
|
||||
TOADSTOOL_1(NPCs.TOADSTOOL_8110,"located in the kingdom of Misthalin.",Location.create(3156, 3178, 0)),
|
||||
TOADSTOOL_2(NPCs.TOADSTOOL_8110,"located in the fairy realm.",Location.create(2409, 4462, 0));
|
||||
TOADSTOOL_2(NPCs.TOADSTOOL_8110,"located in the fairy realm.",Location.create(2409, 4462, 0)), //potentially a spawn from 2010
|
||||
|
||||
BUSH_12(NPCs.BUSH_8105,"located on an island.",Location.create(2534, 3871, 0)),
|
||||
BARREL_2(NPCs.BARREL_8104,"located near the ghost town.",Location.create(3654, 3491, 0)),
|
||||
BUSH_13(NPCs.BUSH_8105,"located where bloodsuckers rule.",Location.create(3600, 3487, 0)),
|
||||
BUSH_14(NPCs.BUSH_8105,"located on islands where brothers quarrel.",Location.create(2355, 3848, 0)),
|
||||
ROCK_6(NPCs.ROCK_8109,"located on a large crescent island.",Location.create(2118, 3943, 0)),
|
||||
ROCK_7(NPCs.ROCK_8109,"located on islands where brothers quarrel.",Location.create(2357, 3797, 0)),
|
||||
ROCK_8(NPCs.ROCK_8109,"located in the Wilderness.",Location.create(3169, 3650, 0)),
|
||||
BARREL_3(NPCs.BARREL_8104,"located where pirates feel mostly harmless.",Location.create(3738, 3001, 0)),
|
||||
CACTUS_3(NPCs.CACTUS_8107,"located in the southern desert.",Location.create(3276, 2797, 0)),
|
||||
TOADSTOOL_3(NPCs.TOADSTOOL_8110,"located near the pointy-eared ones.",Location.create(2314, 3174, 0)),
|
||||
BUSH_15(NPCs.BUSH_8105,"located deep in the jungle.",Location.create(2938, 2978, 0)),
|
||||
TOADSTOOL_4(NPCs.TOADSTOOL_8110,"located near the pointy-eared ones.",Location.create(2219, 3227, 0)),
|
||||
BARREL_4(NPCs.BARREL_8104,"located south of Ardougne.",Location.create(2662, 3152, 0)),
|
||||
//BARREL_5(NPCs.BARREL_8104,"located where monkeys rule.",Location.create(2751, 2700, 0)),
|
||||
//currently not well accessible, will need to add when Ape Atoll is sorted.
|
||||
//BUSH_16(NPCs.BUSH_8105,"located on islands where brothers quarrel.",Location.create(2353, 3834, 0)),
|
||||
//currently not well accessible, will need to add when Neitiznot bridges are fixed.
|
||||
ROCK_9(NPCs.ROCK_8109,"located near a mountain of wolves.",Location.create(2852, 3504, 0)),
|
||||
ROCK_10(NPCs.ROCK_8109,"located on islands where brothers quarrel.",Location.create(2413, 3846, 0)),
|
||||
|
||||
BUSH_17(NPCs.BUSH_8105,"located near some ogres.",Location.create(2578, 2909, 0)),
|
||||
CRATE_4(NPCs.CRATE_8108,"located where banana smugglers dwell.",Location.create(2869, 3157, 0)),
|
||||
//CRATE_5(NPCs.CRATE_8108,"located near the island of Dragontooth.",Location.create(3824, 3562, 0)),
|
||||
//current not accessible, will need to add when Dragontooth island is sorted.
|
||||
ROCK_11(NPCs.ROCK_8109,"located where bloodsuckers rule.",Location.create(3550, 3439, 0)),
|
||||
TOADSTOOL_5(NPCs.TOADSTOOL_8110,"located near the pointy-eared ones.",Location.create(2181, 3172, 0)),
|
||||
BUSH_18(NPCs.BUSH_8105,"located where bloodsuckers rule.",Location.create(3472, 3392, 0)),
|
||||
BUSH_19(NPCs.BUSH_8105,"located near Port Sarim.",Location.create(2989, 3121, 0)),
|
||||
CRATE_6(NPCs.CRATE_8108,"located where fishers colonise.",Location.create(2322, 3658, 0)),
|
||||
ROCK_12(NPCs.ROCK_8109,"located between Fremennik and barbarians.",Location.create(2675, 3717, 0)),
|
||||
ROCK_13(NPCs.ROCK_8109,"located near the pointy-eared ones.",Location.create(2296, 3270, 0)),
|
||||
CRATE_7(NPCs.CRATE_8108,"located where bloodsuckers rule.",Location.create(3637, 3486, 0)),
|
||||
TOADSTOOL_6(NPCs.TOADSTOOL_8110,"located where bloodsuckers rule.",Location.create(3416, 3437, 0)),
|
||||
BUSH_20(NPCs.BUSH_8105,"located where monkeys rule.",Location.create(2802, 2806, 0)),
|
||||
|
||||
ROCK_14(NPCs.ROCK_8109,"located near some ogres.",Location.create(2438, 3050, 0)),
|
||||
CACTUS_4(NPCs.CACTUS_8107,"located in the southern desert.",Location.create(3252, 2963, 0)),
|
||||
ROCK_15(NPCs.ROCK_8109,"located near some ogres.",Location.create(2340, 3064, 0)),
|
||||
ROCK_16(NPCs.ROCK_8109,"located in the Wilderness.",Location.create(3108, 3837, 0)),
|
||||
CACTUS_5(NPCs.CACTUS_8107,"located in the southern desert.",Location.create(3433, 3000, 0)),
|
||||
CACTUS_6(NPCs.CACTUS_8107,"located in the southern desert.",Location.create(3274, 2813, 0)),
|
||||
ROCK_17(NPCs.ROCK_8109,"located in the Wilderness.",Location.create(3019, 3866, 0)),
|
||||
ROCK_18(NPCs.ROCK_8109,"located in the Wilderness.",Location.create(2991, 3824, 0)),
|
||||
BUSH_21(NPCs.BUSH_8105,"located north of Ardougne.",Location.create(2398, 3361, 0)),
|
||||
ROCK_19(NPCs.ROCK_8109,"located near the coast.",Location.create(2733, 3283, 0)),
|
||||
ROCK_20(NPCs.ROCK_8109,"located in the Wilderness.",Location.create(3236, 3927, 0));
|
||||
|
||||
companion object {
|
||||
private val locationMap = values().map { it.location.toString() to it }.toMap()
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import core.game.component.ComponentDefinition
|
|||
import core.game.component.ComponentPlugin
|
||||
import core.game.container.access.InterfaceContainer
|
||||
import core.game.node.entity.player.Player
|
||||
import core.game.node.entity.player.link.diary.DiaryType
|
||||
import core.game.node.item.Item
|
||||
import core.plugin.Initializable
|
||||
import core.plugin.Plugin
|
||||
|
|
@ -165,6 +166,10 @@ class FurClothingInterface : ComponentPlugin(){
|
|||
if (removeItem(player, requiredFur, Container.INVENTORY) &&
|
||||
removeItem(player, coins, Container.INVENTORY)) {
|
||||
addItem(player, clothing.product.id, amount)
|
||||
|
||||
if (clothing == FUR_CLOTHING.DASH_CAPE) {
|
||||
player.achievementDiaryManager.finishTask(player, DiaryType.VARROCK, 2, 2)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package content.global.skill.agility
|
|||
|
||||
import core.api.*
|
||||
import core.cache.def.impl.SceneryDefinition
|
||||
import core.game.interaction.QueueStrength
|
||||
import core.game.node.Node
|
||||
import core.game.node.scenery.Scenery
|
||||
import core.game.node.entity.player.Player
|
||||
|
|
@ -168,25 +169,27 @@ class WildernessCourse
|
|||
private fun handleSteppingStones(player: Player, `object`: Scenery) {
|
||||
lock(player, 50)
|
||||
val fail = AgilityHandler.hasFailed(player, 1, 0.3)
|
||||
val origLoc = player.location
|
||||
registerLogoutListener(player, "steppingstone"){p ->
|
||||
player.location = origLoc
|
||||
}
|
||||
submitWorldPulse(object : Pulse(2, player){
|
||||
var counter = 0
|
||||
override fun pulse(): Boolean {
|
||||
if (counter == 3 && fail) {
|
||||
AgilityHandler.fail(player, -1, Location.create(3001, 3963, 0), Animation.create(771), (player.skills.lifepoints * 0.26).toInt(), "...You lose your footing and fall into the lava.")
|
||||
return true
|
||||
}
|
||||
AgilityHandler.forceWalk(player, if (counter == 5) 2 else -1, player.location, player.location.transform(-1, 0, 0), Animation.create(741), 10, if (counter == 5) 20.0 else 0.0, if (counter != 0) null else "You carefully start crossing the stepping stones...")
|
||||
if(++counter == 6){
|
||||
unlock(player)
|
||||
clearLogoutListener(player, "steppingstone")
|
||||
}
|
||||
return counter == 6
|
||||
queueScript(player, 0, QueueStrength.SOFT) { stage ->
|
||||
val courseIndex = if (stage == 5) 2 else -1
|
||||
val start = player.location
|
||||
val end = player.location.transform(-1, 0, 0)
|
||||
val anim = Animation(741)
|
||||
val xp = if (stage == 5) 20.0 else 0.0
|
||||
val message = if (stage == 0) "You carefully start crossing the stepping stones..." else null
|
||||
AgilityHandler.forceWalk(player, courseIndex, start, end, anim, 10, xp, message)
|
||||
if (stage == 2 && fail) {
|
||||
val dest = Location(3001, 3963, 0)
|
||||
val failanim = Animation(771)
|
||||
val hit = (player.skills.lifepoints * 0.26).toInt()
|
||||
AgilityHandler.fail(player, -1, dest, failanim, hit, "... You lose your footing and fall into the lava.")
|
||||
return@queueScript stopExecuting(player)
|
||||
}
|
||||
})
|
||||
if (stage == 5) {
|
||||
unlock(player)
|
||||
return@queueScript stopExecuting(player)
|
||||
}
|
||||
return@queueScript delayScript(player, 2)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -122,7 +122,7 @@ public final class HouseZone extends MapZone {
|
|||
house.expelGuests(p);
|
||||
int toRemove = previousRegion;
|
||||
int dungRemove = previousDungeon;
|
||||
submitWorldPulse(new Pulse(2) {
|
||||
submitWorldPulse(new Pulse(1) {
|
||||
public boolean pulse() {
|
||||
Region r = RegionManager.forId(toRemove);
|
||||
Region dr = dungRemove != -1 ? RegionManager.forId(dungRemove) : null;
|
||||
|
|
|
|||
|
|
@ -47,11 +47,10 @@ abstract class SpellListener(val bookName: String) : Listener {
|
|||
player.sendMessage("You need a magic level of $magicLevel to cast this spell.")
|
||||
throw IllegalStateException()
|
||||
}
|
||||
for(rune in runes){
|
||||
if(!SpellUtils.hasRune(player,rune)){
|
||||
player.sendMessage("You don't have enough ${rune.definition.name.lowercase()}s to cast this spell.")
|
||||
throw IllegalStateException()
|
||||
}
|
||||
val missing = SpellUtils.hasRunes(player, runes)
|
||||
if (missing != null) {
|
||||
player.sendMessage("You don't have enough ${missing.definition.name.lowercase()}s to cast this spell.")
|
||||
throw IllegalStateException()
|
||||
}
|
||||
for(item in specialEquipment){
|
||||
if(!player.equipment.contains(item,1)){
|
||||
|
|
|
|||
|
|
@ -3,9 +3,9 @@ package content.global.skill.magic
|
|||
import core.game.node.entity.combat.spell.CombinationRune
|
||||
import core.game.node.entity.combat.spell.MagicStaff
|
||||
import core.game.node.entity.combat.spell.Runes
|
||||
import core.game.node.entity.npc.NPC
|
||||
import core.game.node.entity.player.Player
|
||||
import core.game.node.item.Item
|
||||
import kotlin.math.min
|
||||
|
||||
object SpellUtils {
|
||||
/**
|
||||
|
|
@ -32,70 +32,57 @@ object SpellUtils {
|
|||
return false
|
||||
}
|
||||
|
||||
fun hasRune(p:Player,rune:Item):Boolean{
|
||||
val removeItems = p.getAttribute("spell:runes",ArrayList<Item>())
|
||||
if(usingStaff(p,rune.id)) return true
|
||||
if(p.inventory.containsItem(rune)){
|
||||
removeItems.add(rune)
|
||||
p.setAttribute("spell:runes",removeItems)
|
||||
/**
|
||||
* Validates if the player has the necessary runes to cast a spell.
|
||||
*
|
||||
* If the player is able to cast the spell, the "spell:runes" attribute will be set to the list of items that should
|
||||
* be removed from the player's inventory after successfully casting the spell. This accounts for staves and
|
||||
* combination runes.
|
||||
*
|
||||
* @param p The player casting the spell
|
||||
* @param runes The runes and other items required to cast the spell
|
||||
* @return null if the player can cast the spell or an Item representing at least one of the runes the player is missing
|
||||
*/
|
||||
@JvmStatic
|
||||
fun hasRunes(p: Player, runes: Array<Item>): Item? {
|
||||
val cost = HashMap<Int, Int>()
|
||||
// `runes` are mostly actual runes but occasionally other items like staves or unpowered orbs
|
||||
for (rune in runes) {
|
||||
if (usingStaff(p, rune.id)) continue
|
||||
cost[rune.id] = cost.getOrDefault(rune.id, 0) + rune.amount
|
||||
}
|
||||
|
||||
val baseAmt = p.inventory.getAmount(rune.id)
|
||||
var amtRemaining = rune.amount - baseAmt
|
||||
val possibleComboRunes = CombinationRune.eligibleFor(Runes.forId(rune.id))
|
||||
for (r in possibleComboRunes) {
|
||||
if (p.inventory.containsItem(Item(r.id)) && amtRemaining > 0) {
|
||||
val amt = p.inventory.getAmount(r.id)
|
||||
if (amtRemaining <= amt) {
|
||||
removeItems.add(Item(r.id,amtRemaining))
|
||||
amtRemaining = 0
|
||||
break
|
||||
}
|
||||
removeItems.add(Item(r.id,p.inventory.getAmount(r.id)))
|
||||
amtRemaining -= p.inventory.getAmount(r.id)
|
||||
val toRemove = ArrayList<Item>()
|
||||
|
||||
// Combination runes are used before elemental runes.
|
||||
// https://runescape.wiki/w/Runecrafting?oldid=2618332#Function_and_Usage_of_Combination_Runes:
|
||||
for (combo in CombinationRune.values()) {
|
||||
val available = p.inventory.getAmount(combo.id)
|
||||
val maxUsage = combo.types.mapNotNull { cost[it.id] }.maxOrNull() ?: 0
|
||||
if (maxUsage > 0 && available >= 0) {
|
||||
val usage = min(maxUsage, available)
|
||||
|
||||
toRemove.add(Item(combo.id, usage))
|
||||
// Even if a spell uses both parts of a combo rune, it should only consume a single rune. For example,
|
||||
// a spell that requires an air rune and an earth rune should only consume a single dust rune.
|
||||
// https://youtu.be/9gAiqEmF-Hc?t=67
|
||||
combo.types.forEach { cost[it.id] = cost.getOrDefault(it.id, 0) - usage }
|
||||
}
|
||||
}
|
||||
p.setAttribute("spell:runes",removeItems)
|
||||
return amtRemaining <= 0
|
||||
}
|
||||
|
||||
fun hasRune(p: Player, item: Item, toRemove: MutableList<Item?>, message: Boolean): Boolean {
|
||||
if (!usingStaff(p, item.id)) {
|
||||
val hasBaseRune = p.inventory.contains(item.id, item.amount)
|
||||
if (!hasBaseRune) {
|
||||
val baseAmt = p.inventory.getAmount(item.id)
|
||||
if (baseAmt > 0) {
|
||||
toRemove.add(Item(item.id, p.inventory.getAmount(item.id)))
|
||||
}
|
||||
var amtRemaining = item.amount - baseAmt
|
||||
val possibleComboRunes = CombinationRune.eligibleFor(Runes.forId(item.id))
|
||||
for (r in possibleComboRunes) {
|
||||
if (p.inventory.containsItem(Item(r.id)) && amtRemaining > 0) {
|
||||
val amt = p.inventory.getAmount(r.id)
|
||||
if (amtRemaining < amt) {
|
||||
toRemove.add(Item(r.id, amtRemaining))
|
||||
amtRemaining = 0
|
||||
continue
|
||||
}
|
||||
amtRemaining -= p.inventory.getAmount(r.id)
|
||||
toRemove.add(Item(r.id, p.inventory.getAmount(r.id)))
|
||||
}
|
||||
}
|
||||
return if (amtRemaining <= 0) {
|
||||
true
|
||||
} else {
|
||||
p.packetDispatch.sendMessage("You don't have enough " + item.name + "s to cast this spell.")
|
||||
false
|
||||
}
|
||||
for ((runeId, amount) in cost) {
|
||||
if (amount <= 0) continue
|
||||
|
||||
val available = p.inventory.getAmount(runeId)
|
||||
if (available < amount) {
|
||||
return Item(runeId, amount)
|
||||
}
|
||||
toRemove.add(item)
|
||||
return true
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
fun attackableNPC(npc: NPC): Boolean{
|
||||
return npc.definition.hasAction("attack")
|
||||
toRemove.add(Item(runeId, amount))
|
||||
}
|
||||
|
||||
p.setAttribute("spell:runes", toRemove)
|
||||
return null
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ package content.global.skill.magic.modern
|
|||
|
||||
import content.data.Quests
|
||||
import content.global.skill.magic.SpellListener
|
||||
import content.global.skill.magic.SpellUtils.hasRune
|
||||
import content.global.skill.magic.SpellUtils.hasRunes
|
||||
import content.global.skill.magic.TeleportMethod
|
||||
import content.global.skill.magic.homeTeleport
|
||||
import content.global.skill.magic.spellconsts.Modern
|
||||
|
|
@ -323,11 +323,10 @@ class ModernListeners : SpellListener("modern"){
|
|||
sendMessage(player, "You need a magic level of ${spell.level} to cast this spell.")
|
||||
return@queueScript stopExecuting(player)
|
||||
}
|
||||
for (rune in spell.requiredRunes) {
|
||||
if(!hasRune(player,rune)){
|
||||
sendMessage(player, "You don't have enough ${rune.name.lowercase()}s to cast this spell.")
|
||||
return@queueScript stopExecuting(player)
|
||||
}
|
||||
val missing = hasRunes(player, spell.requiredRunes)
|
||||
if (missing != null) {
|
||||
sendMessage(player, "You don't have enough ${missing.name.lowercase()}s to cast this spell.")
|
||||
return@queueScript stopExecuting(player)
|
||||
}
|
||||
visualizeSpell(player, CHARGE_ORB_ANIM, spell.graphics, spell.sound)
|
||||
removeRunes(player)
|
||||
|
|
|
|||
|
|
@ -523,8 +523,7 @@ class Vinesweeper : InteractionListener, InterfaceListener, MapArea {
|
|||
sendNPCDialogue(player, npc.id, "I can't do that, you're teleblocked!", core.game.dialogue.FacialExpression.OLD_ANGRY1)
|
||||
return
|
||||
}
|
||||
npc.animate(Animation(437))
|
||||
npc.faceTemporary(player, 1)
|
||||
// https://youtu.be/61jVjmXf8tU?t=45
|
||||
npc.graphics(Graphics(108))
|
||||
player.lock()
|
||||
playAudio(player, Sounds.CURSE_ALL_125, 0, 1)
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ class FaladorAchievementDiary : DiaryEventHookBase(DiaryType.FALADOR) {
|
|||
private val WAYNES_CHAINS_AREA = ZoneBorders(2969, 3310, 2975, 3314)
|
||||
private val SARAHS_FARMING_SHOP_AREA = ZoneBorders(3021, 3285, 3040, 3296)
|
||||
private val FALADOR_GENERAL_AREA = ZoneBorders(2934, 3399, 3399, 3307)
|
||||
private val CHEMIST_AREA = ZoneBorders(2929, 3213, 2936, 3207)
|
||||
private val CHEMIST_AREA = ZoneBorders(2925, 3213, 2939, 3207)
|
||||
private val PORT_SARIM_FLOWER_PATCH = ZoneBorders(3053, 3306, 3056, 3309)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -64,16 +64,16 @@ public class PrinceAliRescue extends Quest {
|
|||
break;
|
||||
case 10:
|
||||
line(player, "<str>I started this quest by speaking to Hassan in Al-Kharid", 4+ 7);
|
||||
line(player, "<str>Palace. he told me I should speak to Osman the spymaster.", 5+ 7);
|
||||
line(player, "<str>Palace. He told me I should speak to Osman the spymaster.", 5+ 7);
|
||||
line(player, BLUE + "I should go and speak to " + RED + "Osman " + BLUE + "for details on the quest.", 6+ 7);
|
||||
break;
|
||||
case 20:
|
||||
line(player, "<str>I started this quest by speaking to Hassan in Al-Kharid", 4+ 7);
|
||||
line(player, "<str>Palace. he told me I should speak to Osman the spymaster.", 5+ 7);
|
||||
line(player, "<str>Palace. He told me I should speak to Osman the spymaster.", 5+ 7);
|
||||
line(player, "<str>I should go and speak to Osman for details on the quest.", 6+ 7);
|
||||
line(player, RED + "Prince Ali " + BLUE + "has been " + RED + "kidnapped " + BLUE + "but luckily the spy " + RED + "Leela " + BLUE + "has", 7+ 7);
|
||||
line(player, BLUE + "found he is being held near " + RED + "Draynor village. " + BLUE + "I will need to", 8+ 7);
|
||||
line(player, RED + "disguise " + BLUE + "the " + RED + "Price " + BLUE + "and " + RED + "tie " + BLUE + "up his " + RED + "captor " + BLUE + "to " + RED + "free " + BLUE + "him from", 9+ 7);
|
||||
line(player, BLUE + "found he is being held near " + RED + "draynor village. " + BLUE + "I will need to", 8+ 7); //authentic typo on the 'draynor village' capitialization
|
||||
line(player, RED + "disguise " + BLUE + "the " + RED + "Prince " + BLUE + "and " + RED + "tie " + BLUE + "up his " + RED + "captor " + BLUE + "to " + RED + "free " + BLUE + "him from", 9+ 7);
|
||||
line(player, BLUE + "their " + RED + "clutches.", 10+ 7);
|
||||
line(player, BLUE + "To do this I should:-", 11+ 7);
|
||||
line(player, BLUE + "Talk to " + RED + "Leela " + BLUE + "near " + RED + "Draynor Village " + BLUE + "for advice.", 12+ 7);
|
||||
|
|
@ -85,10 +85,10 @@ public class PrinceAliRescue extends Quest {
|
|||
break;
|
||||
case 30:
|
||||
line(player, "<str>I started this quest by speaking to Hassan in Al-Kharid", 4+ 7);
|
||||
line(player, "<str>Palace. he told me I should speak to Osman the spymaster.", 5+ 7);
|
||||
line(player, "<str>Palace. He told me I should speak to Osman the spymaster.", 5+ 7);
|
||||
line(player, "<Str>I should go and speak to Osman for details on the quest.", 6+ 7);
|
||||
line(player, RED + "Prince Ali " + BLUE + "has been " + RED + "kidnapped " + BLUE + "but luckily the spy " + RED + "Leela " + BLUE + "has", 7+ 7);
|
||||
line(player, BLUE + "found he is being held near " + RED + "Draynor village. " + BLUE + "I will need to", 8+ 7);
|
||||
line(player, BLUE + "found he is being held near " + RED + "Draynor Village. " + BLUE + "I will need to", 8+ 7);
|
||||
line(player, RED + "disguise " + BLUE + "the " + RED + "Prince " + BLUE + "and " + RED + "tie " + BLUE + "up his " + RED + "captor " + BLUE + "to " + RED + "free " + BLUE + "him from", 9+ 7);
|
||||
line(player, BLUE + "their " + RED + "clutches.", 10+ 7);
|
||||
line(player, BLUE + "To do this I should:-", 11+ 7);
|
||||
|
|
@ -97,15 +97,15 @@ public class PrinceAliRescue extends Quest {
|
|||
line(player, hasItem(player, ROPE) ? "<str>I have some rope with me." : BLUE + "Get some " + RED + "rope " + BLUE + "to tie up the Princes' " + RED + "kidnapper.", 14+ 7);
|
||||
line(player, hasItem(player, PASTE) ? "<str>I have some skin paste suitable for disguise with me." : BLUE + "Get something to " + RED + "colour " + BLUE + "the " + RED + "Princes' skin " + BLUE + "as a " + RED + "disguise.", 15+ 7);
|
||||
line(player, hasItem(player, SKIRT) ? "<str>I have a skirt suitable for a disguise with me." : BLUE + "Get a " + RED + "skirt " + BLUE + "similar to his " + RED + "kidnapper " + BLUE + "as " + RED + "disguise.", 16+ 7);
|
||||
line(player, hasItem(player, YELLOW_WIG) ? "<str>I have a wig suitable for disguise with me." : BLUE + "Get a " + RED + "Wig " + BLUE + "to " + RED + "help disguise" + BLUE + "the " + RED + "prince.", 17+ 7);
|
||||
line(player, hasItem(player, YELLOW_WIG) ? "<str>I have a wig suitable for disguise with me." : BLUE + "Get a " + RED + "Wig " + BLUE + "to " + RED + "help disguise " + BLUE + "the " + RED + "prince.", 17+ 7);
|
||||
break;
|
||||
case 40:
|
||||
line(player, "<str>I started this quest by speaking to Hassan in Al-Kharid", 4+ 7);
|
||||
line(player, "<str>Palace. he told me I should speak to Osman the spymaster.", 5+ 7);
|
||||
line(player, "<str>Palace. He told me I should speak to Osman the spymaster.", 5+ 7);
|
||||
line(player, "<str>I should go and speak to Osman for details on the quest.", 6+ 7);
|
||||
if (player.getAttribute("guard-drunk", false)) {
|
||||
line(player, "<str>Prince Ali has been kidnapped but luckily the spy Leela has", 7+ 7);
|
||||
line(player, "<str>found he is being held near Draynor village. I will need to", 8+ 7);
|
||||
line(player, "<str>found he is being held near Draynor Village. I will need to", 8+ 7);
|
||||
line(player, "<str>disguise the Prince and tie up his captor to free him from", 9+ 7);
|
||||
line(player, "<str>their clutches.", 10+ 7);
|
||||
line(player, "<str>I also had to prevent the Guard from seeing that I was up", 10+ 7);
|
||||
|
|
@ -116,32 +116,32 @@ public class PrinceAliRescue extends Quest {
|
|||
} else {
|
||||
line(player, BLUE + "Do something to prevent " + RED + "Joe the Guard " + BLUE + "seeing the", 7+ 7);
|
||||
line(player, BLUE + "escape.", 8+ 7);
|
||||
line(player, BLUE + "Use the " + RED + "Skin potion" + BLUE + ", " + RED + "Pink Skirt" + BLUE + "," + RED + "Rope" + BLUE + "," + RED + "Blonde Wig " + BLUE + "and " + RED + "Cell", 9+ 7);
|
||||
line(player, BLUE + "Use the " + RED + "Skin Potion" + BLUE + ", " + RED + "Pink Skirt" + BLUE + ", " + RED + "Rope" + BLUE + ", " + RED + "Blonde Wig " + BLUE + "and " + RED + "Cell", 9+ 7);
|
||||
line(player, RED + "Key" + BLUE + " to free " + RED + "Prince Ali " + BLUE + "from his cell somehow.", 10+ 7);
|
||||
}
|
||||
break;
|
||||
case 50:
|
||||
line(player, "<str>I started this quest by speaking to Hassan in Al-Kharid", 4+ 7);
|
||||
line(player, "<str>Palace. he told me I should speak to Osman the spymaster.", 5+ 7);
|
||||
line(player, "<str>Palace. He told me I should speak to Osman the spymaster.", 5+ 7);
|
||||
line(player, "<str>I should go and speak to Osman for details on the quest.", 6+ 7);
|
||||
line(player, "<str>Prince Ali has been kidnapped but luckily the spy Leela has", 7+ 7);
|
||||
line(player, "<str>found he is being held near Draynor village. I will need to", 8+ 7);
|
||||
line(player, "<str>found he is being held near Draynor Village. I will need to", 8+ 7);
|
||||
line(player, "<str>disguise the Prince and tie up his captor to free him from", 9+ 7);
|
||||
line(player, "<str>their clutches.", 10+ 7);
|
||||
line(player, "<str>I also had to prevent the Guard from seeing that I was up", 10+ 7);
|
||||
line(player, "<str>to, by getting him drunk.", 11+ 7);
|
||||
line(player, "<str>With the guard disposed of, I used my rope to tie up Lady", 11+ 7);
|
||||
line(player, "<str>Keli in a cupboard, so I could disguise the Prince.", 12+ 7);
|
||||
line(player, BLUE + "I need to " + RED + "Unlock the cell door " + BLUE + "and then give the Prince the", 13+ 7);
|
||||
line(player, RED + "Pink Skirt" + BLUE + ", the " + RED + "Skin paste " + BLUE + "and the " + RED + "Blonde Swig " + BLUE + "so that the", 14+ 7);
|
||||
line(player, BLUE + "I need to " + RED + "unlock the cell door " + BLUE + "and then give the Prince the", 13+ 7);
|
||||
line(player, RED + "Pink Skirt" + BLUE + ", the " + RED + "Skin Paste " + BLUE + "and the " + RED + "Blonde Wig " + BLUE + "so that they", 14+ 7);
|
||||
line(player, BLUE + "can safely " + RED + "escape " + BLUE + "disguised as " + RED + "Lady Keli.", 15+ 7);
|
||||
break;
|
||||
case 60:
|
||||
line(player, "<str>I started this quest by speaking to Hassan in Al-Kharid", 4+ 7);
|
||||
line(player, "<str>Palace. he told me I should speak to Osman the spymaster.", 5+ 7);
|
||||
line(player, "<str>Palace. He told me I should speak to Osman the spymaster.", 5+ 7);
|
||||
line(player, "<str>I should go and speak to Osman for details on the quest.", 6+ 7);
|
||||
line(player, "<str>Prince Ali has been kidnapped but luckily the spy Leela has", 7+ 7);
|
||||
line(player, "<str>found he is being held near Draynor village. I will need to", 8+ 7);
|
||||
line(player, "<str>found he is being held near Draynor Village. I will need to", 8+ 7);
|
||||
line(player, "<str>disguise the Prince and tie up his captor to free him from", 9+ 7);
|
||||
line(player, "<str>their clutches.", 10+ 7);
|
||||
line(player, "<str>I also had to prevent the Guard from seeing that I was up", 10+ 7);
|
||||
|
|
@ -155,10 +155,10 @@ public class PrinceAliRescue extends Quest {
|
|||
break;
|
||||
case 100:
|
||||
line(player, "<str>I started this quest by speaking to Hassan in Al-Kharid", 4+ 7);
|
||||
line(player, "<str>Palace. he told me I should speak to Osman the spymaster.", 5+ 7);
|
||||
line(player, "<str>Palace. He told me I should speak to Osman the spymaster.", 5+ 7);
|
||||
line(player, "<str>I should go and speak to Osman for details on the quest.", 6+ 7);
|
||||
line(player, "<str>Prince Ali has been kidnapped but luckily the spy Leela has", 7+ 7);
|
||||
line(player, "<str>found he is being held near Draynor village. I will need to", 8+ 7);
|
||||
line(player, "<str>found he is being held near Draynor Village. I will need to", 8+ 7);
|
||||
line(player, "<str>disguise the Prince and tie up his captor to free him from", 9+ 7);
|
||||
line(player, "<str>their clutches.", 10+ 7);
|
||||
line(player, "<str>I also had to prevent the Guard from seeing that I was up", 10+ 7);
|
||||
|
|
@ -170,7 +170,7 @@ public class PrinceAliRescue extends Quest {
|
|||
line(player, "<str>freedom with Leela after unlocking his cell door.", 15+ 7);
|
||||
line(player, "<str>Hassan the chancellor rewarded me for all of my help.", 16+ 7);
|
||||
line(player, "<str>I am now a friend of Al-Kharid and may pass through the", 17+ 7);
|
||||
line(player, "<str>gate leading between Lumbridge and Al-Kharid for free", 18+ 7);
|
||||
line(player, "<str>gate leading between Lumbridge and Al-Kharid for free.", 18+ 7);
|
||||
line(player, "<col=FF0000>QUEST COMPLETE!", 19+ 7);
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
package content.region.kandarin.ardougne.quest.hazeelcult
|
||||
|
||||
import core.api.*
|
||||
import core.game.node.entity.npc.AbstractNPC
|
||||
import core.game.world.map.Location
|
||||
import core.plugin.Initializable
|
||||
|
|
@ -16,16 +15,18 @@ class ClivetNPC(id: Int = 0, location: Location? = null, ) : AbstractNPC(id, loc
|
|||
|
||||
override fun getIds(): IntArray = intArrayOf(NPCs.CLIVET_893)
|
||||
|
||||
private var invisibilityTimerRunning = false
|
||||
private var invisTicks = 0
|
||||
|
||||
override fun tick() {
|
||||
if (isInvisible && invisTicks <= 0) {
|
||||
invisTicks = 20
|
||||
}
|
||||
|
||||
if (isInvisible && !invisibilityTimerRunning) {
|
||||
invisibilityTimerRunning = true
|
||||
if (invisTicks > 0) {
|
||||
invisTicks--
|
||||
|
||||
runTask(this, 20) {
|
||||
if (invisTicks == 0) {
|
||||
isInvisible = false
|
||||
invisibilityTimerRunning = false
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import core.game.node.entity.npc.NPC;
|
|||
import core.game.node.entity.player.Player;
|
||||
import core.plugin.Initializable;
|
||||
import core.game.node.item.Item;
|
||||
import org.rs09.consts.Items;
|
||||
|
||||
/**
|
||||
* Handles the MathiasFlaconryDialogue dialogue.
|
||||
|
|
@ -49,7 +50,8 @@ public class MathiasFlaconryDialogue extends DialoguePlugin {
|
|||
}
|
||||
break;
|
||||
case 323:
|
||||
end();
|
||||
interpreter.sendDialogues(5093, FacialExpression.NEUTRAL, "Well, you're welcome to come back if you change", "your mind.");
|
||||
stage = 967;
|
||||
break;
|
||||
case 95:
|
||||
if (player.getBank().containsItem(FALCON) || player.getEquipment().containsItem(FALCON) || player.getInventory().containsItem(FALCON)) {
|
||||
|
|
@ -58,7 +60,7 @@ public class MathiasFlaconryDialogue extends DialoguePlugin {
|
|||
return true;
|
||||
}
|
||||
if (player.getEquipment().get(EquipmentContainer.SLOT_HANDS) != null || player.getEquipment().get(EquipmentContainer.SLOT_SHIELD) != null || player.getEquipment().get(EquipmentContainer.SLOT_WEAPON) != null) {
|
||||
interpreter.sendDialogues(5093, FacialExpression.HALF_GUILTY, "Sorry, free your hands, weapon, and shield slot first.");
|
||||
interpreter.sendDialogues(5093, FacialExpression.HALF_GUILTY, "Sorry, you really need both hands free for falconry. I'd", "suggest that you put away your weapons and gloves before", "we start.");
|
||||
stage = 99;
|
||||
break;
|
||||
}
|
||||
|
|
@ -69,11 +71,11 @@ public class MathiasFlaconryDialogue extends DialoguePlugin {
|
|||
stage = 97;
|
||||
} else {
|
||||
end();
|
||||
player.getPacketDispatch().sendMessage("You need 500 gold goins.");
|
||||
player.getPacketDispatch().sendMessage("You need 500 gold coins.");
|
||||
}
|
||||
break;
|
||||
case 97:
|
||||
interpreter.sendDialogues(5093, FacialExpression.HALF_GUILTY, "Don't worry: I'll keep and eye on you to make sure", "you don't upset it roo much.");
|
||||
interpreter.sendDialogues(5093, FacialExpression.HALF_GUILTY, "Don't worry; I'll keep an eye on you to make sure", "you don't upset it too much.");
|
||||
stage = 99;
|
||||
break;
|
||||
case 99:
|
||||
|
|
@ -84,22 +86,109 @@ public class MathiasFlaconryDialogue extends DialoguePlugin {
|
|||
stage = 501;
|
||||
break;
|
||||
case 501:
|
||||
interpreter.sendDialogues(player, FacialExpression.HALF_GUILTY, "Could I have a go with your bird?");
|
||||
interpreter.sendOptions("Select an Option", "Do you have any quests I could do?", "What is this place?", "Could I have a go with your bird?");
|
||||
stage = 502;
|
||||
break;
|
||||
case 502:
|
||||
switch (buttonId) {
|
||||
case 1:
|
||||
interpreter.sendDialogues(player, FacialExpression.ASKING, "Do you have any quests I could do?");
|
||||
stage = 600;
|
||||
break;
|
||||
case 2:
|
||||
interpreter.sendDialogues(player, FacialExpression.ASKING, "What is this place?");
|
||||
stage = 700;
|
||||
break;
|
||||
case 3:
|
||||
interpreter.sendDialogues(player, FacialExpression.ASKING, "Could I have a go with your bird?");
|
||||
stage = 800;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 600:
|
||||
interpreter.sendDialogues(5093, FacialExpression.ASKING, "A quest? What a strange notion. Do you normally go", "around asking complete strangers for quests?");
|
||||
stage = 601;
|
||||
break;
|
||||
case 601:
|
||||
interpreter.sendDialogues(player, FacialExpression.HALF_GUILTY, "Er, yes, now you come to mention it.");
|
||||
stage = 602;
|
||||
break;
|
||||
case 602:
|
||||
interpreter.sendDialogues(5093, FacialExpression.HALF_GUILTY, "Oh, ok then. Well, no, I don't; sorry.");
|
||||
stage = 967;
|
||||
break;
|
||||
|
||||
case 700:
|
||||
interpreter.sendDialogues(5093, FacialExpression.HALF_GUILTY, "A good question; straight and to the point. My name is ", "Matthias, I am a falconer, and this is where I train", "my birds.");
|
||||
stage = 701;
|
||||
break;
|
||||
case 701:
|
||||
interpreter.sendOptions("Select an Option", "Do you have any quests I could do?", "That sounds like fun; could I have a go?", "That doesn't sound like my sort of thing.", "What's this falconry thing all about then?");
|
||||
stage = 702;
|
||||
break;
|
||||
case 702:
|
||||
switch (buttonId) {
|
||||
case 1:
|
||||
interpreter.sendDialogues(player, FacialExpression.ASKING, "Do you have any quests I could do?");
|
||||
stage = 600;
|
||||
break;
|
||||
case 2:
|
||||
interpreter.sendDialogues(player, FacialExpression.ASKING, "That sounds like fun; could I have a go?");
|
||||
stage = 800;
|
||||
break;
|
||||
case 3:
|
||||
interpreter.sendDialogues(player, FacialExpression.HALF_GUILTY, "That doesn't sound like my sort of thing.");
|
||||
stage = 720;
|
||||
break;
|
||||
case 4:
|
||||
interpreter.sendDialogues(player, FacialExpression.HALF_GUILTY, "What's this falconry thing all about then?");
|
||||
stage = 750;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 720:
|
||||
interpreter.sendDialogues(5093, FacialExpression.HALF_GUILTY, "Fair enough; it does require a great deal of patience and", "skill, so I can understand if you might feel intimidated.");
|
||||
stage = 967;
|
||||
break;
|
||||
case 750:
|
||||
interpreter.sendDialogues(5093, FacialExpression.NEUTRAL, "Well, some people see it as a sport, although such a term", "does not really convey the amount of patience and", "dedication required to be proficient at the task.");
|
||||
stage = 751;
|
||||
break;
|
||||
case 751:
|
||||
interpreter.sendDialogues(5093, FacialExpression.NEUTRAL, "Putting it simply, it is the training and use of birds of", "prey in hunting quarry.");
|
||||
stage = 752;
|
||||
break;
|
||||
case 752:
|
||||
interpreter.sendDialogues(player, FacialExpression.ASKING, "So it's like keeping a pet then?");
|
||||
stage = 753;
|
||||
break;
|
||||
case 753:
|
||||
interpreter.sendDialogues(5093, FacialExpression.NEUTRAL, "Not exactly, no. Such a bird can never really be", "considered tame in the same way that a dog can.");
|
||||
stage = 754;
|
||||
break;
|
||||
case 754:
|
||||
interpreter.sendDialogues(5093, FacialExpression.NEUTRAL, "They can be trained to associate people or places with", "food though, and, as such, a good falconer can get a", "trained bird to do as he wishes.");
|
||||
stage = 701;
|
||||
break;
|
||||
|
||||
case 800:
|
||||
if (player.getSkills().getLevel(Skills.HUNTER) < 43) {
|
||||
npc("Try coming back when you're more experienced", "I wouldn't want my birds being injured.");
|
||||
stage = 967;
|
||||
return true;
|
||||
}
|
||||
interpreter.sendDialogues(5093, FacialExpression.HALF_GUILTY, "Training falcons is a lot of work and I", "doubt you're up to the task. However, I suppose", "I could let you try hunting with one.");
|
||||
stage = 503;
|
||||
interpreter.sendDialogues(5093, FacialExpression.HALF_GUILTY, "Training falcons is a lot of work and I doubt you're up", "to the task. However, I suppose I could let you try", "hunting with one.");
|
||||
stage = 801;
|
||||
break;
|
||||
case 503:
|
||||
interpreter.sendDialogues(5093, FacialExpression.HALF_GUILTY, "I have some tamer birds that I occasionally lend to rich", "noblemen who consider it a sufficiently refined sport for", "their tastes. and you look like the kind who might", "appreciate a good hunt.");
|
||||
case 801:
|
||||
interpreter.sendDialogues(5093, FacialExpression.HALF_GUILTY, "I have some tamer birds that I occasionally lend to rich", "noblemen who consider it a sufficiently refined sport for", "their tastes, and you look like the kind who might", "appreciate a good hunt.");
|
||||
stage = 802;
|
||||
break;
|
||||
case 802:
|
||||
interpreter.sendDialogues(5093, FacialExpression.NEUTRAL, "I'd have to request a small fee, mind you; how does", "500 gold pieces sound?");
|
||||
stage = 90;
|
||||
break;
|
||||
|
||||
case 900:
|
||||
interpreter.sendOptions("Select an Option", "Yes, please.", "No thank you.");
|
||||
stage = 901;
|
||||
|
|
@ -125,7 +214,48 @@ public class MathiasFlaconryDialogue extends DialoguePlugin {
|
|||
case 967:
|
||||
end();
|
||||
break;
|
||||
|
||||
case 1000:
|
||||
interpreter.sendDialogues(5093, FacialExpression.HALF_GUILTY, "Ah, you're back. How are you getting along with her then?");
|
||||
stage = 1001;
|
||||
break;
|
||||
case 1001:
|
||||
interpreter.sendDialogues(player, FacialExpression.HALF_GUILTY, "It's certainly harder than it looks.");
|
||||
stage = 1002;
|
||||
break;
|
||||
case 1002:
|
||||
interpreter.sendDialogues(5093, FacialExpression.HALF_GUILTY, "Sorry, but I was talking to the falcon, not you. But yes it", "is. Have you had enough yet?");
|
||||
stage = 1003;
|
||||
break;
|
||||
case 1003:
|
||||
interpreter.sendOptions("Select an Option", "Actually, I'd like to keep trying a little longer.", "I think I'll leave it for now.");
|
||||
stage = 1004;
|
||||
break;
|
||||
case 1004:
|
||||
switch (buttonId) {
|
||||
case 1:
|
||||
interpreter.sendDialogues(player, FacialExpression.ASKING, "Actually, I'd like to keep trying a little longer.");
|
||||
stage = 1010;
|
||||
break;
|
||||
case 2:
|
||||
interpreter.sendDialogues(player, FacialExpression.HALF_GUILTY, "I think I'll leave it for now.");
|
||||
stage = 1020;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 1010:
|
||||
interpreter.sendDialogues(5093, FacialExpression.NEUTRAL, "Ok then, just come talk to me when you're done.");
|
||||
stage = 967;
|
||||
break;
|
||||
case 1020:
|
||||
player.getInventory().remove(FALCON);
|
||||
player.getEquipment().remove(FALCON, true);
|
||||
|
||||
interpreter.sendDialogue("You give the falcon and glove back to Matthias.");
|
||||
stage = 967;
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -145,6 +275,11 @@ public class MathiasFlaconryDialogue extends DialoguePlugin {
|
|||
stage = 900;
|
||||
return true;
|
||||
}
|
||||
if (player.getEquipment().contains(10024, 1) || player.getInventory().contains(10024, 1)) {
|
||||
interpreter.sendDialogues(player, FacialExpression.HALF_GUILTY, "Hello again.");
|
||||
stage = 1000;
|
||||
return true;
|
||||
}
|
||||
if (args.length == 2)
|
||||
quick = true;
|
||||
if (quick) {
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ import core.game.diary.DiaryEventHookBase
|
|||
import core.game.diary.DiaryLevel
|
||||
import core.game.event.*
|
||||
import content.data.Quests
|
||||
import core.game.node.entity.player.link.SpellBookManager
|
||||
|
||||
class LumbridgeAchivementDiary : DiaryEventHookBase(DiaryType.LUMBRIDGE) {
|
||||
|
||||
|
|
@ -401,14 +402,12 @@ class LumbridgeAchivementDiary : DiaryEventHookBase(DiaryType.LUMBRIDGE) {
|
|||
}
|
||||
|
||||
override fun onSpellCast(player: Player, event: SpellCastEvent) {
|
||||
when (event.spellId) {
|
||||
Modern.LUMBRIDGE_TELEPORT -> {
|
||||
finishTask(
|
||||
player,
|
||||
DiaryLevel.MEDIUM,
|
||||
MediumTasks.CAST_LUMBRIDGE_TELEPORT
|
||||
)
|
||||
}
|
||||
if (event.spellBook == SpellBookManager.SpellBook.MODERN && event.spellId == Modern.LUMBRIDGE_TELEPORT) {
|
||||
finishTask(
|
||||
player,
|
||||
DiaryLevel.MEDIUM,
|
||||
MediumTasks.CAST_LUMBRIDGE_TELEPORT
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package content.region.misthalin.lumbridge.quest.therestlessghost;
|
||||
|
||||
import content.data.Quests;
|
||||
import core.game.dialogue.FacialExpression;
|
||||
import core.game.node.entity.npc.NPC;
|
||||
import core.game.node.entity.player.Player;
|
||||
import core.game.node.entity.player.link.diary.DiaryType;
|
||||
|
|
@ -41,7 +42,7 @@ public final class FatherUhrneyDialogue extends DialoguePlugin {
|
|||
@Override
|
||||
public boolean open(Object... args) {
|
||||
npc = (NPC) args[0];
|
||||
npc("Go away! I'm meditating!");
|
||||
npc(FacialExpression.ANGRY, "Go away! I'm meditating!");
|
||||
stage = 0;
|
||||
return true;
|
||||
}
|
||||
|
|
@ -51,13 +52,13 @@ public final class FatherUhrneyDialogue extends DialoguePlugin {
|
|||
switch (stage) {
|
||||
case 0:
|
||||
if (player.getQuestRepository().getQuest(Quests.THE_RESTLESS_GHOST).getStage(player) == 0) {
|
||||
options("Well, that's friendly.", "I've come to respossess your house.");
|
||||
options("Well, that's friendly.", "I've come to repossess your house.");
|
||||
stage = 1;
|
||||
} else if (player.getQuestRepository().getQuest(Quests.THE_RESTLESS_GHOST).getStage(player) == 10) {
|
||||
options("Well, that's friendly.", "I've come to respossess your house.", "Father Aereck sent me to talk to you.");
|
||||
options("Well, that's friendly.", "Father Aereck sent me to talk to you.", "I've come to repossess your house.");
|
||||
stage = 500;
|
||||
} else if (player.getGameAttributes().getAttributes().containsKey("restless-ghost:urhney") || player.getQuestRepository().isComplete(Quests.THE_RESTLESS_GHOST)) {
|
||||
options("Well, that's friendly.", "I've come to respossess your house.", "I've lost the Amulet of Ghostspeak.");
|
||||
options("Well, that's friendly.", "I've lost the Amulet of Ghostspeak.", "I've come to repossess your house.");
|
||||
stage = 514;
|
||||
}
|
||||
break;
|
||||
|
|
@ -68,17 +69,17 @@ public final class FatherUhrneyDialogue extends DialoguePlugin {
|
|||
stage = 10;
|
||||
break;
|
||||
case 2:
|
||||
player("I've come to repossess your house.");
|
||||
stage = 20;
|
||||
break;
|
||||
case 3:
|
||||
player("Father Aereck sent me to talk to you.");
|
||||
stage = 501;
|
||||
break;
|
||||
case 3:
|
||||
player("I've come to repossess your house.");
|
||||
stage = 20;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 501:
|
||||
npc("I suppose I'd better talk to you then. What problems", "has he got himself into this time?");
|
||||
npc(FacialExpression.ANGRY, "I suppose I'd better talk to you then. What problems", "has he got himself into this time?");
|
||||
stage = 502;
|
||||
break;
|
||||
case 502:
|
||||
|
|
@ -86,23 +87,23 @@ public final class FatherUhrneyDialogue extends DialoguePlugin {
|
|||
stage = 503;
|
||||
break;
|
||||
case 503:
|
||||
npc("Oh, the silly fool.");
|
||||
npc(FacialExpression.ANGRY, "Oh, the silly fool.");
|
||||
stage = 504;
|
||||
break;
|
||||
case 504:
|
||||
npc("I leave town for just five months, and ALREADY he", "can't manage.");
|
||||
npc(FacialExpression.ANGRY, "I leave town for just five months, and ALREADY he", "can't manage.");
|
||||
stage = 505;
|
||||
break;
|
||||
case 505:
|
||||
npc("(sigh)");
|
||||
npc(FacialExpression.SAD, "(sigh)");
|
||||
stage = 506;
|
||||
break;
|
||||
case 506:
|
||||
npc("Well, I can't go back and exorcise it. I vowed not to", "leave this place. Until I had done a full two years of", "prayer and meditation.");
|
||||
npc(FacialExpression.ANGRY, "Well, I can't go back and exorcise it. I vowed not to", "leave this place. Until I had done a full two years of", "prayer and meditation.");
|
||||
stage = 507;
|
||||
break;
|
||||
case 507:
|
||||
npc("Tell you what I can do though; take this amulet.");
|
||||
npc(FacialExpression.NEUTRAL, "Tell you what I can do though; take this amulet.");
|
||||
stage = 508;
|
||||
break;
|
||||
case 508:
|
||||
|
|
@ -118,15 +119,15 @@ public final class FatherUhrneyDialogue extends DialoguePlugin {
|
|||
stage = 509;
|
||||
break;
|
||||
case 509:
|
||||
npc("It is an Amulet of Ghostspeak.");
|
||||
npc(FacialExpression.NEUTRAL, "It is an Amulet of Ghostspeak.");
|
||||
stage = 510;
|
||||
break;
|
||||
case 510:
|
||||
npc("So called, because when you wear it you can speak to", "ghosts. A lot of ghosts are doomed to be ghosts because", "they have left some important task uncompleted.");
|
||||
npc(FacialExpression.NEUTRAL, "So called, because when you wear it you can speak to", "ghosts. A lot of ghosts are doomed to be ghosts because", "they have left some important task uncompleted.");
|
||||
stage = 511;
|
||||
break;
|
||||
case 511:
|
||||
npc("Maybe if you know what this task is, you can get rid of", "the ghost. I'm not making any gurantees mind you,", "but it is the best I can do right now.");
|
||||
npc(FacialExpression.NEUTRAL, "Maybe if you know what this task is, you can get rid of", "the ghost. I'm not making any guarantees mind you,", "but it is the best I can do right now.");
|
||||
stage = 512;
|
||||
break;
|
||||
case 512:
|
||||
|
|
@ -143,12 +144,12 @@ public final class FatherUhrneyDialogue extends DialoguePlugin {
|
|||
stage = 10;
|
||||
break;
|
||||
case 2:
|
||||
player("I've come to repossess your house.");
|
||||
stage = 20;
|
||||
player(FacialExpression.NEUTRAL, "I've lost the Amulet of Ghostspeak.");
|
||||
stage = 515;
|
||||
break;
|
||||
case 3:
|
||||
player("I've lost the Amulet of Ghostpeak.");
|
||||
stage = 515;
|
||||
player("I've come to repossess your house.");
|
||||
stage = 20;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
|
@ -171,14 +172,14 @@ public final class FatherUhrneyDialogue extends DialoguePlugin {
|
|||
stage = 518;
|
||||
break;
|
||||
case 517:
|
||||
npc("What are you talking about? I can see you've got it", "in your bank!");
|
||||
npc(FacialExpression.ANGRY, "You come here wasting my time... Has it even", "occurred to you to look in your bank? Now GO", "AWAY!");
|
||||
stage = 518;
|
||||
break;
|
||||
case 518:
|
||||
end();
|
||||
break;
|
||||
case 519:
|
||||
npc("How careless can you get? Those things aren't easy to", "come by you know! It's a good job I've got a spare.");
|
||||
npc(FacialExpression.ANGRY, "How careless can you get? Those things aren't easy to", "come by you know! It's a good job I've got a spare.");
|
||||
stage = 520;
|
||||
break;
|
||||
case 520:
|
||||
|
|
@ -188,7 +189,7 @@ public final class FatherUhrneyDialogue extends DialoguePlugin {
|
|||
stage = 521;
|
||||
break;
|
||||
case 521:
|
||||
npc("Be more careful this time.");
|
||||
npc(FacialExpression.ANGRY, "Be more careful this time.");
|
||||
stage = 522;
|
||||
break;
|
||||
case 522:
|
||||
|
|
@ -252,7 +253,7 @@ public final class FatherUhrneyDialogue extends DialoguePlugin {
|
|||
stage = 102;
|
||||
break;
|
||||
case 102:
|
||||
player("Sorry. I mus thave got the wrong address. All the", "houses look the same around here.");
|
||||
player("Sorry. I must have got the wrong address. All the", "houses look the same around here.");
|
||||
stage = 103;
|
||||
break;
|
||||
case 103:
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import core.game.interaction.InteractionListener
|
|||
import core.game.world.map.Location
|
||||
import org.rs09.consts.Scenery
|
||||
import content.data.Quests
|
||||
import core.game.node.entity.player.link.diary.DiaryType
|
||||
|
||||
// Temporary access since the monsters in there drop nothing.
|
||||
class ASoulsBaneListener : InteractionListener {
|
||||
|
|
@ -16,6 +17,7 @@ class ASoulsBaneListener : InteractionListener {
|
|||
on(RIFT_IDS, SCENERY, "enter") { player, _ ->
|
||||
if (hasRequirement(player, Quests.A_SOULS_BANE)) {
|
||||
teleport(player, Location(3297, 9824, 0))
|
||||
player.achievementDiaryManager.finishTask(player, DiaryType.VARROCK, 1, 9)
|
||||
}
|
||||
return@on true
|
||||
}
|
||||
|
|
|
|||
|
|
@ -247,7 +247,7 @@ public class RomilyWeaklaxDialogue extends DialoguePlugin {
|
|||
@Override
|
||||
public boolean handle(NodeUsageEvent event) {
|
||||
if (!event.getPlayer().getAchievementDiaryManager().getDiary(DiaryType.VARROCK).isComplete(2,5)) {
|
||||
event.getPlayer().getDialogueInterpreter().open(3205, event.getUsedItem());
|
||||
event.getPlayer().getDialogueInterpreter().open(3205, event.getUsedWith().asNpc(), event.getUsedItem());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import core.game.node.entity.player.Player
|
|||
import core.plugin.Initializable
|
||||
import org.rs09.consts.Items
|
||||
import content.data.Quests
|
||||
import core.game.node.entity.player.link.diary.DiaryType
|
||||
|
||||
|
||||
@Initializable
|
||||
|
|
@ -173,6 +174,7 @@ class DimintheisDialogue(player: Player? = null): core.game.dialogue.DialoguePlu
|
|||
6000 -> npc("Not to worry, here they are").also {
|
||||
stage = 1000
|
||||
addItem(player, getAttribute(player, "family-crest:gauntlets", Items.FAMILY_GAUNTLETS_778))
|
||||
player.achievementDiaryManager.finishTask(player, DiaryType.VARROCK, 2, 9)
|
||||
}
|
||||
|
||||
1000 -> end()
|
||||
|
|
|
|||
|
|
@ -502,7 +502,10 @@ class ScriptAPI(private val bot: Player) {
|
|||
}
|
||||
val canSell = GrandExchange.addBotOffer(actualId, itemAmt)
|
||||
if (canSell && saleIsBigNews(actualId, itemAmt)) {
|
||||
Repository.sendNews(SERVER_GE_NAME + " just offered " + itemAmt + " " + ItemDefinition.forId(actualId).name.toLowerCase() + " on the GE.")
|
||||
Repository.sendGrandExchangeNews(
|
||||
SERVER_GE_NAME + " just offered " + itemAmt + " " +
|
||||
ItemDefinition.forId(actualId).name.toLowerCase() + " on the GE."
|
||||
)
|
||||
}
|
||||
bot.bank.remove(Item(id, itemAmt))
|
||||
bot.bank.refresh()
|
||||
|
|
@ -532,7 +535,10 @@ class ScriptAPI(private val bot: Player) {
|
|||
}
|
||||
val canSell = GrandExchange.addBotOffer(actualId, itemAmt)
|
||||
if (canSell && saleIsBigNews(actualId, itemAmt)) {
|
||||
Repository.sendNews(SERVER_GE_NAME + " just offered " + itemAmt + " " + ItemDefinition.forId(actualId).name.toLowerCase() + " on the GE.")
|
||||
Repository.sendGrandExchangeNews(
|
||||
SERVER_GE_NAME + " just offered " + itemAmt + " " +
|
||||
ItemDefinition.forId(actualId).name.toLowerCase() + " on the GE."
|
||||
)
|
||||
}
|
||||
bot.bank.remove(item)
|
||||
bot.bank.refresh()
|
||||
|
|
@ -568,7 +574,10 @@ class ScriptAPI(private val bot: Player) {
|
|||
1517 -> continue
|
||||
1519 -> continue
|
||||
1521 -> continue
|
||||
else -> sendNews(SERVER_GE_NAME + " just offered " + itemAmt + " " + ItemDefinition.forId(actualId).name.lowercase() + " on the GE.")
|
||||
else -> Repository.sendGrandExchangeNews(
|
||||
SERVER_GE_NAME + " just offered " + itemAmt + " " +
|
||||
ItemDefinition.forId(actualId).name.lowercase() + " on the GE."
|
||||
)
|
||||
}
|
||||
}
|
||||
bot.bank.remove(item)
|
||||
|
|
|
|||
|
|
@ -1,12 +1,16 @@
|
|||
package core.game.consumable;
|
||||
|
||||
import content.data.consumables.Consumables;
|
||||
import core.game.interaction.QueueStrength;
|
||||
import core.game.node.entity.player.Player;
|
||||
import core.game.node.entity.player.link.audio.Audio;
|
||||
import core.game.node.item.Item;
|
||||
import core.game.system.task.Pulse;
|
||||
import core.game.world.GameWorld;
|
||||
import core.game.world.update.flag.context.Animation;
|
||||
import org.rs09.consts.Sounds;
|
||||
|
||||
import static core.api.ContentAPIKt.playAudio;
|
||||
import static core.api.ContentAPIKt.*;
|
||||
|
||||
public class Potion extends Drink {
|
||||
|
||||
|
|
@ -15,7 +19,7 @@ public class Potion extends Drink {
|
|||
private static final Audio SOUND = new Audio(2401, 1, 1);
|
||||
|
||||
public Potion(final int[] ids, final ConsumableEffect effect, final String... messages) {
|
||||
super(ids, effect, messages);
|
||||
super(ids, effect, new Animation(829), messages);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -55,13 +59,17 @@ public class Potion extends Drink {
|
|||
}
|
||||
final int dosesLeft = ids.length - consumedDoses;
|
||||
player.getPacketDispatch().sendMessage("You drink some of your " + getFormattedName(item) + ".");
|
||||
if (dosesLeft > 1) {
|
||||
player.getPacketDispatch().sendMessage("You have " + dosesLeft + " doses of potion left.");
|
||||
} else if (dosesLeft == 1) {
|
||||
player.getPacketDispatch().sendMessage("You have 1 dose of potion left.");
|
||||
} else {
|
||||
player.getPacketDispatch().sendMessage("You have finished your potion.");
|
||||
}
|
||||
// Remaining dosages message should be delayed - https://youtu.be/n6CCf4Rj8Lg?t=79
|
||||
queueScript(player, 2, QueueStrength.SOFT, false, (Integer stage) -> {
|
||||
if (dosesLeft > 1) {
|
||||
player.getPacketDispatch().sendMessage("You have " + dosesLeft + " doses of potion left.");
|
||||
} else if (dosesLeft == 1) {
|
||||
player.getPacketDispatch().sendMessage("You have 1 dose of potion left.");
|
||||
} else {
|
||||
player.getPacketDispatch().sendMessage("You have finished your potion.");
|
||||
}
|
||||
return stopExecuting(player);
|
||||
});
|
||||
}
|
||||
|
||||
public int getDose(Item potion){
|
||||
|
|
|
|||
|
|
@ -1,13 +1,10 @@
|
|||
package core.game.container.impl;
|
||||
|
||||
import core.api.IfaceSettingsBuilder;
|
||||
import core.game.container.access.InterfaceContainer;
|
||||
import kotlin.Unit;
|
||||
import kotlin.ranges.IntRange;
|
||||
import org.rs09.consts.Vars;
|
||||
import core.ServerConstants;
|
||||
import core.api.IfaceSettingsBuilder;
|
||||
import core.game.component.Component;
|
||||
import core.game.container.*;
|
||||
import core.game.container.access.InterfaceContainer;
|
||||
import core.game.node.entity.player.Player;
|
||||
import core.game.node.entity.player.link.IronmanMode;
|
||||
import core.game.node.item.Item;
|
||||
|
|
@ -16,8 +13,8 @@ import core.game.world.GameWorld;
|
|||
import core.net.packet.PacketRepository;
|
||||
import core.net.packet.context.ContainerContext;
|
||||
import core.net.packet.out.ContainerPacket;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import kotlin.ranges.IntRange;
|
||||
import org.rs09.consts.Vars;
|
||||
|
||||
import static core.api.ContentAPIKt.*;
|
||||
|
||||
|
|
@ -201,14 +198,9 @@ public final class BankContainer extends Container {
|
|||
}
|
||||
|
||||
item = new Item(item.getId(), amount, item.getCharge());
|
||||
boolean unnote = !item.getDefinition().isUnnoted();
|
||||
Item add = item.toUnnotedItem();
|
||||
|
||||
Item add = unnote ? new Item(item.getDefinition().getNoteId(), amount, item.getCharge()) : item;
|
||||
if (unnote && !add.getDefinition().isUnnoted()) {
|
||||
add = item;
|
||||
}
|
||||
|
||||
int maxCount = super.getMaximumAdd(add);
|
||||
int maxCount = getMaximumAdd(add);
|
||||
if (amount > maxCount) {
|
||||
add.setAmount(maxCount);
|
||||
item.setAmount(maxCount);
|
||||
|
|
@ -474,6 +466,11 @@ public final class BankContainer extends Container {
|
|||
return open;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaximumAdd(Item item) {
|
||||
return super.getMaximumAdd(item.toUnnotedItem());
|
||||
}
|
||||
|
||||
/**
|
||||
* Listens to the bank container.
|
||||
* @author Emperor
|
||||
|
|
|
|||
|
|
@ -221,7 +221,9 @@ class GrandExchange : StartupListener, Commands {
|
|||
//GrandExchangeRecords.getInstance(player).update(offer)
|
||||
|
||||
if (offer.sell && !player.isArtificial) {
|
||||
sendNews(player.username + " just offered " + offer.amount + " " + getItemName(offer.itemID) + " on the GE.")
|
||||
Repository.sendGrandExchangeNews(
|
||||
player.username + " just offered " + offer.amount + " " + getItemName(offer.itemID) + " on the GE."
|
||||
)
|
||||
}
|
||||
|
||||
if (ServerConstants.I_AM_A_CHEATER) {
|
||||
|
|
|
|||
|
|
@ -239,7 +239,7 @@ public enum BoltEffect {
|
|||
// and should be considered a TODO: temporary abuse prevention measure (bolt effect on slayer monsters)
|
||||
boolean rollSuccess = RandomFunction.random(13) == 5;
|
||||
if (!(state.getVictim() instanceof NPC)) return rollSuccess;
|
||||
if (!(state.getAttacker() instanceof Player) && ((NPC) state.getVictim()).getTask() == null) return rollSuccess;
|
||||
if (!(state.getAttacker() instanceof Player) || ((NPC) state.getVictim()).getTask() == null) return rollSuccess;
|
||||
if (state.getVictim().asNpc().getTask().levelReq > state.getAttacker().asPlayer().getSkills().getLevel(Skills.SLAYER)) return false;
|
||||
return rollSuccess;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package core.game.node.entity.combat.spell;
|
||||
|
||||
import content.global.skill.magic.SpellUtils;
|
||||
import core.game.event.SpellCastEvent;
|
||||
import core.game.node.Node;
|
||||
import core.game.node.entity.Entity;
|
||||
|
|
@ -17,7 +18,6 @@ import core.plugin.Plugin;
|
|||
import core.tools.RandomFunction;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static core.api.ContentAPIKt.playGlobalAudio;
|
||||
|
||||
|
|
@ -223,16 +223,17 @@ public abstract class MagicSpell implements Plugin<SpellType> {
|
|||
if (runes == null) {
|
||||
return true;
|
||||
}
|
||||
List<Item> toRemove = new ArrayList<>(20);
|
||||
for (Item item : runes) {
|
||||
if (!hasRune(p, item, toRemove, message)) {
|
||||
return false;
|
||||
Item missing = SpellUtils.hasRunes(p, runes);
|
||||
if (missing != null) {
|
||||
if (message) {
|
||||
p.getPacketDispatch().sendMessage("You don't have enough " + missing.getName() + "s to cast this spell.");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if (remove) {
|
||||
toRemove.forEach(i -> {
|
||||
p.getInventory().remove(i);
|
||||
});
|
||||
ArrayList<Item> toRemove = p.getAttribute("spell:runes", new ArrayList<>());
|
||||
toRemove.forEach(i -> p.getInventory().remove(i));
|
||||
p.removeAttribute("spell:runes");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
@ -255,49 +256,6 @@ public abstract class MagicSpell implements Plugin<SpellType> {
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the player has a rune to remove.
|
||||
* @param p the player.
|
||||
* @param item the item.
|
||||
* @param toRemove the list of items to remove.
|
||||
* @param message the message.
|
||||
* @return {@code True} if so.
|
||||
*/
|
||||
public boolean hasRune(Player p, Item item, List<Item> toRemove, boolean message) {
|
||||
if (!usingStaff(p, item.getId())) {
|
||||
boolean hasBaseRune = p.getInventory().contains(item.getId(),item.getAmount());
|
||||
if(!hasBaseRune){
|
||||
int baseAmt = p.getInventory().getAmount(item.getId());
|
||||
if(baseAmt > 0){
|
||||
toRemove.add(new Item(item.getId(),p.getInventory().getAmount(item.getId())));
|
||||
}
|
||||
int amtRemaining = item.getAmount() - baseAmt;
|
||||
List<CombinationRune> possibleComboRunes = CombinationRune.eligibleFor(Runes.forId(item.getId()));
|
||||
for(CombinationRune r : possibleComboRunes){
|
||||
if(p.getInventory().containsItem(new Item(r.id)) && amtRemaining > 0){
|
||||
int amt = p.getInventory().getAmount(r.id);
|
||||
if(amtRemaining < amt){
|
||||
toRemove.add(new Item(r.id,amtRemaining));
|
||||
amtRemaining = 0;
|
||||
continue;
|
||||
}
|
||||
amtRemaining -= p.getInventory().getAmount(r.id);
|
||||
toRemove.add(new Item(r.id,p.getInventory().getAmount(r.id)));
|
||||
}
|
||||
}
|
||||
if(amtRemaining <= 0){
|
||||
return true;
|
||||
} else {
|
||||
p.getPacketDispatch().sendMessage("You don't have enough " + item.getName() + "s to cast this spell.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
toRemove.add(item);
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the experience for casting this spell.
|
||||
* @param entity The entity to reward with experience.
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
package core.game.node.entity.player.link.diary;
|
||||
|
||||
import core.game.node.entity.player.Player;
|
||||
import org.rs09.consts.Items;
|
||||
import core.game.node.item.Item;
|
||||
import org.rs09.consts.Items;
|
||||
|
||||
/**
|
||||
* An achievement diary type.
|
||||
|
|
@ -118,7 +118,7 @@ public enum DiaryType {
|
|||
"Select a colour for a new kitten", // TODO need ring of charos(a) and garden of tranquility to start
|
||||
"Use the shortcut under the wall, north-west of the Grand<br><br>Exchange",
|
||||
"Enter the A Soul's Bane rift",
|
||||
"Teleport to the Digsite using a Digsite pendant", // TODO need Digsite and museum
|
||||
"Teleport to the Digsite using a Digsite pendant",
|
||||
"Craft an earth tiara on the Earth Altar",
|
||||
"Pickpocket a guard in the Varrock Palace courtyard",
|
||||
"Use the teleport to Varrock spell",
|
||||
|
|
@ -140,7 +140,7 @@ public enum DiaryType {
|
|||
"Craft an air battlestaff",
|
||||
"Give your player-owned house a tropical wood or fancy stone<br><br>finish at the Varrock estate agent's",
|
||||
"Make a Varrock teleport tablet on a mahogany lectern",
|
||||
"Obtain a new set of Family Crest gauntlets from Dimintheis", // TODO need family crest
|
||||
"Obtain a new set of Family Crest gauntlets from Dimintheis",
|
||||
"Make a Waka Canoe near Edgeville",
|
||||
"Use the Home Teleport spell in the Ancient Magicks spellbook<br><br>to teleport to Edgeville",
|
||||
"Use the skull sceptre to teleport to Barbarian Village"
|
||||
|
|
|
|||
|
|
@ -135,6 +135,19 @@ public class Item extends Node{
|
|||
return getId();
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts noted items into unnoted items.
|
||||
*
|
||||
* @return The unnoted version of the item. Returns the original Item if already unnoted.
|
||||
*/
|
||||
public Item toUnnotedItem() {
|
||||
if (definition.isUnnoted()) {
|
||||
return this;
|
||||
} else {
|
||||
return new Item(definition.getNoteId(), getAmount(), getCharge());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the id
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import core.cache.def.impl.NPCDefinition
|
|||
import core.cache.def.impl.VarbitDefinition
|
||||
import core.cache.def.impl.Struct
|
||||
import core.game.node.entity.combat.ImpactHandler.HitsplatType
|
||||
import core.game.node.entity.npc.NPC
|
||||
import core.game.node.entity.player.Player
|
||||
import core.game.node.entity.player.link.SpellBookManager
|
||||
import core.game.node.entity.player.link.diary.DiaryType
|
||||
|
|
@ -30,7 +31,19 @@ import core.tools.Log
|
|||
import core.game.node.entity.player.info.Rights
|
||||
import core.game.node.entity.skill.Skills
|
||||
import core.game.world.map.Location
|
||||
import core.game.world.map.RegionManager.getLocalEntitys
|
||||
import core.game.world.repository.Repository
|
||||
import org.json.simple.JSONArray
|
||||
import kotlin.collections.set
|
||||
import content.global.activity.penguinhns.Penguin
|
||||
import content.global.activity.penguinhns.PenguinHNSEvent
|
||||
import content.global.activity.penguinhns.PenguinManager
|
||||
import content.global.activity.penguinhns.PenguinManager.Companion.penguins
|
||||
import content.global.activity.penguinhns.PenguinManager.Companion.spawner
|
||||
import content.global.activity.penguinhns.PenguinManager.Companion.tagMapping
|
||||
import content.global.activity.penguinhns.PenguinManager.Companion.updateStoreFile
|
||||
import core.ServerStore.Companion.toJSONArray
|
||||
import org.rs09.consts.NPCs
|
||||
|
||||
@Initializable
|
||||
class DevelopmentCommandSet : CommandSet(Privilege.ADMIN) {
|
||||
|
|
@ -304,7 +317,7 @@ class DevelopmentCommandSet : CommandSet(Privilege.ADMIN) {
|
|||
setAttribute (player, "routedraw", !getAttribute(player, "routedraw", false))
|
||||
}
|
||||
|
||||
define ("fmstart", Privilege.ADMIN, description = "Marks your current tile as the force-movement start point.") {player, _ ->
|
||||
define ("fmstart", Privilege.ADMIN, description = "Marks your current tile as the force-movement start point.") {player, _ ->
|
||||
setAttribute(player, "fmstart", Location.create(player.location))
|
||||
}
|
||||
|
||||
|
|
@ -320,7 +333,7 @@ class DevelopmentCommandSet : CommandSet(Privilege.ADMIN) {
|
|||
setAttribute(player, "fmspeedend", args[1].toIntOrNull() ?: 10)
|
||||
}
|
||||
|
||||
define("testfm", Privilege.ADMIN, description = "Runs the configured force-movement from the saved start to end point.") { player, _ ->
|
||||
define("testfm", Privilege.ADMIN, description = "Runs the configured force-movement from the saved start to end point.") { player, _ ->
|
||||
val start = getAttribute(player, "fmstart", Location.create(player.location))
|
||||
val end = getAttribute(player, "fmend", Location.create(player.location))
|
||||
val speed = getAttribute(player, "fmspeed", 10)
|
||||
|
|
@ -427,5 +440,54 @@ class DevelopmentCommandSet : CommandSet(Privilege.ADMIN) {
|
|||
|
||||
target.skills.addExperience(skill, xp!!)
|
||||
}
|
||||
}
|
||||
|
||||
define("renewpenguins", Privilege.ADMIN, "", "Generates a fresh set of weekly penguins") { player, _ ->
|
||||
val spawnedOrdinals = (PenguinHNSEvent.getStoreFile()["spawned-penguins"] as JSONArray).map { it.toString().toInt() }
|
||||
val penguinNPCs = arrayListOf(NPCs.BARREL_8104, NPCs.BUSH_8105,NPCs.CACTUS_8107,NPCs.CRATE_8108,NPCs.ROCK_8109,NPCs.TOADSTOOL_8110)
|
||||
|
||||
spawnedOrdinals.forEach {
|
||||
val peng = Penguin.values()[it]
|
||||
val nearNPCs = getLocalEntitys(peng.location,1)
|
||||
nearNPCs.forEach { npc ->
|
||||
if (npc.id in penguinNPCs) {
|
||||
poofClear(npc as NPC)
|
||||
}
|
||||
}
|
||||
}
|
||||
penguins = spawner.spawnPenguins(10)
|
||||
PenguinHNSEvent.getStoreFile()["spawned-penguins"] = penguins.toJSONArray()
|
||||
tagMapping.clear()
|
||||
for (p in penguins) {
|
||||
tagMapping.put(p, JSONArray())
|
||||
val pengCoord = Penguin.values()[p].location
|
||||
player.debug("Penguin spawned at:$pengCoord")
|
||||
}
|
||||
updateStoreFile()
|
||||
player.debug("Penguin positions have been renewed")
|
||||
}
|
||||
|
||||
define("spawnpenguin",Privilege.ADMIN,"::spawnPenguin <lt>Ordinal<gt>","Adds a new Penguin spawn to this weeks list based on the ordinal provided 0-64"){player,args->
|
||||
if (args.size!=2) reject (player,"Usage: ::spawnpenguin Ordinal")
|
||||
val ordinal = args[1].toIntOrNull()
|
||||
if (ordinal == null) reject(player,"Ordinal must be an integer.")
|
||||
if (ordinal!! > 64 || ordinal < 0) reject(player,"Ordinal must be in the range 0-64 inclusive.")
|
||||
|
||||
val store = PenguinHNSEvent.getStoreFile()
|
||||
val ordinals = (store["spawned-penguins"] as? JSONArray)
|
||||
?.map { it.toString().toInt() }
|
||||
?.toMutableList()
|
||||
?: mutableListOf()
|
||||
val peng = Penguin.values()[ordinal]
|
||||
NPC(peng.id,peng.location)
|
||||
.also { PenguinManager.npcs.add(it); it.isNeverWalks = true; it.isWalks = false }.init()
|
||||
tagMapping.clear()
|
||||
for (p in ordinals) {
|
||||
tagMapping.put(p, JSONArray())
|
||||
}
|
||||
updateStoreFile()
|
||||
val pengCoords = peng.location
|
||||
player.debug("Penguin spawned at:$pengCoords")
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ import core.game.system.command.CommandMapping
|
|||
import core.game.system.command.Privilege
|
||||
import core.game.system.communication.CommunicationInfo
|
||||
import core.game.world.map.RegionManager
|
||||
import core.game.world.repository.GE_NEWS_MUTE_ATTRIBUTE
|
||||
import core.game.world.map.build.DynamicRegion
|
||||
import core.game.world.repository.Repository
|
||||
import core.game.node.entity.combat.equipment.WeaponInterface
|
||||
|
|
@ -252,21 +253,38 @@ class MiscCommandSet : CommandSet(Privilege.ADMIN){
|
|||
}
|
||||
|
||||
/**
|
||||
* Shows the player a list of currently active GE sell offers
|
||||
* Shows the player a list of currently active GE sell offers or toggles muting sell offer News announcements.
|
||||
*/
|
||||
define("ge", Privilege.STANDARD, "::ge <lt>MODE<gt> (Modes: buying, selling, search, bots, botsearch)", "Various commands for viewing GE offers.") { player, args ->
|
||||
if(args.size < 2){
|
||||
reject(player, "Usage: ::ge mode", "Available modes: buying, selling, search, bots, botsearch")
|
||||
define(
|
||||
"ge",
|
||||
Privilege.STANDARD,
|
||||
"::ge <lt>MODE<gt> (Modes: buying, selling, search, bots, botsearch, mute)",
|
||||
"Various commands for viewing GE offers."
|
||||
) { player, args ->
|
||||
if (args.size < 2) {
|
||||
reject(player, "Usage: ::ge mode", "Available modes: buying, selling, search, bots, botsearch, mute")
|
||||
}
|
||||
|
||||
val mode = args[1]
|
||||
when(mode){
|
||||
when (mode) {
|
||||
"buying" -> showGeBuy(player)
|
||||
"selling" -> showGeSell(player)
|
||||
"search" -> showGeInputDialogue(player, args, ::showOffers)
|
||||
"bots" -> showGeBots(player)
|
||||
"botsearch" -> showGeInputDialogue(player, args, ::showGeBotsearch)
|
||||
else -> reject(player, "Invalid mode used. Available modes are: buying, selling, search")
|
||||
"mute" -> {
|
||||
val currentlyMuted = getAttribute(player, GE_NEWS_MUTE_ATTRIBUTE, false)
|
||||
if (currentlyMuted) {
|
||||
removeAttribute(player, GE_NEWS_MUTE_ATTRIBUTE)
|
||||
} else {
|
||||
setAttribute(player, GE_NEWS_MUTE_ATTRIBUTE, true)
|
||||
}
|
||||
sendMessage(player, "GE sell offer news is now ${if (currentlyMuted) "visible" else "hidden"}.")
|
||||
}
|
||||
|
||||
else -> reject(
|
||||
player,
|
||||
"Invalid mode used. Available modes are: buying, selling, search, bots, botsearch, mute"
|
||||
)
|
||||
}
|
||||
}
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -1,16 +1,17 @@
|
|||
package core.game.world.repository
|
||||
|
||||
import core.game.node.entity.npc.NPC
|
||||
import content.region.wilderness.handlers.revenants.RevenantNPC
|
||||
import core.ServerConstants
|
||||
import core.api.sendMessage
|
||||
import core.game.node.entity.npc.NPC
|
||||
import core.game.node.entity.player.Player
|
||||
import core.game.world.map.Location
|
||||
import core.game.world.map.RegionManager
|
||||
import core.ServerConstants
|
||||
import core.api.sendMessage
|
||||
import core.game.world.update.UpdateSequence
|
||||
import java.util.*
|
||||
import java.util.concurrent.CopyOnWriteArrayList
|
||||
|
||||
const val GE_NEWS_MUTE_ATTRIBUTE = "/save:ge:news-mute"
|
||||
|
||||
/**
|
||||
* The repository holding all node lists, etc in the game world.
|
||||
* @author Emperor
|
||||
|
|
@ -64,11 +65,22 @@ object Repository {
|
|||
*/
|
||||
@JvmStatic
|
||||
fun sendNews(string: String, icon: Int = 12, color: String = "CC6600") {
|
||||
sendNews(string, icon, color, false)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun sendGrandExchangeNews(string: String, icon: Int = 12, color: String = "CC6600") {
|
||||
sendNews(string, icon, color, true)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun sendNews(string: String, icon: Int, color: String, isGeNews: Boolean) {
|
||||
if (!ServerConstants.ENABLE_GLOBAL_CHAT) return
|
||||
val players: Array<Any> = playerNames.values.toTypedArray()
|
||||
val size = players.size
|
||||
for (i in 0 until size) {
|
||||
val player = players[i] as Player ?: continue
|
||||
val player = players[i] as? Player ?: continue
|
||||
if (isGeNews && player.getAttribute(GE_NEWS_MUTE_ATTRIBUTE, false)) continue
|
||||
sendMessage(player, "<img=$icon><col=$color>News: $string")
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,7 +11,6 @@ import core.tools.*
|
|||
import core.api.*
|
||||
import core.game.world.GameWorld
|
||||
|
||||
import java.nio.charset.StandardCharsets
|
||||
import kotlin.reflect.*
|
||||
import kotlin.math.max
|
||||
|
||||
|
|
@ -28,12 +27,13 @@ sealed class PlayerFlags530 (p: Int, o: Int, f: EntityFlag) : EFlagProvider (530
|
|||
else
|
||||
buffer.p1 (context.chatIcon)
|
||||
val chatBuf = ByteArray(256)
|
||||
chatBuf[0] = context.text.length.toByte()
|
||||
val encodedText = CP1252.toBytes(context.text)
|
||||
chatBuf[0] = encodedText.size.toByte()
|
||||
val offset = 1 + StringUtils.encryptPlayerChat (
|
||||
chatBuf,
|
||||
0, 1,
|
||||
context.text.length,
|
||||
context.text.toByteArray(StandardCharsets.UTF_8)
|
||||
encodedText.size,
|
||||
encodedText
|
||||
)
|
||||
buffer.p1 (offset + 1)
|
||||
buffer.putReverse (chatBuf, 0, offset)
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import core.net.packet.IoBuffer;
|
|||
import core.net.packet.OutgoingPacket;
|
||||
import core.net.packet.PacketHeader;
|
||||
import core.net.packet.context.MessageContext;
|
||||
import core.tools.CP1252;
|
||||
import core.tools.StringUtils;
|
||||
import core.game.bots.AIPlayer;
|
||||
|
||||
|
|
@ -21,20 +22,21 @@ public final class CommunicationMessage implements OutgoingPacket<MessageContext
|
|||
public void send(MessageContext context) {
|
||||
IoBuffer buffer = new IoBuffer(context.getOpcode(), PacketHeader.BYTE);
|
||||
String message = context.getMessage();
|
||||
byte[] encodedMessage = CP1252.toBytes(message);
|
||||
Player player = context.getPlayer();
|
||||
String other = context.getOther();
|
||||
switch (context.getOpcode()) {
|
||||
case MessageContext.SEND_MESSAGE:
|
||||
byte[] bytes = new byte[256];
|
||||
int length = StringUtils.encryptPlayerChat(bytes, 0, 0, message.length(), message.getBytes());
|
||||
int length = StringUtils.encryptPlayerChat(bytes, 0, 0, encodedMessage.length, encodedMessage);
|
||||
buffer.putLong(StringUtils.stringToLong(other));
|
||||
buffer.put((byte) message.length());
|
||||
buffer.put((byte) encodedMessage.length);
|
||||
buffer.putBytes(bytes, 0, length);
|
||||
break;
|
||||
case MessageContext.RECIEVE_MESSAGE:
|
||||
bytes = new byte[256];
|
||||
bytes[0] = (byte) message.length();
|
||||
length = 1 + StringUtils.encryptPlayerChat(bytes, 0, 1, message.length(), message.getBytes());
|
||||
bytes[0] = (byte) encodedMessage.length;
|
||||
length = 1 + StringUtils.encryptPlayerChat(bytes, 0, 1, encodedMessage.length, encodedMessage);
|
||||
player.setAttribute("replyTo", other);
|
||||
buffer.putLong(StringUtils.stringToLong(other)).putShort(new Random().nextInt(0xFFFF)).putTri(getMessageIndex(player)).put((byte) context.getChatIcon()).putBytes(bytes, 0, length);
|
||||
break;
|
||||
|
|
@ -44,8 +46,8 @@ public final class CommunicationMessage implements OutgoingPacket<MessageContext
|
|||
return;
|
||||
}
|
||||
bytes = new byte[256];
|
||||
bytes[0] = (byte) context.getMessage().length();
|
||||
length = 1 + StringUtils.encryptPlayerChat(bytes, 0, 1, message.length(), message.getBytes());
|
||||
bytes[0] = (byte) encodedMessage.length;
|
||||
length = 1 + StringUtils.encryptPlayerChat(bytes, 0, 1, encodedMessage.length, encodedMessage);
|
||||
buffer.putLong(StringUtils.stringToLong(other));
|
||||
buffer.put((byte) 0);// it's just read does nothing
|
||||
buffer.putLong(StringUtils.stringToLong(clan.getName()));
|
||||
|
|
@ -72,4 +74,4 @@ public final class CommunicationMessage implements OutgoingPacket<MessageContext
|
|||
return count;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,18 +1,22 @@
|
|||
package core.tools;
|
||||
|
||||
public class CP1252 {
|
||||
private static char[] charMap = {'\u20ac', '\0', '\u201a', '\u0192', '\u201e', '\u2026', '\u2020', '\u2021',
|
||||
public final class CP1252 {
|
||||
private static final char[] CHAR_MAP = {'\u20ac', '\0', '\u201a', '\u0192', '\u201e', '\u2026', '\u2020', '\u2021',
|
||||
'\u02c6', '\u2030', '\u0160', '\u2039', '\u0152', '\0', '\u017d', '\0', '\0', '\u2018', '\u2019',
|
||||
'\u201c', '\u201d', '\u2022', '\u2013', '\u2014', '\u02dc', '\u2122', '\u0161', '\u203a', '\u0153',
|
||||
'\0', '\u017e', '\u0178'};
|
||||
|
||||
private CP1252() {
|
||||
/* utility class */
|
||||
}
|
||||
|
||||
public static char getFromByte(byte value) {
|
||||
int out = value & 0xff;
|
||||
if (out == 0) {
|
||||
throw new IllegalArgumentException("Non cp1252 character 0x" + Integer.toString(out, 16) + " provided");
|
||||
}
|
||||
if (out >= 128 && out < 160) {
|
||||
int cp1252 = charMap[out - 128];
|
||||
int cp1252 = CHAR_MAP[out - 128];
|
||||
if (cp1252 == 0) {
|
||||
cp1252 = 63;
|
||||
}
|
||||
|
|
@ -20,4 +24,26 @@ public class CP1252 {
|
|||
}
|
||||
return (char) out;
|
||||
}
|
||||
|
||||
public static byte getByte(char value) {
|
||||
if ((value > 0 && value < 128) || (value >= 160 && value <= 255)) {
|
||||
return (byte) value;
|
||||
}
|
||||
|
||||
for (int i = 0; i < CHAR_MAP.length; i++) {
|
||||
if (CHAR_MAP[i] != 0 && CHAR_MAP[i] == value) {
|
||||
return (byte) (i + 128);
|
||||
}
|
||||
}
|
||||
|
||||
return 63;
|
||||
}
|
||||
|
||||
public static byte[] toBytes(CharSequence value) {
|
||||
byte[] out = new byte[value.length()];
|
||||
for (int i = 0; i < value.length(); i++) {
|
||||
out[i] = getByte(value.charAt(i));
|
||||
}
|
||||
return out;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -502,7 +502,7 @@ public final class StringUtils {
|
|||
return "";
|
||||
int charsDecoded = 0;
|
||||
int i_4_ = 0;
|
||||
String s = "";
|
||||
StringBuilder s = new StringBuilder(totalChars);
|
||||
for (;;) {
|
||||
byte i_7_ = (byte) buffer.get();
|
||||
if (i_7_ >= 0)
|
||||
|
|
@ -511,7 +511,7 @@ public final class StringUtils {
|
|||
i_4_ = anIntArray241[i_4_];
|
||||
int i_8_;
|
||||
if ((i_8_ = anIntArray241[i_4_]) < 0) {
|
||||
s += (char) (byte) (i_8_ ^ 0xffffffff);
|
||||
s.append(CP1252.getFromByte((byte) (i_8_ ^ 0xffffffff)));
|
||||
if (totalChars <= ++charsDecoded)
|
||||
break;
|
||||
i_4_ = 0;
|
||||
|
|
@ -521,7 +521,7 @@ public final class StringUtils {
|
|||
else
|
||||
i_4_++;
|
||||
if ((i_8_ = anIntArray241[i_4_]) < 0) {
|
||||
s += (char) (byte) (i_8_ ^ 0xffffffff);
|
||||
s.append(CP1252.getFromByte((byte) (i_8_ ^ 0xffffffff)));
|
||||
if (++charsDecoded >= totalChars)
|
||||
break;
|
||||
i_4_ = 0;
|
||||
|
|
@ -531,7 +531,7 @@ public final class StringUtils {
|
|||
else
|
||||
i_4_ = anIntArray241[i_4_];
|
||||
if ((i_8_ = anIntArray241[i_4_]) < 0) {
|
||||
s += (char) (byte) (i_8_ ^ 0xffffffff);
|
||||
s.append(CP1252.getFromByte((byte) (i_8_ ^ 0xffffffff)));
|
||||
if (totalChars <= ++charsDecoded)
|
||||
break;
|
||||
i_4_ = 0;
|
||||
|
|
@ -541,7 +541,7 @@ public final class StringUtils {
|
|||
else
|
||||
i_4_ = anIntArray241[i_4_];
|
||||
if ((i_8_ = anIntArray241[i_4_]) < 0) {
|
||||
s += (char) (byte) (i_8_ ^ 0xffffffff);
|
||||
s.append(CP1252.getFromByte((byte) (i_8_ ^ 0xffffffff)));
|
||||
if (totalChars <= ++charsDecoded)
|
||||
break;
|
||||
|
||||
|
|
@ -552,7 +552,7 @@ public final class StringUtils {
|
|||
else
|
||||
i_4_++;
|
||||
if ((i_8_ = anIntArray241[i_4_]) < 0) {
|
||||
s += (char) (byte) (i_8_ ^ 0xffffffff);
|
||||
s.append(CP1252.getFromByte((byte) (i_8_ ^ 0xffffffff)));
|
||||
if (++charsDecoded >= totalChars)
|
||||
break;
|
||||
i_4_ = 0;
|
||||
|
|
@ -562,7 +562,7 @@ public final class StringUtils {
|
|||
else
|
||||
i_4_ = anIntArray241[i_4_];
|
||||
if ((i_8_ = anIntArray241[i_4_]) < 0) {
|
||||
s += (char) (byte) (i_8_ ^ 0xffffffff);
|
||||
s.append(CP1252.getFromByte((byte) (i_8_ ^ 0xffffffff)));
|
||||
if (totalChars <= ++charsDecoded)
|
||||
break;
|
||||
i_4_ = 0;
|
||||
|
|
@ -572,7 +572,7 @@ public final class StringUtils {
|
|||
else
|
||||
i_4_++;
|
||||
if ((i_8_ = anIntArray241[i_4_]) < 0) {
|
||||
s += (char) (byte) (i_8_ ^ 0xffffffff);
|
||||
s.append(CP1252.getFromByte((byte) (i_8_ ^ 0xffffffff)));
|
||||
if (totalChars <= ++charsDecoded)
|
||||
break;
|
||||
i_4_ = 0;
|
||||
|
|
@ -582,13 +582,13 @@ public final class StringUtils {
|
|||
else
|
||||
i_4_++;
|
||||
if ((i_8_ = anIntArray241[i_4_]) < 0) {
|
||||
s += (char) (byte) (i_8_ ^ 0xffffffff);
|
||||
s.append(CP1252.getFromByte((byte) (i_8_ ^ 0xffffffff)));
|
||||
if (++charsDecoded >= totalChars)
|
||||
break;
|
||||
i_4_ = 0;
|
||||
}
|
||||
}
|
||||
return s;
|
||||
return s.toString();
|
||||
} catch (RuntimeException runtimeexception) {
|
||||
runtimeexception.printStackTrace();
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue