267 lines
7.0 KiB
Rust
267 lines
7.0 KiB
Rust
use serde_cbor::{from_slice, to_vec};
|
|
use uuid::Uuid;
|
|
|
|
use postgres::transaction::Transaction;
|
|
use failure::Error;
|
|
|
|
// drops
|
|
use rand::prelude::*;
|
|
use rand::{thread_rng};
|
|
use rand::distributions::{LogNormal,WeightedIndex};
|
|
|
|
use account::Account;
|
|
use rpc::{ItemUseParams};
|
|
use cryp::{Stat, cryp_get, cryp_write};
|
|
use game::{GameMode};
|
|
use spec::{Spec, SpecType};
|
|
|
|
#[derive(Debug,Clone,Copy,PartialEq,Serialize,Deserialize)]
|
|
pub enum ItemAction {
|
|
RerollRedDamage,
|
|
RerollBlueDamage,
|
|
RerollSpeed,
|
|
RerollGreenLife,
|
|
RerollRedLife,
|
|
RerollBlueLife,
|
|
RerollEvasion,
|
|
|
|
SpecRedDamage5,
|
|
SpecBlueDamage5,
|
|
SpecRedLife5,
|
|
SpecBlueLife5,
|
|
SpecBlueEvasion5,
|
|
}
|
|
|
|
#[derive(Debug,Clone,Copy,PartialEq,Serialize,Deserialize)]
|
|
pub struct Item {
|
|
// mods: Vec<Mod>,
|
|
id: Uuid,
|
|
account: Uuid,
|
|
action: ItemAction,
|
|
}
|
|
|
|
impl Item {
|
|
pub fn new(action: ItemAction, account_id: Uuid) -> Item {
|
|
let id = Uuid::new_v4();
|
|
return Item {
|
|
id,
|
|
account: account_id,
|
|
action,
|
|
};
|
|
}
|
|
|
|
fn apply(&mut self, tx: &mut Transaction, target: Uuid) -> Result<(), Error> {
|
|
match self.action {
|
|
ItemAction::RerollGreenLife => reroll(self, tx, target, Stat::GreenLife),
|
|
ItemAction::RerollRedDamage => reroll(self, tx, target, Stat::RedDamage),
|
|
ItemAction::RerollBlueDamage => reroll(self, tx, target, Stat::BlueDamage),
|
|
ItemAction::RerollSpeed => reroll(self, tx, target, Stat::Speed),
|
|
ItemAction::RerollRedLife => reroll(self, tx, target, Stat::RedLife),
|
|
ItemAction::RerollBlueLife => reroll(self, tx, target, Stat::BlueLife),
|
|
ItemAction::RerollEvasion => reroll(self, tx, target, Stat::Evasion),
|
|
|
|
ItemAction::SpecRedDamage5 => spec_add(self, tx, target, SpecType::RedDamage5),
|
|
ItemAction::SpecBlueDamage5 => spec_add(self, tx, target, SpecType::BlueDamage5),
|
|
_ => unimplemented!(),
|
|
}
|
|
}
|
|
}
|
|
|
|
fn spec_add(item: &mut Item, tx: &mut Transaction, target: Uuid, spec_type: SpecType) -> Result<(), Error> {
|
|
let mut cryp = cryp_get(tx, target, item.account)?;
|
|
let spec = Spec::new(spec_type);
|
|
cryp.spec_add(spec)?;
|
|
cryp_write(cryp, tx)?;
|
|
return Ok(());
|
|
}
|
|
|
|
fn reroll(item: &mut Item, tx: &mut Transaction, target: Uuid, stat: Stat) -> Result<(), Error> {
|
|
let mut cryp = cryp_get(tx, target, item.account)?;
|
|
cryp.roll_stat(stat);
|
|
cryp_write(cryp, tx)?;
|
|
return Ok(());
|
|
}
|
|
|
|
fn mode_drops(mode: GameMode) -> Vec<(ItemAction, usize)> {
|
|
match mode {
|
|
GameMode::Normal => vec![
|
|
(ItemAction::RerollGreenLife, 1),
|
|
(ItemAction::RerollRedDamage, 1),
|
|
(ItemAction::RerollBlueDamage, 1),
|
|
],
|
|
GameMode::Pvp => vec![
|
|
(ItemAction::RerollSpeed, 1),
|
|
],
|
|
GameMode::Zone3v2Attack |
|
|
GameMode::Zone2v2Caster |
|
|
GameMode::Zone3v3MeleeMiniboss => vec![
|
|
(ItemAction::RerollEvasion, 1),
|
|
(ItemAction::RerollRedLife, 1),
|
|
(ItemAction::RerollBlueLife, 1),
|
|
],
|
|
GameMode::Zone3v3HealerBoss => vec![
|
|
(ItemAction::RerollSpeed, 1),
|
|
],
|
|
// _ => vec![
|
|
// (ItemAction::RerollGreenLife, 1),
|
|
// (ItemAction::RerollRedDamage, 1),
|
|
// (ItemAction::RerollBlueDamage, 1),
|
|
// (ItemAction::RerollSpeed, 1),
|
|
// (ItemAction::RerollRedLife, 1),
|
|
// (ItemAction::RerollBlueLife, 1),
|
|
// (ItemAction::RerollEvasion, 1),
|
|
// ],
|
|
}
|
|
}
|
|
|
|
pub fn item_drop(tx: &mut Transaction, account_id: Uuid, mode: GameMode) -> Result<(), Error> {
|
|
let mut rng = thread_rng();
|
|
|
|
let log_normal = LogNormal::new(1.0, 1.0);
|
|
let num_drops = log_normal.sample(&mut rng).floor() as u16;
|
|
|
|
let actions = mode_drops(mode);
|
|
println!("{:?} drops", num_drops);
|
|
|
|
for _i in 0..num_drops {
|
|
let dist = WeightedIndex::new(actions.iter().map(|item| item.1)).unwrap();
|
|
let kind = actions[dist.sample(&mut rng)].0;
|
|
let item = Item::new(kind, account_id);
|
|
|
|
println!("{:?} dropped {:?}", account_id, item);
|
|
item_create(item, tx, account_id)?;
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
|
|
|
|
pub fn item_create(item: Item, tx: &mut Transaction, account_id: Uuid) -> Result<Item, Error> {
|
|
let item_bytes = to_vec(&item)?;
|
|
|
|
let query = "
|
|
INSERT INTO items (id, account, data)
|
|
VALUES ($1, $2, $3)
|
|
RETURNING id, account, data;
|
|
";
|
|
|
|
let result = tx
|
|
.query(query, &[&item.id, &account_id, &item_bytes])?;
|
|
|
|
result.iter().next().expect("no row returned");
|
|
|
|
return Ok(item);
|
|
}
|
|
|
|
pub fn item_use(params: ItemUseParams, tx: &mut Transaction, account: &Account) -> Result<(), Error> {
|
|
let query = "
|
|
SELECT data
|
|
FROM items
|
|
WHERE id = $1
|
|
AND account = $2
|
|
FOR UPDATE;
|
|
";
|
|
|
|
let result = tx
|
|
.query(query, &[¶ms.item, &account.id])?;
|
|
|
|
let returned = result.iter().next().expect("no row returned");
|
|
|
|
let item_bytes: Vec<u8> = returned.get(0);
|
|
let mut item = from_slice::<Item>(&item_bytes)?;
|
|
|
|
item.apply(tx, params.target)?;
|
|
item_delete(tx, params.item)?;
|
|
|
|
return Ok(());
|
|
}
|
|
|
|
pub fn item_delete(tx: &mut Transaction, id: Uuid) -> Result<(), Error> {
|
|
let query = "
|
|
DELETE
|
|
FROM items
|
|
WHERE id = $1;
|
|
";
|
|
|
|
let result = tx
|
|
.execute(query, &[&id])?;
|
|
|
|
if result != 1 {
|
|
return Err(format_err!("unable to delete item {:?}", id));
|
|
}
|
|
|
|
// println!("item deleted {:?}", id);
|
|
|
|
return Ok(());
|
|
}
|
|
|
|
pub fn items_list(tx: &mut Transaction, account: &Account) -> Result<Vec<Item>, Error> {
|
|
let query = "
|
|
SELECT data, id
|
|
FROM items
|
|
WHERE account = $1;
|
|
";
|
|
|
|
let result = tx
|
|
.query(query, &[&account.id])?;
|
|
|
|
let mut items = vec![];
|
|
|
|
for row in result.into_iter() {
|
|
let item_bytes: Vec<u8> = row.get(0);
|
|
let id = row.get(1);
|
|
|
|
match from_slice::<Item>(&item_bytes) {
|
|
Ok(i) => items.push(i),
|
|
Err(_e) => {
|
|
item_delete(tx, id)?;
|
|
}
|
|
};
|
|
}
|
|
|
|
return Ok(items);
|
|
}
|
|
|
|
// # max damage potion
|
|
// name
|
|
|
|
// "MapMonstersCurseEffectOnSelfFinal3": {
|
|
// "adds_tags": [],
|
|
// "domain": "area",
|
|
// "generation_type": "prefix",
|
|
// "generation_weights": [],
|
|
// "grants_buff": {},
|
|
// "grants_effect": {},
|
|
// "group": "MapHexproof",
|
|
// "is_essence_only": false,
|
|
// "name": "Hexwarded",
|
|
// "required_level": 1,
|
|
// "spawn_weights": [
|
|
// {
|
|
// "tag": "top_tier_map",
|
|
// "weight": 0
|
|
// },
|
|
// {
|
|
// "tag": "default",
|
|
// "weight": 0
|
|
// }
|
|
// ],
|
|
// "stats": [
|
|
// {
|
|
// "id": "map_item_drop_quantity_+%",
|
|
// "max": 15,
|
|
// "min": 15
|
|
// },
|
|
// {
|
|
// "id": "map_item_drop_rarity_+%",
|
|
// "max": 8,
|
|
// "min": 8
|
|
// },
|
|
// {
|
|
// "id": "map_monsters_curse_effect_on_self_+%_final",
|
|
// "max": -60,
|
|
// "min": -60
|
|
// }
|
|
// ]
|
|
// },
|