Add plugin for consumable food/drink

This commit is contained in:
Gary Tierney
2017-06-22 22:07:59 +01:00
parent b17ad487ab
commit c15f18c609
7 changed files with 396 additions and 1 deletions
@@ -20,7 +20,7 @@ abstract class KotlinPluginTest: KotlinPluginTestHelpers() {
override lateinit var messageHandlers: MessageHandlerChainSet
@Before
fun setup() {
open fun setup() {
messageHandlers = MessageHandlerChainSet()
world = PowerMockito.spy(World())
+8
View File
@@ -0,0 +1,8 @@
name = "consumables"
package = "org.apollo.game.plugin.consumables"
authors = [ "Gary Tierney" ]
dependencies = []
[config]
srcDir = "src/"
testDir = "test/"
@@ -0,0 +1,82 @@
package org.apollo.plugin.consumables
import org.apollo.game.model.entity.Player
import org.apollo.game.model.entity.Skill
/**
* An item that can be consumed to restore or buff stats.
*/
abstract class Consumable(val name: String, val id: Int, val sound: Int, val delay: Int, val replacement: Int?) {
abstract fun addEffect(player: Player)
fun consume(player: Player, slot: Int) {
addEffect(player)
player.inventory.reset(slot)
if (replacement != null) {
player.inventory.add(replacement)
}
}
}
private val consumables = mutableMapOf<Int, Consumable>()
fun isConsumable(itemId: Int) = consumables.containsKey(itemId)
fun lookupConsumable(itemId: Int): Consumable = consumables.get(itemId)!!
fun consumable(consumable: Consumable) = consumables.put(consumable.id, consumable)
enum class FoodOrDrinkType(val action: String) {
FOOD("eat"), DRINK("drink")
}
class FoodOrDrink : Consumable {
companion object {
const val EAT_FOOD_SOUND = 317
}
val restoration: Int
val type: FoodOrDrinkType
constructor(
name: String,
id: Int,
delay: Int,
type: FoodOrDrinkType,
restoration: Int,
replacement: Int? = null
) : super(name, id, EAT_FOOD_SOUND, delay, replacement) {
this.type = type
this.restoration = restoration
}
override fun addEffect(player: Player) {
val hitpoints = player.skillSet.getSkill(Skill.HITPOINTS)
val hitpointsLevel = hitpoints.currentLevel
val newHitpointsLevel = Math.min(hitpointsLevel + restoration, hitpoints.maximumLevel)
player.sendMessage("You ${type.action} the $name.")
if (newHitpointsLevel > hitpointsLevel) {
player.sendMessage("It heals some health.")
}
player.skillSet.setCurrentLevel(Skill.HITPOINTS, newHitpointsLevel)
}
}
/**
* Define a new type of [Consumable] food.
*/
fun food(name: String, id: Int, restoration: Int, replacement: Int? = null, delay: Int = 3) {
consumable(FoodOrDrink(name, id, delay, FoodOrDrinkType.FOOD, restoration, replacement))
}
/**
* Define a new type of [Consumable] drink.
*/
fun drink(name: String, id: Int, restoration: Int, replacement: Int? = null, delay: Int = 3) {
consumable(FoodOrDrink(name, id, delay, FoodOrDrinkType.DRINK, restoration, replacement))
}
@@ -0,0 +1,36 @@
import org.apollo.game.action.AsyncAction
import org.apollo.game.message.impl.ItemOptionMessage
import org.apollo.game.model.Animation
import org.apollo.game.model.entity.Player
import org.apollo.net.message.Message
import org.apollo.plugin.consumables.*
on { ItemOptionMessage::class }
.where { option == 1 && isConsumable(id) }
.then {
ConsumeAction.start(this, it, lookupConsumable(id), slot)
}
class ConsumeAction(val consumable: Consumable, player: Player, val slot: Int) :
AsyncAction<Player>(CONSUME_STARTUP_DELAY, true, player) {
companion object {
const val CONSUME_ANIMATION_ID = 829
const val CONSUME_STARTUP_DELAY = 2
/**
* Starts a [ConsumeAction] for the specified [Player], terminating the [Message] that triggered it.
*/
fun start(message: Message, player: Player, consumable: Consumable, slot: Int) {
player.startAction(ConsumeAction(consumable, player, slot))
message.terminate()
}
}
suspend override fun executeActionAsync() {
consumable.consume(mob, slot)
mob.playAnimation(Animation(CONSUME_ANIMATION_ID))
wait(consumable.delay)
}
}
@@ -0,0 +1,24 @@
import org.apollo.plugin.consumables.drink
//# Wine
drink(name = "jug_of_wine", id = 1993, restoration = 11)
//# Hot Drinks
drink(name = "nettle_tea", id = 4239, restoration = 3)
drink(name = "nettle_tea", id = 4240, restoration = 3)
//# Gnome Cocktails
drink(name = "fruit_blast", id = 2034, restoration = 9)
drink(name = "fruit_blast", id = 2084, restoration = 9)
drink(name = "pineapple_punch", id = 2036, restoration = 9)
drink(name = "pineapple_punch", id = 2048, restoration = 9)
drink(name = "wizard_blizzard", id = 2040, restoration = 5) // -4 attack, +5 strength also
drink(name = "wizard_blizzard", id = 2054, restoration = 5) // -4 attack, +5 strength also
drink(name = "short_green_guy", id = 2038, restoration = 5) // -4 attack, +5 strength also
drink(name = "short_green_guy", id = 2080, restoration = 5) // -4 attack, +5 strength also
drink(name = "drunk_dragon", id = 2032, restoration = 5) // -4 attack, +6 strength also
drink(name = "drunk_dragon", id = 2092, restoration = 5) // -4 attack, +6 strength also
drink(name = "chocolate_saturday", id = 2030, restoration = 7) // -4 attack, +6 strength also
drink(name = "chocolate_saturday", id = 2074, restoration = 7) // -4 attack, +6 strength also
drink(name = "blurberry_special", id = 2028, restoration = 7) // -4 attack, +6 strength also
drink(name = "blurberry_special", id = 2064, restoration = 7) // -4 attack, +6 strength also
@@ -0,0 +1,159 @@
import org.apollo.plugin.consumables.food
food(name = "anchovies", id = 319, restoration = 1)
food(name = "crab_meat", id = 7521, restoration = 2, replacement = 7523)
food(name = "crab_meat", id = 7523, restoration = 2, replacement = 7524)
food(name = "crab_meat", id = 7524, restoration = 2, replacement = 7525)
food(name = "crab_meat", id = 7525, restoration = 2, replacement = 7526)
food(name = "crab_meat", id = 7526, restoration = 2)
food(name = "shrimp", id = 315, restoration = 3)
food(name = "sardine", id = 325, restoration = 3)
food(name = "cooked_meat", id = 2142, restoration = 3)
food(name = "cooked_chicken", id = 2140, restoration = 3)
food(name = "ugthanki_meat", id = 1861, restoration = 3)
food(name = "karambwanji", id = 3151, restoration = 3)
food(name = "cooked_rabbit", id = 3228, restoration = 5)
food(name = "herring", id = 347, restoration = 6)
food(name = "trout", id = 333, restoration = 7)
food(name = "cod", id = 339, restoration = 7)
food(name = "mackeral", id = 355, restoration = 7)
food(name = "roast_rabbit", id = 7223, restoration = 7)
food(name = "pike", id = 351, restoration = 8)
food(name = "lean_snail_meat", id = 3371, restoration = 8)
food(name = "salmon", id = 329, restoration = 9)
food(name = "tuna", id = 361, restoration = 10)
food(name = "lobster", id = 379, restoration = 12)
food(name = "bass", id = 365, restoration = 13)
food(name = "swordfish", id = 373, restoration = 14)
food(name = "cooked_jubbly", id = 7568, restoration = 15)
food(name = "monkfish", id = 7946, restoration = 16)
food(name = "cooked_karambwan", id = 3144, restoration = 18, delay = 0)
food(name = "shark", id = 385, restoration = 20)
food(name = "sea_turtle", id = 397, restoration = 21)
food(name = "manta_ray", id = 391, restoration = 22)
//# Breads/Wraps
food(name = "bread", id = 2309, restoration = 5)
food(name = "oomlie_wrap", id = 2343, restoration = 14)
food(name = "ugthanki_kebab", id = 1883, restoration = 19)
//# Fruits
food(name = "banana", id = 1963, restoration = 2)
food(name = "sliced_banana", id = 3162, restoration = 2)
food(name = "lemon", id = 2102, restoration = 2)
food(name = "lemon_chunks", id = 2104, restoration = 2)
food(name = "lemon_slices", id = 2106, restoration = 2)
food(name = "lime", id = 2120, restoration = 2)
food(name = "lime_chunks", id = 2122, restoration = 2)
food(name = "lime_slices", id = 2124, restoration = 2)
food(name = "strawberry", id = 5504, restoration = 5)
food(name = "papaya_fruit", id = 5972, restoration = 8)
food(name = "pineapple_chunks", id = 2116, restoration = 2)
food(name = "pineapple_ring", id = 2118, restoration = 2)
food(name = "orange", id = 2108, restoration = 2)
food(name = "orange_rings", id = 2110, restoration = 2)
food(name = "orange_slices", id = 2112, restoration = 2)
//# Pies
//# TODO: pie special effects (e.g. fish pie raises fishing level)
food(name = "redberry_pie", id = 2325, restoration = 5, replacement = 2333, delay = 1)
food(name = "redberry_pie", id = 2333, restoration = 5, delay = 1)
food(name = "meat_pie", id = 2327, restoration = 6, replacement = 2331, delay = 1)
food(name = "meat_pie", id = 2331, restoration = 6, delay = 1)
food(name = "apple_pie", id = 2323, restoration = 7, replacement = 2335, delay = 1)
food(name = "apple_pie", id = 2335, restoration = 7, delay = 1)
food(name = "fish_pie", id = 7188, restoration = 6, replacement = 7190, delay = 1)
food(name = "fish_pie", id = 7190, restoration = 6, delay = 1)
food(name = "admiral_pie", id = 7198, restoration = 8, replacement = 7200, delay = 1)
food(name = "admiral_pie", id = 7200, restoration = 8, delay = 1)
food(name = "wild_pie", id = 7208, restoration = 11, replacement = 7210, delay = 1)
food(name = "wild_pie", id = 7210, restoration = 11, delay = 1)
food(name = "summer_pie", id = 7218, restoration = 11, replacement = 7220, delay = 1)
food(name = "summer_pie", id = 7220, restoration = 11, delay = 1)
//# Stews
food(name = "stew", id = 2003, restoration = 11)
food(name = "banana_stew", id = 4016, restoration = 11)
food(name = "curry", id = 2011, restoration = 19)
//# Pizzas
food(name = "plain_pizza", id = 2289, restoration = 7, replacement = 2291)
food(name = "plain_pizza", id = 2291, restoration = 7)
food(name = "meat_pizza", id = 2293, restoration = 8, replacement = 2295)
food(name = "meat_pizza", id = 2295, restoration = 8)
food(name = "anchovy_pizza", id = 2297, restoration = 9, replacement = 2299)
food(name = "anchovy_pizza", id = 2299, restoration = 9)
food(name = "pineapple_pizza", id = 2301, restoration = 11, replacement = 2303)
food(name = "pineapple_pizza", id = 2303, restoration = 11)
//# Cakes
food(name = "fishcake", id = 7530, restoration = 11)
food(name = "cake", id = 1891, restoration = 4, replacement = 1893)
food(name = "cake", id = 1893, restoration = 4, replacement = 1895)
food(name = "cake", id = 1895, restoration = 4)
food(name = "chocolate_cake", id = 1897, restoration = 5, replacement = 1899)
food(name = "chocolate_cake", id = 1899, restoration = 5, replacement = 1901)
food(name = "chocolate_cake", id = 1901, restoration = 5)
//# Vegetables
food(name = "potato", id = 1942, restoration = 1)
food(name = "spinach_roll", id = 1969, restoration = 2)
food(name = "baked_potato", id = 6701, restoration = 4)
food(name = "sweetcorn", id = 5988, restoration = 10)
food(name = "sweetcorn_bowl", id = 7088, restoration = 13)
food(name = "potato_with_butter", id = 6703, restoration = 14)
food(name = "chili_potato", id = 7054, restoration = 14)
food(name = "potato_with_cheese", id = 6705, restoration = 16)
food(name = "egg_potato", id = 7056, restoration = 16)
food(name = "mushroom_potato", id = 7058, restoration = 20)
food(name = "tuna_potato", id = 7060, restoration = 22)
//# Dairy
food(name = "cheese", id = 1985, restoration = 2)
food(name = "pot_of_cream", id = 2130, restoration = 1)
//# Gnome Food
food(name = "toads_legs", id = 2152, restoration = 3)
//# Gnome Bowls
food(name = "worm_hole", id = 2191, restoration = 12)
food(name = "worm_hole", id = 2233, restoration = 12)
food(name = "vegetable_ball", id = 2195, restoration = 12)
food(name = "vegetable_ball", id = 2235, restoration = 12)
food(name = "tangled_toads_legs", id = 2187, restoration = 15)
food(name = "tangled_toads_legs", id = 2231, restoration = 15)
food(name = "chocolate_bomb", id = 2185, restoration = 15)
food(name = "chocolate_bomb", id = 2229, restoration = 15)
//# Gnome Crunchies
food(name = "toad_crunchies", id = 2217, restoration = 7)
food(name = "toad_crunchies", id = 2243, restoration = 7)
food(name = "spicy_crunchies", id = 2213, restoration = 7)
food(name = "spicy_crunchies", id = 2241, restoration = 7)
food(name = "worm_crunchies", id = 2205, restoration = 8)
food(name = "worm_crunchies", id = 2237, restoration = 8)
food(name = "chocchip_crunchies", id = 2209, restoration = 7)
food(name = "chocchip_crunchies", id = 2239, restoration = 7)
//# Gnome Battas
food(name = "fruit_batta", id = 2225, restoration = 11)
food(name = "fruit_batta", id = 2277, restoration = 11)
food(name = "toad_batta", id = 2221, restoration = 11)
food(name = "toad_batta", id = 2255, restoration = 11)
food(name = "worm_batta", id = 2219, restoration = 11)
food(name = "worm_batta", id = 2253, restoration = 11)
food(name = "vegetable_batta", id = 2227, restoration = 11)
food(name = "vegetable_batta", id = 2281, restoration = 11)
food(name = "cheese_tom_batta", id = 2223, restoration = 11)
food(name = "cheese_tom_batta", id = 2259, restoration = 11)
@@ -0,0 +1,86 @@
package org.apollo.plugin.consumables
import org.apollo.game.message.impl.ItemOptionMessage
import org.apollo.game.model.entity.Skill
import org.apollo.game.plugin.testing.KotlinPluginTest
import org.apollo.game.plugin.testing.mockito.KotlinMockitoExtensions.matches
import org.assertj.core.api.Assertions.assertThat
import org.junit.Before
import org.junit.Test
import org.mockito.Mockito.never
import org.mockito.Mockito.verify
class FoodOrDrinkTests : KotlinPluginTest() {
companion object {
const val TEST_FOOD_NAME = "test_food"
const val TEST_FOOD_ID = 2000
const val TEST_FOOD_RESTORATION = 5
const val TEST_DRINK_NAME = "test_drink"
const val TEST_DRINK_ID = 2001
const val TEST_DRINK_RESTORATION = 5
const val HP_LEVEL = 5
const val MAX_HP_LEVEL = 10
}
@Before override fun setup() {
super.setup()
val skills = player.skillSet
skills.setCurrentLevel(Skill.HITPOINTS, HP_LEVEL)
skills.setMaximumLevel(Skill.HITPOINTS, MAX_HP_LEVEL)
food("test_food", TEST_FOOD_ID, TEST_FOOD_RESTORATION)
drink("test_drink", TEST_DRINK_ID, TEST_DRINK_RESTORATION)
}
@Test fun `Consuming food or drink should restore the players hitpoints`() {
val expectedHpLevel = TEST_FOOD_RESTORATION + HP_LEVEL
player.notify(ItemOptionMessage(1, -1, TEST_FOOD_ID, 1))
player.waitForActionCompletion()
val currentHpLevel = player.skillSet.getCurrentLevel(Skill.HITPOINTS)
assertThat(currentHpLevel).isEqualTo(expectedHpLevel)
}
@Test fun `A message should be sent notifying the player if the item restored hitpoints`() {
player.notify(ItemOptionMessage(1, -1, TEST_FOOD_ID, 1))
player.waitForActionCompletion()
verify(player).sendMessage(matches {
assertThat(this).contains("heals some health")
})
}
@Test fun `A message should not be sent to the player if the item did not restore hitpoints`() {
player.skillSet.setCurrentLevel(Skill.HITPOINTS, MAX_HP_LEVEL)
player.notify(ItemOptionMessage(1, -1, TEST_FOOD_ID, 1))
player.waitForActionCompletion()
verify(player, never()).sendMessage(matches {
assertThat(this).contains("heals some health")
})
}
@Test fun `A message should be sent saying the player has drank an item when consuming a drink`() {
player.notify(ItemOptionMessage(1, -1, TEST_DRINK_ID, 1))
player.waitForActionCompletion()
verify(player).sendMessage(matches {
assertThat(this).contains("You drink the ${TEST_DRINK_NAME}")
})
}
@Test fun `A message should be sent saying the player has eaten an item when consuming food`() {
player.notify(ItemOptionMessage(1, -1, TEST_FOOD_ID, 1))
player.waitForActionCompletion()
verify(player).sendMessage(matches {
assertThat(this).contains("You eat the ${TEST_FOOD_NAME}")
})
}
}