Add Changelog to README; Remove /world announcements

This commit is contained in:
Jeff 2024-09-02 01:11:47 -04:00
parent 68e7b675ef
commit ed2fc13217
44 changed files with 750 additions and 529 deletions

703
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -33,12 +33,13 @@ The bot is able to respond to the following commands, which must be sent via "/t
search term. search term.
- `admin_access`: Admin-only, prompts the bot to send a trade invite to the sender, after which it - `admin_access`: Admin-only, prompts the bot to send a trade invite to the sender, after which it
will give away and accept any items until the trade ends. will give away and accept any items until the trade ends.
- `announce`: Admin-only, sends the announcement message to "/world". This will reset the - `announce`: Admin-only, sends the announcement message to "/region". This will reset the
announcement timer to 45 minutes. announcement timer to 45 minutes.
- `location`: Returns the bot's current town or, if it is not in a town, its current position.
- `sort [count (optional)]`: Admin-only, sorts the inventory once or the given number of times. - `sort [count (optional)]`: Admin-only, sorts the inventory once or the given number of times.
- `pos [x] [y] [z]`: Admin-only, sets the bot's desired position where it will try to stand (must - `pos [x] [y] [z]`: Admin-only, sets the bot's desired position where it will try to stand (must
be close to the bot's current position) be close to the bot's current position).
- `ori [0-360]`: Admin-only, sets the bot's desired orientation (or facing direction) - `ori [0-360]`: Admin-only, sets the bot's desired orientation (or facing direction).
## Prerequisites ## Prerequisites
@ -94,10 +95,8 @@ position = [0, 0, 0]
# Its orientation can be changed in-game with the "ori" command. # Its orientation can be changed in-game with the "ori" command.
orientation = 0 orientation = 0
# Optional. Announcements are sent every 45 minutes. Use {location} to insert the bot's current # Optional. Announcements are sent every 45 minutes. If not set, the bot will not make announcements.
# location. If not set, the bot will not send /world announcements but will still send /region announcement = "I love cheese!"
# announcements with usage instructions.
announcement = "I love cheese! I am at {location}."
# The buy_prices and sell_prices tables are required. The keys are item definition IDs and the # The buy_prices and sell_prices tables are required. The keys are item definition IDs and the
# values are the price in coins. You may type in-game "/give_item common.items." and press Tab to # values are the price in coins. You may type in-game "/give_item common.items." and press Tab to
@ -143,6 +142,17 @@ podman build . -t trade_bot
Then follow the [above](#running) steps with the tag "trade_bot" instead of Then follow the [above](#running) steps with the tag "trade_bot" instead of
"git.jeffa.io/jeff/trade_bot". "git.jeffa.io/jeff/trade_bot".
## Changelog
- 9/2/2024:
- Added the "location" command.
- Removed the "{location}" feature from the announcement message. Announcements are now sent to
"/region" so this feature is now used by the "location" command.
- Changed announcements to be sent to "/region" instead of "/world". The moderators on the official
server have asked for this, so please don't run an old version to circumvent the change.
- Removed the "Ouch!" and "That hurt!" messages when the bot is attacked. The moderators have also
asked for this.
## License ## License
This project is licensed under the GPL-3.0 license. See the [LICENSE](LICENSE) file for details. This project is licensed under the GPL-3.0 license. See the [LICENSE](LICENSE) file for details.

View File

@ -771,8 +771,9 @@
primary: Simple(None, "common.abilities.custom.harvester.scythe"), primary: Simple(None, "common.abilities.custom.harvester.scythe"),
secondary: Simple(None, "common.abilities.custom.harvester.firebreath"), secondary: Simple(None, "common.abilities.custom.harvester.firebreath"),
abilities: [ abilities: [
Simple(None, "common.abilities.custom.harvester.ensnaringvines"),
Simple(None, "common.abilities.custom.harvester.explodingpumpkin"), Simple(None, "common.abilities.custom.harvester.explodingpumpkin"),
Simple(None, "common.abilities.custom.harvester.ensnaringvines_sparse"),
Simple(None, "common.abilities.custom.harvester.ensnaringvines_dense"),
], ],
), ),
// TODO: Allow ability sets to expand other ability sets // TODO: Allow ability sets to expand other ability sets

View File

@ -0,0 +1,10 @@
SpriteSummon(
buildup_duration: 0.9,
cast_duration: 0.6,
recover_duration: 0.5,
sprite: EnsnaringVines,
del_timeout: None,
summon_distance: (0, 25),
sparseness: 0.6,
angle: 360,
)

View File

@ -0,0 +1,10 @@
SpriteSummon(
buildup_duration: 0.6,
cast_duration: 0.4,
recover_duration: 0.3,
sprite: EnsnaringVines,
del_timeout: None,
summon_distance: (0, 30),
sparseness: 0.8,
angle: 360,
)

View File

