Fix price bug (thanks Hrom!); Add cost notifying
This commit is contained in:
parent
c731c99208
commit
fc83c2b37e
@ -16,6 +16,7 @@ Create a "secrets.toml" file:
|
|||||||
# secrets.toml
|
# secrets.toml
|
||||||
username = "my_username"
|
username = "my_username"
|
||||||
password = "my_password"
|
password = "my_password"
|
||||||
|
character = "my_character"
|
||||||
```
|
```
|
||||||
|
|
||||||
Then create a secret to pass the file securely to the container.
|
Then create a secret to pass the file securely to the container.
|
||||||
@ -29,7 +30,6 @@ You will also need a "config.toml":
|
|||||||
|
|
||||||
```toml
|
```toml
|
||||||
# config.toml
|
# config.toml
|
||||||
character = "my_character"
|
|
||||||
position = [0.0, 0.0, 0.0] # Change these to the desired X, Y, Z coordinates
|
position = [0.0, 0.0, 0.0] # Change these to the desired X, Y, Z coordinates
|
||||||
orientation = "West"
|
orientation = "West"
|
||||||
|
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
character = "crabobot_test"
|
|
||||||
position = [17726.0, 14957.0, 237.0]
|
position = [17726.0, 14957.0, 237.0]
|
||||||
orientation = "West"
|
orientation = "West"
|
||||||
|
|
||||||
@ -6,6 +5,8 @@ orientation = "West"
|
|||||||
"common.items.food.cheese" = 50
|
"common.items.food.cheese" = 50
|
||||||
|
|
||||||
[sell_prices]
|
[sell_prices]
|
||||||
|
|
||||||
|
# Boreal Armor
|
||||||
"common.items.armor.boreal.back" = 250_000
|
"common.items.armor.boreal.back" = 250_000
|
||||||
"common.items.armor.boreal.belt" = 250_000
|
"common.items.armor.boreal.belt" = 250_000
|
||||||
"common.items.armor.boreal.chest" = 250_000
|
"common.items.armor.boreal.chest" = 250_000
|
||||||
@ -13,31 +14,44 @@ orientation = "West"
|
|||||||
"common.items.armor.boreal.hand" = 250_000
|
"common.items.armor.boreal.hand" = 250_000
|
||||||
"common.items.armor.boreal.pants" = 250_000
|
"common.items.armor.boreal.pants" = 250_000
|
||||||
"common.items.armor.boreal.shoulder" = 250_000
|
"common.items.armor.boreal.shoulder" = 250_000
|
||||||
|
|
||||||
"common.items.armor.misc.head.boreal_warhelm" = 450_000
|
"common.items.armor.misc.head.boreal_warhelm" = 450_000
|
||||||
"common.items.armor.misc.head.cat_capuche" = 600_000
|
|
||||||
|
# Hats
|
||||||
|
"common.items.armor.misc.head.cat_capuche" = 700_000
|
||||||
"common.items.armor.misc.head.hare_hat" = 100_000
|
"common.items.armor.misc.head.hare_hat" = 100_000
|
||||||
"common.items.armor.misc.head.winged_coronet" = 40_000
|
"common.items.armor.misc.head.winged_coronet" = 40_000
|
||||||
|
"common.items.calendar.christmas.armor.misc.head.woolly_wintercap" = 800_000
|
||||||
|
|
||||||
|
# Crafting
|
||||||
"common.items.crafting_ing.brinestone" = 2000
|
"common.items.crafting_ing.brinestone" = 2000
|
||||||
"common.items.crafting_ing.coral_brach" = 1000
|
"common.items.crafting_ing.coral_brach" = 1000
|
||||||
"common.items.crafting_ing.dwarven_battery" = 40000
|
"common.items.crafting_ing.dwarven_battery" = 40000
|
||||||
|
|
||||||
"common.items.consumable.potion_minor" = 150
|
|
||||||
|
|
||||||
"common.items.glider.skullgrin" = 20_000
|
|
||||||
|
|
||||||
"common.items.log.eldwood" = 3000
|
"common.items.log.eldwood" = 3000
|
||||||
|
|
||||||
"common.items.mineral.ingot.orichalcum" = 8000
|
"common.items.mineral.ingot.orichalcum" = 8000
|
||||||
|
|
||||||
|
# Potions
|
||||||
|
"common.items.consumable.potion_minor" = 150
|
||||||
|
|
||||||
|
# Gliders
|
||||||
|
"common.items.glider.skullgrin" = 20_000
|
||||||
|
|
||||||
|
# Recipes
|
||||||
|
"common.items.recipes.equipment.advanced" = 8000
|
||||||
|
"common.items.recipes.unique.mindflayer_spellbag" = 10000
|
||||||
|
"common.items.recipes.unique.abyssal_gorget" = 6000
|
||||||
|
|
||||||
|
# Instruments
|
||||||
"common.items.tool.instruments.icy_talharpa" = 500_000
|
"common.items.tool.instruments.icy_talharpa" = 500_000
|
||||||
"common.items.tool.instruments.steeltonguedrum" = 300_000
|
"common.items.tool.instruments.steeltonguedrum" = 300_000
|
||||||
|
|
||||||
|
# Legendary Weapons
|
||||||
"common.items.weapons.axe.parashu" = 100_000
|
"common.items.weapons.axe.parashu" = 100_000
|
||||||
"common.items.weapons.sword.caladbolg" = 100_000
|
"common.items.weapons.sword.caladbolg" = 150_000
|
||||||
"common.items.weapons.staff.laevateinn" = 60_000
|
"common.items.weapons.staff.laevateinn" = 60_000
|
||||||
"common.items.weapons.hammer.mjolnir" = 100_000
|
"common.items.weapons.hammer.mjolnir" = 150_000
|
||||||
"common.items.weapons.sceptre.caduceus" = 150_000
|
"common.items.weapons.sceptre.caduceus" = 150_000
|
||||||
|
|
||||||
"common.items.lantern.geode_purple" = 20_000
|
# Lanterns
|
||||||
|
"common.items.boss_drops.lantern" = 40_000 # Magic Lantern
|
||||||
|
"common.items.lantern.blue_0" = 20_000
|
||||||
|
"common.items.lantern.geode_purp" = 20_000
|
||||||
|
191
src/bot.rs
191
src/bot.rs
@ -33,10 +33,10 @@ pub struct Bot {
|
|||||||
sell_prices: HashMap<String, u32>,
|
sell_prices: HashMap<String, u32>,
|
||||||
trade_mode: TradeMode,
|
trade_mode: TradeMode,
|
||||||
|
|
||||||
is_player_notified: bool,
|
|
||||||
last_action: Instant,
|
last_action: Instant,
|
||||||
last_announcement: Instant,
|
last_announcement: Instant,
|
||||||
last_ouch: Instant,
|
last_ouch: Instant,
|
||||||
|
last_cost_difference: i32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Bot {
|
impl Bot {
|
||||||
@ -95,10 +95,10 @@ impl Bot {
|
|||||||
buy_prices,
|
buy_prices,
|
||||||
sell_prices,
|
sell_prices,
|
||||||
trade_mode: TradeMode::Trade,
|
trade_mode: TradeMode::Trade,
|
||||||
is_player_notified: false,
|
|
||||||
last_action: now,
|
last_action: now,
|
||||||
last_announcement: now,
|
last_announcement: now,
|
||||||
last_ouch: now,
|
last_ouch: now,
|
||||||
|
last_cost_difference: 0,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -135,7 +135,7 @@ impl Bot {
|
|||||||
if self.last_announcement.elapsed() > Duration::from_secs(1200) {
|
if self.last_announcement.elapsed() > Duration::from_secs(1200) {
|
||||||
self.client.send_command(
|
self.client.send_command(
|
||||||
"region".to_string(),
|
"region".to_string(),
|
||||||
vec!["I'm a bot. You can trade with me or use /say or /tell to check prices: 'price [item_name]' or 'prices'.".to_string()],
|
vec!["I'm a bot. You can trade with me or use /say or /tell to check prices: 'price [item_name]'".to_string()],
|
||||||
);
|
);
|
||||||
|
|
||||||
self.last_announcement = Instant::now();
|
self.last_announcement = Instant::now();
|
||||||
@ -158,58 +158,12 @@ impl Bot {
|
|||||||
};
|
};
|
||||||
let content = message.content().as_plain().unwrap_or_default();
|
let content = message.content().as_plain().unwrap_or_default();
|
||||||
let (command, item_name) = content.split_once(' ').unwrap_or((content, ""));
|
let (command, item_name) = content.split_once(' ').unwrap_or((content, ""));
|
||||||
|
let item_name = item_name.to_lowercase();
|
||||||
|
|
||||||
match command {
|
match command {
|
||||||
"price" => {
|
"price" => {
|
||||||
let player_name = self
|
self.send_price_info(&sender, &item_name)?;
|
||||||
.find_name(&sender)
|
|
||||||
.ok_or("Failed to find player name")?
|
|
||||||
.to_string();
|
|
||||||
let mut found = false;
|
|
||||||
|
|
||||||
for (item_id, price) in &self.buy_prices {
|
|
||||||
if item_id.contains(item_name) {
|
|
||||||
log::debug!("Sending price info on {item_id} to {player_name}");
|
|
||||||
|
|
||||||
self.client.send_command(
|
|
||||||
"tell".to_string(),
|
|
||||||
vec![
|
|
||||||
player_name.clone(),
|
|
||||||
format!("I buy {item_id} for {price} coins."),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
|
|
||||||
found = true;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
for (item_id, price) in &self.sell_prices {
|
|
||||||
if item_id.contains(item_name) {
|
|
||||||
log::debug!("Sending price info on {item_id} to {player_name}");
|
|
||||||
|
|
||||||
self.client.send_command(
|
|
||||||
"tell".to_string(),
|
|
||||||
vec![
|
|
||||||
player_name.clone(),
|
|
||||||
format!("I sell {item_id} for {price} coins."),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
|
|
||||||
found = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if !found {
|
|
||||||
self.client.send_command(
|
|
||||||
"tell".to_string(),
|
|
||||||
vec![
|
|
||||||
player_name.clone(),
|
|
||||||
format!("I don't have a price for that item."),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"prices" => self.send_all_price_info(&sender)?,
|
|
||||||
"take" => {
|
"take" => {
|
||||||
if !self.client.is_trading() {
|
if !self.client.is_trading() {
|
||||||
self.trade_mode = TradeMode::Take;
|
self.trade_mode = TradeMode::Take;
|
||||||
@ -249,7 +203,6 @@ impl Bot {
|
|||||||
log::info!("Completed trade: {result:?}");
|
log::info!("Completed trade: {result:?}");
|
||||||
|
|
||||||
if let TradeMode::Take = self.trade_mode {
|
if let TradeMode::Take = self.trade_mode {
|
||||||
self.is_player_notified = false;
|
|
||||||
self.trade_mode = TradeMode::Trade;
|
self.trade_mode = TradeMode::Trade;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -289,12 +242,6 @@ impl Bot {
|
|||||||
.ok_or("Failed to get offer index")?;
|
.ok_or("Failed to get offer index")?;
|
||||||
let their_offer_index = if my_offer_index == 0 { 1 } else { 0 };
|
let their_offer_index = if my_offer_index == 0 { 1 } else { 0 };
|
||||||
|
|
||||||
if !self.is_player_notified {
|
|
||||||
self.send_all_price_info(&trade.parties[their_offer_index])?;
|
|
||||||
|
|
||||||
self.is_player_notified = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if trade.is_empty_trade() {
|
if trade.is_empty_trade() {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
@ -311,16 +258,14 @@ impl Bot {
|
|||||||
)
|
)
|
||||||
};
|
};
|
||||||
let inventories = self.client.inventories();
|
let inventories = self.client.inventories();
|
||||||
let my_inventory = inventories.get(self.client.entity()).unwrap();
|
let my_inventory = inventories
|
||||||
let my_coins = my_inventory
|
.get(self.client.entity())
|
||||||
.get_slot_of_item_by_def_id(&ItemDefinitionIdOwned::Simple(COINS.to_string()))
|
.ok_or("Failed to find inventory")?;
|
||||||
.ok_or("Failed to find coins".to_string())?;
|
let get_my_coins = my_inventory
|
||||||
let their_inventory = inventories
|
.get_slot_of_item_by_def_id(&ItemDefinitionIdOwned::Simple(COINS.to_string()));
|
||||||
.get(them)
|
let their_inventory = inventories.get(them).ok_or("Failed to find inventory")?;
|
||||||
.ok_or("Failed to find inventory".to_string())?;
|
let get_their_coins = their_inventory
|
||||||
let their_coins = their_inventory
|
.get_slot_of_item_by_def_id(&ItemDefinitionIdOwned::Simple(COINS.to_string()));
|
||||||
.get_slot_of_item_by_def_id(&ItemDefinitionIdOwned::Simple(COINS.to_string()))
|
|
||||||
.ok_or("Failed to find coins")?;
|
|
||||||
let (mut their_offered_coin_amount, mut my_offered_coin_amount) = (0, 0);
|
let (mut their_offered_coin_amount, mut my_offered_coin_amount) = (0, 0);
|
||||||
let their_offered_items_value =
|
let their_offered_items_value =
|
||||||
their_offer
|
their_offer
|
||||||
@ -439,6 +384,13 @@ impl Bot {
|
|||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let (my_coins, their_coins) =
|
||||||
|
if let (Some(mine), Some(theirs)) = (get_my_coins, get_their_coins) {
|
||||||
|
(mine, theirs)
|
||||||
|
} else {
|
||||||
|
return Ok(());
|
||||||
|
};
|
||||||
|
|
||||||
let difference = their_offered_items_value - my_offered_items_value;
|
let difference = their_offered_items_value - my_offered_items_value;
|
||||||
|
|
||||||
// If the trade is balanced
|
// If the trade is balanced
|
||||||
@ -447,7 +399,6 @@ impl Bot {
|
|||||||
self.client
|
self.client
|
||||||
.perform_trade_action(TradeAction::Accept(trade.phase));
|
.perform_trade_action(TradeAction::Accept(trade.phase));
|
||||||
|
|
||||||
return Ok(());
|
|
||||||
// If they are offering more
|
// If they are offering more
|
||||||
} else if difference.is_positive() {
|
} else if difference.is_positive() {
|
||||||
// If they are offering coins
|
// If they are offering coins
|
||||||
@ -488,6 +439,22 @@ impl Bot {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if difference != self.last_cost_difference {
|
||||||
|
let their_name = self
|
||||||
|
.find_name(&trade.parties[their_offer_index])
|
||||||
|
.ok_or("Failed to find player name")?
|
||||||
|
.to_string();
|
||||||
|
|
||||||
|
log::debug!("Sending cost to {their_name}");
|
||||||
|
|
||||||
|
self.client.send_command(
|
||||||
|
"tell".to_string(),
|
||||||
|
vec![their_name, format!("My offer: {my_offered_items_value}. Your offer: {their_offered_items_value}.")],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.last_cost_difference = difference;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -511,55 +478,71 @@ impl Bot {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn send_all_price_info(&mut self, target: &Uid) -> Result<(), String> {
|
fn send_price_info(&mut self, target: &Uid, item_name: &str) -> Result<(), String> {
|
||||||
let player_name = self
|
let player_name = self
|
||||||
.find_name(target)
|
.find_name(target)
|
||||||
.ok_or("Failed to find player name")?
|
.ok_or("Failed to find player name")?
|
||||||
.to_string();
|
.to_string();
|
||||||
|
let mut found = false;
|
||||||
|
|
||||||
|
for (item_id, price) in &self.buy_prices {
|
||||||
|
if item_id.contains(item_name) {
|
||||||
|
let short_id = item_id.splitn(3, '.').last().unwrap_or_default();
|
||||||
|
|
||||||
|
log::debug!("Sending price info on {short_id} to {player_name}");
|
||||||
|
|
||||||
self.client.send_command(
|
self.client.send_command(
|
||||||
"tell".to_string(),
|
"tell".to_string(),
|
||||||
vec![
|
vec![
|
||||||
player_name.clone(),
|
player_name.clone(),
|
||||||
format!("Buy prices: {:?}", self.buy_prices),
|
format!("Buying {short_id} for {price} coins."),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
found = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (item_id, price) in &self.sell_prices {
|
||||||
|
if item_id.contains(item_name) {
|
||||||
|
let short_id = item_id.splitn(3, '.').last().unwrap_or_default();
|
||||||
|
|
||||||
|
log::debug!("Sending price info on {short_id} to {player_name}");
|
||||||
|
|
||||||
self.client.send_command(
|
self.client.send_command(
|
||||||
"tell".to_string(),
|
"tell".to_string(),
|
||||||
vec![player_name, format!("Sell prices: {:?}", self.sell_prices)],
|
vec![
|
||||||
|
player_name.clone(),
|
||||||
|
format!("Selling {short_id} for {price} coins."),
|
||||||
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
found = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !found {
|
||||||
|
log::debug!("Found no price for \"{item_name}\" for {player_name}");
|
||||||
|
|
||||||
|
self.client.send_command(
|
||||||
|
"tell".to_string(),
|
||||||
|
vec![
|
||||||
|
player_name.clone(),
|
||||||
|
format!("I don't have a price for that item."),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn find_name<'a>(&'a self, uid: &Uid) -> Option<&'a String> {
|
fn find_name<'a>(&'a self, uid: &Uid) -> Option<&'a String> {
|
||||||
self.client.player_list().iter().find_map(|(id, info)| {
|
self.client.player_list().iter().find_map(|(id, info)| {
|
||||||
if id == uid {
|
if id == uid {
|
||||||
if let Some(character_info) = &info.character {
|
return Some(&info.player_alias);
|
||||||
return Some(&character_info.name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn _find_uid<'a>(&'a self, name: &str) -> Option<&'a Uid> {
|
|
||||||
self.client.player_list().iter().find_map(|(id, info)| {
|
|
||||||
if info.player_alias == name {
|
|
||||||
Some(id)
|
|
||||||
} else {
|
|
||||||
None
|
None
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn _find_uuid(&self, name: &str) -> Option<String> {
|
|
||||||
self.client.player_list().iter().find_map(|(_, info)| {
|
|
||||||
if info.player_alias == name {
|
|
||||||
Some(info.uuid.to_string())
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -601,6 +584,26 @@ impl Bot {
|
|||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn _find_uid<'a>(&'a self, name: &str) -> Option<&'a Uid> {
|
||||||
|
self.client.player_list().iter().find_map(|(id, info)| {
|
||||||
|
if info.player_alias == name {
|
||||||
|
Some(id)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn _find_uuid(&self, name: &str) -> Option<String> {
|
||||||
|
self.client.player_list().iter().find_map(|(_, info)| {
|
||||||
|
if info.player_alias == name {
|
||||||
|
Some(info.uuid.to_string())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enum TradeMode {
|
enum TradeMode {
|
||||||
|
@ -9,11 +9,11 @@ use serde::{Deserialize, Serialize};
|
|||||||
pub struct Secrets {
|
pub struct Secrets {
|
||||||
pub username: String,
|
pub username: String,
|
||||||
pub password: String,
|
pub password: String,
|
||||||
|
pub character: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
struct Config {
|
struct Config {
|
||||||
pub character: String,
|
|
||||||
pub buy_prices: HashMap<String, u32>,
|
pub buy_prices: HashMap<String, u32>,
|
||||||
pub sell_prices: HashMap<String, u32>,
|
pub sell_prices: HashMap<String, u32>,
|
||||||
pub position: [f32; 3],
|
pub position: [f32; 3],
|
||||||
@ -42,7 +42,7 @@ fn main() {
|
|||||||
let mut bot = Bot::new(
|
let mut bot = Bot::new(
|
||||||
&secrets.username,
|
&secrets.username,
|
||||||
&secrets.password,
|
&secrets.password,
|
||||||
&config.character,
|
&secrets.character,
|
||||||
config.buy_prices,
|
config.buy_prices,
|
||||||
config.sell_prices,
|
config.sell_prices,
|
||||||
config.position,
|
config.position,
|
||||||
|
Loading…
Reference in New Issue
Block a user