Small fixes

This commit is contained in:
Isse 2023-03-29 23:11:59 +00:00
parent a737a1862c
commit c34e5ad4ed
99 changed files with 952 additions and 411 deletions

View File

@ -0,0 +1,24 @@
#![enable(implicit_some)]
(
name: Name("Trickster"),
body: RandomWith("draugr"),
alignment: Alignment(Enemy),
loot: LootTable("common.loot_tables.calendar.april_fools.trickster"),
inventory: (
loadout: Inline((
inherit: Asset("common.loadout.calendar.halloween.trickster"),
active_hands: InHands((Choice([
(1, Item("common.items.tool.instruments.double_bass")),
(1, Item("common.items.tool.instruments.flute")),
(1, Item("common.items.tool.instruments.lyre")),
(1, Item("common.items.tool.instruments.kalimba")),
(1, Item("common.items.tool.instruments.sitar")),
(1, Item("common.items.tool.instruments.washboard")),
(1, Item("common.items.tool.instruments.lute")),
(1, Item("common.items.tool.instruments.guitar")),
(1, Item("common.items.tool.instruments.melodica")),
]), None)),
)),
),
meta: [],
)

View File

@ -3,7 +3,7 @@ ItemDef(
description: "A potent healing potion.", description: "A potent healing potion.",
kind: Consumable( kind: Consumable(
kind: Drink, kind: Drink,
effects: [ effects: All([
Buff(( Buff((
kind: Potion, kind: Potion,
data: ( data: (
@ -21,7 +21,7 @@ ItemDef(
), ),
cat_ids: [Natural], cat_ids: [Natural],
)), )),
] ])
), ),
quality: High, quality: High,
tags: [Potion], tags: [Potion],

View File

@ -0,0 +1,67 @@
ItemDef(
name: "Curious Potion",
description: "Wonder what this does...",
kind: Consumable(
kind: Drink,
effects: Any([
Buff((
kind: Polymorphed(QuadrupedSmall(( species: Frog, body_type: Female ))),
data: (
strength: 0.0,
duration: Some(60),
),
cat_ids: [Natural],
)),
Buff((
kind: Polymorphed(QuadrupedSmall(( species: Rabbit, body_type: Female ))),
data: (
strength: 0.0,
duration: Some(60),
),
cat_ids: [Natural],
)),
Buff((
kind: Polymorphed(QuadrupedSmall(( species: Rat, body_type: Female ))),
data: (
strength: 0.0,
duration: Some(60),
),
cat_ids: [Natural],
)),
Buff((
kind: Polymorphed(QuadrupedSmall(( species: Squirrel, body_type: Female ))),
data: (
strength: 0.0,
duration: Some(60),
),
cat_ids: [Natural],
)),
Buff((
kind: Polymorphed(QuadrupedSmall(( species: Cat, body_type: Female ))),
data: (
strength: 0.0,
duration: Some(60),
),
cat_ids: [Natural],
)),
Buff((
kind: Polymorphed(QuadrupedSmall(( species: Fungome, body_type: Female ))),
data: (
strength: 0.0,
duration: Some(60),
),
cat_ids: [Natural],
)),
Buff((
kind: Polymorphed(QuadrupedSmall(( species: Pig, body_type: Female ))),
data: (
strength: 0.0,
duration: Some(60),
),
cat_ids: [Natural],
)),
])
),
quality: Common,
tags: [Potion],
)

View File

@ -3,7 +3,7 @@ ItemDef(
description: "Precious medicine, it makes for the largest rejuvenative flask yet.", description: "Precious medicine, it makes for the largest rejuvenative flask yet.",
kind: Consumable( kind: Consumable(
kind: Drink, kind: Drink,
effects: [ effects: All([
Buff(( Buff((
kind: Potion, kind: Potion,
data: ( data: (
@ -20,7 +20,7 @@ ItemDef(
), ),
cat_ids: [Natural], cat_ids: [Natural],
)), )),
] ])
), ),
quality: Common, quality: Common,
tags: [Potion], tags: [Potion],

View File

@ -3,7 +3,7 @@ ItemDef(
description: "An innovative invention from an apothecary, better than its smaller precursors.", description: "An innovative invention from an apothecary, better than its smaller precursors.",
kind: Consumable( kind: Consumable(
kind: Drink, kind: Drink,
effects: [ effects: All([
Buff(( Buff((
kind: Potion, kind: Potion,
data: ( data: (
@ -20,7 +20,7 @@ ItemDef(
), ),
cat_ids: [Natural], cat_ids: [Natural],
)), )),
] ])
), ),
quality: Common, quality: Common,
tags: [Potion], tags: [Potion],

View File

@ -3,7 +3,7 @@ ItemDef(
description: "A small potion concocted from apples and honey.", description: "A small potion concocted from apples and honey.",
kind: Consumable( kind: Consumable(
kind: Drink, kind: Drink,
effects: [ effects: All([
Buff(( Buff((
kind: Potion, kind: Potion,
data: ( data: (
@ -20,7 +20,7 @@ ItemDef(
), ),
cat_ids: [Natural], cat_ids: [Natural],
)), )),
] ])
), ),
quality: Common, quality: Common,
tags: [Potion], tags: [Potion],

View File

@ -3,7 +3,7 @@ ItemDef(
description: "They say gods eat it to get eternal youth.", description: "They say gods eat it to get eternal youth.",
kind: Consumable( kind: Consumable(
kind: Drink, kind: Drink,
effects: [ effects: All([
Buff(( Buff((
kind: Regeneration, kind: Regeneration,
data: ( data: (
@ -36,7 +36,7 @@ ItemDef(
), ),
cat_ids: [Natural], cat_ids: [Natural],
)), )),
] ])
), ),
quality: Debug, quality: Debug,
tags: [Food], tags: [Food],

View File

@ -3,7 +3,7 @@ ItemDef(
description: "Red and juicy", description: "Red and juicy",
kind: Consumable( kind: Consumable(
kind: Food, kind: Food,
effects: [ effects: One(
Buff(( Buff((
kind: Saturation, kind: Saturation,
data: ( data: (
@ -12,7 +12,7 @@ ItemDef(
), ),
cat_ids: [Natural], cat_ids: [Natural],
)), )),
] )
), ),
quality: Common, quality: Common,
tags: [Food], tags: [Food],

View File

@ -3,7 +3,7 @@ ItemDef(
description: "Who could say no to that?", description: "Who could say no to that?",
kind: Consumable( kind: Consumable(
kind: ComplexFood, kind: ComplexFood,
effects: [ effects: All([
Buff(( Buff((
kind: Saturation, kind: Saturation,
data: ( data: (
@ -20,7 +20,7 @@ ItemDef(
), ),
cat_ids: [Natural], cat_ids: [Natural],
)), )),
] ])
), ),
quality: Moderate, quality: Moderate,
tags: [Food], tags: [Food],

View File

@ -3,7 +3,7 @@ ItemDef(
description: "The stick makes it easier to carry!", description: "The stick makes it easier to carry!",
kind: Consumable( kind: Consumable(
kind: Food, kind: Food,
effects: [ effects: One(
Buff(( Buff((
kind: Saturation, kind: Saturation,
data: ( data: (
@ -12,7 +12,7 @@ ItemDef(
), ),
cat_ids: [Natural], cat_ids: [Natural],
)), )),
] )
), ),
quality: Common, quality: Common,
tags: [Food], tags: [Food],

View File

@ -3,7 +3,7 @@ ItemDef(
description: "Pungent and filling", description: "Pungent and filling",
kind: Consumable( kind: Consumable(
kind: Food, kind: Food,
effects: [ effects: One(
Buff(( Buff((
kind: Saturation, kind: Saturation,
data: ( data: (
@ -12,7 +12,7 @@ ItemDef(
), ),
cat_ids: [Natural], cat_ids: [Natural],
)), )),
] )
), ),
quality: High, quality: High,
tags: [Food], tags: [Food],

View File

@ -3,7 +3,7 @@ ItemDef(
description: "Giving you that special prickle.", description: "Giving you that special prickle.",
kind: Consumable( kind: Consumable(
kind: Drink, kind: Drink,
effects: [ effects: One(
Buff(( Buff((
kind: Saturation, kind: Saturation,
data: ( data: (
@ -12,7 +12,7 @@ ItemDef(
), ),
cat_ids: [Natural], cat_ids: [Natural],
)), )),
] )
), ),
quality: Moderate, quality: Moderate,
tags: [Food], tags: [Food],

View File

@ -3,7 +3,7 @@ ItemDef(
description: "An orange root vegetable. They say it'll improve your vision!", description: "An orange root vegetable. They say it'll improve your vision!",
kind: Consumable( kind: Consumable(
kind: Food, kind: Food,
effects: [ effects: One(
Buff(( Buff((
kind: Saturation, kind: Saturation,
data: ( data: (
@ -12,7 +12,7 @@ ItemDef(
), ),
cat_ids: [Natural], cat_ids: [Natural],
)), )),
] )
), ),
quality: Common, quality: Common,
tags: [Food], tags: [Food],

View File

@ -3,7 +3,7 @@ ItemDef(
description: "Made from goat milk from the finest dwarven produce. Aromatic and nutritious!", description: "Made from goat milk from the finest dwarven produce. Aromatic and nutritious!",
kind: Consumable( kind: Consumable(
kind: Food, kind: Food,
effects: [ effects: One(
Buff(( Buff((
kind: Saturation, kind: Saturation,
data: ( data: (
@ -12,7 +12,7 @@ ItemDef(
), ),
cat_ids: [Natural], cat_ids: [Natural],
)), )),
] )
), ),
quality: Common, quality: Common,
tags: [Food], tags: [Food],

View File

@ -3,7 +3,7 @@ ItemDef(
description: "Reliable source of water and fat. Can often be found growing on palm trees.", description: "Reliable source of water and fat. Can often be found growing on palm trees.",
kind: Consumable( kind: Consumable(
kind: Food, kind: Food,
effects: [ effects: One(
Buff(( Buff((
kind: Saturation, kind: Saturation,
data: ( data: (
@ -12,7 +12,7 @@ ItemDef(
), ),
cat_ids: [Natural], cat_ids: [Natural],
)), )),
] )
), ),
quality: Common, quality: Common,
tags: [Food], tags: [Food],

View File

@ -3,7 +3,7 @@ ItemDef(
description: "A daisy-like flower often used in herbal teas.", description: "A daisy-like flower often used in herbal teas.",
kind: Consumable( kind: Consumable(
kind: Food, kind: Food,
effects: [ effects: One(
Buff(( Buff((
kind: Saturation, kind: Saturation,
data: ( data: (
@ -12,7 +12,7 @@ ItemDef(
), ),
cat_ids: [Natural], cat_ids: [Natural],
)), )),
] )
), ),
quality: Common, quality: Common,
tags: [Food], tags: [Food],

View File

@ -3,7 +3,7 @@ ItemDef(
description: "A small, yellow flower. Uses the wind to spread its seeds.", description: "A small, yellow flower. Uses the wind to spread its seeds.",
kind: Consumable( kind: Consumable(
kind: Food, kind: Food,
effects: [ effects: One(
Buff(( Buff((
kind: Saturation, kind: Saturation,
data: ( data: (
@ -12,7 +12,7 @@ ItemDef(
), ),
cat_ids: [Natural], cat_ids: [Natural],
)), )),
] )
), ),
quality: Common, quality: Common,
tags: [Food], tags: [Food],

View File

@ -3,7 +3,7 @@ ItemDef(
description: "Make sure to brush your teeth after eating.", description: "Make sure to brush your teeth after eating.",
kind: Consumable( kind: Consumable(
kind: Food, kind: Food,
effects: [ effects: One(
Buff(( Buff((
kind: Saturation, kind: Saturation,
data: ( data: (
@ -12,7 +12,7 @@ ItemDef(
), ),
cat_ids: [Natural], cat_ids: [Natural],
)), )),
] )
), ),
quality: Common, quality: Common,
tags: [Food], tags: [Food],

View File

@ -3,7 +3,7 @@ ItemDef(
description: "Sweeet", description: "Sweeet",
kind: Consumable( kind: Consumable(
kind: Food, kind: Food,
effects: [ effects: One(
Buff(( Buff((
kind: Saturation, kind: Saturation,
data: ( data: (
@ -12,7 +12,7 @@ ItemDef(
), ),
cat_ids: [Natural], cat_ids: [Natural],
)), )),
] )
), ),
quality: Common, quality: Common,
tags: [Food], tags: [Food],

View File

@ -3,7 +3,7 @@ ItemDef(
description: "A vibrant green leafy vegetable. Lettuce make some salads!", description: "A vibrant green leafy vegetable. Lettuce make some salads!",
kind: Consumable( kind: Consumable(
kind: Food, kind: Food,
effects: [ effects: One(
Buff(( Buff((
kind: Saturation, kind: Saturation,
data: ( data: (
@ -12,7 +12,7 @@ ItemDef(
), ),
cat_ids: [Natural], cat_ids: [Natural],
)), )),
] )
), ),
quality: Common, quality: Common,
tags: [Food], tags: [Food],

View File

@ -3,7 +3,7 @@ ItemDef(
description: "Meat. The lifeblood of mankind.", description: "Meat. The lifeblood of mankind.",
kind: Consumable( kind: Consumable(
kind: Food, kind: Food,
effects: [ effects: One(
Buff(( Buff((
kind: Saturation, kind: Saturation,
data: ( data: (
@ -12,7 +12,7 @@ ItemDef(
), ),
cat_ids: [Natural], cat_ids: [Natural],
)), )),
] )
), ),
quality: Common, quality: Common,
tags: [Food], tags: [Food],

View File

@ -3,7 +3,7 @@ ItemDef(
description: "Medium Rare.", description: "Medium Rare.",
kind: Consumable( kind: Consumable(
kind: Food, kind: Food,
effects: [ effects: One(
Buff(( Buff((
kind: Saturation, kind: Saturation,
data: ( data: (
@ -12,7 +12,7 @@ ItemDef(
), ),
cat_ids: [Natural], cat_ids: [Natural],
)), )),
] )
), ),
quality: Common, quality: Common,
tags: [Food], tags: [Food],

View File

@ -3,7 +3,7 @@ ItemDef(
description: "Chunk of beastly animal meat, best after cooking.", description: "Chunk of beastly animal meat, best after cooking.",
kind: Consumable( kind: Consumable(
kind: Food, kind: Food,
effects: [ effects: One(
Buff(( Buff((
kind: Saturation, kind: Saturation,
data: ( data: (
@ -12,7 +12,7 @@ ItemDef(
), ),
cat_ids: [Natural], cat_ids: [Natural],
)), )),
] )
), ),
quality: Common, quality: Common,
tags: [Food], tags: [Food],

View File

@ -3,7 +3,7 @@ ItemDef(
description: "Medium Rare.", description: "Medium Rare.",
kind: Consumable( kind: Consumable(
kind: Food, kind: Food,
effects: [ effects: One(
Buff(( Buff((
kind: Saturation, kind: Saturation,
data: ( data: (
@ -12,7 +12,7 @@ ItemDef(
), ),
cat_ids: [Natural], cat_ids: [Natural],
)), )),
] )
), ),
quality: Common, quality: Common,
tags: [Food], tags: [Food],

View File

@ -3,7 +3,7 @@ ItemDef(
description: "Small hunk of beastly animal meat, best after cooking.", description: "Small hunk of beastly animal meat, best after cooking.",
kind: Consumable( kind: Consumable(
kind: Food, kind: Food,
effects: [ effects: One(
Buff(( Buff((
kind: Saturation, kind: Saturation,
data: ( data: (
@ -12,7 +12,7 @@ ItemDef(
), ),
cat_ids: [Natural], cat_ids: [Natural],
)), )),
] )
), ),
quality: Common, quality: Common,
tags: [Food], tags: [Food],

View File

@ -3,7 +3,7 @@ ItemDef(
description: "Best enjoyed with one in each hand.", description: "Best enjoyed with one in each hand.",
kind: Consumable( kind: Consumable(
kind: Food, kind: Food,
effects: [ effects: One(
Buff(( Buff((
kind: Saturation, kind: Saturation,
data: ( data: (
@ -12,7 +12,7 @@ ItemDef(
), ),
cat_ids: [Natural], cat_ids: [Natural],
)), )),
] )
), ),
quality: Common, quality: Common,
tags: [Food], tags: [Food],

View File

@ -3,7 +3,7 @@ ItemDef(
description: "Makes for a legendary meal.", description: "Makes for a legendary meal.",
kind: Consumable( kind: Consumable(
kind: Food, kind: Food,
effects: [ effects: One(
Buff(( Buff((
kind: Saturation, kind: Saturation,
data: ( data: (
@ -12,7 +12,7 @@ ItemDef(
), ),
cat_ids: [Natural], cat_ids: [Natural],
)), )),
] )
), ),
quality: Common, quality: Common,
tags: [Food], tags: [Food],

View File

@ -3,7 +3,7 @@ ItemDef(
description: "It's magnificent.", description: "It's magnificent.",
kind: Consumable( kind: Consumable(
kind: Food, kind: Food,
effects: [ effects: One(
Buff(( Buff((
kind: Saturation, kind: Saturation,
data: ( data: (
@ -12,7 +12,7 @@ ItemDef(
), ),
cat_ids: [Natural], cat_ids: [Natural],
)), )),
] )
), ),
quality: Common, quality: Common,
tags: [Food], tags: [Food],

View File

@ -3,7 +3,7 @@ ItemDef(
description: "A hefty drumstick.", description: "A hefty drumstick.",
kind: Consumable( kind: Consumable(
kind: Food, kind: Food,
effects: [ effects: One(
Buff(( Buff((
kind: Saturation, kind: Saturation,
data: ( data: (
@ -12,7 +12,7 @@ ItemDef(
), ),
cat_ids: [Natural], cat_ids: [Natural],
)), )),
] )
), ),
quality: Common, quality: Common,
tags: [Food], tags: [Food],

View File

@ -3,7 +3,7 @@ ItemDef(
description: "A fresh cooked seafood steak.", description: "A fresh cooked seafood steak.",
kind: Consumable( kind: Consumable(
kind: Food, kind: Food,
effects: [ effects: One(
Buff(( Buff((
kind: Saturation, kind: Saturation,
data: ( data: (
@ -12,7 +12,7 @@ ItemDef(
), ),
cat_ids: [Natural], cat_ids: [Natural],
)), )),
] )
), ),
quality: Common, quality: Common,
tags: [Food], tags: [Food],

View File

@ -3,7 +3,7 @@ ItemDef(
description: "A steak chopped from a fish, best after cooking.", description: "A steak chopped from a fish, best after cooking.",
kind: Consumable( kind: Consumable(
kind: Food, kind: Food,
effects: [ effects: One(
Buff(( Buff((
kind: Saturation, kind: Saturation,
data: ( data: (
@ -12,7 +12,7 @@ ItemDef(
), ),
cat_ids: [Natural], cat_ids: [Natural],
)), )),
] )
), ),
quality: Common, quality: Common,
tags: [Food], tags: [Food],

View File

@ -3,7 +3,7 @@ ItemDef(
description: "Tastes exotic.", description: "Tastes exotic.",
kind: Consumable( kind: Consumable(
kind: Food, kind: Food,
effects: [ effects: One(
Buff(( Buff((
kind: Saturation, kind: Saturation,
data: ( data: (
@ -12,7 +12,7 @@ ItemDef(
), ),
cat_ids: [Natural], cat_ids: [Natural],
)), )),
] )
), ),
quality: Common, quality: Common,
tags: [Food], tags: [Food],

View File

@ -3,7 +3,7 @@ ItemDef(
description: "Peculiar bit of meat, best after cooking.", description: "Peculiar bit of meat, best after cooking.",
kind: Consumable( kind: Consumable(
kind: Food, kind: Food,
effects: [ effects: One(
Buff(( Buff((
kind: Saturation, kind: Saturation,
data: ( data: (
@ -12,7 +12,7 @@ ItemDef(
), ),
cat_ids: [Natural], cat_ids: [Natural],
)), )),
] )
), ),
quality: Common, quality: Common,
tags: [Food], tags: [Food],

View File

@ -3,7 +3,7 @@ ItemDef(
description: "Hopefully this one is not poisonous", description: "Hopefully this one is not poisonous",
kind: Consumable( kind: Consumable(
kind: Food, kind: Food,
effects: [ effects: One(
Buff(( Buff((
kind: Saturation, kind: Saturation,
data: ( data: (
@ -12,7 +12,7 @@ ItemDef(
), ),
cat_ids: [Natural], cat_ids: [Natural],
)), )),
] )
), ),
quality: Common, quality: Common,
tags: [Food], tags: [Food],

View File

@ -3,7 +3,7 @@ ItemDef(
description: "Roasted mushrooms on a stick for easy carrying", description: "Roasted mushrooms on a stick for easy carrying",
kind: Consumable( kind: Consumable(
kind: Food, kind: Food,
effects: [ effects: One(
Buff(( Buff((
kind: Saturation, kind: Saturation,
data: ( data: (
@ -12,7 +12,7 @@ ItemDef(
), ),
cat_ids: [Natural], cat_ids: [Natural],
)), )),
] )
), ),
quality: Common, quality: Common,
tags: [Food], tags: [Food],

View File

@ -3,7 +3,7 @@ ItemDef(
description: "A vegetable that's made the toughest men cry.", description: "A vegetable that's made the toughest men cry.",
kind: Consumable( kind: Consumable(
kind: Food, kind: Food,
effects: [ effects: One(
Buff(( Buff((
kind: Saturation, kind: Saturation,
data: ( data: (
@ -12,7 +12,7 @@ ItemDef(
), ),
cat_ids: [Natural], cat_ids: [Natural],
)), )),
] )
), ),
quality: Common, quality: Common,
tags: [Food], tags: [Food],

View File

@ -3,7 +3,7 @@ ItemDef(
description: "Literally just chopped lettuce. Does this even count as a salad?", description: "Literally just chopped lettuce. Does this even count as a salad?",
kind: Consumable( kind: Consumable(
kind: Food, kind: Food,
effects: [ effects: One(
Buff(( Buff((
kind: Saturation, kind: Saturation,
data: ( data: (
@ -12,7 +12,7 @@ ItemDef(
), ),
cat_ids: [Natural], cat_ids: [Natural],
)), )),
] )
), ),
quality: Common, quality: Common,
tags: [Food], tags: [Food],

View File

@ -3,7 +3,7 @@ ItemDef(
description: "Brewed from moldy pumpkins.", description: "Brewed from moldy pumpkins.",
kind: Consumable( kind: Consumable(
kind: Drink, kind: Drink,
effects: [ effects: One(
Buff(( Buff((
kind: Saturation, kind: Saturation,
data: ( data: (
@ -12,7 +12,7 @@ ItemDef(
), ),
cat_ids: [Natural], cat_ids: [Natural],
)), )),
] )
), ),
quality: Moderate, quality: Moderate,
tags: [Food], tags: [Food],

View File

@ -3,7 +3,7 @@ ItemDef(
description: "A herb commonly used in tea.", description: "A herb commonly used in tea.",
kind: Consumable( kind: Consumable(
kind: Food, kind: Food,
effects: [ effects: One(
Buff(( Buff((
kind: Saturation, kind: Saturation,
data: ( data: (
@ -12,7 +12,7 @@ ItemDef(
), ),
cat_ids: [Natural], cat_ids: [Natural],
)), )),
] )
), ),
quality: Common, quality: Common,
tags: [Food], tags: [Food],

View File

@ -3,7 +3,7 @@ ItemDef(
description: "You feel an evil force pulsating within.\n\nIt may be unwise to hold on to it for too long...", description: "You feel an evil force pulsating within.\n\nIt may be unwise to hold on to it for too long...",
kind: Consumable( kind: Consumable(
kind: ComplexFood, kind: ComplexFood,
effects: [ effects: All([
Buff(( Buff((
kind: Frenzied, kind: Frenzied,
data: ( data: (
@ -20,7 +20,7 @@ ItemDef(
), ),
cat_ids: [Natural], cat_ids: [Natural],
)), )),
] ])
), ),
quality: Epic, quality: Epic,
tags: [Food], tags: [Food],

View File

@ -3,7 +3,7 @@ ItemDef(
description: "Brewed from freshly shelled sunflower seeds", description: "Brewed from freshly shelled sunflower seeds",
kind: Consumable( kind: Consumable(
kind: Drink, kind: Drink,
effects: [ effects: One(
Buff(( Buff((
kind: Saturation, kind: Saturation,
data: ( data: (
@ -12,7 +12,7 @@ ItemDef(
), ),
cat_ids: [Natural], cat_ids: [Natural],
)), )),
] )
), ),
quality: Moderate, quality: Moderate,
tags: [Food], tags: [Food],

View File

@ -3,7 +3,7 @@ ItemDef(
description: "A red fruit. It's not actually a vegetable!", description: "A red fruit. It's not actually a vegetable!",
kind: Consumable( kind: Consumable(
kind: Food, kind: Food,
effects: [ effects: One(
Buff(( Buff((
kind: Saturation, kind: Saturation,
data: ( data: (
@ -12,7 +12,7 @@ ItemDef(
), ),
cat_ids: [Natural], cat_ids: [Natural],
)), )),
] )
), ),
quality: Common, quality: Common,
tags: [Food], tags: [Food],

View File

@ -3,7 +3,7 @@ ItemDef(
description: "Leafy salad with some chopped, juicy tomatoes mixed in.", description: "Leafy salad with some chopped, juicy tomatoes mixed in.",
kind: Consumable( kind: Consumable(
kind: Food, kind: Food,
effects: [ effects: One(
Buff(( Buff((
kind: Saturation, kind: Saturation,
data: ( data: (
@ -12,7 +12,7 @@ ItemDef(
), ),
cat_ids: [Natural], cat_ids: [Natural],
)), )),
] )
), ),
quality: Common, quality: Common,
tags: [Food], tags: [Food],

View File

@ -0,0 +1,4 @@
[
(1.0, Item("common.items.consumable.curious_potion")),
(19.0, Nothing),
]

BIN
assets/voxygen/element/de_buffs/debuff_polymorphed.png (Stored with Git LFS) Normal file

Binary file not shown.

View File

@ -76,7 +76,11 @@ buff-stat-potionsickness =
## Reckless ## Reckless
buff-title-reckless = Reckless buff-title-reckless = Reckless
buff-desc-reckless = Your attacks are more powerful, however you are leaving your defenses open. buff-desc-reckless = Your attacks are more powerful, however you are leaving your defenses open.
## Polymorped
buff-title-polymorphed = Polymorphed
buff-desc-polymorphed = Your body changes form.
## Util ## Util
buff-text-over_seconds = over { $dur_secs } seconds buff-text-over_seconds = over { $dur_secs } seconds
buff-text-for_seconds = for { $dur_secs } seconds buff-text-for_seconds = for { $dur_secs } seconds
buff-mysterious = Mysterious effect
buff-remove = Click to remove buff-remove = Click to remove

View File

@ -3134,6 +3134,10 @@
"voxel.object.potion_red", "voxel.object.potion_red",
(0.0, 0.0, 0.0), (-50.0, 30.0, 20.0), 0.9, (0.0, 0.0, 0.0), (-50.0, 30.0, 20.0), 0.9,
), ),
Simple("common.items.consumable.curious_potion"): VoxTrans(
"voxel.object.curious_potion",
(0.0, 0.0, 0.0), (-50.0, 30.0, 20.0), 0.7,
),
Simple("common.items.food.cheese"): VoxTrans( Simple("common.items.food.cheese"): VoxTrans(
"voxel.object.cheese", "voxel.object.cheese",
(0.0, 0.0, 0.0), (-60.0, 27.0, 17.0), 0.7, (0.0, 0.0, 0.0), (-60.0, 27.0, 17.0), 0.7,

View File

@ -794,6 +794,7 @@
Simple("common.items.consumable.potion_med"): "voxel.object.potion_red", Simple("common.items.consumable.potion_med"): "voxel.object.potion_red",
Simple("common.items.consumable.potion_minor"): "voxel.object.potion_red", Simple("common.items.consumable.potion_minor"): "voxel.object.potion_red",
Simple("common.items.consumable.potion_big"): "voxel.object.potion_red", Simple("common.items.consumable.potion_big"): "voxel.object.potion_red",
Simple("common.items.consumable.curious_potion"): "voxel.object.curious_potion",
Simple("common.items.boss_drops.potions"): "voxel.object.potion_red", Simple("common.items.boss_drops.potions"): "voxel.object.potion_red",
Simple("common.items.food.cheese"): "voxel.object.cheese", Simple("common.items.food.cheese"): "voxel.object.cheese",
Simple("common.items.food.blue_cheese"): "voxel.object.blue_cheese", Simple("common.items.food.blue_cheese"): "voxel.object.blue_cheese",

BIN
assets/voxygen/voxel/object/curious_potion.vox (Stored with Git LFS) Normal file

Binary file not shown.

View File

@ -0,0 +1,14 @@
SpawnEntry (
name: "April Fools Jungle Area",
note: "April Fools NPCs",
rules: [
Pack(
groups: [
(3, (3, 6, "common.entity.calendar.april_fools.aggressive.trickster")),
],
spawn_mode: Land,
calendar_events: Some([AprilFools]),
day_period: [Night, Morning, Noon, Evening],
),
],
)

View File

@ -0,0 +1,14 @@
SpawnEntry (
name: "April Fools Jungle Core",
note: "April Fools NPCs",
rules: [
Pack(
groups: [
(3, (3, 6, "common.entity.calendar.april_fools.aggressive.trickster")),
],
spawn_mode: Land,
calendar_events: Some([AprilFools]),
day_period: [Night, Morning, Noon, Evening],
),
],
)

View File

@ -0,0 +1,14 @@
SpawnEntry (
name: "April Fools Temperate Rainforest",
note: "April Fools NPCs",
rules: [
Pack(
groups: [
(3, (3, 6, "common.entity.calendar.april_fools.aggressive.trickster")),
],
spawn_mode: Land,
calendar_events: Some([AprilFools]),
day_period: [Night, Morning, Noon, Evening],
),
],
)

View File

@ -0,0 +1,14 @@
SpawnEntry (
name: "April Fools Tropical Rainforest",
note: "April Fools NPCs",
rules: [
Pack(
groups: [
(3, (3, 6, "common.entity.calendar.april_fools.aggressive.trickster")),
],
spawn_mode: Land,
calendar_events: Some([AprilFools]),
day_period: [Night, Morning, Noon, Evening],
),
],
)

View File

@ -0,0 +1,14 @@
SpawnEntry (
name: "April Fools Tundra Core",
note: "April Fools NPCs",
rules: [
Pack(
groups: [
(3, (3, 6, "common.entity.calendar.april_fools.aggressive.trickster")),
],
spawn_mode: Land,
calendar_events: Some([AprilFools]),
day_period: [Night, Morning, Noon, Evening],
),
],
)

View File

@ -0,0 +1,14 @@
SpawnEntry (
name: "April Fools Tundra Forest",
note: "April Fools NPCs",
rules: [
Pack(
groups: [
(3, (3, 6, "common.entity.calendar.april_fools.aggressive.trickster")),
],
spawn_mode: Land,
calendar_events: Some([AprilFools]),
day_period: [Night, Morning, Noon, Evening],
),
],
)

View File

@ -0,0 +1,14 @@
SpawnEntry (
name: "April Fools Tundra Snow",
note: "April Fools NPCs",
rules: [
Pack(
groups: [
(3, (3, 6, "common.entity.calendar.april_fools.aggressive.trickster")),
],
spawn_mode: Land,
calendar_events: Some([AprilFools]),
day_period: [Night, Morning, Noon, Evening],
),
],
)

View File

@ -8,6 +8,7 @@ use strum::EnumIter;
pub enum CalendarEvent { pub enum CalendarEvent {
Christmas = 0, Christmas = 0,
Halloween = 1, Halloween = 1,
AprilFools = 2,
} }
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)] #[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
@ -43,6 +44,10 @@ impl Calendar {
this.events.push(CalendarEvent::Halloween); this.events.push(CalendarEvent::Halloween);
} }
if now.month() == 4 && now.day() == 1 {
this.events.push(CalendarEvent::AprilFools);
}
this this
} }
} }

View File

@ -157,6 +157,7 @@ lazy_static! {
BuffKind::Parried => "parried", BuffKind::Parried => "parried",
BuffKind::PotionSickness => "potion_sickness", BuffKind::PotionSickness => "potion_sickness",
BuffKind::Reckless => "reckless", BuffKind::Reckless => "reckless",
BuffKind::Polymorphed(_) => "polymorphed",
}; };
let mut buff_parser = HashMap::new(); let mut buff_parser = HashMap::new();
for kind in BuffKind::iter() { for kind in BuffKind::iter() {

View File

@ -31,7 +31,7 @@ use super::{BuffKind, Collider, Density, Mass, Scale};
make_case_elim!( make_case_elim!(
body, body,
#[derive(Copy, Clone, Debug, Display, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, Display, PartialEq, PartialOrd, Ord, Eq, Hash, Serialize, Deserialize)]
#[repr(u32)] #[repr(u32)]
pub enum Body { pub enum Body {
Humanoid(body: humanoid::Body) = 0, Humanoid(body: humanoid::Body) = 0,
@ -54,6 +54,16 @@ make_case_elim!(
} }
); );
// Implemented for Buff, to be able to implement EnumIter.
impl Default for Body {
fn default() -> Self {
Body::QuadrupedSmall(quadruped_small::Body {
species: quadruped_small::Species::Frog,
body_type: quadruped_small::BodyType::Female,
})
}
}
/// Data representing data generic to the body together with per-species data. /// Data representing data generic to the body together with per-species data.
/// ///
/// NOTE: Deliberately don't (yet?) implement serialize. /// NOTE: Deliberately don't (yet?) implement serialize.

View File

@ -1,7 +1,7 @@
use rand::{seq::SliceRandom, thread_rng}; use rand::{seq::SliceRandom, thread_rng};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
pub struct Body { pub struct Body {
pub species: Species, pub species: Species,
pub body_type: BodyType, pub body_type: BodyType,
@ -25,7 +25,7 @@ impl From<Body> for super::Body {
fn from(body: Body) -> Self { super::Body::Arthropod(body) } fn from(body: Body) -> Self { super::Body::Arthropod(body) }
} }
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
#[repr(u32)] #[repr(u32)]
pub enum Species { pub enum Species {
Tarantula = 0, Tarantula = 0,
@ -99,7 +99,7 @@ impl<'a, SpeciesMeta: 'a> IntoIterator for &'a AllSpecies<SpeciesMeta> {
fn into_iter(self) -> Self::IntoIter { ALL_SPECIES.iter().copied() } fn into_iter(self) -> Self::IntoIter { ALL_SPECIES.iter().copied() }
} }
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
#[repr(u32)] #[repr(u32)]
pub enum BodyType { pub enum BodyType {
Female = 0, Female = 0,

View File

@ -4,7 +4,7 @@ use serde::{Deserialize, Serialize};
make_proj_elim!( make_proj_elim!(
body, body,
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
pub struct Body { pub struct Body {
pub species: Species, pub species: Species,
pub body_type: BodyType, pub body_type: BodyType,
@ -31,7 +31,7 @@ impl From<Body> for super::Body {
make_case_elim!( make_case_elim!(
species, species,
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
#[repr(u32)] #[repr(u32)]
pub enum Species { pub enum Species {
Ogre = 0, Ogre = 0,
@ -158,7 +158,7 @@ impl<'a, SpeciesMeta: 'a> IntoIterator for &'a AllSpecies<SpeciesMeta> {
make_case_elim!( make_case_elim!(
body_type, body_type,
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
#[repr(u32)] #[repr(u32)]
pub enum BodyType { pub enum BodyType {
Female = 0, Female = 0,

View File

@ -4,7 +4,7 @@ use serde::{Deserialize, Serialize};
make_proj_elim!( make_proj_elim!(
body, body,
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
pub struct Body { pub struct Body {
pub species: Species, pub species: Species,
pub body_type: BodyType, pub body_type: BodyType,
@ -31,7 +31,7 @@ impl From<Body> for super::Body {
make_case_elim!( make_case_elim!(
species, species,
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
#[repr(u32)] #[repr(u32)]
pub enum Species { pub enum Species {
Gnome = 0, Gnome = 0,
@ -114,7 +114,7 @@ impl<'a, SpeciesMeta: 'a> IntoIterator for &'a AllSpecies<SpeciesMeta> {
make_case_elim!( make_case_elim!(
body_type, body_type,
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
#[repr(u32)] #[repr(u32)]
pub enum BodyType { pub enum BodyType {
Female = 0, Female = 0,

View File

@ -4,7 +4,7 @@ use serde::{Deserialize, Serialize};
make_proj_elim!( make_proj_elim!(
body, body,
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
pub struct Body { pub struct Body {
pub species: Species, pub species: Species,
pub body_type: BodyType, pub body_type: BodyType,
@ -31,7 +31,7 @@ impl From<Body> for super::Body {
make_case_elim!( make_case_elim!(
species, species,
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
#[repr(u32)] #[repr(u32)]
pub enum Species { pub enum Species {
Phoenix = 0, Phoenix = 0,
@ -98,7 +98,7 @@ impl<'a, SpeciesMeta: 'a> IntoIterator for &'a AllSpecies<SpeciesMeta> {
make_case_elim!( make_case_elim!(
body_type, body_type,
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
#[repr(u32)] #[repr(u32)]
pub enum BodyType { pub enum BodyType {
Female = 0, Female = 0,

View File

@ -5,7 +5,7 @@ use strum::{Display, EnumString};
make_proj_elim!( make_proj_elim!(
body, body,
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
pub struct Body { pub struct Body {
pub species: Species, pub species: Species,
pub body_type: BodyType, pub body_type: BodyType,
@ -33,7 +33,18 @@ impl From<Body> for super::Body {
make_case_elim!( make_case_elim!(
species, species,
#[derive( #[derive(
Copy, Clone, Debug, Display, EnumString, PartialEq, Eq, Hash, Serialize, Deserialize, Copy,
Clone,
Debug,
Display,
EnumString,
PartialEq,
Eq,
PartialOrd,
Ord,
Hash,
Serialize,
Deserialize,
)] )]
#[repr(u32)] #[repr(u32)]
pub enum Species { pub enum Species {
@ -134,7 +145,18 @@ impl<'a, SpeciesMeta: 'a> IntoIterator for &'a AllSpecies<SpeciesMeta> {
make_case_elim!( make_case_elim!(
body_type, body_type,
#[derive( #[derive(
Copy, Clone, Debug, Display, EnumString, PartialEq, Eq, Hash, Serialize, Deserialize, Copy,
Clone,
Debug,
Display,
EnumString,
PartialEq,
Eq,
PartialOrd,
Ord,
Hash,
Serialize,
Deserialize,
)] )]
#[repr(u32)] #[repr(u32)]
pub enum BodyType { pub enum BodyType {

View File

@ -4,7 +4,7 @@ use serde::{Deserialize, Serialize};
make_proj_elim!( make_proj_elim!(
body, body,
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
pub struct Body { pub struct Body {
pub species: Species, pub species: Species,
pub body_type: BodyType, pub body_type: BodyType,
@ -31,7 +31,7 @@ impl From<Body> for super::Body {
make_case_elim!( make_case_elim!(
species, species,
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
#[repr(u32)] #[repr(u32)]
pub enum Species { pub enum Species {
Reddragon = 0, Reddragon = 0,
@ -68,7 +68,7 @@ impl<'a, SpeciesMeta: 'a> IntoIterator for &'a AllSpecies<SpeciesMeta> {
make_case_elim!( make_case_elim!(
body_type, body_type,
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
#[repr(u32)] #[repr(u32)]
pub enum BodyType { pub enum BodyType {
Female = 0, Female = 0,

View File

@ -4,7 +4,7 @@ use serde::{Deserialize, Serialize};
make_proj_elim!( make_proj_elim!(
body, body,
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
pub struct Body { pub struct Body {
pub species: Species, pub species: Species,
pub body_type: BodyType, pub body_type: BodyType,
@ -31,7 +31,7 @@ impl From<Body> for super::Body {
make_case_elim!( make_case_elim!(
species, species,
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
#[repr(u32)] #[repr(u32)]
pub enum Species { pub enum Species {
Marlin = 0, Marlin = 0,
@ -71,7 +71,7 @@ impl<'a, SpeciesMeta: 'a> IntoIterator for &'a AllSpecies<SpeciesMeta> {
make_case_elim!( make_case_elim!(
body_type, body_type,
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
#[repr(u32)] #[repr(u32)]
pub enum BodyType { pub enum BodyType {
Female = 0, Female = 0,

View File

@ -4,7 +4,7 @@ use serde::{Deserialize, Serialize};
make_proj_elim!( make_proj_elim!(
body, body,
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
pub struct Body { pub struct Body {
pub species: Species, pub species: Species,
pub body_type: BodyType, pub body_type: BodyType,
@ -31,7 +31,7 @@ impl From<Body> for super::Body {
make_case_elim!( make_case_elim!(
species, species,
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
#[repr(u32)] #[repr(u32)]
pub enum Species { pub enum Species {
Clownfish = 0, Clownfish = 0,
@ -71,7 +71,7 @@ impl<'a, SpeciesMeta: 'a> IntoIterator for &'a AllSpecies<SpeciesMeta> {
make_case_elim!( make_case_elim!(
body_type, body_type,
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
#[repr(u32)] #[repr(u32)]
pub enum BodyType { pub enum BodyType {
Female = 0, Female = 0,

View File

@ -4,7 +4,7 @@ use serde::{Deserialize, Serialize};
make_proj_elim!( make_proj_elim!(
body, body,
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
pub struct Body { pub struct Body {
pub species: Species, pub species: Species,
pub body_type: BodyType, pub body_type: BodyType,
@ -31,7 +31,7 @@ impl From<Body> for super::Body {
make_case_elim!( make_case_elim!(
species, species,
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
#[repr(u32)] #[repr(u32)]
pub enum Species { pub enum Species {
StoneGolem = 0, StoneGolem = 0,
@ -82,7 +82,7 @@ impl<'a, SpeciesMeta: 'a> IntoIterator for &'a AllSpecies<SpeciesMeta> {
make_case_elim!( make_case_elim!(
body_type, body_type,
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
#[repr(u32)] #[repr(u32)]
pub enum BodyType { pub enum BodyType {
Female = 0, Female = 0,

View File

@ -5,7 +5,7 @@ use serde_repr::{Deserialize_repr, Serialize_repr};
make_proj_elim!( make_proj_elim!(
body, body,
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
pub struct Body { pub struct Body {
pub species: Species, pub species: Species,
pub body_type: BodyType, pub body_type: BodyType,
@ -90,7 +90,7 @@ impl From<Body> for super::Body {
make_case_elim!( make_case_elim!(
species, species,
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
#[repr(u32)] #[repr(u32)]
pub enum Species { pub enum Species {
Danari = 0, Danari = 0,
@ -413,7 +413,7 @@ impl Species {
make_case_elim!( make_case_elim!(
body_type, body_type,
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
#[repr(u32)] #[repr(u32)]
pub enum BodyType { pub enum BodyType {
Female = 0, Female = 0,

View File

@ -18,7 +18,7 @@ use vek::Vec3;
make_case_elim!( make_case_elim!(
armor, armor,
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
#[repr(u32)] #[repr(u32)]
pub enum ItemDropArmorKind { pub enum ItemDropArmorKind {
Shoulder = 0, Shoulder = 0,
@ -38,7 +38,7 @@ make_case_elim!(
make_case_elim!( make_case_elim!(
body, body,
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
#[repr(u32)] #[repr(u32)]
pub enum Body { pub enum Body {
Tool(tool: ToolKind) = 0, Tool(tool: ToolKind) = 0,

View File

@ -9,7 +9,7 @@ use vek::Vec3;
make_case_elim!( make_case_elim!(
body, body,
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
#[repr(u32)] #[repr(u32)]
pub enum Body { pub enum Body {
Arrow = 0, Arrow = 0,

View File

@ -5,7 +5,7 @@ use strum::{Display, EnumString};
make_proj_elim!( make_proj_elim!(
body, body,
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
pub struct Body { pub struct Body {
pub species: Species, pub species: Species,
pub body_type: BodyType, pub body_type: BodyType,
@ -35,7 +35,18 @@ impl From<Body> for super::Body {
make_case_elim!( make_case_elim!(
species, species,
#[derive( #[derive(
Copy, Clone, Debug, Display, EnumString, PartialEq, Eq, Hash, Serialize, Deserialize, Copy,
Clone,
Debug,
Display,
EnumString,
PartialEq,
Eq,
PartialOrd,
Ord,
Hash,
Serialize,
Deserialize,
)] )]
#[repr(u32)] #[repr(u32)]
pub enum Species { pub enum Species {
@ -158,7 +169,18 @@ impl<'a, SpeciesMeta: 'a> IntoIterator for &'a AllSpecies<SpeciesMeta> {
make_case_elim!( make_case_elim!(
body_type, body_type,
#[derive( #[derive(
Copy, Clone, Debug, Display, EnumString, PartialEq, Eq, Hash, Serialize, Deserialize, Copy,
Clone,
Debug,
Display,
EnumString,
PartialEq,
Eq,
PartialOrd,
Ord,
Hash,
Serialize,
Deserialize,
)] )]
#[repr(u32)] #[repr(u32)]
pub enum BodyType { pub enum BodyType {

View File

@ -5,7 +5,7 @@ use strum::{Display, EnumString};
make_proj_elim!( make_proj_elim!(
body, body,
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
pub struct Body { pub struct Body {
pub species: Species, pub species: Species,
pub body_type: BodyType, pub body_type: BodyType,
@ -32,7 +32,20 @@ impl From<Body> for super::Body {
// Renaming any enum entries here (re-ordering is fine) will require a // Renaming any enum entries here (re-ordering is fine) will require a
// database migration to ensure pets correctly de-serialize on player login. // database migration to ensure pets correctly de-serialize on player login.
#[derive(Copy, Clone, Debug, Display, EnumString, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(
Copy,
Clone,
Debug,
Display,
EnumString,
PartialEq,
Eq,
PartialOrd,
Ord,
Hash,
Serialize,
Deserialize,
)]
#[repr(u32)] #[repr(u32)]
pub enum Species { pub enum Species {
Grolgar = 0, Grolgar = 0,
@ -213,7 +226,18 @@ impl<'a, SpeciesMeta: 'a> IntoIterator for &'a AllSpecies<SpeciesMeta> {
make_case_elim!( make_case_elim!(
body_type, body_type,
#[derive( #[derive(
Copy, Clone, Debug, Display, EnumString, PartialEq, Eq, Hash, Serialize, Deserialize, Copy,
Clone,
Debug,
Display,
EnumString,
PartialEq,
Eq,
PartialOrd,
Ord,
Hash,
Serialize,
Deserialize,
)] )]
#[repr(u32)] #[repr(u32)]
pub enum BodyType { pub enum BodyType {

View File

@ -5,7 +5,7 @@ use strum::{Display, EnumString};
make_proj_elim!( make_proj_elim!(
body, body,
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
pub struct Body { pub struct Body {
pub species: Species, pub species: Species,
pub body_type: BodyType, pub body_type: BodyType,
@ -32,7 +32,20 @@ impl From<Body> for super::Body {
// Renaming any enum entries here (re-ordering is fine) will require a // Renaming any enum entries here (re-ordering is fine) will require a
// database migration to ensure pets correctly de-serialize on player login. // database migration to ensure pets correctly de-serialize on player login.
#[derive(Copy, Clone, Debug, Display, EnumString, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(
Copy,
Clone,
Debug,
Display,
EnumString,
PartialEq,
Eq,
PartialOrd,
Ord,
Hash,
Serialize,
Deserialize,
)]
#[repr(u32)] #[repr(u32)]
pub enum Species { pub enum Species {
Pig = 0, Pig = 0,
@ -177,7 +190,18 @@ impl<'a, SpeciesMeta: 'a> IntoIterator for &'a AllSpecies<SpeciesMeta> {
make_case_elim!( make_case_elim!(
body_type, body_type,
#[derive( #[derive(
Copy, Clone, Debug, Display, EnumString, PartialEq, Eq, Hash, Serialize, Deserialize, Copy,
Clone,
Debug,
Display,
EnumString,
PartialEq,
Eq,
PartialOrd,
Ord,
Hash,
Serialize,
Deserialize,
)] )]
#[repr(u32)] #[repr(u32)]
pub enum BodyType { pub enum BodyType {

View File

@ -21,7 +21,7 @@ pub const ALL_SHIPS: [Body; 2] = [Body::SailBoat, Body::Galleon];
make_case_elim!( make_case_elim!(
body, body,
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
#[repr(u32)] #[repr(u32)]
pub enum Body { pub enum Body {
DefaultAirship = 0, DefaultAirship = 0,

View File

@ -1,7 +1,7 @@
use rand::{seq::SliceRandom, thread_rng}; use rand::{seq::SliceRandom, thread_rng};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
pub struct Body { pub struct Body {
pub species: Species, pub species: Species,
pub body_type: BodyType, pub body_type: BodyType,
@ -25,7 +25,7 @@ impl From<Body> for super::Body {
fn from(body: Body) -> Self { super::Body::Theropod(body) } fn from(body: Body) -> Self { super::Body::Theropod(body) }
} }
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
#[repr(u32)] #[repr(u32)]
pub enum Species { pub enum Species {
Archaeos = 0, Archaeos = 0,
@ -95,7 +95,7 @@ impl<'a, SpeciesMeta: 'a> IntoIterator for &'a AllSpecies<SpeciesMeta> {
fn into_iter(self) -> Self::IntoIter { ALL_SPECIES.iter().copied() } fn into_iter(self) -> Self::IntoIter { ALL_SPECIES.iter().copied() }
} }
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
#[repr(u32)] #[repr(u32)]
pub enum BodyType { pub enum BodyType {
Female = 0, Female = 0,

View File

@ -13,6 +13,8 @@ use serde::{Deserialize, Serialize};
use specs::{Component, DerefFlaggedStorage, VecStorage}; use specs::{Component, DerefFlaggedStorage, VecStorage};
use strum::EnumIter; use strum::EnumIter;
use super::Body;
/// De/buff Kind. /// De/buff Kind.
/// This is used to determine what effects a buff will have /// This is used to determine what effects a buff will have
#[derive( #[derive(
@ -107,6 +109,8 @@ pub enum BuffKind {
/// Results from drinking a potion. /// Results from drinking a potion.
/// Decreases the health gained from subsequent potions. /// Decreases the health gained from subsequent potions.
PotionSickness, PotionSickness,
// Changed into another body.
Polymorphed(Body),
} }
#[cfg(not(target_arch = "wasm32"))] #[cfg(not(target_arch = "wasm32"))]
@ -136,7 +140,8 @@ impl BuffKind {
| BuffKind::Ensnared | BuffKind::Ensnared
| BuffKind::Poisoned | BuffKind::Poisoned
| BuffKind::Parried | BuffKind::Parried
| BuffKind::PotionSickness => false, | BuffKind::PotionSickness
| BuffKind::Polymorphed(_) => false,
} }
} }
@ -150,149 +155,17 @@ impl BuffKind {
/// Checks if multiple instances of the buff should be processed, instead of /// Checks if multiple instances of the buff should be processed, instead of
/// only the strongest. /// only the strongest.
pub fn stacks(self) -> bool { matches!(self, BuffKind::PotionSickness) } pub fn stacks(self) -> bool { matches!(self, BuffKind::PotionSickness) }
}
// Struct used to store data relevant to a buff pub fn effects(
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)] &self,
pub struct BuffData { data: &BuffData,
pub strength: f32,
pub duration: Option<Secs>,
pub delay: Option<Secs>,
}
#[cfg(not(target_arch = "wasm32"))]
impl BuffData {
pub fn new(strength: f32, duration: Option<Secs>, delay: Option<Secs>) -> Self {
Self {
strength,
duration,
delay,
}
}
}
/// De/buff category ID.
/// Similar to `BuffKind`, but to mark a category (for more generic usage, like
/// positive/negative buffs).
#[derive(Clone, Copy, Eq, PartialEq, Debug, Serialize, Deserialize)]
pub enum BuffCategory {
Natural,
Physical,
Magical,
Divine,
PersistOnDeath,
FromActiveAura(Uid, AuraKey),
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub enum ModifierKind {
Additive,
Fractional,
}
/// Data indicating and configuring behaviour of a de/buff.
#[derive(Clone, Debug, Serialize, Deserialize)]
pub enum BuffEffect {
/// Periodically damages or heals entity
HealthChangeOverTime {
rate: f32,
kind: ModifierKind,
instance: u64,
},
/// Periodically consume entity energy
EnergyChangeOverTime { rate: f32, kind: ModifierKind },
/// Changes maximum health by a certain amount
MaxHealthModifier { value: f32, kind: ModifierKind },
/// Changes maximum energy by a certain amount
MaxEnergyModifier { value: f32, kind: ModifierKind },
/// Reduces damage after armor is accounted for by this fraction
DamageReduction(f32),
/// Gradually changes an entities max health over time
MaxHealthChangeOverTime {
rate: f32,
kind: ModifierKind,
target_fraction: f32,
},
/// Modifies move speed of target
MovementSpeed(f32),
/// Modifies attack speed of target
AttackSpeed(f32),
/// Modifies ground friction of target
GroundFriction(f32),
/// Reduces poise damage taken after armor is accounted for by this fraction
PoiseReduction(f32),
/// Reduces amount healed by consumables
HealReduction(f32),
/// Increases poise damage dealt when health is lost
PoiseDamageFromLostHealth { initial_health: f32, strength: f32 },
/// Modifier to the amount of damage dealt with attacks
AttackDamage(f32),
/// Multiplies crit chance of attacks
CriticalChance(f32),
}
/// Actual de/buff.
/// Buff can timeout after some time if `time` is Some. If `time` is None,
/// Buff will last indefinitely, until removed manually (by some action, like
/// uncursing).
///
/// Buff has a kind, which is used to determine the effects in a builder
/// function.
///
/// To provide more classification info when needed,
/// buff can be in one or more buff category.
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct Buff {
pub kind: BuffKind,
pub data: BuffData,
pub cat_ids: Vec<BuffCategory>,
pub end_time: Option<Time>,
pub start_time: Time,
pub effects: Vec<BuffEffect>,
pub source: BuffSource,
}
/// Information about whether buff addition or removal was requested.
/// This to implement "on_add" and "on_remove" hooks for constant buffs.
#[derive(Clone, Debug)]
pub enum BuffChange {
/// Adds this buff.
Add(Buff),
/// Removes all buffs with this ID.
RemoveByKind(BuffKind),
/// Removes all buffs with this ID, but not debuffs.
RemoveFromController(BuffKind),
/// Removes buffs of these indices (first vec is for active buffs, second is
/// for inactive buffs), should only be called when buffs expire
RemoveById(Vec<BuffId>),
/// Removes buffs of these categories (first vec is of categories of which
/// all are required, second vec is of categories of which at least one is
/// required, third vec is of categories that will not be removed)
RemoveByCategory {
all_required: Vec<BuffCategory>,
any_required: Vec<BuffCategory>,
none_required: Vec<BuffCategory>,
},
// Refreshes durations of all buffs with this kind
Refresh(BuffKind),
}
#[cfg(not(target_arch = "wasm32"))]
impl Buff {
/// Builder function for buffs
pub fn new(
kind: BuffKind,
data: BuffData,
cat_ids: Vec<BuffCategory>,
source: BuffSource,
time: Time,
stats: Option<&Stats>, stats: Option<&Stats>,
health: Option<&Health>, health: Option<&Health>,
) -> Self { ) -> Vec<BuffEffect> {
// Normalized nonlinear scaling // Normalized nonlinear scaling
let nn_scaling = |a| a / (a + 0.5); let nn_scaling = |a| a / (a + 0.5);
let instance = rand::random(); let instance = rand::random();
let effects = match kind { match self {
BuffKind::Bleeding => vec![BuffEffect::HealthChangeOverTime { BuffKind::Bleeding => vec![BuffEffect::HealthChangeOverTime {
rate: -data.strength, rate: -data.strength,
kind: ModifierKind::Additive, kind: ModifierKind::Additive,
@ -397,7 +270,151 @@ impl Buff {
BuffEffect::DamageReduction(-data.strength), BuffEffect::DamageReduction(-data.strength),
BuffEffect::AttackDamage(1.0 + data.strength), BuffEffect::AttackDamage(1.0 + data.strength),
], ],
}; BuffKind::Polymorphed(body) => vec![BuffEffect::BodyChange(*body)],
}
}
}
// Struct used to store data relevant to a buff
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
pub struct BuffData {
pub strength: f32,
pub duration: Option<Secs>,
pub delay: Option<Secs>,
}
#[cfg(not(target_arch = "wasm32"))]
impl BuffData {
pub fn new(strength: f32, duration: Option<Secs>, delay: Option<Secs>) -> Self {
Self {
strength,
duration,
delay,
}
}
}
/// De/buff category ID.
/// Similar to `BuffKind`, but to mark a category (for more generic usage, like
/// positive/negative buffs).
#[derive(Clone, Copy, Eq, PartialEq, Debug, Serialize, Deserialize)]
pub enum BuffCategory {
Natural,
Physical,
Magical,
Divine,
PersistOnDeath,
FromActiveAura(Uid, AuraKey),
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub enum ModifierKind {
Additive,
Fractional,
}
/// Data indicating and configuring behaviour of a de/buff.
#[derive(Clone, Debug, Serialize, Deserialize)]
pub enum BuffEffect {
/// Periodically damages or heals entity
HealthChangeOverTime {
rate: f32,
kind: ModifierKind,
instance: u64,
},
/// Periodically consume entity energy
EnergyChangeOverTime { rate: f32, kind: ModifierKind },
/// Changes maximum health by a certain amount
MaxHealthModifier { value: f32, kind: ModifierKind },
/// Changes maximum energy by a certain amount
MaxEnergyModifier { value: f32, kind: ModifierKind },
/// Reduces damage after armor is accounted for by this fraction
DamageReduction(f32),
/// Gradually changes an entities max health over time
MaxHealthChangeOverTime {
rate: f32,
kind: ModifierKind,
target_fraction: f32,
},
/// Modifies move speed of target
MovementSpeed(f32),
/// Modifies attack speed of target
AttackSpeed(f32),
/// Modifies ground friction of target
GroundFriction(f32),
/// Reduces poise damage taken after armor is accounted for by this fraction
PoiseReduction(f32),
/// Reduces amount healed by consumables
HealReduction(f32),
/// Increases poise damage dealt when health is lost
PoiseDamageFromLostHealth { initial_health: f32, strength: f32 },
/// Modifier to the amount of damage dealt with attacks
AttackDamage(f32),
/// Multiplies crit chance of attacks
CriticalChance(f32),
/// Changes body.
BodyChange(Body),
}
/// Actual de/buff.
/// Buff can timeout after some time if `time` is Some. If `time` is None,
/// Buff will last indefinitely, until removed manually (by some action, like
/// uncursing).
///
/// Buff has a kind, which is used to determine the effects in a builder
/// function.
///
/// To provide more classification info when needed,
/// buff can be in one or more buff category.
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct Buff {
pub kind: BuffKind,
pub data: BuffData,
pub cat_ids: Vec<BuffCategory>,
pub end_time: Option<Time>,
pub start_time: Time,
pub effects: Vec<BuffEffect>,
pub source: BuffSource,
}
/// Information about whether buff addition or removal was requested.
/// This to implement "on_add" and "on_remove" hooks for constant buffs.
#[derive(Clone, Debug)]
pub enum BuffChange {
/// Adds this buff.
Add(Buff),
/// Removes all buffs with this ID.
RemoveByKind(BuffKind),
/// Removes all buffs with this ID, but not debuffs.
RemoveFromController(BuffKind),
/// Removes buffs of these indices (first vec is for active buffs, second is
/// for inactive buffs), should only be called when buffs expire
RemoveById(Vec<BuffId>),
/// Removes buffs of these categories (first vec is of categories of which
/// all are required, second vec is of categories of which at least one is
/// required, third vec is of categories that will not be removed)
RemoveByCategory {
all_required: Vec<BuffCategory>,
any_required: Vec<BuffCategory>,
none_required: Vec<BuffCategory>,
},
// Refreshes durations of all buffs with this kind
Refresh(BuffKind),
}
#[cfg(not(target_arch = "wasm32"))]
impl Buff {
/// Builder function for buffs
pub fn new(
kind: BuffKind,
data: BuffData,
cat_ids: Vec<BuffCategory>,
source: BuffSource,
time: Time,
stats: Option<&Stats>,
health: Option<&Health>,
) -> Self {
let effects = kind.effects(&data, stats, health);
let start_time = Time(time.0 + data.delay.map_or(0.0, |delay| delay.0)); let start_time = Time(time.0 + data.delay.map_or(0.0, |delay| delay.0));
let end_time = if cat_ids let end_time = if cat_ids
.iter() .iter()

View File

@ -265,6 +265,23 @@ impl TagExampleInfo for ItemTag {
} }
} }
#[derive(Clone, Debug, Serialize, Deserialize)]
pub enum Effects {
Any(Vec<Effect>),
All(Vec<Effect>),
One(Effect),
}
impl Effects {
pub fn effects(&self) -> &[Effect] {
match self {
Effects::Any(effects) => effects,
Effects::All(effects) => effects,
Effects::One(effect) => std::slice::from_ref(effect),
}
}
}
#[derive(Clone, Debug, Serialize, Deserialize)] #[derive(Clone, Debug, Serialize, Deserialize)]
pub enum ItemKind { pub enum ItemKind {
/// Something wieldable /// Something wieldable
@ -275,7 +292,7 @@ pub enum ItemKind {
Glider, Glider,
Consumable { Consumable {
kind: ConsumableKind, kind: ConsumableKind,
effects: Vec<Effect>, effects: Effects,
}, },
Throwable { Throwable {
kind: Throwable, kind: Throwable,

View File

@ -1046,6 +1046,7 @@ impl TradePricing {
} else if let ItemKind::Consumable { kind: _, effects } = &*i.kind() { } else if let ItemKind::Consumable { kind: _, effects } = &*i.kind() {
( (
effects effects
.effects()
.iter() .iter()
.map(|e| { .map(|e| {
if let crate::effect::Effect::Buff(b) = e { if let crate::effect::Effect::Buff(b) = e {

View File

@ -2,6 +2,8 @@ use serde::{Deserialize, Serialize};
use specs::{Component, DerefFlaggedStorage}; use specs::{Component, DerefFlaggedStorage};
use std::{error::Error, fmt}; use std::{error::Error, fmt};
use super::Body;
#[derive(Debug)] #[derive(Debug)]
#[allow(dead_code)] // TODO: remove once trade sim hits master #[allow(dead_code)] // TODO: remove once trade sim hits master
pub enum StatChangeError { pub enum StatChangeError {
@ -48,6 +50,7 @@ impl Error for StatChangeError {}
#[derive(Clone, Debug, Serialize, Deserialize)] #[derive(Clone, Debug, Serialize, Deserialize)]
pub struct Stats { pub struct Stats {
pub name: String, pub name: String,
pub original_body: Body,
pub damage_reduction: f32, pub damage_reduction: f32,
pub poise_reduction: f32, pub poise_reduction: f32,
pub heal_multiplier: f32, pub heal_multiplier: f32,
@ -62,9 +65,10 @@ pub struct Stats {
} }
impl Stats { impl Stats {
pub fn new(name: String) -> Self { pub fn new(name: String, body: Body) -> Self {
Self { Self {
name, name,
original_body: body,
damage_reduction: 0.0, damage_reduction: 0.0,
poise_reduction: 0.0, poise_reduction: 0.0,
heal_multiplier: 1.0, heal_multiplier: 1.0,
@ -81,12 +85,14 @@ impl Stats {
/// Creates an empty `Stats` instance - used during character loading from /// Creates an empty `Stats` instance - used during character loading from
/// the database /// the database
pub fn empty() -> Self { Self::new("".to_string()) } pub fn empty(body: Body) -> Self { Self::new("".to_string(), body) }
/// Resets temporary modifiers to default values /// Resets temporary modifiers to default values
pub fn reset_temp_modifiers(&mut self) { pub fn reset_temp_modifiers(&mut self) {
// TODO: Figure out how to avoid clone let name = std::mem::take(&mut self.name);
*self = Self::new(self.name.clone()); let body = self.original_body;
*self = Self::new(name, body);
} }
} }

View File

@ -111,7 +111,7 @@ impl CharacterBehavior for Data {
} }
}; };
let stats = comp::Stats::new("Summon".to_string()); let stats = comp::Stats::new("Summon".to_string(), body);
let health = self.static_data.summon_info.has_health.then(|| { let health = self.static_data.summon_info.has_health.then(|| {
let health_level = skill_set let health_level = skill_set

View File

@ -125,10 +125,11 @@ impl<'a> System<'a> for Sys {
} }
} }
for (entity, buff_comp, mut stat, health, energy, physics_state) in ( for (entity, buff_comp, mut stat, mut body, health, energy, physics_state) in (
&read_data.entities, &read_data.entities,
&read_data.buffs, &read_data.buffs,
&mut stats, &mut stats,
&mut bodies,
&read_data.healths, &read_data.healths,
&read_data.energies, &read_data.energies,
read_data.physics_states.maybe(), read_data.physics_states.maybe(),
@ -330,6 +331,8 @@ impl<'a> System<'a> for Sys {
// Call to reset stats to base values // Call to reset stats to base values
stat.reset_temp_modifiers(); stat.reset_temp_modifiers();
let mut body_override = stat.original_body;
// Iterator over the lists of buffs by kind // Iterator over the lists of buffs by kind
let mut buff_kinds = buff_comp let mut buff_kinds = buff_comp
.kinds .kinds
@ -368,6 +371,7 @@ impl<'a> System<'a> for Sys {
kind_start_time, kind_start_time,
&read_data, &read_data,
&mut stat, &mut stat,
&mut body_override,
health, health,
energy, energy,
entity, entity,
@ -382,6 +386,11 @@ impl<'a> System<'a> for Sys {
} }
} }
// Update body if needed.
if body_override != *body {
*body = body_override;
}
// Remove buffs that expire // Remove buffs that expire
if !expired_buffs.is_empty() { if !expired_buffs.is_empty() {
server_emitter.emit(ServerEvent::Buff { server_emitter.emit(ServerEvent::Buff {
@ -414,6 +423,7 @@ fn execute_effect(
buff_kind_start_time: Time, buff_kind_start_time: Time,
read_data: &ReadData, read_data: &ReadData,
stat: &mut Stats, stat: &mut Stats,
body_override: &mut Body,
health: &Health, health: &Health,
energy: &Energy, energy: &Energy,
entity: Entity, entity: Entity,
@ -592,5 +602,6 @@ fn execute_effect(
BuffEffect::CriticalChance(cc) => { BuffEffect::CriticalChance(cc) => {
stat.crit_chance_modifier *= *cc; stat.crit_chance_modifier *= *cc;
}, },
BuffEffect::BodyChange(b) => *body_override = *b,
}; };
} }

View File

@ -69,7 +69,7 @@ mod tests {
.with(Poise::new(body)) .with(Poise::new(body))
.with(skill_set) .with(skill_set)
.with(PhysicsState::default()) .with(PhysicsState::default())
.with(Stats::empty()) .with(Stats::empty(body))
.with(Uid(1)) .with(Uid(1))
.build() .build()
} }

View File

@ -133,7 +133,7 @@ pub fn create_player(state: &mut State) -> Entity {
)) ))
.with(Health::new(body, body.base_health())) .with(Health::new(body, body.base_health()))
.with(skill_set) .with(skill_set)
.with(Stats::empty()) .with(Stats::empty(body))
.build() .build()
} }

View File

@ -15,11 +15,10 @@ use common::{
comp::{ comp::{
self, self,
agent::{Sound, SoundKind, Target}, agent::{Sound, SoundKind, Target},
buff::BuffKind,
inventory::slot::EquipSlot, inventory::slot::EquipSlot,
item::{ item::{
tool::{AbilitySpec, ToolKind}, tool::{AbilitySpec, ToolKind},
ConsumableKind, Item, ItemDesc, ItemKind, ConsumableKind, Effects, Item, ItemDesc, ItemKind,
}, },
item_drop, item_drop,
projectile::ProjectileConstructor, projectile::ProjectileConstructor,
@ -541,39 +540,74 @@ impl<'a> AgentData<'a> {
if heal_multiplier < 0.5 { if heal_multiplier < 0.5 {
return false; return false;
} }
// (healing_value, heal_reduction)
let effect_healing_value = |effect: &Effect| -> (f32, f32) {
let mut value = 0.0;
let mut heal_reduction = 0.0;
match effect {
Effect::Health(HealthChange { amount, .. }) => {
value += *amount;
},
Effect::Buff(BuffEffect { kind, data, .. }) => {
if let Some(duration) = data.duration {
for effect in kind.effects(data, self.stats, self.health) {
match effect {
comp::BuffEffect::HealthChangeOverTime { rate, kind, .. } => {
let amount = match kind {
comp::ModifierKind::Additive => rate * duration.0 as f32,
comp::ModifierKind::Fractional => {
(1.0 + rate).powf(duration.0 as f32)
},
};
value += amount;
},
comp::BuffEffect::HealReduction(amount) => {
heal_reduction =
heal_reduction + amount - heal_reduction * amount;
},
_ => {},
}
}
value += data.strength * data.duration.map_or(0.0, |d| d.0 as f32);
}
},
_ => {},
}
(value, heal_reduction)
};
let healing_value = |item: &Item| { let healing_value = |item: &Item| {
let mut value = 0.0; let mut value = 0.0;
let mut causes_potion_sickness = false; let mut heal_multiplier_value = 1.0;
if let ItemKind::Consumable { kind, effects, .. } = &*item.kind() { if let ItemKind::Consumable { kind, effects, .. } = &*item.kind() {
if matches!(kind, ConsumableKind::Drink) if matches!(kind, ConsumableKind::Drink)
|| (relaxed && matches!(kind, ConsumableKind::Food)) || (relaxed && matches!(kind, ConsumableKind::Food))
{ {
match effects {
Effects::Any(effects) => {
// Add the average of all effects.
for effect in effects.iter() { for effect in effects.iter() {
use BuffKind::*; let (add, red) = effect_healing_value(effect);
match effect { value += add / effects.len() as f32;
Effect::Health(HealthChange { amount, .. }) => { heal_multiplier_value *= 1.0 - red / effects.len() as f32;
value += *amount;
},
Effect::Buff(BuffEffect { kind, data, .. })
if matches!(kind, Regeneration | Saturation | Potion) =>
{
value += data.strength * data.duration.map_or(0.0, |d| d.0 as f32);
},
Effect::Buff(BuffEffect { kind, .. })
if matches!(kind, PotionSickness) =>
{
causes_potion_sickness = true;
},
_ => {},
} }
},
Effects::All(_) | Effects::One(_) => {
for effect in effects.effects() {
let (add, red) = effect_healing_value(effect);
value += add;
heal_multiplier_value *= 1.0 - red;
}
},
} }
} }
} }
// Prefer non-potion sources of healing when under at least one stack of potion // Prefer non-potion sources of healing when under at least one stack of potion
// sickness, or when incurring potion sickness is unnecessary // sickness, or when incurring potion sickness is unnecessary
if causes_potion_sickness && (heal_multiplier < 1.0 || relaxed) { if heal_multiplier_value < 1.0 && (heal_multiplier < 1.0 || relaxed) {
value *= 0.1; value *= 0.1;
} }
value as i32 value as i32

View File

@ -51,7 +51,7 @@ pub fn create_character(
.active_offhand(character_offhand.map(|x| Item::new_from_asset_expect(&x))) .active_offhand(character_offhand.map(|x| Item::new_from_asset_expect(&x)))
.build(); .build();
let mut inventory = Inventory::with_loadout_humanoid(loadout); let mut inventory = Inventory::with_loadout_humanoid(loadout);
let stats = Stats::new(character_alias.to_string()); let stats = Stats::new(character_alias.to_string(), body);
let skill_set = SkillSet::default(); let skill_set = SkillSet::default();
// Default items for new characters // Default items for new characters
inventory inventory

View File

@ -1220,7 +1220,7 @@ fn handle_spawn(
.state .state
.create_npc( .create_npc(
pos, pos,
comp::Stats::new(get_npc_name(id, npc::BodyType::from_body(body))), comp::Stats::new(get_npc_name(id, npc::BodyType::from_body(body)), body),
comp::SkillSet::default(), comp::SkillSet::default(),
Some(comp::Health::new(body, 0)), Some(comp::Health::new(body, 0)),
comp::Poise::new(body), comp::Poise::new(body),
@ -1294,7 +1294,7 @@ fn handle_spawn_training_dummy(
let body = comp::Body::Object(comp::object::Body::TrainingDummy); let body = comp::Body::Object(comp::object::Body::TrainingDummy);
let stats = comp::Stats::new("Training Dummy".to_string()); let stats = comp::Stats::new("Training Dummy".to_string(), body);
let skill_set = comp::SkillSet::default(); let skill_set = comp::SkillSet::default();
let health = comp::Health::new(body, 0); let health = comp::Health::new(body, 0);
let poise = comp::Poise::new(body); let poise = comp::Poise::new(body);
@ -3823,6 +3823,15 @@ fn handle_body(
insert_or_replace_component(server, target, body.mass(), "mass")?; insert_or_replace_component(server, target, body.mass(), "mass")?;
insert_or_replace_component(server, target, body.density(), "density")?; insert_or_replace_component(server, target, body.density(), "density")?;
insert_or_replace_component(server, target, body.collider(), "collider")?; insert_or_replace_component(server, target, body.collider(), "collider")?;
if let Some(mut stat) = server
.state
.ecs_mut()
.write_storage::<comp::Stats>()
.get_mut(target)
{
stat.original_body = body;
}
Ok(()) Ok(())
} else { } else {
Err(action.help_string()) Err(action.help_string())

View File

@ -1,5 +1,5 @@
use hashbrown::HashSet; use hashbrown::HashSet;
use rand::Rng; use rand::{seq::IteratorRandom, Rng};
use specs::{join::Join, world::WorldExt, Builder, Entity as EcsEntity, WriteStorage}; use specs::{join::Join, world::WorldExt, Builder, Entity as EcsEntity, WriteStorage};
use tracing::{debug, error, warn}; use tracing::{debug, error, warn};
use vek::{Rgb, Vec3}; use vek::{Rgb, Vec3};
@ -542,9 +542,21 @@ pub fn handle_inventory(server: &mut Server, entity: EcsEntity, manip: comp::Inv
drop(inventories); drop(inventories);
if let Some(effects) = maybe_effect { if let Some(effects) = maybe_effect {
match effects {
item::Effects::Any(effects) => {
if let Some(effect) = effects.into_iter().choose(&mut rand::thread_rng()) {
state.apply_effect(entity, effect, None);
}
},
item::Effects::All(effects) => {
for effect in effects { for effect in effects {
state.apply_effect(entity, effect, None); state.apply_effect(entity, effect, None);
} }
},
item::Effects::One(effect) => {
state.apply_effect(entity, effect, None);
},
}
} }
if let Some(event) = event { if let Some(event) = event {
state state
@ -950,7 +962,10 @@ pub fn handle_inventory(server: &mut Server, entity: EcsEntity, manip: comp::Inv
}); });
}, },
item::Throwable::TrainingDummy => { item::Throwable::TrainingDummy => {
new_entity = new_entity.with(comp::Stats::new("Training Dummy".to_string())); new_entity = new_entity.with(comp::Stats::new(
"Training Dummy".to_string(),
Body::Object(common::comp::object::Body::TrainingDummy),
));
}, },
}; };

View File

@ -231,7 +231,7 @@ pub fn load_character_data(
let pet = comp::Pet::new_from_database( let pet = comp::Pet::new_from_database(
NonZeroU64::new(db_pet.database_id as u64).unwrap(), NonZeroU64::new(db_pet.database_id as u64).unwrap(),
); );
let pet_stats = comp::Stats::new(db_pet.name.to_owned()); let pet_stats = comp::Stats::new(db_pet.name.to_owned(), pet_body);
Some((pet, pet_body, pet_stats)) Some((pet, pet_body, pet_stats))
} else { } else {
warn!( warn!(
@ -259,10 +259,11 @@ pub fn load_character_data(
let (skill_set, skill_set_persistence_load_error) = let (skill_set, skill_set_persistence_load_error) =
convert_skill_set_from_database(&skill_group_data); convert_skill_set_from_database(&skill_group_data);
let body = convert_body_from_database(&body_data.variant, &body_data.body_data)?;
Ok(( Ok((
PersistedComponents { PersistedComponents {
body: convert_body_from_database(&body_data.variant, &body_data.body_data)?, body,
stats: convert_stats_from_database(character_data.alias), stats: convert_stats_from_database(character_data.alias, body),
skill_set, skill_set,
inventory: convert_inventory_from_database_items( inventory: convert_inventory_from_database_items(
character_containers.inventory_container_id, character_containers.inventory_container_id,

View File

@ -600,8 +600,8 @@ pub fn convert_character_from_database(character: &Character) -> common::charact
} }
} }
pub fn convert_stats_from_database(alias: String) -> Stats { pub fn convert_stats_from_database(alias: String, body: Body) -> Stats {
let mut new_stats = Stats::empty(); let mut new_stats = Stats::empty(body);
new_stats.name = alias; new_stats.name = alias;
new_stats new_stats
} }

View File

@ -356,7 +356,7 @@ impl StateExt for State {
// TODO: some of these are required in order for the character_behavior system to // TODO: some of these are required in order for the character_behavior system to
// recognize a possesed airship; that system should be refactored to use `.maybe()` // recognize a possesed airship; that system should be refactored to use `.maybe()`
.with(comp::Energy::new(ship.into(), 0)) .with(comp::Energy::new(ship.into(), 0))
.with(comp::Stats::new("Airship".to_string())) .with(comp::Stats::new("Airship".to_string(), body))
.with(comp::SkillSet::default()) .with(comp::SkillSet::default())
.with(comp::ActiveAbilities::default()) .with(comp::ActiveAbilities::default())
.with(comp::Combo::default()); .with(comp::Combo::default());

View File

@ -454,7 +454,7 @@ impl NpcData {
} }
let name = name.unwrap_or_else(|| "Unnamed".to_string()); let name = name.unwrap_or_else(|| "Unnamed".to_string());
let stats = comp::Stats::new(name); let stats = comp::Stats::new(name, body);
let skill_set = { let skill_set = {
let skillset_builder = SkillSetBuilder::default(); let skillset_builder = SkillSetBuilder::default();

View File

@ -111,7 +111,8 @@ pub fn localize_chat_message(
| BuffKind::Ensnared | BuffKind::Ensnared
| BuffKind::Poisoned | BuffKind::Poisoned
| BuffKind::Parried | BuffKind::Parried
| BuffKind::PotionSickness => { | BuffKind::PotionSickness
| BuffKind::Polymorphed(_) => {
tracing::error!("Player was killed by a debuff that doesn't do damage!"); tracing::error!("Player was killed by a debuff that doesn't do damage!");
"hud-outcome-mysterious" "hud-outcome-mysterious"
}, },

View File

@ -531,6 +531,15 @@ impl MusicMgr {
soundtrack.tracks.push(track) soundtrack.tracks.push(track)
} }
}, },
_ => {
for track in SoundtrackCollection::load_expect("voxygen.audio.soundtrack")
.read()
.tracks
.clone()
{
soundtrack.tracks.push(track)
}
},
} }
} }
} }
@ -615,6 +624,7 @@ mod tests {
"voxygen.audio.calendar.christmas.soundtrack", "voxygen.audio.calendar.christmas.soundtrack",
); );
}, },
_ => {},
} }
} }
} }

View File

@ -754,6 +754,7 @@ image_ids! {
debuff_poisoned_0: "voxygen.element.de_buffs.debuff_poisoned_0", debuff_poisoned_0: "voxygen.element.de_buffs.debuff_poisoned_0",
debuff_parried_0: "voxygen.element.de_buffs.debuff_parried_0", debuff_parried_0: "voxygen.element.de_buffs.debuff_parried_0",
debuff_potionsickness_0: "voxygen.element.de_buffs.debuff_potionsickness_0", debuff_potionsickness_0: "voxygen.element.de_buffs.debuff_potionsickness_0",
debuff_polymorphed: "voxygen.element.de_buffs.debuff_polymorphed",
// Animation Frames // Animation Frames
// Buff Frame // Buff Frame

View File

@ -4946,6 +4946,7 @@ pub fn get_buff_image(buff: BuffKind, imgs: &Imgs) -> conrod_core::image::Id {
BuffKind::Poisoned => imgs.debuff_poisoned_0, BuffKind::Poisoned => imgs.debuff_poisoned_0,
BuffKind::Parried => imgs.debuff_parried_0, BuffKind::Parried => imgs.debuff_parried_0,
BuffKind::PotionSickness => imgs.debuff_potionsickness_0, BuffKind::PotionSickness => imgs.debuff_potionsickness_0,
BuffKind::Polymorphed(_) => imgs.debuff_polymorphed,
} }
} }
@ -4980,6 +4981,7 @@ pub fn get_buff_title(buff: BuffKind, localized_strings: &Localization) -> Cow<s
BuffKind::Poisoned { .. } => localized_strings.get_msg("buff-title-poisoned"), BuffKind::Poisoned { .. } => localized_strings.get_msg("buff-title-poisoned"),
BuffKind::Parried { .. } => localized_strings.get_msg("buff-title-parried"), BuffKind::Parried { .. } => localized_strings.get_msg("buff-title-parried"),
BuffKind::PotionSickness { .. } => localized_strings.get_msg("buff-title-potionsickness"), BuffKind::PotionSickness { .. } => localized_strings.get_msg("buff-title-potionsickness"),
BuffKind::Polymorphed { .. } => localized_strings.get_msg("buff-title-polymorphed"),
} }
} }
@ -5018,6 +5020,7 @@ pub fn get_buff_desc(buff: BuffKind, data: BuffData, localized_strings: &Localiz
BuffKind::Poisoned { .. } => localized_strings.get_msg("buff-desc-poisoned"), BuffKind::Poisoned { .. } => localized_strings.get_msg("buff-desc-poisoned"),
BuffKind::Parried { .. } => localized_strings.get_msg("buff-desc-parried"), BuffKind::Parried { .. } => localized_strings.get_msg("buff-desc-parried"),
BuffKind::PotionSickness { .. } => localized_strings.get_msg("buff-desc-potionsickness"), BuffKind::PotionSickness { .. } => localized_strings.get_msg("buff-desc-potionsickness"),
BuffKind::Polymorphed { .. } => localized_strings.get_msg("buff-desc-polymorphed"),
} }
} }

View File

@ -5,7 +5,7 @@ use common::{
item::{ item::{
armor::{Armor, ArmorKind, Protection}, armor::{Armor, ArmorKind, Protection},
tool::{Hands, Tool, ToolKind}, tool::{Hands, Tool, ToolKind},
ItemDefinitionId, ItemDesc, ItemKind, MaterialKind, MaterialStatManifest, Effects, ItemDefinitionId, ItemDesc, ItemKind, MaterialKind, MaterialStatManifest,
}, },
BuffKind, BuffKind,
}, },
@ -112,7 +112,10 @@ pub fn stats_count(item: &dyn ItemDesc, msm: &MaterialStatManifest) -> usize {
+ (item.num_slots() > 0) as usize + (item.num_slots() > 0) as usize
}, },
ItemKind::Tool(_) => 7, ItemKind::Tool(_) => 7,
ItemKind::Consumable { effects, .. } => effects.len(), ItemKind::Consumable { effects, .. } => match effects {
Effects::Any(_) | Effects::One(_) => 1,
Effects::All(effects) => effects.len(),
},
ItemKind::ModularComponent { .. } => 7, ItemKind::ModularComponent { .. } => 7,
_ => 0, _ => 0,
} }
@ -138,10 +141,14 @@ pub fn line_count(item: &dyn ItemDesc, msm: &MaterialStatManifest, i18n: &Locali
/// ///
/// FIXME: handle which effects should have description in `stats_count` /// FIXME: handle which effects should have description in `stats_count`
/// to not waste space in item box /// to not waste space in item box
pub fn consumable_desc(effects: &[Effect], i18n: &Localization) -> Vec<String> { pub fn consumable_desc(effects: &Effects, i18n: &Localization) -> Vec<String> {
let mut descriptions = Vec::new(); let mut descriptions = Vec::new();
match effects {
for effect in effects { Effects::Any(_) => {
descriptions.push(i18n.get_msg("buff-mysterious").into_owned());
},
Effects::All(_) | Effects::One(_) => {
for effect in effects.effects() {
let mut description = String::new(); let mut description = String::new();
if let Effect::Buff(buff) = effect { if let Effect::Buff(buff) = effect {
let strength = buff.data.strength; let strength = buff.data.strength;
@ -191,21 +198,26 @@ pub fn consumable_desc(effects: &[Effect], i18n: &Localization) -> Vec<String> {
| BuffKind::Hastened | BuffKind::Hastened
| BuffKind::Fortitude | BuffKind::Fortitude
| BuffKind::Parried | BuffKind::Parried
| BuffKind::Reckless => Cow::Borrowed(""), | BuffKind::Reckless
| BuffKind::Polymorphed(_) => Cow::Borrowed(""),
}; };
write!(&mut description, "{}", buff_desc).unwrap(); write!(&mut description, "{}", buff_desc).unwrap();
let dur_desc = if let Some(dur_secs) = dur_secs { let dur_desc = if let Some(dur_secs) = dur_secs {
match buff.kind { match buff.kind {
BuffKind::Saturation | BuffKind::Regeneration | BuffKind::EnergyRegen => i18n BuffKind::Saturation
.get_msg_ctx("buff-text-over_seconds", &i18n::fluent_args! { | BuffKind::Regeneration
| BuffKind::EnergyRegen => {
i18n.get_msg_ctx("buff-text-over_seconds", &i18n::fluent_args! {
"dur_secs" => dur_secs "dur_secs" => dur_secs
}), })
},
BuffKind::IncreaseMaxEnergy BuffKind::IncreaseMaxEnergy
| BuffKind::IncreaseMaxHealth | BuffKind::IncreaseMaxHealth
| BuffKind::Invulnerability | BuffKind::Invulnerability
| BuffKind::PotionSickness => { | BuffKind::PotionSickness
| BuffKind::Polymorphed(_) => {
i18n.get_msg_ctx("buff-text-for_seconds", &i18n::fluent_args! { i18n.get_msg_ctx("buff-text-for_seconds", &i18n::fluent_args! {
"dur_secs" => dur_secs "dur_secs" => dur_secs
}) })
@ -227,8 +239,9 @@ pub fn consumable_desc(effects: &[Effect], i18n: &Localization) -> Vec<String> {
| BuffKind::Parried | BuffKind::Parried
| BuffKind::Reckless => Cow::Borrowed(""), | BuffKind::Reckless => Cow::Borrowed(""),
} }
} else if let BuffKind::Saturation | BuffKind::Regeneration | BuffKind::EnergyRegen = } else if let BuffKind::Saturation
buff.kind | BuffKind::Regeneration
| BuffKind::EnergyRegen = buff.kind
{ {
i18n.get_msg("buff-text-every_second") i18n.get_msg("buff-text-every_second")
} else { } else {
@ -239,7 +252,8 @@ pub fn consumable_desc(effects: &[Effect], i18n: &Localization) -> Vec<String> {
} }
descriptions.push(description); descriptions.push(description);
} }
},
}
descriptions descriptions
} }

View File

@ -1375,6 +1375,41 @@ impl ParticleMgr {
}, },
); );
}, },
BuffKind::Polymorphed(_) => {
let mut multiplicity = 0;
// Only show particles for polymorph at the beginning, after the
// drinking animation finishes
if buff_ids.0
.iter()
.filter_map(|id| buffs.buffs.get(id))
.any(|buff| {
matches!(buff.elapsed(Time(time)), dur if (0.1..=0.3).contains(&dur.0))
})
{
multiplicity = 1;
}
self.particles.resize_with(
self.particles.len()
+ multiplicity
* self.scheduler.heartbeats(Duration::from_millis(3)) as usize,
|| {
let start_pos = pos + Vec3::unit_z() * body.eye_height() / 2.0;
let end_pos = start_pos
+ Vec3::<f32>::zero()
.map(|_| rng.gen_range(-1.0..1.0))
.normalized()
* 5.0;
Particle::new_directed(
Duration::from_secs(2),
time,
ParticleMode::Explosion,
start_pos,
end_pos,
)
},
)
},
_ => {}, _ => {},
} }
} }

View File

@ -171,6 +171,10 @@ pub fn spawn_manifest() -> Vec<(&'static str, DensityFn)> {
"world.wildlife.spawn.calendar.halloween.tundra.core", "world.wildlife.spawn.calendar.halloween.tundra.core",
|c, _col| close(c.temp, CONFIG.snow_temp, 0.15) * BASE_DENSITY * 0.5, |c, _col| close(c.temp, CONFIG.snow_temp, 0.15) * BASE_DENSITY * 0.5,
), ),
(
"world.wildlife.spawn.calendar.april_fools.tundra.core",
|c, _col| close(c.temp, CONFIG.snow_temp, 0.15) * BASE_DENSITY * 0.5,
),
// Snowy animals // Snowy animals
("world.wildlife.spawn.tundra.snow", |c, col| { ("world.wildlife.spawn.tundra.snow", |c, col| {
close(c.temp, CONFIG.snow_temp, 0.3) * BASE_DENSITY * col.snow_cover as i32 as f32 * 1.0 close(c.temp, CONFIG.snow_temp, 0.3) * BASE_DENSITY * col.snow_cover as i32 as f32 * 1.0
@ -194,6 +198,15 @@ pub fn spawn_manifest() -> Vec<(&'static str, DensityFn)> {
* 1.0 * 1.0
}, },
), ),
(
"world.wildlife.spawn.calendar.april_fools.tundra.snow",
|c, col| {
close(c.temp, CONFIG.snow_temp, 0.3)
* BASE_DENSITY
* col.snow_cover as i32 as f32
* 1.0
},
),
// Forest animals // Forest animals
("world.wildlife.spawn.tundra.forest", |c, col| { ("world.wildlife.spawn.tundra.forest", |c, col| {
close(c.temp, CONFIG.snow_temp, 0.3) * col.tree_density * BASE_DENSITY * 1.4 close(c.temp, CONFIG.snow_temp, 0.3) * col.tree_density * BASE_DENSITY * 1.4
@ -207,6 +220,10 @@ pub fn spawn_manifest() -> Vec<(&'static str, DensityFn)> {
"world.wildlife.spawn.calendar.halloween.tundra.forest", "world.wildlife.spawn.calendar.halloween.tundra.forest",
|c, col| close(c.temp, CONFIG.snow_temp, 0.3) * col.tree_density * BASE_DENSITY * 1.4, |c, col| close(c.temp, CONFIG.snow_temp, 0.3) * col.tree_density * BASE_DENSITY * 1.4,
), ),
(
"world.wildlife.spawn.calendar.april_fools.tundra.forest",
|c, col| close(c.temp, CONFIG.snow_temp, 0.3) * col.tree_density * BASE_DENSITY * 1.4,
),
// **Taiga** // **Taiga**
// Forest core animals // Forest core animals
("world.wildlife.spawn.taiga.core_forest", |c, col| { ("world.wildlife.spawn.taiga.core_forest", |c, col| {
@ -225,6 +242,12 @@ pub fn spawn_manifest() -> Vec<(&'static str, DensityFn)> {
close(c.temp, CONFIG.snow_temp + 0.2, 0.2) * col.tree_density * BASE_DENSITY * 0.4 close(c.temp, CONFIG.snow_temp + 0.2, 0.2) * col.tree_density * BASE_DENSITY * 0.4
}, },
), ),
(
"world.wildlife.spawn.calendar.april_fools.taiga.core",
|c, col| {
close(c.temp, CONFIG.snow_temp + 0.2, 0.2) * col.tree_density * BASE_DENSITY * 0.4
},
),
// Core animals // Core animals
("world.wildlife.spawn.taiga.core", |c, _col| { ("world.wildlife.spawn.taiga.core", |c, _col| {
close(c.temp, CONFIG.snow_temp + 0.2, 0.2) * BASE_DENSITY * 1.0 close(c.temp, CONFIG.snow_temp + 0.2, 0.2) * BASE_DENSITY * 1.0
@ -276,6 +299,15 @@ pub fn spawn_manifest() -> Vec<(&'static str, DensityFn)> {
* 4.0 * 4.0
}, },
), ),
(
"world.wildlife.spawn.calendar.april_fools.temperate.rainforest",
|c, _col| {
close(c.temp, CONFIG.temperate_temp + 0.1, 0.6)
* close(c.humidity, CONFIG.forest_hum, 0.6)
* BASE_DENSITY
* 4.0
},
),
// Water animals // Water animals
("world.wildlife.spawn.temperate.water", |c, col| { ("world.wildlife.spawn.temperate.water", |c, col| {
close(c.temp, CONFIG.temperate_temp, 1.0) * col.tree_density * BASE_DENSITY * 5.0 close(c.temp, CONFIG.temperate_temp, 1.0) * col.tree_density * BASE_DENSITY * 5.0
@ -305,6 +337,15 @@ pub fn spawn_manifest() -> Vec<(&'static str, DensityFn)> {
* 8.0 * 8.0
}, },
), ),
(
"world.wildlife.spawn.calendar.april_fools.jungle.area",
|c, _col| {
close(c.temp, CONFIG.tropical_temp + 0.2, 0.3)
* close(c.humidity, CONFIG.jungle_hum, 0.2)
* BASE_DENSITY
* 8.0
},
),
// **Tropical** // **Tropical**
// Rare river animals // Rare river animals
("world.wildlife.spawn.tropical.river_rare", |_c, col| { ("world.wildlife.spawn.tropical.river_rare", |_c, col| {
@ -361,6 +402,15 @@ pub fn spawn_manifest() -> Vec<(&'static str, DensityFn)> {
* 2.0 * 2.0
}, },
), ),
(
"world.wildlife.spawn.calendar.april_fools.tropical.rainforest",
|c, _col| {
close(c.temp, CONFIG.tropical_temp + 0.1, 0.4)
* close(c.humidity, CONFIG.desert_hum, 0.4)
* BASE_DENSITY
* 2.0
},
),
// Rock animals // Rock animals
("world.wildlife.spawn.tropical.rock", |c, col| { ("world.wildlife.spawn.tropical.rock", |c, col| {
close(c.temp, CONFIG.tropical_temp + 0.1, 0.5) * col.rock_density * BASE_DENSITY * 5.0 close(c.temp, CONFIG.tropical_temp + 0.1, 0.5) * col.rock_density * BASE_DENSITY * 5.0