Add support for modular weapons
This commit is contained in:
parent
c52613fa20
commit
19d0aa7e44
10
README.md
10
README.md
@ -101,11 +101,17 @@ announcement = "I love cheese! I am at {location}."
|
||||
# values are the price in coins. You may type in-game "/give_item common.items." and press Tab to
|
||||
# explore the item definition IDs. Then just leave off the "common.items." part in this file.
|
||||
|
||||
[buy_prices]
|
||||
[buy_prices.simple]
|
||||
"food.cheese" = 50
|
||||
|
||||
[sell_prices]
|
||||
[sell_prices.simple]
|
||||
"consumable.potion_minor" = 150
|
||||
|
||||
[sell_prices.modular]
|
||||
material = "mineral.ingot.orichalcum"
|
||||
primary = "sword.greatsword"
|
||||
seconday = "sword.long"
|
||||
price = 45_000
|
||||
```
|
||||
|
||||
### Running
|
||||
|
@ -1,63 +1,20 @@
|
||||
position = [17720.0, 14951.0, 237.0]
|
||||
orientation = 0
|
||||
|
||||
[buy_prices]
|
||||
[buy_prices.simple]
|
||||
"food.cheese" = 50
|
||||
|
||||
[sell_prices]
|
||||
# Armor
|
||||
"armor.misc.neck.carcanet_of_wrath" = 20_000
|
||||
[[buy_prices.modular]]
|
||||
material = "Iron"
|
||||
primary = "sword.greatsword"
|
||||
secondary = "sword.long"
|
||||
price = 1000
|
||||
|
||||
## Boreal Armor
|
||||
"armor.boreal.back" = 250_000
|
||||
"armor.boreal.belt" = 250_000
|
||||
"armor.boreal.chest" = 250_000
|
||||
"armor.boreal.foot" = 250_000
|
||||
"armor.boreal.hand" = 250_000
|
||||
"armor.boreal.pants" = 250_000
|
||||
"armor.boreal.shoulder" = 250_000
|
||||
"armor.misc.head.boreal_warhelm" = 450_000
|
||||
|
||||
# Hats
|
||||
"armor.misc.head.cat_capuche" = 750_000
|
||||
"armor.misc.head.hare_hat" = 150_000
|
||||
"armor.misc.head.winged_coronet" = 40_000
|
||||
"calendar.christmas.armor.misc.head.woolly_wintercap" = 250_000
|
||||
|
||||
# Crafting
|
||||
"crafting_ing.alkahest" = 6_000
|
||||
"crafting_ing.brinestone" = 2_000
|
||||
"crafting_ing.coral_branch" = 1_000
|
||||
"crafting_ing.hide.dragon_scale" = 5_000
|
||||
"crafting_ing.dwarven_battery" = 40_000
|
||||
"log.eldwood" = 3_000
|
||||
"mineral.ingot.orichalcum" = 8_000
|
||||
"mineral.ore.ancient_gold" = 10_000
|
||||
|
||||
# Potions
|
||||
[sell_prices.simple]
|
||||
"consumable.potion_minor" = 150
|
||||
|
||||
# Gliders
|
||||
"glider.skullgrin" = 20_000
|
||||
|
||||
# Recipes
|
||||
"recipes.armor.brinestone" = 8_000
|
||||
"recipes.equipment.advanced" = 8_000
|
||||
"recipes.unique.mindflayer_spellbag" = 10_000
|
||||
"recipes.unique.abyssal_gorget" = 6_000
|
||||
|
||||
# Instruments
|
||||
"tool.instruments.icy_talharpa" = 500_000
|
||||
"tool.instruments.steeltonguedrum" = 300_000
|
||||
|
||||
# Legendary Weapons
|
||||
"weapons.axe.parashu" = 100_000
|
||||
"weapons.sword.caladbolg" = 150_000
|
||||
"weapons.staff.laevateinn" = 60_000
|
||||
"weapons.hammer.mjolnir" = 150_000
|
||||
"weapons.sceptre.caduceus" = 150_000
|
||||
|
||||
# Lanterns
|
||||
"boss_drops.lantern" = 40_000 # Magic Lantern
|
||||
"lantern.blue_0" = 20_000
|
||||
"lantern.geode_purp" = 20_000
|
||||
[[sell_prices.modular]]
|
||||
material = "Iron"
|
||||
primary = "sword.greatsword"
|
||||
secondary = "sword.long"
|
||||
price = 1000
|
||||
|
167
src/bot.rs
167
src/bot.rs
@ -16,7 +16,10 @@ use veloren_common::{
|
||||
clock::Clock,
|
||||
comp::{
|
||||
invite::InviteKind,
|
||||
item::{ItemDefinitionId, ItemDefinitionIdOwned, ItemDesc, ItemI18n, MaterialStatManifest},
|
||||
item::{
|
||||
modular, ItemBase, ItemDef, ItemDefinitionId, ItemDefinitionIdOwned, ItemDesc,
|
||||
ItemI18n, MaterialStatManifest,
|
||||
},
|
||||
slot::InvSlotId,
|
||||
tool::AbilityMap,
|
||||
ChatType, ControllerInputs, Item, Ori, Pos,
|
||||
@ -30,7 +33,10 @@ use veloren_common::{
|
||||
};
|
||||
use veloren_common_net::sync::WorldSyncExt;
|
||||
|
||||
use crate::PriceList;
|
||||
|
||||
const COINS: &str = "common.items.utility.coins";
|
||||
const COINS_ID: ItemDefinitionId = ItemDefinitionId::Simple(Cow::Borrowed(COINS));
|
||||
|
||||
/// An active connection to the Veloren server that will attempt to run every time the `tick`
|
||||
/// function is called.
|
||||
@ -50,8 +56,8 @@ pub struct Bot {
|
||||
item_i18n: ItemI18n,
|
||||
localization: LocalizationHandle,
|
||||
|
||||
buy_prices: HashMap<String, u32>,
|
||||
sell_prices: HashMap<String, u32>,
|
||||
buy_prices: PriceList,
|
||||
sell_prices: PriceList,
|
||||
trade_mode: TradeMode,
|
||||
|
||||
previous_offer: Option<(HashMap<InvSlotId, u32>, HashMap<InvSlotId, u32>)>,
|
||||
@ -72,8 +78,8 @@ impl Bot {
|
||||
password: &str,
|
||||
character: &str,
|
||||
admins: Vec<String>,
|
||||
buy_prices: HashMap<String, u32>,
|
||||
sell_prices: HashMap<String, u32>,
|
||||
buy_prices: PriceList,
|
||||
sell_prices: PriceList,
|
||||
position: Option<[f32; 3]>,
|
||||
orientation: Option<f32>,
|
||||
announcement: Option<String>,
|
||||
@ -547,9 +553,9 @@ impl Bot {
|
||||
inventories.get(them).ok_or("Failed to find inventory")?,
|
||||
);
|
||||
|
||||
let coins = ItemDefinitionIdOwned::Simple(COINS.to_string());
|
||||
let get_my_coins = my_inventory.get_slot_of_item_by_def_id(&coins);
|
||||
let get_their_coins = their_inventory.get_slot_of_item_by_def_id(&coins);
|
||||
let coins_owned = COINS_ID.to_owned();
|
||||
let get_my_coins = my_inventory.get_slot_of_item_by_def_id(&coins_owned);
|
||||
let get_their_coins = their_inventory.get_slot_of_item_by_def_id(&coins_owned);
|
||||
|
||||
let (mut my_offered_coin_amount, mut their_offered_coin_amount) = (0, 0);
|
||||
let my_offered_items_value =
|
||||
@ -557,18 +563,20 @@ impl Bot {
|
||||
.into_iter()
|
||||
.fold(0, |acc: i32, (slot_id, quantity)| {
|
||||
if let Some(item) = my_inventory.get(*slot_id) {
|
||||
let item_id = item.persistence_item_id();
|
||||
let item_id = item.item_definition_id();
|
||||
|
||||
let item_value = if item_id == COINS {
|
||||
let item_value = if item_id == COINS_ID {
|
||||
my_offered_coin_amount = *quantity as i32;
|
||||
|
||||
1
|
||||
} else {
|
||||
self.sell_prices
|
||||
.simple
|
||||
.get(&item_id)
|
||||
.map(|int| *int as i32)
|
||||
.unwrap_or_else(|| {
|
||||
self.buy_prices
|
||||
.simple
|
||||
.get(&item_id)
|
||||
.map(|int| 0 - *int as i32)
|
||||
.unwrap_or(i32::MIN)
|
||||
@ -585,18 +593,20 @@ impl Bot {
|
||||
.into_iter()
|
||||
.fold(0, |acc: i32, (slot_id, quantity)| {
|
||||
if let Some(item) = their_inventory.get(*slot_id) {
|
||||
let item_id = item.persistence_item_id();
|
||||
let item_id = item.item_definition_id();
|
||||
|
||||
let item_value = if item_id == COINS {
|
||||
let item_value = if item_id == COINS_ID {
|
||||
their_offered_coin_amount = *quantity as i32;
|
||||
|
||||
1
|
||||
} else {
|
||||
self.buy_prices
|
||||
.simple
|
||||
.get(&item_id)
|
||||
.map(|int| *int as i32)
|
||||
.unwrap_or_else(|| {
|
||||
self.sell_prices
|
||||
.simple
|
||||
.get(&item_id)
|
||||
.map(|int| 0 - *int as i32)
|
||||
.unwrap_or(0)
|
||||
@ -613,13 +623,13 @@ impl Bot {
|
||||
|
||||
for (slot_id, amount) in my_offer {
|
||||
let item = my_inventory.get(*slot_id).ok_or("Failed to get item")?;
|
||||
let item_id = item.persistence_item_id();
|
||||
let item_id = item.item_definition_id();
|
||||
|
||||
if item_id == COINS {
|
||||
if item_id == COINS_ID {
|
||||
continue;
|
||||
}
|
||||
|
||||
if !self.sell_prices.contains_key(&item_id) {
|
||||
if !self.sell_prices.simple.contains_key(&item_id) {
|
||||
my_item_to_remove = Some((slot_id, amount));
|
||||
}
|
||||
}
|
||||
@ -628,13 +638,13 @@ impl Bot {
|
||||
|
||||
for (slot_id, amount) in their_offer {
|
||||
let item = their_inventory.get(*slot_id).ok_or("Failed to get item")?;
|
||||
let item_id = item.persistence_item_id();
|
||||
let item_id = item.item_definition_id();
|
||||
|
||||
if item_id == COINS {
|
||||
if item_id == COINS_ID {
|
||||
continue;
|
||||
}
|
||||
|
||||
if !self.buy_prices.contains_key(&item_id) {
|
||||
if !self.buy_prices.simple.contains_key(&item_id) {
|
||||
their_item_to_remove = Some((slot_id, amount));
|
||||
}
|
||||
}
|
||||
@ -741,8 +751,8 @@ impl Bot {
|
||||
.to_string();
|
||||
let mut found = false;
|
||||
|
||||
for (item_id, price) in &self.buy_prices {
|
||||
let item_name = self.get_item_name(item_id);
|
||||
for (item_id, price) in &self.buy_prices.simple {
|
||||
let item_name = self.get_item_name(item_id.as_ref());
|
||||
|
||||
if item_name.to_lowercase().contains(&search_term) {
|
||||
log::info!("Sending price info on {item_name} to {player_name}");
|
||||
@ -756,16 +766,60 @@ impl Bot {
|
||||
);
|
||||
|
||||
found = true;
|
||||
} else if item_id.contains(&search_term) {
|
||||
let short_id = item_id.splitn(3, '.').last().unwrap_or_default();
|
||||
|
||||
log::info!("Sending price info on {short_id} to {player_name}");
|
||||
continue;
|
||||
}
|
||||
|
||||
if let Some(item_id_string) = item_id.as_ref().itemdef_id() {
|
||||
if item_id_string.to_lowercase().contains(&search_term) {
|
||||
log::info!("Sending price info on {item_id_string} to {player_name}");
|
||||
|
||||
self.client.send_command(
|
||||
"tell".to_string(),
|
||||
vec![
|
||||
player_name.clone(),
|
||||
format!("Buying {short_id} for {price} coins."),
|
||||
format!("Buying {item_id_string} for {price} coins."),
|
||||
],
|
||||
);
|
||||
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for modular_item_listing in &self.buy_prices.modular {
|
||||
let material = ItemDefinitionId::Simple(Cow::Borrowed(
|
||||
modular_item_listing
|
||||
.material
|
||||
.asset_identifier()
|
||||
.ok_or(format!(
|
||||
"{:?} is not a valid material for modular crafted items",
|
||||
modular_item_listing.material
|
||||
))?,
|
||||
));
|
||||
let primary = modular_item_listing.primary.as_ref();
|
||||
let secondary = ItemDefinitionId::Compound {
|
||||
// This unwrap is safe because the ItemDefinitionId is always Simple.
|
||||
simple_base: primary.itemdef_id().unwrap(),
|
||||
components: vec![material],
|
||||
};
|
||||
let item_id = ItemDefinitionId::Modular {
|
||||
pseudo_base: "veloren.core.pseudo_items.modular.tool",
|
||||
components: vec![secondary],
|
||||
};
|
||||
let item_name = self.get_item_name(item_id);
|
||||
|
||||
if item_name.to_lowercase().contains(&search_term) {
|
||||
log::info!("Sending price info on {item_name} to {player_name}");
|
||||
|
||||
self.client.send_command(
|
||||
"tell".to_string(),
|
||||
vec![
|
||||
player_name.clone(),
|
||||
format!(
|
||||
"Buying {item_name} for {} coins.",
|
||||
modular_item_listing.price
|
||||
),
|
||||
],
|
||||
);
|
||||
|
||||
@ -773,8 +827,8 @@ impl Bot {
|
||||
}
|
||||
}
|
||||
|
||||
for (item_id, price) in &self.sell_prices {
|
||||
let item_name = self.get_item_name(item_id);
|
||||
for (item_id, price) in &self.sell_prices.simple {
|
||||
let item_name = self.get_item_name(item_id.as_ref());
|
||||
|
||||
if item_name.to_lowercase().contains(&search_term) {
|
||||
log::info!("Sending price info on {item_name} to {player_name}");
|
||||
@ -788,16 +842,60 @@ impl Bot {
|
||||
);
|
||||
|
||||
found = true;
|
||||
} else if item_id.contains(&search_term) {
|
||||
let short_id = item_id.splitn(3, '.').last().unwrap_or_default();
|
||||
|
||||
log::info!("Sending price info on {short_id} to {player_name}");
|
||||
continue;
|
||||
}
|
||||
|
||||
if let Some(item_id_string) = item_id.as_ref().itemdef_id() {
|
||||
if item_id_string.to_lowercase().contains(&search_term) {
|
||||
log::info!("Sending price info on {item_id_string} to {player_name}");
|
||||
|
||||
self.client.send_command(
|
||||
"tell".to_string(),
|
||||
vec![
|
||||
player_name.clone(),
|
||||
format!("Selling {short_id} for {price} coins."),
|
||||
format!("Selling {item_id_string} for {price} coins."),
|
||||
],
|
||||
);
|
||||
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for modular_item_listing in &self.sell_prices.modular {
|
||||
let material = ItemDefinitionId::Simple(Cow::Borrowed(
|
||||
modular_item_listing
|
||||
.material
|
||||
.asset_identifier()
|
||||
.ok_or(format!(
|
||||
"{:?} is not a valid material for modular crafted items",
|
||||
modular_item_listing.material
|
||||
))?,
|
||||
));
|
||||
let primary = modular_item_listing.primary.as_ref();
|
||||
let secondary = ItemDefinitionId::Compound {
|
||||
// This unwrap is safe because the ItemDefinitionId is always Simple.
|
||||
simple_base: primary.itemdef_id().unwrap(),
|
||||
components: vec![material],
|
||||
};
|
||||
let item_id = ItemDefinitionId::Modular {
|
||||
pseudo_base: "veloren.core.pseudo_items.modular.tool",
|
||||
components: vec![secondary],
|
||||
};
|
||||
let item_name = self.get_item_name(item_id);
|
||||
|
||||
if item_name.to_lowercase().contains(&search_term) {
|
||||
log::info!("Sending price info on {item_name} to {player_name}");
|
||||
|
||||
self.client.send_command(
|
||||
"tell".to_string(),
|
||||
vec![
|
||||
player_name.clone(),
|
||||
format!(
|
||||
"Selling {item_name} for {} coins.",
|
||||
modular_item_listing.price
|
||||
),
|
||||
],
|
||||
);
|
||||
|
||||
@ -866,12 +964,9 @@ impl Bot {
|
||||
}
|
||||
|
||||
/// Gets the name of an item from its id.
|
||||
fn get_item_name(&self, item_id: &str) -> String {
|
||||
let item = Item::new_from_item_definition_id(
|
||||
ItemDefinitionId::Simple(Cow::Borrowed(item_id)),
|
||||
&self.ability_map,
|
||||
&self.material_manifest,
|
||||
)
|
||||
fn get_item_name(&self, item_id: ItemDefinitionId) -> String {
|
||||
let item =
|
||||
Item::new_from_item_definition_id(item_id, &self.ability_map, &self.material_manifest)
|
||||
.unwrap();
|
||||
let (item_name_i18n_id, _) = item.i18n(&self.item_i18n);
|
||||
|
||||
|
175
src/main.rs
175
src/main.rs
@ -2,24 +2,165 @@
|
||||
|
||||
mod bot;
|
||||
|
||||
use std::{env::var, fs::read_to_string};
|
||||
use std::{borrow::Cow, env::var, fs::read_to_string, str::FromStr};
|
||||
|
||||
use bot::Bot;
|
||||
use hashbrown::HashMap;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde::{de::Visitor, Deserialize};
|
||||
use veloren_common::comp::item::{ItemDefinitionId, ItemDefinitionIdOwned, Material};
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct PriceList {
|
||||
pub simple: HashMap<ItemDefinitionIdOwned, u32>,
|
||||
pub modular: Vec<ModularItemPrice>,
|
||||
}
|
||||
|
||||
impl<'de> Deserialize<'de> for PriceList {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: serde::Deserializer<'de>,
|
||||
{
|
||||
deserializer.deserialize_map(PriceListVisitor)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct PriceListVisitor;
|
||||
|
||||
impl<'de> Visitor<'de> for PriceListVisitor {
|
||||
type Value = PriceList;
|
||||
|
||||
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
formatter.write_str("a map with simple and/or modular keys")
|
||||
}
|
||||
|
||||
fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
|
||||
where
|
||||
A: serde::de::MapAccess<'de>,
|
||||
{
|
||||
let mut simple = None;
|
||||
let mut modular = None;
|
||||
|
||||
while let Some(key) = map.next_key::<String>()? {
|
||||
match key.as_str() {
|
||||
"simple" => {
|
||||
let simple_prices_with_item_string =
|
||||
map.next_value::<HashMap<String, u32>>()?;
|
||||
let simple_prices_with_item_id = simple_prices_with_item_string
|
||||
.into_iter()
|
||||
.map(|(mut key, value)| {
|
||||
key.insert_str(0, "common.items.");
|
||||
|
||||
(ItemDefinitionIdOwned::Simple(key), value)
|
||||
})
|
||||
.collect();
|
||||
|
||||
simple = Some(simple_prices_with_item_id);
|
||||
}
|
||||
"modular" => {
|
||||
modular = Some(map.next_value()?);
|
||||
}
|
||||
_ => {
|
||||
return Err(serde::de::Error::unknown_field(
|
||||
&key,
|
||||
&["simple", "modular"],
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(PriceList {
|
||||
simple: simple.ok_or_else(|| serde::de::Error::missing_field("simple"))?,
|
||||
modular: modular.ok_or_else(|| serde::de::Error::missing_field("modular"))?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Hash)]
|
||||
pub struct ModularItemPrice {
|
||||
pub material: Material,
|
||||
pub primary: ItemDefinitionIdOwned,
|
||||
pub secondary: ItemDefinitionIdOwned,
|
||||
pub price: u32,
|
||||
}
|
||||
|
||||
impl<'de> Deserialize<'de> for ModularItemPrice {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: serde::Deserializer<'de>,
|
||||
{
|
||||
deserializer.deserialize_map(ModularPriceVisitor)
|
||||
}
|
||||
}
|
||||
|
||||
struct ModularPriceVisitor;
|
||||
|
||||
impl<'de> Visitor<'de> for ModularPriceVisitor {
|
||||
type Value = ModularItemPrice;
|
||||
|
||||
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
formatter.write_str("a map with material, primary, secondary and price keys")
|
||||
}
|
||||
|
||||
fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
|
||||
where
|
||||
A: serde::de::MapAccess<'de>,
|
||||
{
|
||||
let mut material = None;
|
||||
let mut primary = None;
|
||||
let mut secondary = None;
|
||||
let mut price = None;
|
||||
|
||||
while let Some(key) = map.next_key::<String>()? {
|
||||
match key.as_str() {
|
||||
"material" => {
|
||||
material = Some(map.next_value()?);
|
||||
}
|
||||
"primary" => {
|
||||
let mut primary_string = map.next_value::<String>()?;
|
||||
|
||||
primary_string.insert_str(0, "common.items.modular.weapon.primary.");
|
||||
|
||||
primary = Some(ItemDefinitionIdOwned::Simple(primary_string));
|
||||
}
|
||||
"secondary" => {
|
||||
let mut secondary_string = map.next_value::<String>()?;
|
||||
|
||||
secondary_string.insert_str(0, "common.items.modular.weapon.secondary.");
|
||||
|
||||
secondary = Some(ItemDefinitionIdOwned::Simple(secondary_string));
|
||||
}
|
||||
"price" => {
|
||||
price = Some(map.next_value()?);
|
||||
}
|
||||
_ => {
|
||||
return Err(serde::de::Error::unknown_field(
|
||||
&key,
|
||||
&["material", "primary", "secondary", "price"],
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(ModularItemPrice {
|
||||
material: material.ok_or_else(|| serde::de::Error::missing_field("material"))?,
|
||||
primary: primary.ok_or_else(|| serde::de::Error::missing_field("primary"))?,
|
||||
secondary: secondary.ok_or_else(|| serde::de::Error::missing_field("secondary"))?,
|
||||
price: price.ok_or_else(|| serde::de::Error::missing_field("price"))?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct Config {
|
||||
pub game_server: Option<String>,
|
||||
pub auth_server: Option<String>,
|
||||
pub position: Option<[f32; 3]>,
|
||||
pub orientation: Option<f32>,
|
||||
pub announcement: Option<String>,
|
||||
pub buy_prices: HashMap<String, u32>,
|
||||
pub sell_prices: HashMap<String, u32>,
|
||||
pub buy_prices: PriceList,
|
||||
pub sell_prices: PriceList,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[derive(Deserialize)]
|
||||
pub struct Secrets {
|
||||
pub username: String,
|
||||
pub password: String,
|
||||
@ -50,24 +191,6 @@ fn main() {
|
||||
let auth_server = config
|
||||
.auth_server
|
||||
.unwrap_or("https://auth.veloren.net".to_string());
|
||||
let buy_prices_with_full_id = config
|
||||
.buy_prices
|
||||
.into_iter()
|
||||
.map(|(mut item_id, price)| {
|
||||
item_id.insert_str(0, "common.items.");
|
||||
|
||||
(item_id, price)
|
||||
})
|
||||
.collect();
|
||||
let sell_prices_with_full_id = config
|
||||
.sell_prices
|
||||
.into_iter()
|
||||
.map(|(mut item_id, price)| {
|
||||
item_id.insert_str(0, "common.items.");
|
||||
|
||||
(item_id, price)
|
||||
})
|
||||
.collect();
|
||||
let mut bot = Bot::new(
|
||||
game_server,
|
||||
&auth_server,
|
||||
@ -75,8 +198,8 @@ fn main() {
|
||||
&secrets.password,
|
||||
&secrets.character,
|
||||
secrets.admins,
|
||||
buy_prices_with_full_id,
|
||||
sell_prices_with_full_id,
|
||||
config.buy_prices,
|
||||
config.sell_prices,
|
||||
config.position,
|
||||
config.orientation,
|
||||
config.announcement,
|
||||
|
Loading…
Reference in New Issue
Block a user