@ -1,21 +1,21 @@
BasicRanged( BasicRanged(
energy_cost: 0, energy_cost: 0,
buildup_duration: 0.75, buildup_duration: 1.0,
recover_duration: 1.6, recover_duration: 1.6,
projectile: ( projectile: (
kind: Explosive( kind: Explosive(
radius: 5, radius: 7.2,
min_falloff: 0.6, min_falloff: 0.6,
reagent: Some(Red), reagent: Some(Red),
terrain: Some((5, Black)), terrain: Some((5, Black)),
), ),
attack: Some(( attack: Some((
damage: 37.5, damage: 20,
knockback: Some(25), knockback: Some(22),
energy: 0, energy: 0,
buff: Some(( buff: Some((
kind: Burning, kind: Burning,
dur_secs: 5, dur_secs: 4,
strength: DamageFraction(0.2), strength: DamageFraction(0.2),
chance: 1.0, chance: 1.0,
)), )),

View File

@ -2,18 +2,18 @@ BasicBeam(
buildup_duration: 1.4, buildup_duration: 1.4,
recover_duration: 0.9, recover_duration: 0.9,
beam_duration: 1.0, beam_duration: 1.0,
damage: 9.0, damage: 5.0,
tick_rate: 1.5, tick_rate: 1.5,
range: 20.0, range: 20.0,
max_angle: 15.0, max_angle: 15.0,
damage_effect: Some(Buff(( damage_effect: Some(Buff((
kind: Burning, kind: Burning,
dur_secs: 10.0, dur_secs: 3.0,
strength: DamageFraction(1.0), strength: DamageFraction(0.8),
chance: 1.0, chance: 1.0,
))), ))),
energy_regen: 0, energy_regen: 0,
energy_drain: 0, energy_drain: 0,
ori_rate: 0.3, ori_rate: 0.7,
specifier: Flamethrower, specifier: Flamethrower,
) )

View File

@ -1,19 +1,19 @@
BasicMelee( BasicMelee(
energy_cost: 0, energy_cost: 0,
buildup_duration: 0.9, buildup_duration: 1.0,
swing_duration: 0.1, swing_duration: 0.2,
hit_timing: 0.5, hit_timing: 0.5,
recover_duration: 1.2, recover_duration: 1.0,
melee_constructor: ( melee_constructor: (
kind: Slash( kind: Slash(
damage: 21.0, damage: 15.0,
poise: 10.0, poise: 10.0,
knockback: 10.0, knockback: 10.0,
energy_regen: 0.0, energy_regen: 0.0,
), ),
range: 4.0, range: 4.5,
angle: 60.0, angle: 50.0,
multi_target: Some(Normal), multi_target: Some(Normal),
), ),
ori_modifier: 1.0, ori_modifier: 0.5,
) )

View File

@ -7,7 +7,7 @@ BasicMelee(
melee_constructor: ( melee_constructor: (
kind: Bash( kind: Bash(
damage: 8, damage: 8,
poise: 5, poise: 10,
knockback: 0, knockback: 0,
energy_regen: 0, energy_regen: 0,
), ),

View File

@ -7,7 +7,7 @@ BasicMelee(
melee_constructor: ( melee_constructor: (
kind: SonicWave( kind: SonicWave(
damage: 10, damage: 10,
poise: 100, poise: 75,
knockback: 20, knockback: 20,
energy_regen: 0, energy_regen: 0,
), ),

View File

@ -1,20 +1,20 @@
Shockwave( Shockwave(
energy_cost: 0, energy_cost: 0,
buildup_duration: 3.0, buildup_duration: 1.2,
swing_duration: 0.12, swing_duration: 0.12,
recover_duration: 2.4, recover_duration: 1.5,
damage: 60.0, damage: 22.0,
poise_damage: 30, poise_damage: 30,
knockback: (strength: 30.0, direction: TowardsUp), knockback: (strength: 20.0, direction: TowardsUp),
shockwave_angle: 90.0, shockwave_angle: 90.0,
shockwave_vertical_angle: 90.0, shockwave_vertical_angle: 90.0,
shockwave_speed: 15.0, shockwave_speed: 15.0,
shockwave_duration: 2.0, shockwave_duration: 1.9,
dodgeable: Jump, dodgeable: Jump,
move_efficiency: 0.0, move_efficiency: 0.0,
damage_kind: Crushing, damage_kind: Crushing,
specifier: Ground, specifier: Ground,
ori_rate: 1.0, ori_rate: 0.9,
timing: PostBuildup, timing: PostBuildup,
emit_outcome: true, emit_outcome: true,
) )

View File

@ -1,18 +1,18 @@
BasicMelee( BasicMelee(
energy_cost: 0, energy_cost: 0,
buildup_duration: 0.9, buildup_duration: 1.2,
swing_duration: 0.3, swing_duration: 0.3,
hit_timing: 0.6, hit_timing: 0.6,
recover_duration: 0.6, recover_duration: 1.2,
melee_constructor: ( melee_constructor: (
kind: Bash( kind: Bash(
damage: 45, damage: 18,
poise: 30, poise: 30,
knockback: 20, knockback: 20,
energy_regen: 0, energy_regen: 0,
), ),
range: 7.5, range: 5.0,
angle: 360, angle: 360,
), ),
ori_modifier: 1.0, ori_modifier: 0.75,
) )

View File

@ -1,18 +1,18 @@
BasicMelee( BasicMelee(
energy_cost: 0, energy_cost: 0,
buildup_duration: 1.6, buildup_duration: 1.0,
swing_duration: 0.1, swing_duration: 0.2,
hit_timing: 0.6, hit_timing: 0.6,
recover_duration: 1.0, recover_duration: 1.0,
melee_constructor: ( melee_constructor: (
kind: Bash( kind: Bash(
damage: 30.0, damage: 12.0,
poise: 25.0, poise: 25.0,
knockback: 15.0, knockback: 15.0,
energy_regen: 0.0, energy_regen: 0.0,
), ),
range: 4.0, range: 4.0,
angle: 45.0, angle: 55.0,
), ),
ori_modifier: 0.4, ori_modifier: 0.7,
) )

View File

@ -1,28 +1,28 @@
BasicRanged( BasicRanged(
energy_cost: 0, energy_cost: 0,
buildup_duration: 0.825, buildup_duration: 1.0,
recover_duration: 0.6, recover_duration: 0.6,
projectile: ( projectile: (
kind: Explosive( kind: Explosive(
radius: 2, radius: 3,
min_falloff: 0.5, min_falloff: 0.7,
reagent: Some(Red), reagent: Some(Red),
terrain: Some((2, Black)) terrain: Some((2, Black))
), ),
attack: Some(( attack: Some((
damage: 13.5, damage: 5.5,
energy: 10, energy: 10,
buff: Some(( buff: Some((
kind: Burning, kind: Burning,
dur_secs: 5, dur_secs: 3,
strength: DamageFraction(0.1), strength: DamageFraction(0.3),
chance: 0.1, chance: 0.1,
)), )),
)), )),
), ),
projectile_body: Object(BoltFire), projectile_body: Object(BoltFire),
projectile_speed: 25, projectile_speed: 25,
num_projectiles: 8, num_projectiles: 5,
projectile_spread: 0.125, projectile_spread: 0.125,
move_efficiency: 0.3, move_efficiency: 0.3,
) )

View File

@ -1,16 +1,16 @@
Shockwave( Shockwave(
energy_cost: 0, energy_cost: 0,
buildup_duration: 0.975, buildup_duration: 1.2,
swing_duration: 0.1, swing_duration: 0.1,
recover_duration: 0.6, recover_duration: 0.8,
damage: 30, damage: 16,
poise_damage: 0, poise_damage: 0,
knockback: ( strength: 25, direction: Away), knockback: ( strength: 15, direction: Away),
shockwave_angle: 360, shockwave_angle: 360,
shockwave_vertical_angle: 90, shockwave_vertical_angle: 90,
shockwave_speed: 10, shockwave_speed: 12,
shockwave_duration: 1, shockwave_duration: 1.0,
dodgeable: Roll, dodgeable: Jump,
move_efficiency: 0, move_efficiency: 0,
damage_kind: Energy, damage_kind: Energy,
specifier: Fire, specifier: Fire,

View File

@ -1,21 +1,21 @@
BasicMelee( BasicMelee(
energy_cost: 0, energy_cost: 0,
buildup_duration: 0.6, buildup_duration: 0.75,
swing_duration: 0.1, swing_duration: 0.4,
hit_timing: 0.5, hit_timing: 0.5,
recover_duration: 0.45, recover_duration: 0.6,
melee_constructor: ( melee_constructor: (
kind: Bash( kind: Bash(
damage: 12, damage: 9,
poise: 10, poise: 10,
knockback: 0, knockback: 0,
energy_regen: 0, energy_regen: 0,
), ),
range: 7.5, range: 3.0,
angle: 60.0, angle: 40.0,
damage_effect: Some(Buff(( damage_effect: Some(Buff((
kind: Burning, kind: Burning,
dur_secs: 10.0, dur_secs: 4.0,
strength: DamageFraction(0.5), strength: DamageFraction(0.5),
chance: 0.5, chance: 0.5,
))), ))),

View File

@ -1,24 +1,24 @@
BasicAura( BasicAura(
buildup_duration: 0.375, buildup_duration: 0.2,
cast_duration: 0.5, cast_duration: 0.4,
recover_duration: 0.375, recover_duration: 0.2,
targets: InGroup, targets: InGroup,
auras: [ auras: [
( (
kind: Regeneration, kind: Regeneration,
strength: 7.5, strength: 1,
duration: Some(5), duration: Some(1),
category: Magical, category: Magical,
), ),
( (
kind: ProtectingWard, kind: ProtectingWard,
strength: 0.75, strength: 0.5,
duration: Some(5), duration: Some(1),
category: Magical, category: Magical,
), ),
], ],
aura_duration: Some(2), aura_duration: Some(1),
range: 50, range: 15,
energy_cost: 0, energy_cost: 0,
scales_with_combo: false, scales_with_combo: false,
) )

View File

@ -1,18 +1,18 @@
BasicAura( BasicAura(
buildup_duration: 0.375, buildup_duration: 0.2,
cast_duration: 0.5, cast_duration: 0.4,
recover_duration: 0.375, recover_duration: 0.2,
targets: OutOfGroup, targets: OutOfGroup,
auras: [ auras: [
( (
kind: Burning, kind: Burning,
strength: 0.75, strength: 1.2,
duration: Some(5), duration: Some(1),
category: Magical, category: Magical,
), ),
], ],
aura_duration: Some(2), aura_duration: Some(1),
range: 50, range: 15,
energy_cost: 0, energy_cost: 0,
scales_with_combo: false, scales_with_combo: false,
) )

View File

@ -1,18 +1,18 @@
BasicAura( BasicAura(
buildup_duration: 0.375, buildup_duration: 0.2,
cast_duration: 0.5, cast_duration: 0.4,
recover_duration: 0.375, recover_duration: 0.2,
targets: InGroup, targets: InGroup,
auras: [ auras: [
( (
kind: Hastened, kind: Hastened,
strength: 0.75, strength: 0.4,
duration: Some(5), duration: Some(1),
category: Magical, category: Magical,
), ),
], ],
aura_duration: Some(2), aura_duration: Some(1),
range: 50, range: 15,
energy_cost: 0, energy_cost: 0,
scales_with_combo: false, scales_with_combo: false,
) )

View File

@ -2,7 +2,7 @@
#![enable(implicit_some)] #![enable(implicit_some)]
( (
name: Name("Gnarling Chieftain"), name: Name("Gnarling Chieftain"),
body: RandomWith("gnarling"), body: RandomWith("gnarling_chieftain"),
alignment: Alignment(Enemy), alignment: Alignment(Enemy),
loot: LootTable("common.loot_tables.dungeon.gnarling.chieftain"), loot: LootTable("common.loot_tables.dungeon.gnarling.chieftain"),
inventory: ( inventory: (

View File

@ -3183,6 +3183,9 @@
Simple( Simple(
"common.items.consumable.potion_minor", "common.items.consumable.potion_minor",
): "object-potion_minor", ): "object-potion_minor",
Simple(
"common.items.consumable.potion_freezing",
): "object-potion_freezing",
Simple( Simple(
"common.items.lantern.black_0", "common.items.lantern.black_0",
): "lantern-black", ): "lantern-black",

View File

@ -6,10 +6,10 @@ ItemDef(
stats: Direct(( stats: Direct((
protection: Some(Normal(3.0)), protection: Some(Normal(3.0)),
poise_resilience: Some(Normal(1.0)), poise_resilience: Some(Normal(1.0)),
energy_max: Some(14.0), energy_max: Some(6.0),
)), )),
)), )),
quality: High, quality: Moderate,
tags: [ tags: [
Gnarling, Gnarling,
SalvageInto(Lifecloth, 1), SalvageInto(Lifecloth, 1),

View File

@ -17,5 +17,5 @@ ItemDef(
]) ])
), ),
quality: Legendary, quality: Legendary,
tags: [], tags: [Charm],
) )

View File

@ -17,5 +17,5 @@ ItemDef(
]) ])
), ),
quality: Legendary, quality: Legendary,
tags: [], tags: [Charm],
) )

View File

@ -16,5 +16,5 @@ ItemDef(
]) ])
), ),
quality: Legendary, quality: Legendary,
tags: [], tags: [Charm],
) )

View File

@ -11,7 +11,15 @@ ItemDef(
duration: Some(10) duration: Some(10)
), ),
cat_ids: [Natural], cat_ids: [Natural],
)) )),
Buff((
kind: PotionSickness,
data: (
strength: 0.15,
duration: Some(30),
),
cat_ids: [Natural],
)),
]) ])
), ),
quality: Moderate, quality: Moderate,

