diff --git a/Server/data/configs/npc_configs.json b/Server/data/configs/npc_configs.json index 3d837994f..129f8fd4a 100644 --- a/Server/data/configs/npc_configs.json +++ b/Server/data/configs/npc_configs.json @@ -10047,10 +10047,11 @@ }, { "examine": "He's had a fair bit to drink...", - "start_gfx": "33", + "start_gfx": "", "combat_style": "1", "melee_animation": "99", "range_animation": "99", + "combat_audio": "2707,419,418", "attack_speed": "5", "magic_level": "20", "defence_animation": "101", @@ -24669,6 +24670,7 @@ "combat_style": "1", "melee_animation": "4230", "range_animation": "4230", + "combat_audio": "2695,513,512", "attack_speed": "5", "magic_level": "30", "defence_animation": "404", @@ -24682,7 +24684,9 @@ "id": "2476", "bonuses": "30,20,10,20,20,30,30,10,20,10,30,30,20,30,20", "range_level": "20", - "attack_level": "8" + "projectile": "27", + "attack_level": "8", + "prj_height": "" }, { "examine": "Apparently a master of quizzes!", @@ -49160,10 +49164,10 @@ "range_animation": "0", "attack_speed": "4", "magic_level": "1", - "respawn_degitlay": "60", "defence_animation": "0", "weakness": "2", "slayer_exp": "93", + "respawn_delay": "60", "magic_animation": "0", "death_animation": "6081", "name": "Cave bug", diff --git a/Server/src/main/content/global/ame/RandomEvents.kt b/Server/src/main/content/global/ame/RandomEvents.kt index ec7066858..9afadba57 100644 --- a/Server/src/main/content/global/ame/RandomEvents.kt +++ b/Server/src/main/content/global/ame/RandomEvents.kt @@ -4,10 +4,12 @@ import org.rs09.consts.Items import content.global.ame.events.MysteriousOldManNPC import content.global.ame.events.certer.CerterNPC import content.global.ame.events.drilldemon.SeargentDamienNPC +import content.global.ame.events.drunkendwarf.DrunkenDwarfNPC import content.global.ame.events.evilbob.EvilBobNPC import content.global.ame.events.evilchicken.EvilChickenNPC import content.global.ame.events.freakyforester.FreakyForesterNPC import content.global.ame.events.genie.GenieNPC +import content.global.ame.events.rickturpentine.RickTurpentineNPC import content.global.ame.events.rivertroll.RiverTrollRENPC import content.global.ame.events.rockgolem.RockGolemRENPC import content.global.ame.events.sandwichlady.SandwichLadyRENPC @@ -42,6 +44,8 @@ enum class RandomEvents(val npc: RandomEventNPC, val loot: WeightBasedTable? = n DRILL_DEMON(npc = SeargentDamienNPC()), EVIL_CHICKEN(npc = EvilChickenNPC()), EVIL_BOB(npc = EvilBobNPC(), skillIds = intArrayOf(Skills.FISHING, Skills.MAGIC)), + DRUNKEN_DWARF(npc = DrunkenDwarfNPC()), + RICK_TURPENTINE(npc = RickTurpentineNPC(), loot = CERTER.loot), SURPRISE_EXAM(npc = MysteriousOldManNPC(), type = "sexam"), FREAKY_FORESTER(npc = FreakyForesterNPC(), skillIds = intArrayOf(Skills.WOODCUTTING)), TREE_SPIRIT(npc = TreeSpiritRENPC(), skillIds = intArrayOf(Skills.WOODCUTTING)), diff --git a/Server/src/main/content/global/ame/events/drunkendwarf/DrunkenDwarfBehavior.kt b/Server/src/main/content/global/ame/events/drunkendwarf/DrunkenDwarfBehavior.kt new file mode 100644 index 000000000..a92c554f4 --- /dev/null +++ b/Server/src/main/content/global/ame/events/drunkendwarf/DrunkenDwarfBehavior.kt @@ -0,0 +1,14 @@ +package content.global.ame.events.drunkendwarf + +import core.game.node.entity.Entity +import core.game.node.entity.combat.BattleState +import core.game.node.entity.npc.NPC +import core.game.node.entity.npc.NPCBehavior +import core.tools.RandomFunction +import org.rs09.consts.NPCs + +class DrunkenDwarfBehavior : NPCBehavior(NPCs.DRUNKEN_DWARF_956) { + override fun beforeAttackFinalized(self: NPC, victim: Entity, state: BattleState) { + state.estimatedHit = RandomFunction.getRandom(3) + } +} \ No newline at end of file diff --git a/Server/src/main/content/global/ame/events/drunkendwarf/DrunkenDwarfDialogue.kt b/Server/src/main/content/global/ame/events/drunkendwarf/DrunkenDwarfDialogue.kt new file mode 100644 index 000000000..010f5c366 --- /dev/null +++ b/Server/src/main/content/global/ame/events/drunkendwarf/DrunkenDwarfDialogue.kt @@ -0,0 +1,21 @@ +package content.global.ame.events.drunkendwarf + +import core.api.addItemOrDrop +import core.game.dialogue.DialogueFile +import core.game.dialogue.FacialExpression +import core.game.system.timer.impl.AntiMacro +import org.rs09.consts.Items + +class DrunkenDwarfDialogue : DialogueFile() { + override fun handle(componentID: Int, buttonID: Int) { + when (stage) { + 0 -> npcl(FacialExpression.OLD_DRUNK_RIGHT, "I 'new it were you matey! 'Ere, have some ob the good stuff!").also { stage++ } + 1 -> { + addItemOrDrop(player!!, Items.BEER_1917) + addItemOrDrop(player!!, Items.KEBAB_1971) + AntiMacro.terminateEventNpc(player!!) + end() + } + } + } +} \ No newline at end of file diff --git a/Server/src/main/content/global/ame/events/drunkendwarf/DrunkenDwarfNPC.kt b/Server/src/main/content/global/ame/events/drunkendwarf/DrunkenDwarfNPC.kt new file mode 100644 index 000000000..1485dd8c4 --- /dev/null +++ b/Server/src/main/content/global/ame/events/drunkendwarf/DrunkenDwarfNPC.kt @@ -0,0 +1,50 @@ +package content.global.ame.events.drunkendwarf + +import content.global.ame.RandomEventNPC +import core.api.* +import core.api.utils.WeightBasedTable +import core.game.node.entity.npc.NPC +import core.tools.RandomFunction +import org.rs09.consts.NPCs +import org.rs09.consts.Sounds + +class DrunkenDwarfNPC(override var loot: WeightBasedTable? = null) : RandomEventNPC(NPCs.DRUNKEN_DWARF_956) { + private val phrases = arrayOf("Oi, are you der @name!","Dunt ignore your matey!","Aww comeon, talk to ikle me @name!") + private var attackPhrase = false + private var attackDelay = 0 + private var lastPhraseTime = 0 + + private fun sendPhrases() { + if (getWorldTicks() > lastPhraseTime + 5) { + playGlobalAudio(this.location, Sounds.DWARF_WHISTLE_2297) + sendChat(this, phrases.random().replace("@name",player.username.capitalize())) + this.face(player) + lastPhraseTime = getWorldTicks() + } + } + + override fun init() { + super.init() + playGlobalAudio(this.location, Sounds.DWARF_WHISTLE_2297) + sendChat(this, "'Ello der ${player.username.capitalize()}! *hic*") + } + + override fun tick() { + if (RandomFunction.roll(20) && !attackPhrase) + sendPhrases() + if (ticksLeft <= 10) { + ticksLeft = 10 + if (!attackPhrase) + sendChat("I hates you, ${player.username.capitalize()}!").also { attackPhrase = true } + if (attackDelay <= getWorldTicks()) + this.attack(player) + } + super.tick() + } + + override fun talkTo(npc: NPC) { + attackDelay = getWorldTicks() + 10 + this.pulseManager.clear() + openDialogue(player, DrunkenDwarfDialogue(), this.asNpc()) + } +} \ No newline at end of file diff --git a/Server/src/main/content/global/ame/events/rickturpentine/RickTurpentineBehavior.kt b/Server/src/main/content/global/ame/events/rickturpentine/RickTurpentineBehavior.kt new file mode 100644 index 000000000..dbf6a8616 --- /dev/null +++ b/Server/src/main/content/global/ame/events/rickturpentine/RickTurpentineBehavior.kt @@ -0,0 +1,14 @@ +package content.global.ame.events.rickturpentine + +import core.game.node.entity.Entity +import core.game.node.entity.combat.BattleState +import core.game.node.entity.npc.NPC +import core.game.node.entity.npc.NPCBehavior +import core.tools.RandomFunction +import org.rs09.consts.NPCs + +class RickTurpentineBehavior : NPCBehavior(NPCs.RICK_TURPENTINE_2476) { + override fun beforeAttackFinalized(self: NPC, victim: Entity, state: BattleState) { + state.estimatedHit = RandomFunction.getRandom(3) + } +} \ No newline at end of file diff --git a/Server/src/main/content/global/ame/events/rickturpentine/RickTurpentineDialogue.kt b/Server/src/main/content/global/ame/events/rickturpentine/RickTurpentineDialogue.kt new file mode 100644 index 000000000..0b24b3ef7 --- /dev/null +++ b/Server/src/main/content/global/ame/events/rickturpentine/RickTurpentineDialogue.kt @@ -0,0 +1,19 @@ +package content.global.ame.events.rickturpentine + +import core.api.addItemOrDrop +import core.game.dialogue.DialogueFile +import core.game.dialogue.FacialExpression +import core.game.system.timer.impl.AntiMacro + +class RickTurpentineDialogue : DialogueFile() { + override fun handle(componentID: Int, buttonID: Int) { + when (stage) { + 0 -> npcl(FacialExpression.NEUTRAL, "Today is your lucky day, " + (if (player!!.isMale) "sirrah!" else "madam!") + " I am donating to the victims of crime to atone for my past actions!").also { stage++ } + 1 -> { + AntiMacro.rollEventLoot(player!!).forEach { addItemOrDrop(player!!, it.id, it.amount) } + AntiMacro.terminateEventNpc(player!!) + end() + } + } + } +} \ No newline at end of file diff --git a/Server/src/main/content/global/ame/events/rickturpentine/RickTurpentineNPC.kt b/Server/src/main/content/global/ame/events/rickturpentine/RickTurpentineNPC.kt new file mode 100644 index 000000000..ba731de03 --- /dev/null +++ b/Server/src/main/content/global/ame/events/rickturpentine/RickTurpentineNPC.kt @@ -0,0 +1,31 @@ +package content.global.ame.events.rickturpentine + +import content.global.ame.RandomEventNPC +import core.api.* +import core.api.utils.WeightBasedTable +import core.game.node.entity.npc.NPC +import org.rs09.consts.NPCs + +class RickTurpentineNPC(override var loot: WeightBasedTable? = null) : RandomEventNPC(NPCs.RICK_TURPENTINE_2476) { + private var attackDelay = 0 + + override fun init() { + super.init() + sendChat("Good day to you, " + (if(player.isMale) "milord " else "milady ") + player.username.capitalize() + ".") + } + + override fun tick() { + if (ticksLeft <= 10) { + ticksLeft = 10 + if (attackDelay <= getWorldTicks()) + this.attack(player) + } + super.tick() + } + + override fun talkTo(npc: NPC) { + attackDelay = getWorldTicks() + 10 + this.pulseManager.clear() + openDialogue(player, RickTurpentineDialogue(), this.asNpc()) + } +} \ No newline at end of file diff --git a/Server/src/main/core/game/node/entity/combat/CombatPulse.kt b/Server/src/main/core/game/node/entity/combat/CombatPulse.kt index 6ea12e2d9..cbdb10701 100644 --- a/Server/src/main/core/game/node/entity/combat/CombatPulse.kt +++ b/Server/src/main/core/game/node/entity/combat/CombatPulse.kt @@ -1,5 +1,6 @@ package core.game.node.entity.combat +import content.global.ame.RandomEventNPC import content.global.handlers.item.equipment.special.SalamanderSwingHandler import core.game.container.impl.EquipmentContainer import core.game.interaction.MovementPulse @@ -132,7 +133,7 @@ class CombatPulse( if (handler == null) { handler = entity.getSwingHandler(true) } - if (!v.isAttackable(entity, handler!!.type, true)) { + if (!v.isAttackable(entity, handler!!.type, true) && entity != getAttribute(v, AntiMacro.EVENT_NPC, null)) { return true } if (!swing(entity, victim, handler)) { @@ -440,6 +441,8 @@ class CombatPulse( if (DeathTask.isDead(victim) || DeathTask.isDead(entity)) { return true } + if (entity is NPC) + entity.asNpc().behavior.beforeAttackFinalized(entity, victim, state) if (impact || getDelay() == 0) { if (state.estimatedHit != 0 && victim is NPC && entity is Player) { val n = victim.asNpc()