Skip to content

Commit

Permalink
Shooting Star Distractions and Diversion (#458)
Browse files Browse the repository at this point in the history
* Add Crashed star objects to objects.yml

* Add xp value & mining chance to stardust in item.yml

* Add various locations for Crashed Stars in StarLocationData class

* Add star_sprite to npcs yml.

* Add examine text to crashed_star objects in objects yml.

* Add Prospecting crashed stars that will display progress to the next layer.

* Add rewards when the star is completed, converting stardust to coins, astral runes, cosmic runes and gold ore. inline with runescape

* Add dialog to star sprite after star completion

* Add check to mining to make sure that a player doesn't exceed 200 stardust in inventory and bank (a player will still gain experience)

* Add shooting_star_shadow to npcs yml

* Change some star `collect_for_next_layer` values, forgot to change them from testing

* Add Star shadow moving to crashing tile before star spawning (missing crashing animation)

* Add check to `mining.kts` if the player is the first to mine the star they will be granted `(miningLevel * 75)` inline with runescape.

* Add Fall in star object to `objects.yml`

* Add replacing falling star object with crashed star object

* Add player animation when moved due to being under a crashing star

* Change code formatting Intelij plugin formats code that doesn't follow Voids code format

* Add "step_back_startled" animation to `animation.yml`

* Add various sounds for `Star Falling`, `Star despawning`, `Star changing tier`, `Star Sprite spawning`

* Fix force movement

---------

Co-authored-by: GregHib <[email protected]>
  • Loading branch information
Syntax2022 and GregHib authored Feb 28, 2024
1 parent 8e9d403 commit 074840b
Show file tree
Hide file tree
Showing 11 changed files with 383 additions and 19 deletions.
2 changes: 2 additions & 0 deletions data/definitions/animations.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1370,6 +1370,8 @@ ice_cleave: 7070
sweep: 1203
powerstab: 7078
shove: 1064
fall_back_on_butt: 4172
step_back_startled: 4835
quick_smash: 1667
clobber: 2876
disrupt: 14788
Expand Down
3 changes: 3 additions & 0 deletions data/definitions/items.yml
Original file line number Diff line number Diff line change
Expand Up @@ -58302,6 +58302,9 @@ elemental_spell:
stardust:
id: 13727
tradeable: false
mining:
xp: 80.0
chance: 10-75
destroy: "You can mine more if you find another crashed star."
examine: "Small, shiny bits of rock."
kept: "Wilderness"
Expand Down
6 changes: 6 additions & 0 deletions data/definitions/npcs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,12 @@ cook_lumbridge:
race: human
wander_radius: 4
examine: "Lumbridge Castle's head cook."
star_sprite:
id: 8091
examine: "A shiny, happy star sprite."
shooting_star_shadow:
id: 8092
examine: "The shadow of a shooting star"
doric:
id: 284
race: dwarf
Expand Down
76 changes: 76 additions & 0 deletions data/definitions/objects.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3969,8 +3969,84 @@ fire_green:
fire_blue:
id: 11406
examine: "Hot!"
crashed_star_falling_object:
id: 38659
examine: "It's a crashed star."
crashed_star_tier_9:
id: 38660
collect_for_next_layer: 15
mining:
level: 90
ores: [ stardust ]
gems: true
examine: "This is a size-9 star."
crashed_star_tier_8:
id: 38661
collect_for_next_layer: 40
mining:
level: 80
ores: [ stardust ]
gems: true
examine: "This is a size-8 star."
crashed_star_tier_7:
id: 38662
collect_for_next_layer: 40
mining:
level: 70
ores: [ stardust ]
gems: true
examine: "This is a size-7 star."
crashed_star_tier_6:
id: 38663
collect_for_next_layer: 80
mining:
level: 60
ores: [ stardust ]
gems: true
examine: "This is a size-6 star."
crashed_star_tier_5:
id: 38664
collect_for_next_layer: 175
mining:
level: 50
ores: [ stardust ]
gems: true
examine: "This is a size-5 star."
crashed_star_tier_4:
id: 38665
collect_for_next_layer: 250
mining:
level: 40
ores: [ stardust ]
gems: true
examine: "This is a size-4 star."
crashed_star_tier_3:
id: 38666
collect_for_next_layer: 450
mining:
level: 30
ores: [ stardust ]
gems: true
examine: "This is a size-3 star."
crashed_star_tier_2:
id: 38667
collect_for_next_layer: 700
mining:
level: 20
ores: [ stardust ]
gems: true
examine: "This is a size-2 star."
crashed_star_tier_1:
id: 38668
collect_for_next_layer: 1200
mining:
level: 10
ores: [ stardust ]
gems: true
examine: "This is a size-1 star."
evil_tree:
id: 11434
upgrade_time: 50
examine: "This looks like a challenge anyone can deal with."
evil_tree_stump:
id: 11435
Expand Down
11 changes: 11 additions & 0 deletions data/definitions/sounds.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,17 @@ chest_open: 52
casket_open: 50
cupboard_close: 57
cupboard_open: 58
star_meteor_falling: 5206
star_meteor_landing: 5188
star_meteor_change: 5189
star_sprite_shake: 5193
star_sprite_appear: 5195
star_sprite_twinkle: 5197
star_sprite_yawn: 5200
star_sprite_wipe: 5201
star_sprite_yawn_end1: 5202
star_sprite_blink: 5205
star_meteor_despawn: 5207
destroy_object: 2381
coffin_open: 54
demon_slayer_crystal_ball_anim: 2971
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ class WalkHandler : InstructionHandler<Walk>() {

override fun validate(player: Player, instruction: Walk) {
if (player.hasClock("delay") || player.hasClock("input_delay")) {
println("Ignored")
return
}
player.closeInterfaces()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import world.gregs.voidps.engine.entity.character.move.tele
import world.gregs.voidps.engine.entity.character.npc.NPC
import world.gregs.voidps.engine.entity.character.player.Player
import world.gregs.voidps.engine.entity.character.player.appearance
import world.gregs.voidps.engine.entity.character.player.movementType
import world.gregs.voidps.engine.entity.character.player.skill.Skill
import world.gregs.voidps.engine.entity.obj.GameObject
import world.gregs.voidps.engine.entity.obj.ObjectShape
Expand All @@ -18,6 +19,8 @@ import world.gregs.voidps.network.visual.VisualMask
import world.gregs.voidps.network.visual.Visuals
import world.gregs.voidps.network.visual.update.Hitsplat
import world.gregs.voidps.network.visual.update.Turn
import world.gregs.voidps.network.visual.update.player.MoveType
import world.gregs.voidps.network.visual.update.player.TemporaryMoveType
import world.gregs.voidps.type.Delta
import world.gregs.voidps.type.Direction
import world.gregs.voidps.type.Distance
Expand Down Expand Up @@ -192,24 +195,16 @@ fun Character.setForceMovement(
flagForceMovement()
}

fun Character.forceWalk(delta: Delta, delay: Int = 0, direction: Direction = Direction.NONE, block: () -> Unit = {}) {
setForceMovement(delta, delay, direction = direction)
this["force_walk"] = block
if (this is Player) {
strongQueue("force_walk", delay / 30) {
tele(delta)
clearAnimation()
}
} else if (this is NPC) {
strongQueue("force_walk", delay / 30) {
tele(delta)
clearAnimation()
}
}
fun Character.forceWalk(delta: Delta, delay: Int = tile.distanceTo(tile.add(delta)) * 30, direction: Direction = Direction.NONE) {
val start = tile
tele(delta)
setForceMovement(Delta.EMPTY, delay, start.delta(tile), direction = direction)
}

fun Character.forceWalk(target: Tile, delay: Int = tile.distanceTo(target) * 30, direction: Direction = Direction.NONE, block: () -> Unit = {}) {
forceWalk(target.delta(tile), delay, direction, block)
fun Character.forceWalk(target: Tile, delay: Int = tile.distanceTo(target) * 30, direction: Direction = Direction.NONE) {
val start = tile
tele(target)
setForceMovement(Delta.EMPTY, delay, start.delta(tile), direction = direction)
}

val Character.turn: Delta
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
package world.gregs.voidps.world.activity.dnd.shootingstar

import com.github.michaelbull.logging.InlineLogger
import world.gregs.voidps.engine.client.message
import world.gregs.voidps.engine.client.ui.chat.plural
import world.gregs.voidps.engine.client.variable.start
import world.gregs.voidps.engine.data.definition.data.Rock
import world.gregs.voidps.engine.entity.World
import world.gregs.voidps.engine.entity.character.forceWalk
import world.gregs.voidps.engine.entity.character.mode.interact.Interact
import world.gregs.voidps.engine.entity.character.move.walkTo
import world.gregs.voidps.engine.entity.character.npc.NPC
import world.gregs.voidps.engine.entity.character.npc.NPCs
import world.gregs.voidps.engine.entity.character.npc.npcOperate
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.chat.ChatType
import world.gregs.voidps.engine.entity.character.player.skill.Skill
import world.gregs.voidps.engine.entity.character.setAnimation
import world.gregs.voidps.engine.entity.obj.*
import world.gregs.voidps.engine.entity.objectDespawn
import world.gregs.voidps.engine.entity.worldSpawn
import world.gregs.voidps.engine.inject
import world.gregs.voidps.engine.inv.add
import world.gregs.voidps.engine.inv.inventory
import world.gregs.voidps.engine.inv.remove
import world.gregs.voidps.engine.map.collision.blocked
import world.gregs.voidps.engine.queue.softQueue
import world.gregs.voidps.engine.timer.timerStart
import world.gregs.voidps.engine.timer.toTicks
import world.gregs.voidps.type.Direction
import world.gregs.voidps.type.Tile
import world.gregs.voidps.type.random
import world.gregs.voidps.world.activity.dnd.shootingstar.ShootingStarHandler.currentActiveObject
import world.gregs.voidps.world.activity.dnd.shootingstar.ShootingStarHandler.currentStarTile
import world.gregs.voidps.world.activity.dnd.shootingstar.ShootingStarHandler.startEvent
import world.gregs.voidps.world.activity.dnd.shootingstar.ShootingStarHandler.totalCollected
import world.gregs.voidps.world.interact.dialogue.Cheerful
import world.gregs.voidps.world.interact.dialogue.Sad
import world.gregs.voidps.world.interact.dialogue.type.npc
import world.gregs.voidps.world.interact.entity.combat.hit.damage
import world.gregs.voidps.world.interact.entity.sound.areaSound
import java.util.concurrent.TimeUnit
import kotlin.math.roundToInt

val objects: GameObjects by inject()
val npcs: NPCs by inject()
val players: Players by inject()
val logger = InlineLogger()

worldSpawn { eventUpdate() }

fun eventUpdate() {
World.queue("shooting_star_event_timer", startEvent) {
if (currentStarTile != Tile.EMPTY) {
cleanseEvent(true)
logger.info { "There was already an active star, deleted it and started a new event" }
}
startCrashedStarEvent()
eventUpdate()
}
}

fun startCrashedStarEvent() {
val location = StarLocationData.entries.random()
currentStarTile = location.tile
val tier = random.nextInt(1, 9)
logger.info { "Crashed star event has started at: $location (${currentStarTile.x}, ${currentStarTile.y}) tier ${tier}." }
val shootingStarShadow: NPC? = npcs.add("shooting_star_shadow", Tile(currentStarTile.x, currentStarTile.y + 6), Direction.NONE)
shootingStarShadow?.walkTo(currentStarTile, noCollision = true, noRun = true)
areaSound("star_meteor_falling", currentStarTile, radius = 15, delay = 20)
World.queue("awaiting_shadow_walk", 6) {
val shootingStarObjectFalling: GameObject = objects.add("crashed_star_falling_object", currentStarTile)
val under = mutableListOf<Player>()
for (tile in currentStarTile.toCuboid(2, 2)) {
for (player in players[tile]) {
under.add(player)
}
}
for (player in under) {
player.damage(random.nextInt(10, 50))
val direction = Direction.all.first { !player.blocked(it) }
player.forceWalk(direction.delta, 1, direction = direction.inverse())
player.setAnimation("step_back_startled")
}
World.queue("falling_star_object_removal", 1) {
currentActiveObject = shootingStarObjectFalling.replace("crashed_star_tier_${tier}")
npcs.remove(shootingStarShadow)
}
}
}

fun cleanseEvent(forceStopped: Boolean) {
currentActiveObject?.let { current -> objects[currentStarTile, current.id] }?.remove()
if (!forceStopped) {
areaSound("star_sprite_appear", currentStarTile, radius = 10)
val starSprite = npcs.add("star_sprite", currentStarTile, Direction.NONE, 0)
World.queue("start_sprite_despawn_timer", TimeUnit.MINUTES.toTicks(10)) {
npcs.remove(starSprite)
}
}
totalCollected = 0
currentStarTile = Tile.EMPTY
currentActiveObject = null
ShootingStarHandler.earlyBird = false
}

fun getLayerPercentage(totalCollected: Int, totalNeeded: Int): String {
val remaining = totalNeeded - totalCollected
val percentageRemaining = (remaining.toDouble() / totalNeeded.toDouble()) * 100
return String.format("%.2f", percentageRemaining)
}

fun calculateRewards(stardust: Int): Map<String, Int> {
val coinsPerStardust = 50002.0 / 200
val astralRunesPerStardust = 52.0 / 200
val cosmicRunesPerStardust = 152.0 / 200
val goldOresPerStardust = 20.0 / 200

val coins = (coinsPerStardust * stardust).toInt()
val astralRunes = (astralRunesPerStardust * stardust).roundToInt()
val cosmicRunes = (cosmicRunesPerStardust * stardust).roundToInt()
val goldOres = (goldOresPerStardust * stardust).roundToInt()

return mapOf(
"coins" to coins,
"astral_rune" to astralRunes,
"cosmic_rune" to cosmicRunes,
"gold_ore_noted" to goldOres
)
}

objectDespawn("shooting_star_tier_1") {
areaSound("star_meteor_despawn", it.tile, radius = 15)
cleanseEvent(false)
}

timerStart("mining") { player ->
val target = (player.mode as? Interact)?.target as GameObject
val isStar = target.id.startsWith("crashed_star")
if (isStar) {
val isEarlyBird = ShootingStarHandler.isEarlyBird()
if (isEarlyBird) {
player.message("Congratulations!, You were the first person to find this star!")
val xpToAdd: Double = player.levels.get(Skill.Mining) * 75.0
player.experience.add(Skill.Mining, xpToAdd)
}
}
}

objectApproach("Prospect", "crashed_star_tier_#") {
if (player.queue.contains("prospect")) {
return@objectApproach
}
val starPayout = target.def["collect_for_next_layer", -1]
player.message("You examine the crashed star...")
player.start("movement_delay", 4)
player.softQueue("prospect", 4) {
val star = def.getOrNull<Rock>("mining")?.ores?.firstOrNull()
if (star == null) {
player.message("Star has been mined...")
} else if (starPayout != -1) {
val percentageCollected = getLayerPercentage(totalCollected, starPayout)
player.message("There is $percentageCollected% left of this layer.")
}
}
}

npcOperate("Talk-to", "star_sprite") {
npc<Cheerful>("Thank you for helping me out of here")
val starDustCount = player.inventory.count("stardust")
if (player.inventory.isFull()) {
player.message("Inventory full. To make more room, sell, drop or bank something.", ChatType.Game)
} else if (starDustCount == 0) {
npc<Sad>("You don't seem to have any stardust that I can exchange for a reward")
} else if (starDustCount > 0) {
val rewards = calculateRewards(starDustCount)
player.inventory.remove("stardust", starDustCount)
val messageBuilder = StringBuilder("Also, ")
rewards.entries.forEachIndexed { index, (reward, amount) ->
player.inventory.add(reward, amount)
if (index == 0) {
messageBuilder.append("have $amount $reward")
} else {
messageBuilder.append(", $amount ${reward.replace("_", " ").replace("noted", "").plural(amount)}")
}
}
npc<Cheerful>("I have rewarded you by making it so you can mine extra ore for the next 15 minutes, ${messageBuilder}.")
}
}
Loading

0 comments on commit 074840b

Please sign in to comment.