diff --git a/engine/src/main/kotlin/world/gregs/voidps/engine/client/instruction/handle/InterfaceOnPlayerOptionHandler.kt b/engine/src/main/kotlin/world/gregs/voidps/engine/client/instruction/handle/InterfaceOnPlayerOptionHandler.kt index a48c61fc67..30b3bce033 100644 --- a/engine/src/main/kotlin/world/gregs/voidps/engine/client/instruction/handle/InterfaceOnPlayerOptionHandler.kt +++ b/engine/src/main/kotlin/world/gregs/voidps/engine/client/instruction/handle/InterfaceOnPlayerOptionHandler.kt @@ -1,11 +1,14 @@ package world.gregs.voidps.engine.client.instruction.handle +import com.github.michaelbull.logging.InlineLogger import world.gregs.voidps.engine.client.instruction.InstructionHandler import world.gregs.voidps.engine.client.instruction.InterfaceHandler import world.gregs.voidps.engine.client.ui.closeInterfaces import world.gregs.voidps.engine.entity.character.mode.interact.ItemOnPlayerInteract import world.gregs.voidps.engine.entity.character.player.Player import world.gregs.voidps.engine.entity.character.player.Players +import world.gregs.voidps.engine.entity.character.player.name +import world.gregs.voidps.engine.entity.item.Item import world.gregs.voidps.network.client.instruction.InteractInterfacePlayer class InterfaceOnPlayerOptionHandler( @@ -16,9 +19,19 @@ class InterfaceOnPlayerOptionHandler( val (playerIndex, interfaceId, componentId, itemId, itemSlot) = instruction val target = Players.indexed(playerIndex) ?: return false - val (id, component, item) = handler.getInterfaceItem(player, interfaceId, componentId, itemId, itemSlot) ?: return false + if ((interfaceId == 192 || interfaceId == 193) && itemId == -1) { + player.closeInterfaces() + player["magic_spell"] = "$interfaceId:$componentId" + player["spellbook"] = if (interfaceId == 193) 1 else 0 + player.mode = ItemOnPlayerInteract(target, "$interfaceId:$componentId", Item.EMPTY, -1, player) + return true + } + + val (id, component, item) = handler.getInterfaceItem(player, interfaceId, componentId, itemId, itemSlot) + ?: return false player.closeInterfaces() player.mode = ItemOnPlayerInteract(target, "$id:$component", item, itemSlot, player) + return true } } diff --git a/engine/src/main/kotlin/world/gregs/voidps/engine/entity/character/mode/interact/Interact.kt b/engine/src/main/kotlin/world/gregs/voidps/engine/entity/character/mode/interact/Interact.kt index e2dc9308d3..71e044ea49 100644 --- a/engine/src/main/kotlin/world/gregs/voidps/engine/entity/character/mode/interact/Interact.kt +++ b/engine/src/main/kotlin/world/gregs/voidps/engine/entity/character/mode/interact/Interact.kt @@ -130,7 +130,8 @@ open class Interact( interacted = false clearInteracted = false } - if (!character.hasMenuOpen()) { + // Don't move if we just interacted at range + if (!character.hasMenuOpen() && !interacted) { super.tick() } if (!interacted || updateRange) { diff --git a/game/src/main/kotlin/content/skill/magic/CombatSpellsOnPlayer.kt b/game/src/main/kotlin/content/skill/magic/CombatSpellsOnPlayer.kt new file mode 100644 index 0000000000..bde7e84e86 --- /dev/null +++ b/game/src/main/kotlin/content/skill/magic/CombatSpellsOnPlayer.kt @@ -0,0 +1,49 @@ +package content.skill.magic + +import com.github.michaelbull.logging.InlineLogger +import content.skill.magic.spell.spell +import world.gregs.voidps.cache.definition.Params +import world.gregs.voidps.engine.Script +import world.gregs.voidps.engine.client.variable.hasClock +import world.gregs.voidps.engine.client.variable.start +import world.gregs.voidps.engine.data.definition.InterfaceDefinitions +import world.gregs.voidps.engine.entity.Approachable +import world.gregs.voidps.engine.entity.character.mode.EmptyMode +import world.gregs.voidps.engine.entity.character.player.name + +class CombatSpellsOnPlayer : Script { + private val logger = InlineLogger() + + init { + Approachable.onPlayer.getOrPut("*") { mutableListOf() }.add { interact -> + val id = interact.id + if (!id.startsWith("192:") &&!id.startsWith("193:") &&!id.startsWith("194:") &&!id.startsWith("430:")) return@add + if (hasClock("action_delay")) return@add + + val parts = id.split(":") + val ifaceId = parts[0].toInt() + val compId = parts[1].toInt() + + val defs = InterfaceDefinitions.definitions + if (ifaceId >= defs.size) return@add + val def = defs[ifaceId] + val component = def.components?.get(compId)?: return@add + val spell = component.stringId + + if (component.params?.get(Params.id("cast_id")) == null) return@add + + logger.debug { "Spell $id ($spell) on ${interact.target.name}" } + approachRange(10) + this.spell = spell + set("one_time", true) + + start("action_delay", 4) + Magic.castSpell(this@add, interact.target) + + // End Interact, let Combat mode handle subsequent casts + if (mode == interact) { + mode = EmptyMode + } + } + } +} \ No newline at end of file diff --git a/game/src/main/kotlin/content/skill/magic/spell/Spells.kt b/game/src/main/kotlin/content/skill/magic/spell/Spells.kt index 76b944e802..e5a13f80d4 100644 --- a/game/src/main/kotlin/content/skill/magic/spell/Spells.kt +++ b/game/src/main/kotlin/content/skill/magic/spell/Spells.kt @@ -21,9 +21,11 @@ class Spells : Script { return@combatAttack } if (spell.endsWith("_burst") || spell.endsWith("_barrage")) { - val targets = multiTargets(target, 9) + val targets = multiTargets(this, target, 9) for (targ in targets) { - targ.directHit(this, random.nextInt(0..damage), type, weapon, spell) + // damage can be -1 on a miss — clamp to 0 + val splash = if (damage > 0) random.nextInt(0..damage) else 0 + targ.directHit(this, splash, type, weapon, spell) } } } diff --git a/game/src/main/kotlin/content/skill/melee/weapon/SpecialAttackMelee.kt b/game/src/main/kotlin/content/skill/melee/weapon/SpecialAttackMelee.kt index 9622b23c2b..f1a4f74243 100644 --- a/game/src/main/kotlin/content/skill/melee/weapon/SpecialAttackMelee.kt +++ b/game/src/main/kotlin/content/skill/melee/weapon/SpecialAttackMelee.kt @@ -8,13 +8,13 @@ import world.gregs.voidps.engine.entity.character.player.Players import world.gregs.voidps.engine.entity.character.player.skill.Skill import world.gregs.voidps.engine.map.spiral -fun multiTargets(target: Character, hits: Int): List { +fun multiTargets(source: Character, target: Character, hits: Int): List { val group = if (target is Player) Players else NPCs val targets = mutableListOf() for (tile in target.tile.spiral(1)) { val characters = group.at(tile) for (character in characters) { - if (character == target || !character.inMultiCombat) { + if (character == target || character == source || !character.inMultiCombat) { continue } targets.add(character) diff --git a/game/src/main/kotlin/content/skill/ranged/weapon/Chinchompa.kt b/game/src/main/kotlin/content/skill/ranged/weapon/Chinchompa.kt index aa7a7658cb..37d1219856 100644 --- a/game/src/main/kotlin/content/skill/ranged/weapon/Chinchompa.kt +++ b/game/src/main/kotlin/content/skill/ranged/weapon/Chinchompa.kt @@ -19,7 +19,7 @@ class Chinchompa : Script { combatAttack("range") { (target, damage, type, weapon, spell) -> if (weapon.id.endsWith("chinchompa") && target.inMultiCombat) { - val targets = multiTargets(target, if (target is Player) 9 else 11) + val targets = multiTargets(this, target, if (target is Player) 9 else 11) for (targ in targets) { targ.directHit(this, random.nextInt(0..damage), type, weapon, spell) }