View File

@ -0,0 +1,27 @@
ItemDef(
legacy_name: "Freezing Potion",
legacy_description: "Freezes the user's brain",
kind: Consumable(
kind: Drink,
effects: All([
Buff((
kind: Frozen,
data: (
strength: 0.1,
duration: Some(30)
),
cat_ids: [Natural],
)),
Buff((
kind: PotionSickness,
data: (
strength: 0.15,
duration: Some(30),
),
cat_ids: [Natural],
)),
])
),
quality: Moderate,
tags: [Potion],
)

View File

@ -2,6 +2,6 @@ ItemDef(
legacy_name: "Green Luna", legacy_name: "Green Luna",
legacy_description: "The delicate wings flutter faintly.", legacy_description: "The delicate wings flutter faintly.",
kind: Glider, kind: Glider,
quality: High, quality: Moderate,
tags: [], tags: [],
) )

View File

@ -8,6 +8,6 @@ ItemDef(
flicker_thousandths: 600, flicker_thousandths: 600,
), ),
), ),
quality: High, quality: Moderate,
tags: [Utility], tags: [Utility],
) )

View File

@ -4,6 +4,7 @@ ItemDef(
kind: RecipeGroup( kind: RecipeGroup(
recipes: [ recipes: [
"potion_combustion", "potion_combustion",
"potion_freezing",
"potion_agility", "potion_agility",
"potion_minor", "potion_minor",
"potion_medium", "potion_medium",

View File

@ -1,12 +1,14 @@
[ [
// Weapons (1, All([
(5.0, LootTable("common.loot_tables.weapons.tier-1")), All([
// Armor LootTable("common.loot_tables.armor.tier-1"),
(5.0, LootTable("common.loot_tables.armor.tier-1")), LootTable("common.loot_tables.weapons.tier-1"),
// Misc ]),
(3.0, Item("common.items.armor.misc.neck.scratched")), Lottery([
(2.0, Item("common.items.armor.misc.head.wanderers_hat")), (2.0, Nothing),
(3.0, Item("common.items.armor.misc.head.bamboo_twig")), (1.0, Item("common.items.armor.misc.neck.scratched")),
// Chieftain Mask (1.0, Item("common.items.armor.misc.head.gnarling_mask")),
(1.0, Item("common.items.armor.misc.head.gnarling_mask")), (1.0, Item("common.items.glider.moth")),
]),
])),
] ]

View File

@ -1,10 +1,13 @@
[ [
// Weapons (1, All([
(5.0, LootTable("common.loot_tables.weapons.tier-3")), All([
// Armor LootTable("common.loot_tables.armor.tier-2"),
(5.0, LootTable("common.loot_tables.armor.tier-3")), LootTable("common.loot_tables.weapons.tier-2"),
// Misc ]),
(3.0, Item("common.items.armor.misc.neck.scratched")), Lottery([
(2.0, Item("common.items.lantern.pumpkin")), (3.0, Nothing),
(1.0, Item("common.items.glider.moth")), (1.0, Item("common.items.lantern.pumpkin")),
(1.0, Item("common.items.armor.misc.head.wanderers_hat")),
]),
])),
] ]

View File

@ -1,6 +1,16 @@
[ [
// Crafting ingredients (1, Lottery([
(2.4, MultiDrop(Item("common.items.log.wood"), 5, 10)), (0.7, All([
(0.1, MultiDrop(Item("common.items.log.hardwood"), 1, 2)), MultiDrop(Item("common.items.log.wood"), 3, 4),
(0.5, LootTable("common.loot_tables.weapons.components.secondary.sceptre")), MultiDrop(Item("common.items.crafting_ing.twigs"), 1, 2),
Lottery([
(0.6, MultiDrop(Item("common.items.log.bamboo"), 1, 2)),
(0.4, LootTable("common.loot_tables.weapons.components.secondary.sceptre")),
]),
])),
(0.3, All([
MultiDrop(Item("common.items.log.wood"), 5, 7),
MultiDrop(Item("common.items.crafting_ing.twigs"), 3, 5),
])),
]))
] ]

View File

@ -4,7 +4,7 @@
// Ingredients // Ingredients
(2.0, Item("common.items.crafting_ing.coral_branch")), (2.0, Item("common.items.crafting_ing.coral_branch")),
(0.5, Item("common.items.crafting_ing.pearl")), (0.5, Item("common.items.crafting_ing.pearl")),
(0.25, Item("common.items.recipes.unique.seashell_necklace")), (0.5, Item("common.items.recipes.armor.brinestone")),
(0.25, Item("common.items.recipes.unique.winged_coronet")), (0.25, Item("common.items.recipes.unique.winged_coronet")),
(0.25, Item("common.items.recipes.unique.abyssal_ring")), (0.25, Item("common.items.recipes.unique.abyssal_ring")),
]), ]),

View File

@ -1,3 +1,5 @@
[ [
(1.0, Item("common.items.recipes.armor.brinestone")), (1.0, Nothing),
(1.0, LootTable("common.loot_tables.food.prepared")),
(0.5, Item("common.items.recipes.unique.seashell_necklace")),
] ]

View File

@ -1,5 +1,5 @@
[ [
(1.0, LootTable("common.loot_tables.weapons.components.tier-1")), (1.0, LootTable("common.loot_tables.weapons.components.tier-0")),
(1.0, LootTable("common.loot_tables.armor.cloth")), (1.0, LootTable("common.loot_tables.armor.cloth")),
(0.5, Item("common.items.recipes.explosives")), (0.5, Item("common.items.recipes.explosives")),
] ]

View File

@ -1,7 +1,16 @@
[ [
(1.0, LootTable("common.loot_tables.weapons.components.tier-0")), (0.5, LootTable("common.loot_tables.weapons.components.tier-0")),
(1.0, LootTable("common.loot_tables.weapons.components.tier-1")), (0.25, LootTable("common.loot_tables.weapons.tier-0")),
(1.0, LootTable("common.loot_tables.armor.cloth")), (0.25, LootTable("common.loot_tables.armor.tier-0")),
(0.25, Item("common.items.armor.misc.head.bamboo_twig")),
// Currency
(3.0, MultiDrop(Item("common.items.utility.coins"), 25, 50)),
// Materials
(0.5, MultiDrop(Item("common.items.mineral.ore.veloritefrag"), 5, 10)),
// Consumables
(2.0, MultiDrop(Item("common.items.consumable.potion_minor"), 2, 5)),
// Food
(1.0, MultiDrop(LootTable("common.loot_tables.food.prepared"), 1, 2)),
(0.2, Item("common.items.recipes.explosives")), (0.2, Item("common.items.recipes.explosives")),
(0.5, Item("common.items.recipes.instruments")), (0.5, Item("common.items.recipes.instruments")),
(0.2, Item("common.items.recipes.charms")), (0.2, Item("common.items.recipes.charms")),

View File

@ -1233,6 +1233,10 @@
keyword: "treasure_egg", keyword: "treasure_egg",
generic: "Treasure Egg", generic: "Treasure Egg",
), ),
gnarling_chieftain: (
keyword: "gnarling_chieftain",
generic: "Gnarling Chieftain"
),
) )
), ),
fish_small: ( fish_small: (

View File

@ -31,6 +31,15 @@
], ],
craft_sprite: Some(Anvil), craft_sprite: Some(Anvil),
), ),
"potion_freezing": (
output: ("common.items.consumable.potion_freezing", 1),
inputs: [
(Item("common.items.crafting_ing.empty_vial"), 1, false),
(Item("common.items.crafting_ing.animal_misc.icy_fang"), 3, false),
(Item("common.items.crafting_ing.animal_misc.viscous_ooze"), 1, false),
],
craft_sprite: Some(Cauldron),
),
"potion_combustion": ( "potion_combustion": (
output: ("common.items.consumable.potion_combustion", 1), output: ("common.items.consumable.potion_combustion", 1),
inputs: [ inputs: [

View File

@ -24,8 +24,8 @@ loot_tables: [
(20.375, true, "common.trading.food"), (20.375, true, "common.trading.food"),
// Recipes // Recipes
(1.0, true, "common.trading.sellable_recipe"), (1.8, true, "common.trading.sellable_recipe"),
(1.0, false, "common.trading.unsellable_recipe"), (1.5, false, "common.trading.unsellable_recipe"),
// Potions // Potions
// //
@ -50,5 +50,6 @@ good_scaling: [
(Armor, 0.025), // common.items.armor.misc.pants.worker_blue (Armor, 0.025), // common.items.armor.misc.pants.worker_blue
(Tools, 0.015487), // common.items.weapons.staff.starter_staff (Tools, 0.015487), // common.items.weapons.staff.starter_staff
(Ingredients, 0.034626), // common.items.crafting_ing.leather_scraps (Ingredients, 0.034626), // common.items.crafting_ing.leather_scraps
(Wood, 0.034626), // common.items.log.wood
(Recipe, 0.01), // common.items.recipes (Recipe, 0.01), // common.items.recipes
]) ])

View File

@ -1,7 +1,50 @@
[ [
// Legendary sceptres // Purple Linen set
Set([ Set([
"common.items.weapons.sceptre.root_evil", "common.items.armor.cloth_purple.belt",
"common.items.weapons.sceptre.caduceus", "common.items.armor.cloth_purple.chest",
"common.items.armor.cloth_purple.foot",
"common.items.armor.cloth_purple.hand",
"common.items.armor.cloth_purple.pants",
"common.items.armor.cloth_purple.shoulder",
]),
// Green Linen set
Set([
"common.items.armor.cloth_green.belt",
"common.items.armor.cloth_green.chest",
"common.items.armor.cloth_green.foot",
"common.items.armor.cloth_green.hand",
"common.items.armor.cloth_green.pants",
"common.items.armor.cloth_green.shoulder",
]),
// Blue Linen set
Set([
"common.items.armor.cloth_blue.belt",
"common.items.armor.cloth_blue.chest",
"common.items.armor.cloth_blue.foot",
"common.items.armor.cloth_blue.hand",
"common.items.armor.cloth_blue.pants",
"common.items.armor.cloth_blue.shoulder_0",
"common.items.armor.cloth_blue.shoulder_1",
]),
// Worker/starter clothing
Set([
"common.items.armor.misc.chest.worker_green_0",
"common.items.armor.misc.chest.worker_green_1",
"common.items.armor.misc.chest.worker_orange_0",
"common.items.armor.misc.chest.worker_orange_1",
"common.items.armor.misc.chest.worker_purple_0",
"common.items.armor.misc.chest.worker_purple_1",
"common.items.armor.misc.chest.worker_purple_brown",
"common.items.armor.misc.chest.worker_red_0",
"common.items.armor.misc.chest.worker_red_1",
"common.items.armor.misc.chest.worker_yellow_0",
"common.items.armor.misc.chest.worker_yellow_1",
"common.items.armor.misc.pants.worker_blue",
"common.items.armor.misc.pants.worker_brown",
"common.items.armor.misc.foot.sandals",
]), ]),
] ]

View File

@ -6,40 +6,40 @@
[ [
// Recipes // Recipes
// Misc Groups // Misc Groups
(1.0, Item("common.items.recipes.charms")), (1.25, Item("common.items.recipes.charms")),
(1.0, Item("common.items.recipes.explosives")), (1.25, Item("common.items.recipes.explosives")),
(1.0, Item("common.items.recipes.gliders")), (1.25, Item("common.items.recipes.gliders")),
(1.0, Item("common.items.recipes.instruments")), (1.25, Item("common.items.recipes.instruments")),
// Equipment // Equipment
(1.0, Item("common.items.recipes.equipment.moderate")), (1.0, Item("common.items.recipes.equipment.moderate")),
(0.2, Item("common.items.recipes.equipment.advanced")), (0.3, Item("common.items.recipes.equipment.advanced")),
// Armors // Armors
(0.7, Item("common.items.recipes.armor.steel")), (1.25, Item("common.items.recipes.armor.steel")),
(0.7, Item("common.items.recipes.armor.silken")), (1.25, Item("common.items.recipes.armor.silken")),
(0.7, Item("common.items.recipes.armor.scale")), (1.25, Item("common.items.recipes.armor.scale")),
(0.7, Item("common.items.recipes.weapons.steel")), (1.25, Item("common.items.recipes.weapons.steel")),
(0.7, Item("common.items.recipes.weapons.hardwood")), (1.25, Item("common.items.recipes.weapons.hardwood")),
(0.4, Item("common.items.recipes.armor.cobalt")), (0.65, Item("common.items.recipes.armor.cobalt")),
(0.4, Item("common.items.recipes.armor.druid")), (0.65, Item("common.items.recipes.armor.druid")),
(0.4, Item("common.items.recipes.armor.carapace")), (0.65, Item("common.items.recipes.armor.carapace")),
(0.4, Item("common.items.recipes.weapons.cobalt")), (0.65, Item("common.items.recipes.weapons.cobalt")),
(0.4, Item("common.items.recipes.weapons.ironwood")), (0.65, Item("common.items.recipes.weapons.ironwood")),
(0.2, Item("common.items.recipes.armor.bloodsteel")), (0.38, Item("common.items.recipes.armor.bloodsteel")),
(0.2, Item("common.items.recipes.armor.moonweave")), (0.38, Item("common.items.recipes.armor.moonweave")),
(0.2, Item("common.items.recipes.armor.primal")), (0.38, Item("common.items.recipes.armor.primal")),
(0.2, Item("common.items.recipes.weapons.bloodsteel")), (0.38, Item("common.items.recipes.weapons.bloodsteel")),
(0.2, Item("common.items.recipes.weapons.frostwood")), (0.38, Item("common.items.recipes.weapons.frostwood")),
(0.1, Item("common.items.recipes.armor.orichalcum")), (0.25, Item("common.items.recipes.armor.sunsilk")),
(0.1, Item("common.items.recipes.armor.sunsilk")), (0.25, Item("common.items.recipes.armor.orichalcum")),
(0.1, Item("common.items.recipes.armor.dragonscale")), (0.25, Item("common.items.recipes.armor.dragonscale")),
(0.1, Item("common.items.recipes.armor.brinestone")), (0.25, Item("common.items.recipes.weapons.orichalcum")),
(0.1, Item("common.items.recipes.weapons.orichalcum")), (0.25, Item("common.items.recipes.weapons.eldwood")),
(0.1, Item("common.items.recipes.weapons.eldwood")), (0.25, Item("common.items.recipes.armor.brinestone")),
// Unique items // Unique items
(1.0, Item("common.items.recipes.unique.seashell_necklace")), (1.25, Item("common.items.recipes.unique.seashell_necklace")),
(0.8, Item("common.items.recipes.unique.winged_coronet")), (0.6, Item("common.items.recipes.unique.winged_coronet")),
(0.5, Item("common.items.recipes.unique.troll_hide_pack")), (0.5, Item("common.items.recipes.unique.troll_hide_pack")),
(0.3, Item("common.items.recipes.unique.abyssal_gorget")), (0.2, Item("common.items.recipes.unique.abyssal_gorget")),
(0.1, Item("common.items.recipes.unique.mindflayer_spellbag")), (0.15, Item("common.items.recipes.unique.mindflayer_spellbag")),
(0.1, Item("common.items.recipes.unique.polaris")), (0.1, Item("common.items.recipes.unique.polaris")),
] ]

View File

@ -1,3 +1,4 @@
announcement = "Beep Boop!"
position = [17720.0, 14951.0, 237.0] position = [17720.0, 14951.0, 237.0]
orientation = 0 orientation = 0

View File

@ -21,12 +21,11 @@ use veloren_common::{
tool::AbilityMap, tool::AbilityMap,
ChatType, ControllerInputs, Item, Ori, Pos, ChatType, ControllerInputs, Item, Ori, Pos,
}, },
outcome::Outcome,
time::DayPeriod, time::DayPeriod,
trade::{PendingTrade, TradeAction, TradeResult}, trade::{PendingTrade, TradeAction, TradeResult},
uid::Uid, uid::Uid,
uuid::Uuid, uuid::Uuid,
DamageSource, ViewDistances, ViewDistances,
}; };
use veloren_common_net::sync::WorldSyncExt; use veloren_common_net::sync::WorldSyncExt;
@ -37,12 +36,10 @@ const COINS: ItemDefinitionId =
const CLIENT_TPS: Duration = Duration::from_millis(33); const CLIENT_TPS: Duration = Duration::from_millis(33);
const TRADE_ACTION_DELAY: Duration = Duration::from_millis(300); const TRADE_ACTION_DELAY: Duration = Duration::from_millis(300);
const ACCOUNCEMENT_DELAY: Duration = Duration::from_mins(45); const ACCOUNCEMENT_DELAY: Duration = Duration::from_mins(45);
const OUCH_DELAY: Duration = Duration::from_secs(2);
/// An active connection to the Veloren server that will attempt to run every time the `tick` /// An active connection to the Veloren server that will attempt to run every time the `tick`
/// function is called. /// function is called.
pub struct Bot { pub struct Bot {
username: String,
position: Pos, position: Pos,
orientation: Ori, orientation: Ori,
admins: Vec<String>, admins: Vec<String>,
@ -63,7 +60,6 @@ pub struct Bot {
previous_trade_receipt: Option<Reciept>, previous_trade_receipt: Option<Reciept>,
last_trade_action: Instant, last_trade_action: Instant,
last_announcement: Instant, last_announcement: Instant,
last_ouch: Instant,
sort_count: u8, sort_count: u8,
} }
@ -140,7 +136,6 @@ impl Bot {
let now = Instant::now(); let now = Instant::now();
Ok(Bot { Ok(Bot {
username,
position, position,
orientation, orientation,
admins, admins,
@ -157,7 +152,6 @@ impl Bot {
previous_trade_receipt: None, previous_trade_receipt: None,
last_trade_action: now, last_trade_action: now,
last_announcement: now, last_announcement: now,
last_ouch: now,
sort_count: 0, sort_count: 0,
announcement, announcement,
}) })
@ -284,6 +278,11 @@ impl Bot {
Some(price_correction_message) Some(price_correction_message)
} }
} }
"location" => {
self.send_location_info(&sender)?;
None
}
"ori" => { "ori" => {
if self.is_user_admin(&sender)? { if self.is_user_admin(&sender)? {
if let Some(new_rotation) = split_content.next() { if let Some(new_rotation) = split_content.next() {
@ -366,36 +365,6 @@ impl Bot {
); );
} }
} }
VelorenEvent::Outcome(Outcome::ProjectileHit {
target: Some(target),
..
}) => {
if let Some(uid) = self.client.uid() {
if uid == target && self.last_ouch.elapsed() > OUCH_DELAY {
self.client
.send_command("say".to_string(), vec!["Ouch!".to_string()]);
self.last_ouch = Instant::now();
}
}
}
VelorenEvent::Outcome(Outcome::HealthChange { info, .. }) => {
if let Some(DamageSource::Buff(_)) = info.cause {
return Ok(true);
}
if let Some(uid) = self.client.uid() {
if uid == info.target
&& info.amount.is_sign_negative()
&& self.last_ouch.elapsed() > OUCH_DELAY
{
self.client
.send_command("say".to_string(), vec!["That hurt!".to_string()]);
self.last_ouch = Instant::now();
}
}
}
VelorenEvent::TradeComplete { result, trade } => { VelorenEvent::TradeComplete { result, trade } => {
let my_party = trade let my_party = trade
.which_party(self.client.uid().ok_or("Failed to find uid")?) .which_party(self.client.uid().ok_or("Failed to find uid")?)
@ -439,47 +408,46 @@ impl Bot {
Ok(true) Ok(true)
} }
fn send_location_info(&mut self, target: &Uid) -> Result<(), String> {
let player_name = self
.find_player_alias(target)
.ok_or("Failed to find player alias")?
.to_string();
let location = self
.client
.sites()
.into_iter()
.find_map(|(_, SiteInfoRich { site, .. })| {
let x_difference = self.position.0[0] - site.wpos[0] as f32;
let y_difference = self.position.0[1] - site.wpos[1] as f32;
if x_difference.abs() < 100.0 && y_difference.abs() < 100.0 {
site.name.clone()
} else {
None
}
})
.unwrap_or(format!("{:?}", self.position));
self.client.send_command(
"tell".to_string(),
vec![player_name, format!("I am at {location}.")],
);
Ok(())
}
/// Make the bot's trading and help accouncements /// Make the bot's trading and help accouncements
/// ///
/// Currently, this can make two announcements: one in /region with basic usage instructions /// Currently, this can make two announcements: one in /region with basic usage instructions
/// is always made. If an announcement was provided when the bot was created, it will make it /// is always made. If an announcement was provided when the bot was created, it will make it
/// in /world. /// in /world.
fn handle_announcement(&mut self) -> Result<(), String> { fn handle_announcement(&mut self) -> Result<(), String> {
debug!("Making an announcement");
self.client.send_command(
"region".to_string(),
vec![format!(
"I'm a bot. You can trade with me or check prices: '/tell {} price [search_term]'.",
self.username
)],
);
if let Some(announcement) = &self.announcement { if let Some(announcement) = &self.announcement {
let announcement = if announcement.contains("{location}") { debug!("Making an announcement");
let location = self
.client
.sites()
.into_iter()
.find_map(|(_, SiteInfoRich { site, .. })| {
let x_difference = self.position.0[0] - site.wpos[0] as f32;
let y_difference = self.position.0[1] - site.wpos[1] as f32;
if x_difference.abs() < 100.0 && y_difference.abs() < 100.0 {
site.name.clone()
} else {
None
}
})
.unwrap_or(format!("{:?}", self.position));
announcement.replace("{location}", &location)
} else {
announcement.clone()
};
self.client self.client
.send_command("world".to_string(), vec![announcement]); .send_command("region".to_string(), vec![announcement.to_string()]);
} }
Ok(()) Ok(())