1 /* 2 * Copyright (c) 2017-2019 sel-project 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a copy 5 * of this software and associated documentation files (the "Software"), to deal 6 * in the Software without restriction, including without limitation the rights 7 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 * copies of the Software, and to permit persons to whom the Software is 9 * furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice shall be included in all 12 * copies or substantial portions of the Software. 13 * 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 * SOFTWARE. 21 * 22 */ 23 /** 24 * Copyright: Copyright (c) 2017-2019 sel-project 25 * License: MIT 26 * Authors: Kripth 27 * Source: $(HTTP github.com/sel-project/selery/source/selery/item/consumeable.d, selery/item/consumeable.d) 28 */ 29 module selery.item.consumeable; 30 31 import std.random : uniform, uniform01; 32 33 import selery.about : block_t, item_t; 34 import selery.block.block : compareBlock, blockInto; 35 import selery.block.blocks : Blocks; 36 import selery.effect; 37 import selery.item.item : Item, SimpleItem; 38 import selery.item.items : Items; 39 import selery.math.vector; 40 import selery.player.player : Player; 41 import selery.util.tuple : Tuple; 42 import selery.world.world : World; 43 44 import roman : fromRoman; 45 46 static import sul.effects; 47 static import sul.items; 48 49 enum Residue { 50 51 substract, 52 bowl, 53 bottle 54 55 } 56 57 alias EffectInfo = Tuple!(sul.effects.Effect, "effect", uint, "duration", ubyte, "level", float, "probability"); 58 59 public EffectInfo effectInfo(sul.effects.Effect effect, uint duration, string level, float prob=1) { 60 return EffectInfo(effect, duration, (level.fromRoman - 1) & 255, prob); 61 } 62 63 enum Potions : EffectInfo { 64 65 // extended = duration extended 66 // plus = level 1 (default is 0) 67 68 nightVision = effectInfo(Effects.nightVision, 180, "I"), 69 nightVisionExtended = effectInfo(Effects.nightVision, 480, "I"), 70 invisibility = effectInfo(Effects.invisibility, 180, "I"), 71 invisibilityExtended = effectInfo(Effects.invisibility, 480, "I"), 72 leaping = effectInfo(Effects.jumpBoost, 180, "I"), 73 leapingExtended = effectInfo(Effects.jumpBoost, 480, "I"), 74 leapingPlus = effectInfo(Effects.jumpBoost, 90, "II"), 75 fireResistance = effectInfo(Effects.fireResistance, 180, "I"), 76 fireResistanceExtended = effectInfo(Effects.fireResistance, 480, "I"), 77 swiftness = effectInfo(Effects.speed, 180, "I"), 78 swiftnessExtended = effectInfo(Effects.speed, 480, "I"), 79 swiftnessPlus = effectInfo(Effects.speed, 90, "II"), 80 slowness = effectInfo(Effects.slowness, 60, "I"), 81 slownessExtended = effectInfo(Effects.slowness, 240, "I"), 82 waterBreathing = effectInfo(Effects.waterBreathing, 180, "I"), 83 waterBreathingExtended = effectInfo(Effects.waterBreathing, 480, "I"), 84 healing = effectInfo(Effects.instantHealth, 0, "I"), 85 healingPlus = effectInfo(Effects.instantHealth, 0, "II"), 86 harming = effectInfo(Effects.instantDamage, 0, "I"), 87 harmingPlus = effectInfo(Effects.instantDamage, 0, "II"), 88 poison = effectInfo(Effects.poison, 45, "I"), 89 poisonExtended = effectInfo(Effects.poison, 120, "I"), 90 poisonPlus = effectInfo(Effects.poison, 22, "II"), 91 regeneration = effectInfo(Effects.regeneration, 45, "I"), 92 regenerationExtended = effectInfo(Effects.regeneration, 120, "I"), 93 regenerationPlus = effectInfo(Effects.regeneration, 22, "II"), 94 strength = effectInfo(Effects.strength, 180, "I"), 95 strengthExtended = effectInfo(Effects.strength, 480, "I"), 96 strengthPlus = effectInfo(Effects.strength, 90, "II"), 97 weakness = effectInfo(Effects.weakness, 90, "I"), 98 weaknessExtended = effectInfo(Effects.weakness, 240, "I"), 99 decay = effectInfo(Effects.wither, 40, "II"), 100 101 } 102 103 class ConsumeableItem(sul.items.Item si, EffectInfo[] effects, Residue residue=Residue.substract) : SimpleItem!(si) { 104 105 alias sul = si; 106 107 public @safe this(E...)(E args) { 108 super(args); 109 } 110 111 public final override pure nothrow @property @safe @nogc bool consumeable() { 112 return true; 113 } 114 115 public override Item onConsumed(Player player) { 116 static if(effects.length) { 117 foreach(EffectInfo effect ; effects) { 118 if(effect.probability >= 1 || uniform01!float(player.world.random) >= effect.probability) { 119 player.addEffect(effect.effect, effect.level, effect.duration); 120 } 121 } 122 } 123 static if(residue == Residue.substract) return null; 124 else static if(residue == Residue.bottle) return player.world.items.get(Items.glassBottle); 125 else return player.world.items.get(Items.bowl); 126 } 127 128 alias slot this; 129 130 } 131 132 class FoodItem(sul.items.Item si, uint ghunger, float gsaturation, EffectInfo[] effects=[], Residue residue=Residue.substract) : ConsumeableItem!(si, effects, residue) { 133 134 alias sul = si; 135 136 public @safe this(E...)(E args) { 137 super(args); 138 } 139 140 public static pure nothrow @property @safe @nogc uint hunger() { return ghunger; } 141 142 public static pure nothrow @property @safe @nogc float saturation() { return gsaturation; } 143 144 public override Item onConsumed(Player player) { 145 player.hunger = player.hunger + ghunger; 146 player.saturate(gsaturation); 147 return super.onConsumed(player); 148 } 149 150 alias slot this; 151 152 } 153 154 alias SoupItem(sul.items.Item si, uint ghunger, float gsaturation) = FoodItem!(si, ghunger, gsaturation, [], Residue.bowl); 155 156 class CropFoodItem(sul.items.Item si, uint ghunger, float gsaturation, block_t block) : FoodItem!(si, ghunger, gsaturation) { 157 158 alias sul = si; 159 160 public @safe this(E...)(E args) { 161 super(args); 162 } 163 164 public override pure nothrow @property @safe @nogc bool placeable() { 165 return true; 166 } 167 168 public override block_t place(World world, BlockPosition position, uint face) { 169 if(compareBlock!(Blocks.farmland)(world[position - [0, 1, 0]])) return block; 170 else return Blocks.air; 171 } 172 173 alias slot this; 174 175 } 176 177 class TeleportationItem(sul.items.Item si, uint ghunger, float gsaturation) : FoodItem!(si, ghunger, gsaturation) { 178 179 alias sul = si; 180 181 public @safe this(E...)(E args) { 182 super(args); 183 } 184 185 public override Item onConsumed(Player player) { 186 @property int rand() { 187 return uniform!"[]"(-8, 8, player.world.random); 188 } 189 auto center = BlockPosition(player.position.x.blockInto, player.position.y.blockInto, player.position.z.blockInto); 190 foreach(i ; 0..16) { 191 auto position = center + [rand, rand, rand]; 192 if(!player.world[position].hasBoundingBox && !player.world[position + [0, 1, 0]].hasBoundingBox) { 193 player.teleport(cast(EntityPosition)position + [.5, 0, .5]); 194 break; 195 } 196 } 197 return super.onConsumed(player); 198 } 199 200 alias slot this; 201 202 } 203 204 alias PotionItem(sul.items.Item si) = ConsumeableItem!(si, [], Residue.bottle); 205 206 alias PotionItem(sul.items.Item si, EffectInfo effect) = ConsumeableItem!(si, [effect], Residue.bottle); 207 208 class ClearEffectsItem(sul.items.Item si, item_t residue) : SimpleItem!(si) { 209 210 alias sul = si; 211 212 public @safe this(E...)(E args) { 213 super(args); 214 } 215 216 public final override pure nothrow @property @safe @nogc bool consumeable() { 217 return true; 218 } 219 220 public override Item onConsumed(Player player) { 221 player.clearEffects(); 222 return player.world.items.get(residue); 223 } 224 225 alias slot this; 226 227 }