Thread: Alchemical Hydra combat script

Page 1 of 2 12 LastLast
Results 1 to 10 of 17
  1. #1 Alchemical Hydra combat script 
    Silent project - coming soon


    Join Date
    Jan 2019
    Posts
    194
    Thanks given
    55
    Thanks received
    83
    Rep Power
    0
    Alchemical hydra script


    Code:
    /**
     * The Npc extension for the hydras.
     * 
     */
    class Hydra : Npc {
    
        /**
         * The amount of attacks left until it changes.
         */
        var recordedAttaacks: Int = 3
    
        /**
         * The hydra's current attack.
         */
        var currentAttack: HydraAttacks = HydraAttacks.MAGIC
    
        /**
         * The moment of the last hydra's poison pool attack.
         */
        var lastPoisonPool: Long = System.currentTimeMillis()
    
        constructor(id: Int, world: World?, tile: Tile?) : super(id, world, tile)
    
    
        override fun takeHit(hit: Hit?) {
            super.takeHit(hit)
    
            if (System.currentTimeMillis() - lastPoisonPool > 60000L) {
                lastPoisonPool = System.currentTimeMillis()
            }
        }
    }
    
    /**
     * The combat script for the hydra.
     */
    object HydraCombatScript {
    
        @JvmField
        val script: Function1<Script, Unit> = s@ @Suspendable {
            val npc = it.npc()
    
            if (npc !is Hydra) {
                return@s
            }
    
            var target = EntityCombat.getTarget(it) ?: return@s
    
            while (!npc.locked() && EntityCombat.targetOk(npc, target) && PlayerCombat.canAttack(npc, target)) {
                if (EntityCombat.canAttackDistant(npc, target, true, 5) && EntityCombat.attackTimerReady(npc)) {
    
                    if (System.currentTimeMillis() - npc.lastPoisonPool >= 30000L) {
                        sendPoisonAttack(npc, target)
                        npc.lastPoisonPool = System.currentTimeMillis()
                    } else {
                        regularAttack(npc, target)
                    }
                    target.putattrib(AttributeKey.LAST_DAMAGER, npc)
                    target.putattrib(AttributeKey.LAST_WAS_ATTACKED_TIME, System.currentTimeMillis())
                    npc.putattrib(AttributeKey.LAST_TARGET, target)
                    EntityCombat.putCombatDelay(npc, npc.combatInfo().attackspeed)
                }
    
                EntityCombat.postHitLogic(npc)
                it.delay(1)
                target = EntityCombat.refreshTarget(it) ?: return@s
    
            }
        }
    
        /**
         * Sends the hydra's ranged or magical attack.
         */
        @Suspendable
        fun regularAttack(hydra: Hydra, target: Entity) {
            hydra.world().executeScript @Suspendable {
                hydra.animate(hydraAttacks[Misc.random(hydraAttacks.size - 1)])
    
                hydra.recordedAttaacks--
    
                if (hydra.recordedAttaacks == 0) {
                    hydra.currentAttack = if (hydra.currentAttack == HydraAttacks.MAGIC) HydraAttacks.RANGED else HydraAttacks.MAGIC
                    hydra.recordedAttaacks = 3
                }
    
                sendProjectile(hydra, target, if (hydra.currentAttack == HydraAttacks.MAGIC) 1663 else 1662)
                it.delay(if (hydra.currentAttack == HydraAttacks.MAGIC) Misc.getMagicDelay(hydra.tile(), target.tile()) else Misc.getRangeDelay(hydra.tile(), target.tile()))
                target.hit(hydra, Misc.random(hydra.combatInfo().maxhit), 0, Hit.Type.REGULAR).combatStyle(if (hydra.currentAttack == HydraAttacks.MAGIC) CombatStyle.MAGIC else CombatStyle.RANGE)
            }
        }
    
        /**
         * Sends the poison pool attack.
         */
        @Suspendable
        fun sendPoisonAttack(hydra: Npc, target: Entity) {
            hydra.world().executeScript @Suspendable {
                val poolAmount = Misc.random(1, 2)
                val pools = ArrayList<Tile>()
                pools.add(target.tile())
                for (i in 1..poolAmount) {
                    pools.add(target.tile().transform(Misc.random(-3, 3), Misc.random(-3, 3), 0))
                }
                hydra.animate(hydraAttacks[Misc.random(hydraAttacks.size - 1)])
    
                for (pool in pools) {
                    fireProjectileToLocation(hydra, pool, 1644, 50, 90, 0, 5, 55, 0)
                }
    
                it.delay(3)
    
                for (pool in pools) {
                    hydra.world().tileGraphic(1645, pool, 0, 0)
                }
    
                it.delay(1)
    
    
                for (pool in pools) {
                    val graphicId = getPoolGraphic(hydra, pool)
                    hydra.world().tileGraphic(graphicId, pool, 0, 0)
                }
    
                for (i in 0..10) {
                    for (pool in pools) {
                        if (pool == target.tile()) {
                            target.hit(hydra, Misc.random(12), 0, Hit.Type.POISON)
                        }
                    }
                    it.delay(1)
                }
            }
        }
    
        /**
         * Fires a projectile from the hydra to a tile.
         */
        private fun fireProjectileToLocation(hydra: Npc, tile: Tile, projectile: Int, delay: Int, projectileSpeed: Int, angle: Int, stepness: Int, startHeight: Int, endHeight: Int) {
            val center = Misc.getCenterLocation(hydra)
            val dir = Direction.of(tile.x - center.x, tile.z - center.z)
            val from = center.transform(dir.x * 2, dir.y * 2)
            hydra.world().spawnProjectile(from, tile, projectile, startHeight, endHeight, delay, projectileSpeed, angle, stepness)
        }
    
        /**
         * Sends the projectile from the hydra to the target.
         */
        private fun sendProjectile(npc: Npc, target: Entity, projectile: Int) {
            val center = Misc.getCenterLocation(npc)
            val dir = Direction.of(target.tile().x - center.x, target.tile().z - center.z)
            val speed = Misc.getSpeedModifier(npc.tile(), target.tile())
            val from = center.transform(dir.x, dir.y)
            npc.world().spawnProjectile(from, target.tile(), projectile, 35, 30, 30, speed, 10, 10)
        }
    
    }
    
    /**
     * The hydra's attack animations.
     */
    private val hydraAttacks = arrayOf(8261, 8262, 8263)
    Code:
    /**
     * The alchemical hydra SCRIPT.
     * 
     */
    class AlchemicalHydra : Npc {
    
        /**
         * The amount of attacks left until it changes.
         */
        var recordedAttaacks: Int = 3
    
        /**
         * The hydra's current phase.
         */
        var currentPhase: HydraPhase = HydraPhase.GREEN
    
        /**
         * The hydra's current attack.
         */
        var currentAttack: HydraAttacks = HydraAttacks.MAGIC
    
        /**
         * The moment of the last hydra's fire wall attack.
         */
        var lastFirewall: Long = 0L
    
        /**
         * The moment of the last hydra's poison pool attack.
         */
        var lastPoisonPool: Long = 0L
    
        /**
         * The moment of the last hydra's lightning attack.
         */
        var lastLightning: Long = 0L
    
        /**
         * The hydra's instance base location
         */
        val baseLocation: Tile
    
        /**
         * If the hydra's shield is dropped.
         */
        var shieldDropped: Boolean = false
    
        /**
         * The delay for the vent to show up
         */
        var ventsDelay: Int = 15
    
        /**
         * The owner of this instanced hydra
         */
        var owner: Player
    
        /**
         * Constructor for the hydra.
         */
        constructor(world: World?, tile: Tile, owner: Player) : super(8615, world, tile) {
            putattrib(AttributeKey.MAX_DISTANCE_FROM_SPAWN, 30)
            respawns(false)
            baseLocation = tile.transform(-hydraSpawnLoc.x, -hydraSpawnLoc.z, 0)
            this.owner = owner
            animateVents(-1)
        }
    
        override fun cycle() {
            super.cycle()
    
            if (locked()) {
                return
            }
    
            ventsDelay--
    
            if(ventsDelay == 5) {
                animateVents(8279)
            }
    
            if (ventsDelay == 3 && !isEnraged() && !shieldDropped) {
                val baseTile = tile().transform(-baseLocation.x, -baseLocation.z)
                if (isWithinRedVent(baseTile, size())) {
                    if (currentPhase == HydraPhase.GREEN) {
                        sync().shout("Roaaaaaaaaaaar!")
                        shieldDropped = true
                    } else if (currentPhase == HydraPhase.RED) {
                        owner.message("The chemicals are absorbed by the Alchemical Hydra; empowering it further!")
                    }
                } else if (isWithinBlueVent(baseTile, size())) {
                    if (currentPhase == HydraPhase.RED) {
                        sync().shout("Roaaaaaaaaaaar!")
                        shieldDropped = true
                    } else if (currentPhase == HydraPhase.BLUE) {
                        owner.message("The chemicals are absorbed by the Alchemical Hydra; empowering it further!")
                    }
                } else if (isWithinGreenVent(baseTile, size())) {
                    if (currentPhase == HydraPhase.BLUE) {
                        sync().shout("Roaaaaaaaaaaar!")
                        shieldDropped = true
                    } else if (currentPhase == HydraPhase.GREEN) {
                        owner.message("The chemicals are absorbed by the Alchemical Hydra; empowering it further!")
                    }
                }
    
                if (shieldDropped) {
                    owner.message("The chemicals neutralise the Alchemical Hydra's defence!")
                }
            }
    
    
            if (ventsDelay == 0) {
                animateVents(8280)
                ventsDelay = 20
            }
    
            val healthAmount = hp() * 1.0 / (maxHp() * 1.0)
    
            if (healthAmount <= 0.75 && healthAmount > 0.50 && currentPhase === HydraPhase.GREEN) {
                changePhase()
            }
            if (healthAmount <= 0.50 && healthAmount > 0.25 && currentPhase === HydraPhase.BLUE) {
                changePhase()
            }
            if (healthAmount <= 0.25 && currentPhase === HydraPhase.RED) {
                changePhase()
            }
        }
    
        fun isEnraged(): Boolean {
            return currentPhase == HydraPhase.ENRAGED
        }
    
        /**
         * Returns the hydra's current attack anim based on its recorded attacks
         */
        fun getAttackAnim(): Int {
            return currentPhase.attackAnims[if (recordedAttaacks == 0) recordedAttaacks else recordedAttaacks - 1]
        }
    
        /**
         * Returns the hydra's next attack.
         */
        fun getNextAttack(): HydraAttacks {
            if (recordedAttaacks > 0) {
                return currentAttack
            }
            val possibleAttacks = ArrayList<HydraAttacks>()
    
            for (value in HydraAttacks.values()) {
                if (value.phaseRequired == null || value.phaseRequired == currentPhase) {
                    if (value == HydraAttacks.FIRE_WALL) {
                        if ((System.currentTimeMillis() - lastFirewall > fireWallDelay)) {
                            possibleAttacks.add(value)
                        }
                    } else if (value == HydraAttacks.POISON) {
                        if ((System.currentTimeMillis() - lastPoisonPool > poisonPoolDelay)) {
                            possibleAttacks.add(value)
                        }
                    } else if (value == HydraAttacks.LIGHTNING) {
                        if ((System.currentTimeMillis() - lastLightning > lightningDelay)) {
                            possibleAttacks.add(value)
                        }
                    } else {
                        possibleAttacks.add(value)
                    }
                }
            }
    
            recordedAttaacks = if (isEnraged()) 1 else 3
    
            var attack = possibleAttacks[Misc.random(possibleAttacks.size - 1)]
    
            if (attack == HydraAttacks.POISON) {
                lastPoisonPool = System.currentTimeMillis()
            } else if (attack == HydraAttacks.FIRE_WALL) {
                lastFirewall = System.currentTimeMillis()
            } else if (attack == HydraAttacks.LIGHTNING) {
                lastLightning = System.currentTimeMillis()
            } else if (attack == HydraAttacks.RANGED && currentAttack == HydraAttacks.RANGED) {
                attack = HydraAttacks.MAGIC
            } else if (attack == HydraAttacks.MAGIC && currentAttack == HydraAttacks.MAGIC) {
                attack = HydraAttacks.RANGED
            }
    
            return attack
        }
    
        /**
         * Changes the hydra's phase to the next phase
         */
        fun changePhase() {
            currentPhase.switchPhase(this)
            currentPhase = HydraPhase.values()[currentPhase.ordinal + 1]
    
            if (currentPhase == HydraPhase.RED) {
                lastFirewall = 10000L
            }
            shieldDropped = false
        }
    
        /**
         * Animates the vent within the instance area.
         */
        fun animateVents(animId: Int) {
            for (vent in vents) {
                val instanceVent = world().objById(vent.id(), baseLocation.transform(vent.tile()))
                owner.write(SetMapBase(owner, instanceVent.tile()))
                owner.write(AnimateObject(instanceVent, animId))
            }
        }
    }
    
    /**
     * The script for the hydra's attack.
     */
    object AlchemicalHydraAttackScript {
    
        @JvmField
        val script: Function1<Script, Unit> = s@ @Suspendable {
            val npc = it.npc()
            if (npc !is AlchemicalHydra) {
                return@s
            }
            var target = EntityCombat.getTarget(it) ?: return@s
    
            while (!npc.locked() && EntityCombat.targetOk(npc, target) && PlayerCombat.canAttack(npc, target)) {
                if (EntityCombat.canAttackDistant(npc, target, true, 5) && EntityCombat.attackTimerReady(npc)) {
    
                    npc.recordedAttaacks--
    
                    var nextAttackType = npc.getNextAttack()
    
                    if (nextAttackType == HydraAttacks.RANGED || nextAttackType == HydraAttacks.MAGIC) {
                        npc.currentAttack = nextAttackType
                    }
    
                    nextAttackType.executeAttack(npc, target as Player)
    
                    EntityCombat.putCombatDelay(npc, 5)
                }
    
                EntityCombat.postHitLogic(npc)
                it.delay(1)
                target = EntityCombat.refreshTarget(it) ?: return@s
    
            }
        }
    
    }
    Code:
    [/**
     * The attacks that the hydra can perform.
     *
     */
    enum class HydraAttacks(val phaseRequired: HydraPhase?) {
    
        /**
         * The default magical attack.
         */
        MAGIC(null) {
            @Suspendable
            override fun executeAttack(hydra: AlchemicalHydra, target: Entity) {
                hydra.world().executeScript @Suspendable {
                    hydra.animate(hydra.getAttackAnim())
                    fireProjectileToEntity(hydra, target, 1663, 50)
                    it.delay(Misc.getMagicDelay(hydra.tile(), target.tile()))
                    target.hit(hydra, hydra.world().random(if (hydra.isEnraged()) 26 else 17), 0).combatStyle(CombatStyle.MAGIC)
                }
            }
        },
    
        /**
         * The default ranged attack.
         */
        RANGED(null) {
            @Suspendable
            override fun executeAttack(hydra: AlchemicalHydra, target: Entity) {
                hydra.world().executeScript @Suspendable {
                    hydra.animate(hydra.getAttackAnim())
                    fireProjectileToEntity(hydra, target, 1662, 50)
                    fireProjectileToEntity(hydra, target, 1662, 60)
                    it.delay(Misc.getRangeDelay(hydra.tile(), target.tile()))
                    target.hit(hydra, hydra.world().random(if (hydra.isEnraged()) 26 else 17), 0).combatStyle(CombatStyle.RANGE)
                }
            }
        },
    
        /**
         * The poison pool for the first phase.
         */
        POISON(HydraPhase.GREEN) {
            @Suspendable
            override fun executeAttack(hydra: AlchemicalHydra, target: Entity) {
                hydra.world().executeScript @Suspendable {
                    val poolAmount = Misc.random(4, 5)
                    val pools = getPoolTiles(hydra.baseLocation, target.tile(), poolAmount)
                    hydra.animate(HydraPhase.GREEN.attackAnims[Misc.random(HydraPhase.GREEN.attackAnims.size - 1)])
    
                    for (pool in pools) {
                        fireProjectileToLocation(hydra, pool, 1644, 50, 90, 0, 5, 55, 0)
                    }
    
                    it.delay(3)
    
                    for (pool in pools) {
                        hydra.world().tileGraphic(1645, pool, 0, 0)
                    }
    
                    it.delay(1)
    
    
                    for (pool in pools) {
                        val graphicId = getPoolGraphic(hydra, pool)
                        hydra.world().tileGraphic(graphicId, pool, 0, 0)
                    }
    
                    for (i in 0..10) {
                        for (pool in pools) {
                            if (pool == target.tile()) {
                                target.hit(hydra, Misc.random(12), 0, Hit.Type.POISON)
                            }
                        }
                        it.delay(1)
                    }
                }
            }
        },
    
        /**
         * The lightning strike for the second phase.
         */
        LIGHTNING(HydraPhase.BLUE) {
            @Suspendable
            override fun executeAttack(hydra: AlchemicalHydra, target: Entity) {
                hydra.world().executeScript @Suspendable {
                    hydra.animate(HydraPhase.BLUE.attackAnims[Misc.random(HydraPhase.BLUE.attackAnims.size - 1)])
    
                    val base = hydra.baseLocation
                    val central = base.transform(centralLightningSpot)
                    var spots = ArrayList<Tile>(lightningSpots)
    
                    fireProjectileToLocation(hydra, central, 1664, 50, 80, 0, 0, 0, 0)
    
                    it.delay(2)
    
                    hydra.world().tileGraphic(1664, central, 0, 0)
    
                    it.delay(1)
    
                    for (spot in spots) {
                        fireProjectileToLocation(hydra.world(), central, base.transform(spot), 1665, 0, 40, 0, 5, 55, 0)
                    }
    
                    it.delay(1)
    
                    for (i in 0..10) {
                        for (spot in spots) {
                            hydra.world().tileGraphic(1666, base.transform(spot), 0, 0)
                        }
                        val newSpots = ArrayList<Tile>()
                        for (spot in ArrayList<Tile>(spots)) {
                            if (base.transform(spot) == target.tile()) {
                                target.hit(hydra, Misc.random(20), 0, Hit.Type.REGULAR)
                                if (target is Player) {
                                    target.message("<col=ff0000>The electricity temporarily paralyzes you!")
                                    target.stun(8, false, false)
                                }
                            } else {
                                val newSpot = getMoveLocation(base, spot, target.tile())
                                newSpots.add(newSpot)
                            }
                        }
                        spots = newSpots
                        it.delay(1)
                    }
                }
            }
        },
    
        /**
         * The wall of fire for the third phase.
         */
        FIRE_WALL(HydraPhase.RED) {
            @Suspendable
            override fun executeAttack(hydra: AlchemicalHydra, target: Entity) {
                hydra.world().executeScript @Suspendable {
                    hydra.lockNoAttack()
    
                    hydra.face(null)
    
                    val base = hydra.baseLocation
                    hydra.walkTo(base.transform(hydraSpawnLoc), PathQueue.StepType.FORCED_WALK)
    
                    it.delay(1)
    
                    while (hydra.tile() != base.transform(hydraSpawnLoc)) {
                        it.delay(1)
                    }
    
                    it.delay(1)
    
                    val fireWallSpots = getWallFireSpots(target.tile(), base)
                    val spotOffsets = fireWallSpots.spots
                    val spots = ArrayList<Tile>()
    
                    for (i in 0..1) {
                        val faceSpot = base.transform((spotOffsets[i * 2].x + spotOffsets[i * 2 + 1].x) / 2, (spotOffsets[i * 2].z + spotOffsets[i * 2 + 1].z) / 2)
                        hydra.faceTile(faceSpot)
                        hydra.animate(hydra.getAttackAnim())
    
                        for (spot in fireWallSpots.projectileSpots) {
                            for (x in fireWallSpots.projectileSpots[i * 2].x..fireWallSpots.projectileSpots[i * 2 + 1].x) {
                                for (z in fireWallSpots.projectileSpots[i * 2].z..fireWallSpots.projectileSpots[i * 2 + 1].z) {
                                    fireProjectileToLocation(hydra, base.transform(Tile(x, z, 0)), 1667, 45, 55, 15, 15, 55, 0)
                                }
                            }
                        }
    
                        it.delay(1)
    
                        for (spot in spots) {
                            if (target.tile() == spot) {
                                target.hit(hydra, Misc.random(20), 0, Hit.Type.REGULAR)
                            }
                        }
    
                        it.delay(1)
    
                        for (spot in spots) {
                            if (target.tile() == spot) {
                                target.hit(hydra, Misc.random(20), 0, Hit.Type.REGULAR)
                            }
                        }
    
                        fireWallSpots.spawnFireWall(hydra, base, i, spots)
    
                        it.delay(1)
    
                        for (spot in spots) {
                            if (target.tile() == spot) {
                                target.hit(hydra, Misc.random(20), 0, Hit.Type.REGULAR)
                            }
                        }
                    }
    
                    it.delay(1)
    
                    for (spot in spots) {
                        if (target.tile() == spot) {
                            target.hit(hydra, Misc.random(20), 0, Hit.Type.REGULAR)
                        }
                    }
    
                    hydra.face(target)
    
                    var startMovingFire = Tile(Misc.random(spotOffsets[0].x, spotOffsets[1].x), Misc.random(spotOffsets[0].z, spotOffsets[1].z), 0)
    
                    hydra.animate(hydra.getAttackAnim())
                    fireProjectileToLocation(hydra, base.transform(startMovingFire), 1667, 45, 50, 0, 5, 55, 0)
    
                    it.delay(1)
    
                    for (spot in spots) {
                        if (target.tile() == spot) {
                            target.hit(hydra, Misc.random(20), 0, Hit.Type.REGULAR)
                        }
                    }
    
                    it.delay(1)
    
                    spots.add(base.transform(startMovingFire))
    
                    for (i in 0..fireWallDuration) {
                        for (spot in spots) {
                            if (target.tile() == spot) {
                                target.hit(hydra, Misc.random(20), 0, Hit.Type.REGULAR)
                            }
                        }
                        if (i < 16) {
                            if (base.transform(startMovingFire) == target.tile()) {
                                target.hit(hydra, Misc.random(20), 0, Hit.Type.REGULAR)
                            } else {
                                startMovingFire = getMoveLocation(base, startMovingFire, target.tile())
                                spots.add(startMovingFire)
                                hydra.world().tileGraphic(1668, base.transform(startMovingFire), 0, 0)
                            }
                        } else if (i == 16) {
                            hydra.unlock()
                        }
                        it.delay(1)
                    }
                }
            }
        },
    
        /**
         * The poison pool for the final and enraged version.
         */
        ENRAGED_POISON(HydraPhase.ENRAGED) {
            @Suspendable
            override fun executeAttack(hydra: AlchemicalHydra, target: Entity) {
                hydra.world().executeScript @Suspendable {
                    val poolAmount = if (Misc.randomFloat() < 0.6) 1 else Misc.random(4, 5)
                    val pools = getPoolTiles(hydra.baseLocation, target.tile(), poolAmount)
                    hydra.animate(HydraPhase.ENRAGED.attackAnims[Misc.random(HydraPhase.ENRAGED.attackAnims.size - 1)])
    
                    for (pool in pools) {
                        fireProjectileToLocation(hydra, pool, 1644, 50, 90, 0, 5, 55, 0)
                    }
    
                    it.delay(3)
    
                    for (pool in pools) {
                        hydra.world().tileGraphic(1645, pool, 0, 0)
                    }
    
                    it.delay(1)
    
    
                    for (pool in pools) {
                        val graphicId = getPoolGraphic(hydra, pool)
                        hydra.world().tileGraphic(graphicId, pool, 0, 0)
                    }
    
                    for (i in 0..10) {
                        for (pool in pools) {
                            if (pool == target.tile()) {
                                target.hit(hydra, Misc.random(12), 0, Hit.Type.POISON)
                            }
                        }
                        it.delay(1)
                    }
                }
            }
        },
    
        ;
    
        /**
         * Executes the hydra's attack.
         */
        @Suspendable
        abstract fun executeAttack(hydra: AlchemicalHydra, target: Entity)
    
        /**
         * Fires a projectile from the hydra to the target.
         */
        internal fun fireProjectileToEntity(hydra: AlchemicalHydra, target: Entity, projectile: Int, delay: Int) {
            val center = Misc.getCenterLocation(hydra)
            val dir = Direction.of(target.tile().x - center.x, target.tile().z - center.z)
            val from = center.transform(dir.x * 2, dir.y * 2)
            val speed = Misc.getSpeedModifier(from, target.tile())
            hydra.world().spawnProjectile(from, target, projectile, 55, 25, delay, speed, 15, 15)
        }
    
        /**
         * Fires a projectile from the hydra to a tile.
         */
        internal fun fireProjectileToLocation(hydra: AlchemicalHydra, tile: Tile, projectile: Int, delay: Int, projectileSpeed: Int, angle: Int, stepness: Int, startHeight: Int, endHeight: Int) {
            val center = Misc.getCenterLocation(hydra)
            val dir = Direction.of(tile.x - center.x, tile.z - center.z)
            val from = center.transform(dir.x * 2, dir.y * 2)
            hydra.world().spawnProjectile(from, tile, projectile, startHeight, endHeight, delay, projectileSpeed, angle, stepness)
        }
    
        /**
         * Fires a projectile from a tile to another.
         */
        internal fun fireProjectileToLocation(world: World, from: Tile, to: Tile, projectile: Int, delay: Int, projectileSpeed: Int, angle: Int, stepness: Int, startHeight: Int, endHeight: Int) {
            world.spawnProjectile(from, to, projectile, startHeight, endHeight, delay, projectileSpeed, angle, stepness)
        }
    }
    Code:
    /**
     * The alchemical hydra SCRIPT.
     *  
     */
    
    /**
     * The delay between the fire wall attacks.
     */
    val fireWallDelay = 45000L
    
    /**
     * The delay between the poison pool attacks.
     */
    val poisonPoolDelay = 15000L
    
    /**
     * The delay between the lightning attacks.
     */
    val lightningDelay = 25000L
    
    /**
     * The duration for the fire wall effect.
     */
    val fireWallDuration = 43
    
    /**
     * The base location for the instances.
     */
    val baseLocation = Tile(1328, 10248, 0)
    
    /**
     * The hydra's spawn location.
     */
    val hydraSpawnLoc = Tile(36, 17, 0)
    
    /**
     * The blue vent central spot.
     */
    val blueVentLoc = Tile(34, 24, 0)
    
    /**
     * The green vent central spot.
     */
    val greenVentLoc = Tile(43, 24, 0)
    
    /**
     * The red vent central spot.
     */
    val redVentLoc = Tile(43, 15, 0)
    
    /**
     * The blue vent object.
     */
    val blueVent = MapObj(blueVentLoc, 34570, 10, 0, false)
    
    /**
     * The red vent object.
     */
    val redVent = MapObj(redVentLoc, 34568, 10, 0, false)
    
    /**
     * The green vent object.
     */
    val greenVent = MapObj(greenVentLoc, 34569, 10, 0, false)
    
    /**
     * The list of vents.
     */
    val vents = arrayListOf(blueVent, redVent, greenVent)
    
    /**
     * The spot the hydra will send the first projectile for lightning.
     */
    val centralLightningSpot = Tile(39, 14, 0)
    
    /**
     * The forbidden spots for the attacks.
     */
    val forbiddenSpots = arrayListOf(blueVentLoc, greenVentLoc, redVentLoc, Tile(48, 29, 0), Tile(49, 30, 0), Tile(49, 29, 0), Tile(49, 30, 0), Tile(28, 29, 0), Tile(28, 30, 0), Tile(29, 29, 0), Tile(29, 30, 0), Tile(48, 9, 0), Tile(49, 9, 0), Tile(48, 10, 0), Tile(49, 10, 0))
    
    /**
     * The spots the lightning spawns
     */
    val lightningSpots = arrayListOf(Tile(44, 15, 0), Tile(34, 15, 0), Tile(44, 24, 0), Tile(33, 24, 0))
    
    /**
     * Returns if the location is within the instance's chamber.
     */
    fun isWithinChamber(baseLocation: Tile, location: Tile): Boolean {
        val xOffset = location.x - baseLocation.x
        val zOffset = location.z - baseLocation.z
        return xOffset in 28..49 && zOffset in 9..30 && !isForbiddenSpot(Tile(xOffset, zOffset, location.level))
    }
    
    /**
     * Returns if the tile is a forbidden one.
     */
    fun isForbiddenSpot(tile: Tile): Boolean {
        for (forbiddenSpot in forbiddenSpots) {
            if (forbiddenSpot == tile) {
                return true
            }
        }
        return false
    }
    
    /**
     * Returns if the tile is within the blue vent.
     */
    fun isWithinBlueVent(tile: Tile, size: Int): Boolean {
        return Misc.isWithinDiagonalDistance(tile, blueVentLoc, size, 1, 0)
    }
    
    /**
     * Returns if the tile is within the gree vent.
     */
    fun isWithinGreenVent(tile: Tile, size: Int): Boolean {
        return Misc.isWithinDiagonalDistance(tile, greenVentLoc, size, 1, 0)
    }
    
    /**
     * Returns if the tile is within the red vent.
     */
    fun isWithinRedVent(tile: Tile, size: Int): Boolean {
        return Misc.isWithinDiagonalDistance(tile, redVentLoc, size, 1, 0)
    }
    
    /**
     * Returns the pool graphic for the poison pool attack.
     */
    fun getPoolGraphic(hydra: Npc, targetTile: Tile): Int {
        val center = Misc.getCenterLocation(hydra)
        val dir = Direction.of(targetTile.x - center.x, targetTile.z - center.z)
        for (pool in PoisonPools.values()) {
            if (pool.offsetX == dir.x && pool.offsetZ == dir.y) {
                return pool.graphicId
            }
        }
        return 1654
    }
    
    /**
     * Returns the list of pool tiles.
     */
    fun getPoolTiles(baseLocation: Tile, tile: Tile, poolAmount: Int): ArrayList<Tile> {
        val pools = ArrayList<Tile>()
        for (i in 0..poolAmount) {
            var randTile: Tile
            for (x in 0..100) {
                randTile = tile.transform(Misc.random(-3, 3), Misc.random(-3, 3), 0)
                var matches = false
                for (pool in pools) {
                    if (pool == randTile) {
                        matches = true
                        break
                    }
                }
                if (!matches && isWithinChamber(baseLocation, tile)) {
                    pools.add(randTile)
                    break
                }
            }
        }
        return pools
    }
    
    /**
     * Returns the location the tile has to move to reach the target.
     */
    fun getMoveLocation(baseLocation: Tile, currentLoc: Tile, target: Tile): Tile {
        val dir = Direction.of(target.x - (baseLocation.x + currentLoc.x), target.z - (baseLocation.z + currentLoc.z))
        return currentLoc.transform(dir.x, dir.y, 0)
    }
    
    /**
     * The poison pools graphics based on the position offset.
     * 
     */
    enum class PoisonPools(val offsetX: Int, val offsetZ: Int, val graphicId: Int) {
    
        NORTH(0, 1, 1659),
    
        NORTH_EAST(1, 1, 1660),
    
        EAST(1, 0, 1661),
    
        SOUTH_EAST(1, -1, 1654),
    
        SOUTH(0, -1, 1655),
    
        SOUTH_WEST(-1, -1, 1656),
    
        WEST(-1, 0, 1657),
    
        NORTH_WEST(-1, 1, 1658);
    
    }
    
    /**
     * The fire wall spots.
     * 
     */
    enum class FireWallSpots(val requiredArea: Area, val projectileSpots: ArrayList<Tile>, val spots: ArrayList<Tile>) {
    
        SOUTH_WEST(Area(28, 9, 38, 19), arrayListOf(Tile(35, 18, 0), Tile(35, 21, 0), Tile(37, 16, 0), Tile(40, 16, 0)), arrayListOf(Tile(28, 18, 0), Tile(35, 21, 0), Tile(37, 9, 0), Tile(40, 16, 0))),
    
        NORTH_WEST(Area(28, 20, 38, 30), arrayListOf(Tile(35, 18, 0), Tile(35, 21, 0), Tile(37, 23, 0), Tile(40, 23, 0)), arrayListOf(Tile(28, 18, 0), Tile(35, 21, 0), Tile(37, 23, 0), Tile(40, 30, 0))),
    
        NORTH_EAST(Area(39, 20, 49, 30), arrayListOf(Tile(42, 18, 0), Tile(42, 21, 0), Tile(37, 23, 0), Tile(40, 23, 0)), arrayListOf(Tile(42, 18, 0), Tile(49, 21, 0), Tile(37, 23, 0), Tile(40, 30, 0))),
    
        SOUTH_EAST(Area(39, 9, 49, 20), arrayListOf(Tile(42, 18, 0), Tile(42, 21, 0), Tile(37, 16, 0), Tile(40, 16, 0)), arrayListOf(Tile(42, 18, 0), Tile(49, 21, 0), Tile(37, 9, 0), Tile(40, 16, 0)));
    
        /**
         * Spawns the fire wall based on the fire wall spot.
         */
        fun spawnFireWall(hydra: AlchemicalHydra, base: Tile, index: Int, spots: ArrayList<Tile>) {
            when (this) {
                SOUTH_WEST -> {
                    spawnWall(hydra, base, index, if (index == 0) Direction.West else Direction.South, spots)
                }
                NORTH_WEST -> {
                    spawnWall(hydra, base, index, if (index == 0) Direction.West else Direction.North, spots)
                }
                NORTH_EAST -> {
                    spawnWall(hydra, base, index, if (index == 0) Direction.East else Direction.North, spots)
                }
                SOUTH_EAST -> {
                    spawnWall(hydra, base, index, if (index == 0) Direction.East else Direction.South, spots)
                }
            }
        }
    
        /**
         * Spawns the wall based on the direction and the spots.
         */
        private fun spawnWall(hydra: AlchemicalHydra, base: Tile, index: Int, direction: Direction, hydraSpots: ArrayList<Tile>) {
            var delay = 0
            when (direction) {
                Direction.South -> {
                    for (z in spots[index * 2 + 1].z downTo spots[index * 2].z) {
                        for (x in spots[index * 2].x..spots[index * 2 + 1].x) {
                            val tile = Tile(base.transform(x, z, 0))
                            spawn(hydra, tile, delay, hydraSpots)
                        }
                        delay += 10
                    }
                }
                Direction.North -> {
                    for (z in spots[index * 2].z..spots[index * 2 + 1].z) {
                        for (x in spots[index * 2].x..spots[index * 2 + 1].x) {
                            val tile = Tile(base.transform(x, z, 0))
                            spawn(hydra, tile, delay, hydraSpots)
                        }
                        delay += 10
                    }
                }
                Direction.East -> {
                    for (x in spots[index * 2].x..spots[index * 2 + 1].x) {
                        for (z in spots[index * 2].z..spots[index * 2 + 1].z) {
                            val tile = Tile(base.transform(x, z, 0))
                            spawn(hydra, tile, delay, hydraSpots)
                        }
                        delay += 10
                    }
                }
                Direction.West -> {
                    for (x in spots[index * 2 + 1].x downTo spots[index * 2].x) {
                        for (z in spots[index * 2].z..spots[index * 2 + 1].z) {
                            val tile = Tile(base.transform(x, z, 0))
                            spawn(hydra, tile, delay, hydraSpots)
                        }
                        delay += 10
                    }
                }
            }
        }
    
        /**
         * Spawns the graphics.
         */
        private fun spawn(hydra: AlchemicalHydra, tile: Tile, delay: Int, spots: ArrayList<Tile>) {
            hydra.world().tileGraphic(1668, tile, 0, delay)
            spots.add(tile)
        }
    
    }
    
    /**
     * Returns the spots where the fire wall will be sent.
     */
    fun getWallFireSpots(playerLoc: Tile, base: Tile): FireWallSpots {
        for (value in FireWallSpots.values()) {
            if (value.requiredArea.contains(playerLoc.transform(-base.x, -base.z))) {
                return value
            }
        }
        return FireWallSpots.SOUTH_WEST
    }
    Code:
    /**
     * The hydra phases.
     * 
     */
    enum class HydraPhase {
    
    
        /**
         * The first phase with poison special.
         */
        GREEN(8616, 8615, 8237, arrayOf(8234, 8235, 8236)) {
    
            @Suspendable
            override fun switchPhase(hydra: AlchemicalHydra) {
                hydra.world().executeScript @Suspendable {
                    hydra.lock()
                    hydra.sync().transmog(phaseSwitchID)
                    hydra.animate(phaseSwitchAnimID)
                    it.delay(3)
                    hydra.animate(phaseSwitchAnimID + 1)
                    hydra.sync().transmog(BLUE.phaseID)
                    it.delay(2)
                    hydra.unlock()
                }
            }
        },
    
        /**
         * The second phase with lightning special.
         */
        BLUE(8617, 8619, 8244, arrayOf(8241, 8242, 8243)) {
            @Suspendable
            override fun switchPhase(hydra: AlchemicalHydra) {
                hydra.world().executeScript @Suspendable {
                    hydra.lock()
                    hydra.sync().transmog(phaseSwitchID)
                    hydra.animate(phaseSwitchAnimID)
                    it.delay(2)
                    hydra.animate(phaseSwitchAnimID + 1)
                    hydra.sync().transmog(RED.phaseID)
                    it.delay(2)
                    hydra.unlock()
                }
            }
        },
    
        /**
         * The third phase with fire special.
         */
        RED(8618, 8620, 8251, arrayOf(8248, 8249, 8250)) {
            @Suspendable
            override fun switchPhase(hydra: AlchemicalHydra) {
                hydra.world().executeScript @Suspendable {
                    hydra.lock()
                    hydra.sync().transmog(phaseSwitchID)
                    hydra.animate(phaseSwitchAnimID)
                    it.delay(3)
                    hydra.animate(phaseSwitchAnimID + 1)
                    hydra.sync().transmog(ENRAGED.phaseID)
                    it.delay(2)
                    hydra.unlock()
                }
            }
        },
    
        /**
         * The final phase, stronger and with poison special
         */
        ENRAGED(8622, 8621, 8262, arrayOf(8255, 8256)) {
            @Suspendable
            override fun switchPhase(hydra: AlchemicalHydra) {
            }
        },
    
        ;
    
        /**
         * The NPC ID for the phase switching moment.
         */
        val phaseSwitchID: Int
    
        /**
         * The NPC ID for the phase already switched.
         */
        val phaseID: Int
    
        /**
         * The animation of switching phases.
         */
        val phaseSwitchAnimID: Int
    
        /**
         * The attack anims for range and magic for this phase.
         */
        val attackAnims: Array<Int>
    
        /**
         * Constructor for the phase.
         */
        constructor(phaseSwitchID: Int, phaseID: Int, phaseSwitchAnimID: Int, attackAnims: Array<Int>) {
            this.phaseSwitchID = phaseSwitchID
            this.phaseID = phaseID
            this.phaseSwitchAnimID = phaseSwitchAnimID
            this.attackAnims = attackAnims
        }
    
        /**
         * Called upon phase switch.
         */
        @Suspendable
        abstract fun switchPhase(hydra: AlchemicalHydra)
    }
    Last edited by C.T.; 09-01-2019 at 03:30 PM.
    Reply With Quote  
     

  2. Thankful users:


  3. #2  
    Super Donator

    StanDev's Avatar
    Join Date
    Apr 2014
    Posts
    660
    Thanks given
    82
    Thanks received
    255
    Rep Power
    592
    Thanks for the contribution
    Reply With Quote  
     

  4. #3  
    Throne Scape - Founder/Developer
    Mokhtar's Avatar
    Join Date
    Mar 2018
    Posts
    803
    Thanks given
    43
    Thanks received
    171
    Rep Power
    299
    Thank you
    Reply With Quote  
     

  5. #4  
    Banned

    Join Date
    Mar 2015
    Age
    31
    Posts
    1,332
    Thanks given
    215
    Thanks received
    329
    Rep Power
    0
    thanks
    Reply With Quote  
     

  6. #5  
    Banned

    Join Date
    Jun 2019
    Posts
    203
    Thanks given
    99
    Thanks received
    44
    Rep Power
    0
    Thanks but this is way to overdocumented.
    Reply With Quote  
     

  7. #6  
    Developer of SerenPS
    combatx's Avatar
    Join Date
    Mar 2013
    Posts
    118
    Thanks given
    6
    Thanks received
    10
    Rep Power
    0
    Thank you for this! keep up the good work!
    Attached image
    Reply With Quote  
     

  8. #7  
    Respected Member


    Kris's Avatar
    Join Date
    Jun 2016
    Age
    26
    Posts
    3,638
    Thanks given
    820
    Thanks received
    2,642
    Rep Power
    5000
    Quote Originally Posted by Zerikoth View Post
    Thanks but this is way to overdocumented.
    No it's not. That's about appropriate amount of documentation for something of this size. I would personally document it similarly.
    Attached image
    Reply With Quote  
     


  9. #8  
    Banned

    Join Date
    Jun 2019
    Posts
    203
    Thanks given
    99
    Thanks received
    44
    Rep Power
    0
    Quote Originally Posted by Kris View Post
    No it's not. That's about appropriate amount of documentation for something of this size. I would personally document it similarly.
    Bro, he documented every single line. The params method names variables etc already tell what they do. There is no point in commenting every single line.
    I did some googling but couldn't find anything regarding documenting. Or it's my bad search or there is no such thing. But however, I still stand to my point its more like a personal preference then. I rather not document every single line and rather use variables that make sense.
    Reply With Quote  
     

  10. #9  
    Registered Member
    Join Date
    Dec 2011
    Posts
    706
    Thanks given
    9
    Thanks received
    3
    Rep Power
    30
    Is this Kotlin?
    Reply With Quote  
     

  11. #10  
    Respected Member


    George's Avatar
    Join Date
    Mar 2009
    Posts
    7,099
    Thanks given
    2,226
    Thanks received
    3,146
    Rep Power
    5000
    Quote Originally Posted by Zerikoth View Post
    Bro, he documented every single line. The params method names variables etc already tell what they do. There is no point in commenting every single line.
    I did some googling but couldn't find anything regarding documenting. Or it's my bad search or there is no such thing. But however, I still stand to my point its more like a personal preference then. I rather not document every single line and rather use variables that make sense.
    How do u expect another developer to work efficiently on ur ass code if u don’t actually properly document ur code?

    Also, its nice to be able to actually read through ur own code, knowing the purpose of all the functions, unless u memorize the exact purpose of every function / method in ur server/client.
    Attached image

    Spoiler for Spoilers!:
    Attached image
    Attached image
    Attached image
    Attached image
    Reply With Quote  
     


Page 1 of 2 12 LastLast

Thread Information
Users Browsing this Thread

There are currently 1 users browsing this thread. (0 members and 1 guests)


User Tag List

Similar Threads

  1. Combat scripts
    By k0ed ur mom in forum Help
    Replies: 10
    Last Post: 07-02-2013, 03:51 AM
  2. 718+ buying a nice combat script coder
    By unrealscape in forum Buying
    Replies: 0
    Last Post: 06-22-2013, 12:09 PM
  3. Frost Dragon Combat Script
    By Bart in forum Snippets
    Replies: 26
    Last Post: 11-15-2012, 03:35 AM
  4. Basic Combat Script
    By Logical in forum Website Development
    Replies: 8
    Last Post: 08-20-2009, 07:01 PM
  5. [REQ] Combat Scripts!!!!
    By Gromit in forum RuneScape Underground
    Replies: 1
    Last Post: 03-16-2009, 06:03 AM
Posting Permissions
  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •