1 /* 2 * Copyright (c) 2017-2018 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: 2017-2018 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.util.util : roman; 43 import selery.world.world : World; 44 45 static import sul.effects; 46 static import sul.items; 47 48 enum Residue { 49 50 substract, 51 bowl, 52 bottle 53 54 } 55 56 alias EffectInfo = Tuple!(sul.effects.Effect, "effect", uint, "duration", ubyte, "level", float, "probability"); 57 58 public EffectInfo effectInfo(sul.effects.Effect effect, uint duration, string level, float prob=1) { 59 return EffectInfo(effect, duration, (level.roman - 1) & 255, prob); 60 } 61 62 enum Potions : EffectInfo { 63 64 // extended = duration extended 65 // plus = level 1 (default is 0) 66 67 nightVision = effectInfo(Effects.nightVision, 180, "I"), 68 nightVisionExtended = effectInfo(Effects.nightVision, 480, "I"), 69 invisibility = effectInfo(Effects.invisibility, 180, "I"), 70 invisibilityExtended = effectInfo(Effects.invisibility, 480, "I"), 71 leaping = effectInfo(Effects.jumpBoost, 180, "I"), 72 leapingExtended = effectInfo(Effects.jumpBoost, 480, "I"), 73 leapingPlus = effectInfo(Effects.jumpBoost, 90, "II"), 74 fireResistance = effectInfo(Effects.fireResistance, 180, "I"), 75 fireResistanceExtended = effectInfo(Effects.fireResistance, 480, "I"), 76 swiftness = effectInfo(Effects.speed, 180, "I"), 77 swiftnessExtended = effectInfo(Effects.speed, 480, "I"), 78 swiftnessPlus = effectInfo(Effects.speed, 90, "II"), 79 slowness = effectInfo(Effects.slowness, 60, "I"), 80 slownessExtended = effectInfo(Effects.slowness, 240, "I"), 81 waterBreathing = effectInfo(Effects.waterBreathing, 180, "I"), 82 waterBreathingExtended = effectInfo(Effects.waterBreathing, 480, "I"), 83 healing = effectInfo(Effects.instantHealth, 0, "I"), 84 healingPlus = effectInfo(Effects.instantHealth, 0, "II"), 85 harming = effectInfo(Effects.instantDamage, 0, "I"), 86 harmingPlus = effectInfo(Effects.instantDamage, 0, "II"), 87 poison = effectInfo(Effects.poison, 45, "I"), 88 poisonExtended = effectInfo(Effects.poison, 120, "I"), 89 poisonPlus = effectInfo(Effects.poison, 22, "II"), 90 regeneration = effectInfo(Effects.regeneration, 45, "I"), 91 regenerationExtended = effectInfo(Effects.regeneration, 120, "I"), 92 regenerationPlus = effectInfo(Effects.regeneration, 22, "II"), 93 strength = effectInfo(Effects.strength, 180, "I"), 94 strengthExtended = effectInfo(Effects.strength, 480, "I"), 95 strengthPlus = effectInfo(Effects.strength, 90, "II"), 96 weakness = effectInfo(Effects.weakness, 90, "I"), 97 weaknessExtended = effectInfo(Effects.weakness, 240, "I"), 98 decay = effectInfo(Effects.wither, 40, "II"), 99 100 } 101 102 class ConsumeableItem(sul.items.Item si, EffectInfo[] effects, Residue residue=Residue.substract) : SimpleItem!(si) { 103 104 alias sul = si; 105 106 public @safe this(E...)(E args) { 107 super(args); 108 } 109 110 public final override pure nothrow @property @safe @nogc bool consumeable() { 111 return true; 112 } 113 114 public override Item onConsumed(Player player) { 115 static if(effects.length) { 116 foreach(EffectInfo effect ; effects) { 117 if(effect.probability >= 1 || uniform01!float(player.world.random) >= effect.probability) { 118 player.addEffect(effect.effect, effect.level, effect.duration); 119 } 120 } 121 } 122 static if(residue == Residue.substract) return null; 123 else static if(residue == Residue.bottle) return player.world.items.get(Items.glassBottle); 124 else return player.world.items.get(Items.bowl); 125 } 126 127 alias slot this; 128 129 } 130 131 class FoodItem(sul.items.Item si, uint ghunger, float gsaturation, EffectInfo[] effects=[], Residue residue=Residue.substract) : ConsumeableItem!(si, effects, residue) { 132 133 alias sul = si; 134 135 public @safe this(E...)(E args) { 136 super(args); 137 } 138 139 public static pure nothrow @property @safe @nogc uint hunger() { return ghunger; } 140 141 public static pure nothrow @property @safe @nogc float saturation() { return gsaturation; } 142 143 public override Item onConsumed(Player player) { 144 player.hunger = player.hunger + ghunger; 145 player.saturate(gsaturation); 146 return super.onConsumed(player); 147 } 148 149 alias slot this; 150 151 } 152 153 alias SoupItem(sul.items.Item si, uint ghunger, float gsaturation) = FoodItem!(si, ghunger, gsaturation, [], Residue.bowl); 154 155 class CropFoodItem(sul.items.Item si, uint ghunger, float gsaturation, block_t block) : FoodItem!(si, ghunger, gsaturation) { 156 157 alias sul = si; 158 159 public @safe this(E...)(E args) { 160 super(args); 161 } 162 163 public override pure nothrow @property @safe @nogc bool placeable() { 164 return true; 165 } 166 167 public override block_t place(World world, BlockPosition position, uint face) { 168 if(compareBlock!(Blocks.farmland)(world[position - [0, 1, 0]])) return block; 169 else return Blocks.air; 170 } 171 172 alias slot this; 173 174 } 175 176 class TeleportationItem(sul.items.Item si, uint ghunger, float gsaturation) : FoodItem!(si, ghunger, gsaturation) { 177 178 alias sul = si; 179 180 public @safe this(E...)(E args) { 181 super(args); 182 } 183 184 public override Item onConsumed(Player player) { 185 @property int rand() { 186 return uniform!"[]"(-8, 8, player.world.random); 187 } 188 auto center = BlockPosition(player.position.x.blockInto, player.position.y.blockInto, player.position.z.blockInto); 189 foreach(i ; 0..16) { 190 auto position = center + [rand, rand, rand]; 191 if(!player.world[position].hasBoundingBox && !player.world[position + [0, 1, 0]].hasBoundingBox) { 192 player.teleport(cast(EntityPosition)position + [.5, 0, .5]); 193 break; 194 } 195 } 196 return super.onConsumed(player); 197 } 198 199 alias slot this; 200 201 } 202 203 alias PotionItem(sul.items.Item si) = ConsumeableItem!(si, [], Residue.bottle); 204 205 alias PotionItem(sul.items.Item si, EffectInfo effect) = ConsumeableItem!(si, [effect], Residue.bottle); 206 207 class ClearEffectsItem(sul.items.Item si, item_t residue) : SimpleItem!(si) { 208 209 alias sul = si; 210 211 public @safe this(E...)(E args) { 212 super(args); 213 } 214 215 public final override pure nothrow @property @safe @nogc bool consumeable() { 216 return true; 217 } 218 219 public override Item onConsumed(Player player) { 220 player.clearEffects(); 221 return player.world.items.get(residue); 222 } 223 224 alias slot this; 225 226 }