Merge pull request 'mag feeding!' (#207) from mag_feeding into master
This commit is contained in:
commit
b0be92cb50
@ -28,4 +28,5 @@ derive_more = { version = "0.99.3", features = ["display"]}
|
|||||||
thiserror = "1.0.15"
|
thiserror = "1.0.15"
|
||||||
ages-prs = "0.1"
|
ages-prs = "0.1"
|
||||||
async-trait = "0.1.31"
|
async-trait = "0.1.31"
|
||||||
|
lazy_static = "1.4.0"
|
||||||
|
|
||||||
|
@ -6,96 +6,124 @@ feed_table = 1
|
|||||||
|
|
||||||
[Mitra]
|
[Mitra]
|
||||||
feed_table = 3
|
feed_table = 3
|
||||||
|
photon_blast = "Pilla"
|
||||||
|
|
||||||
[Surya]
|
[Surya]
|
||||||
feed_table = 3
|
feed_table = 3
|
||||||
|
photon_blast = "Leilla"
|
||||||
|
|
||||||
[Vayu]
|
[Vayu]
|
||||||
feed_table = 4
|
feed_table = 4
|
||||||
|
photon_blast = "MyllaYoulla"
|
||||||
|
|
||||||
[Varaha]
|
[Varaha]
|
||||||
feed_table = 4
|
feed_table = 4
|
||||||
|
photon_blast = "Leilla"
|
||||||
|
|
||||||
[Kama]
|
[Kama]
|
||||||
feed_table = 4
|
feed_table = 4
|
||||||
|
photon_blast = "Pilla"
|
||||||
|
|
||||||
[Ushasu]
|
[Ushasu]
|
||||||
feed_table = 4
|
feed_table = 4
|
||||||
|
photon_blast = "Leilla"
|
||||||
|
|
||||||
[Apsaras]
|
[Apsaras]
|
||||||
feed_table = 4
|
feed_table = 4
|
||||||
|
photon_blast = "Estlla"
|
||||||
|
|
||||||
[Kumara]
|
[Kumara]
|
||||||
feed_table = 4
|
feed_table = 4
|
||||||
|
photon_blast = "Leilla"
|
||||||
|
|
||||||
[Kaitabha]
|
[Kaitabha]
|
||||||
feed_table = 4
|
feed_table = 4
|
||||||
|
photon_blast = "MyllaYoulla"
|
||||||
|
|
||||||
[Tapas]
|
[Tapas]
|
||||||
feed_table = 3
|
feed_table = 3
|
||||||
|
photon_blast = "MyllaYoulla"
|
||||||
|
|
||||||
[Bhirava]
|
[Bhirava]
|
||||||
feed_table = 4
|
feed_table = 4
|
||||||
|
photon_blast = "Pilla"
|
||||||
|
|
||||||
[Kalki]
|
[Kalki]
|
||||||
feed_table = 1
|
feed_table = 1
|
||||||
|
photon_blast = "Estlla"
|
||||||
|
|
||||||
[Rudra]
|
[Rudra]
|
||||||
feed_table = 2
|
feed_table = 2
|
||||||
|
photon_blast = "Leilla"
|
||||||
|
|
||||||
[Marutah]
|
[Marutah]
|
||||||
feed_table = 2
|
feed_table = 2
|
||||||
|
photon_blast = "Pilla"
|
||||||
|
|
||||||
[Yaksa]
|
[Yaksa]
|
||||||
feed_table = 5
|
feed_table = 5
|
||||||
|
photon_blast = "Leilla"
|
||||||
|
|
||||||
[Sita]
|
[Sita]
|
||||||
feed_table = 5
|
feed_table = 5
|
||||||
|
photon_blast = "Pilla"
|
||||||
|
|
||||||
[Garuda]
|
[Garuda]
|
||||||
feed_table = 5
|
feed_table = 5
|
||||||
|
photon_blast = "Pilla"
|
||||||
|
|
||||||
[Nandin]
|
[Nandin]
|
||||||
feed_table = 5
|
feed_table = 5
|
||||||
|
photon_blast = "Estlla"
|
||||||
|
|
||||||
[Ashvinau]
|
[Ashvinau]
|
||||||
feed_table = 2
|
feed_table = 2
|
||||||
|
photon_blast = "Pilla"
|
||||||
|
|
||||||
[Ribhava]
|
[Ribhava]
|
||||||
feed_table = 5
|
feed_table = 5
|
||||||
|
|
||||||
[Soma]
|
[Soma]
|
||||||
feed_table = 5
|
feed_table = 5
|
||||||
|
photon_blast = "Estlla"
|
||||||
|
|
||||||
[Ila]
|
[Ila]
|
||||||
feed_table = 5
|
feed_table = 5
|
||||||
|
photon_blast = "MyllaYoulla"
|
||||||
|
|
||||||
[Durga]
|
[Durga]
|
||||||
feed_table = 5
|
feed_table = 5
|
||||||
|
photon_blast = "Estlla"
|
||||||
|
|
||||||
[Vritra]
|
[Vritra]
|
||||||
feed_table = 1
|
feed_table = 1
|
||||||
|
photon_blast = "Golla"
|
||||||
|
|
||||||
[Namuci]
|
[Namuci]
|
||||||
feed_table = 2
|
feed_table = 2
|
||||||
|
photon_blast = "MyllaYoulla"
|
||||||
|
|
||||||
[Sumba]
|
[Sumba]
|
||||||
feed_table = 2
|
feed_table = 2
|
||||||
|
photon_blast = "Leilla"
|
||||||
|
|
||||||
[Naga]
|
[Naga]
|
||||||
feed_table = 6
|
feed_table = 6
|
||||||
|
photon_blast = "MyllaYoulla"
|
||||||
|
|
||||||
[Pitri]
|
[Pitri]
|
||||||
feed_table = 7
|
feed_table = 7
|
||||||
|
|
||||||
[Kabanda]
|
[Kabanda]
|
||||||
feed_table = 6
|
feed_table = 6
|
||||||
|
photon_blast = "MyllaYoulla"
|
||||||
|
|
||||||
[Ravana]
|
[Ravana]
|
||||||
feed_table = 6
|
feed_table = 6
|
||||||
|
|
||||||
[Marica]
|
[Marica]
|
||||||
feed_table = 6
|
feed_table = 6
|
||||||
|
photon_blast = "Pilla"
|
||||||
|
|
||||||
[Soniti]
|
[Soniti]
|
||||||
feed_table = 7
|
feed_table = 7
|
||||||
@ -105,15 +133,19 @@ feed_table = 7
|
|||||||
|
|
||||||
[Andhaka]
|
[Andhaka]
|
||||||
feed_table = 6
|
feed_table = 6
|
||||||
|
photon_blast = "Estlla"
|
||||||
|
|
||||||
[Bana]
|
[Bana]
|
||||||
feed_table = 6
|
feed_table = 6
|
||||||
|
photon_blast = "Estlla"
|
||||||
|
|
||||||
[Naraka]
|
[Naraka]
|
||||||
feed_table = 6
|
feed_table = 6
|
||||||
|
photon_blast = "Leilla"
|
||||||
|
|
||||||
[Madhu]
|
[Madhu]
|
||||||
feed_table = 6
|
feed_table = 6
|
||||||
|
photon_blast = "MyllaYoulla"
|
||||||
|
|
||||||
[Churel]
|
[Churel]
|
||||||
feed_table = 7
|
feed_table = 7
|
||||||
|
@ -7,7 +7,7 @@ use libpso::character::character::{DEFAULT_PALETTE_CONFIG, DEFAULT_TECH_MENU};
|
|||||||
use crate::entity::item::tech::Technique;
|
use crate::entity::item::tech::Technique;
|
||||||
use crate::entity::account::UserAccountId;
|
use crate::entity::account::UserAccountId;
|
||||||
|
|
||||||
#[derive(Copy, Clone, Hash, PartialEq, Eq)]
|
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
|
||||||
pub enum CharacterClass {
|
pub enum CharacterClass {
|
||||||
HUmar,
|
HUmar,
|
||||||
HUnewearl,
|
HUnewearl,
|
||||||
@ -64,7 +64,7 @@ impl Into<u8> for CharacterClass {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[derive(Copy, Clone, Hash, PartialEq, Eq, derive_more::Display)]
|
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, derive_more::Display)]
|
||||||
pub enum SectionID {
|
pub enum SectionID {
|
||||||
Viridia,
|
Viridia,
|
||||||
Greenill,
|
Greenill,
|
||||||
|
@ -60,6 +60,18 @@ pub trait EntityGateway: Send + Sync + Clone {
|
|||||||
unimplemented!();
|
unimplemented!();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn feed_mag(&mut self, _mag_item_id: &ItemEntityId, _tool_item_id: &ItemEntityId) {
|
||||||
|
unimplemented!();
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn change_mag_owner(&mut self, _mag_item_id: &ItemEntityId, _character: &CharacterEntity) {
|
||||||
|
unimplemented!();
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn use_mag_cell(&mut self, _mag_item_id: &ItemEntityId, _mag_cell_id: &ItemEntityId) {
|
||||||
|
unimplemented!();
|
||||||
|
}
|
||||||
|
|
||||||
async fn get_items_by_character(&self, _char: &CharacterEntity) -> Vec<ItemEntity> {
|
async fn get_items_by_character(&self, _char: &CharacterEntity) -> Vec<ItemEntity> {
|
||||||
unimplemented!();
|
unimplemented!();
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
|
use std::convert::TryInto;
|
||||||
|
|
||||||
use crate::entity::account::*;
|
use crate::entity::account::*;
|
||||||
use crate::entity::character::*;
|
use crate::entity::character::*;
|
||||||
@ -13,6 +14,7 @@ pub struct InMemoryGateway {
|
|||||||
user_settings: Arc<Mutex<BTreeMap<UserSettingsId, UserSettingsEntity>>>,
|
user_settings: Arc<Mutex<BTreeMap<UserSettingsId, UserSettingsEntity>>>,
|
||||||
characters: Arc<Mutex<BTreeMap<CharacterEntityId, CharacterEntity>>>,
|
characters: Arc<Mutex<BTreeMap<CharacterEntityId, CharacterEntity>>>,
|
||||||
items: Arc<Mutex<BTreeMap<ItemEntityId, ItemEntity>>>,
|
items: Arc<Mutex<BTreeMap<ItemEntityId, ItemEntity>>>,
|
||||||
|
mag_modifiers: Arc<Mutex<BTreeMap<ItemEntityId, Vec<mag::MagModifier>>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl InMemoryGateway {
|
impl InMemoryGateway {
|
||||||
@ -22,6 +24,7 @@ impl InMemoryGateway {
|
|||||||
user_settings: Arc::new(Mutex::new(BTreeMap::new())),
|
user_settings: Arc::new(Mutex::new(BTreeMap::new())),
|
||||||
characters: Arc::new(Mutex::new(BTreeMap::new())),
|
characters: Arc::new(Mutex::new(BTreeMap::new())),
|
||||||
items: Arc::new(Mutex::new(BTreeMap::new())),
|
items: Arc::new(Mutex::new(BTreeMap::new())),
|
||||||
|
mag_modifiers: Arc::new(Mutex::new(BTreeMap::new())),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -165,6 +168,29 @@ impl EntityGateway for InMemoryGateway {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn feed_mag(&mut self, mag_item_id: &ItemEntityId, tool_item_id: &ItemEntityId) {
|
||||||
|
self.mag_modifiers.lock().unwrap()
|
||||||
|
.entry(*mag_item_id)
|
||||||
|
.or_insert(Vec::new())
|
||||||
|
.push(mag::MagModifier::FeedMag {
|
||||||
|
food: *tool_item_id
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn change_mag_owner(&mut self, mag_item_id: &ItemEntityId, character: &CharacterEntity) {
|
||||||
|
self.mag_modifiers.lock().unwrap()
|
||||||
|
.entry(*mag_item_id)
|
||||||
|
.or_insert(Vec::new())
|
||||||
|
.push(mag::MagModifier::OwnerChange(character.char_class, character.section_id));
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn use_mag_cell(&mut self, mag_item_id: &ItemEntityId, mag_cell_id: &ItemEntityId) {
|
||||||
|
self.mag_modifiers.lock().unwrap()
|
||||||
|
.entry(*mag_item_id)
|
||||||
|
.or_insert(Vec::new())
|
||||||
|
.push(mag::MagModifier::MagCell(mag_cell_id.clone()));
|
||||||
|
}
|
||||||
|
|
||||||
async fn get_items_by_character(&self, character: &CharacterEntity) -> Vec<ItemEntity> {
|
async fn get_items_by_character(&self, character: &CharacterEntity) -> Vec<ItemEntity> {
|
||||||
let items = self.items.lock().unwrap();
|
let items = self.items.lock().unwrap();
|
||||||
items
|
items
|
||||||
@ -179,6 +205,41 @@ impl EntityGateway for InMemoryGateway {
|
|||||||
.map(|(_, k)| {
|
.map(|(_, k)| {
|
||||||
k.clone()
|
k.clone()
|
||||||
})
|
})
|
||||||
|
.map(|mut item| {
|
||||||
|
item.item = match item.item {
|
||||||
|
ItemDetail::Mag(mut mag) => {
|
||||||
|
self.mag_modifiers.lock().unwrap().get(&item.id).map(|mag_modifiers| {
|
||||||
|
for mag_modifier in mag_modifiers.iter() {
|
||||||
|
match mag_modifier {
|
||||||
|
mag::MagModifier::FeedMag {food} => {
|
||||||
|
items.get(&food).map(|mag_feed| {
|
||||||
|
match mag_feed.item {
|
||||||
|
ItemDetail::Tool(mag_feed) => mag.feed(mag_feed.tool),
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
mag::MagModifier::OwnerChange(class, section_id) => {
|
||||||
|
mag.change_owner(*class, *section_id)
|
||||||
|
},
|
||||||
|
mag::MagModifier::MagCell(mag_cell_id) => {
|
||||||
|
items.get(&mag_cell_id).map(|mag_cell| {
|
||||||
|
match mag_cell.item {
|
||||||
|
ItemDetail::Tool(mag_cell) => mag.apply_mag_cell(mag_cell.tool.try_into().unwrap()),
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
ItemDetail::Mag(mag)
|
||||||
|
}
|
||||||
|
_ => item.item
|
||||||
|
};
|
||||||
|
item
|
||||||
|
})
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,62 @@
|
|||||||
|
use std::collections::HashMap;
|
||||||
use serde::{Serialize, Deserialize};
|
use serde::{Serialize, Deserialize};
|
||||||
|
use crate::entity::item::tool::ToolType;
|
||||||
|
use crate::entity::character::{CharacterClass, SectionID};
|
||||||
use crate::entity::item::ItemEntityId;
|
use crate::entity::item::ItemEntityId;
|
||||||
|
use std::io::Read;
|
||||||
|
|
||||||
|
use std::cmp::Ordering::{Less, Greater, Equal};
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize)]
|
||||||
|
struct MagStats {
|
||||||
|
feed_table: usize,
|
||||||
|
photon_blast: Option<PhotonBlast>
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize)]
|
||||||
|
struct MagFeedTable {
|
||||||
|
def: i16,
|
||||||
|
pow: i16,
|
||||||
|
dex: i16,
|
||||||
|
mnd: i16,
|
||||||
|
iq: i8,
|
||||||
|
syn: i8,
|
||||||
|
}
|
||||||
|
|
||||||
|
lazy_static::lazy_static! {
|
||||||
|
static ref MAG_STATS: HashMap<MagType, MagStats> = {
|
||||||
|
let mut f = std::fs::File::open("data/item_stats/mag_stats.toml").unwrap();
|
||||||
|
let mut s = String::new();
|
||||||
|
f.read_to_string(&mut s).unwrap();
|
||||||
|
|
||||||
|
let mag_stats: HashMap<String, MagStats> = toml::from_str(&s).unwrap();
|
||||||
|
mag_stats.into_iter()
|
||||||
|
.map(|(name, stats)| {
|
||||||
|
(name.parse().unwrap(), stats)
|
||||||
|
})
|
||||||
|
.collect::<HashMap<MagType, MagStats>>()
|
||||||
|
};
|
||||||
|
|
||||||
|
static ref MAG_FEEDING_TABLES: Vec<HashMap<ToolType, MagFeedTable>> = {
|
||||||
|
let mut f = std::fs::File::open("data/item_stats/mag_feed_table.toml").unwrap();
|
||||||
|
let mut s = String::new();
|
||||||
|
f.read_to_string(&mut s).unwrap();
|
||||||
|
|
||||||
|
let mut feed: HashMap<String, Vec<HashMap<String, MagFeedTable>>> = toml::from_str(&s).unwrap();
|
||||||
|
let feed = feed.remove("feedtable".into()).unwrap();
|
||||||
|
feed.into_iter()
|
||||||
|
.map(|table| {
|
||||||
|
table.into_iter()
|
||||||
|
.map(|(tool, stats)| {
|
||||||
|
(tool.parse().unwrap(), stats)
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
})
|
||||||
|
.collect::<Vec<HashMap<ToolType, MagFeedTable>>>()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone)]
|
#[derive(Debug, Copy, Clone)]
|
||||||
pub enum ItemParseError {
|
pub enum ItemParseError {
|
||||||
@ -250,6 +307,206 @@ impl MagType {
|
|||||||
_ => Err(ItemParseError::InvalidMagType),
|
_ => Err(ItemParseError::InvalidMagType),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn can_evolve(&self) -> bool {
|
||||||
|
match self {
|
||||||
|
MagType::Mag => true,
|
||||||
|
MagType::Varuna => true,
|
||||||
|
MagType::Mitra => true,
|
||||||
|
MagType::Surya => true,
|
||||||
|
MagType::Vayu => true,
|
||||||
|
MagType::Varaha => true,
|
||||||
|
MagType::Kama => true,
|
||||||
|
MagType::Ushasu => true,
|
||||||
|
MagType::Apsaras => true,
|
||||||
|
MagType::Kumara => true,
|
||||||
|
MagType::Kaitabha => true,
|
||||||
|
MagType::Tapas => true,
|
||||||
|
MagType::Bhirava => true,
|
||||||
|
MagType::Kalki => true,
|
||||||
|
MagType::Rudra => true,
|
||||||
|
MagType::Marutah => true,
|
||||||
|
MagType::Yaksa => true,
|
||||||
|
MagType::Sita => true,
|
||||||
|
MagType::Garuda => true,
|
||||||
|
MagType::Nandin => true,
|
||||||
|
MagType::Ashvinau => true,
|
||||||
|
MagType::Ribhava => true,
|
||||||
|
MagType::Soma => true,
|
||||||
|
MagType::Ila => true,
|
||||||
|
MagType::Durga => true,
|
||||||
|
MagType::Vritra => true,
|
||||||
|
MagType::Namuci => true,
|
||||||
|
MagType::Sumba => true,
|
||||||
|
MagType::Naga => true,
|
||||||
|
MagType::Pitri => true,
|
||||||
|
MagType::Kabanda => true,
|
||||||
|
MagType::Ravana => true,
|
||||||
|
MagType::Marica => true,
|
||||||
|
MagType::Soniti => true,
|
||||||
|
MagType::Preta => true,
|
||||||
|
MagType::Andhaka => true,
|
||||||
|
MagType::Bana => true,
|
||||||
|
MagType::Naraka => true,
|
||||||
|
MagType::Madhu => true,
|
||||||
|
MagType::Churel => false,
|
||||||
|
MagType::Robochao => false,
|
||||||
|
MagType::OpaOpa => false,
|
||||||
|
MagType::Pian => false,
|
||||||
|
MagType::Chao => false,
|
||||||
|
MagType::ChuChu => false,
|
||||||
|
MagType::KapuKapu => false,
|
||||||
|
MagType::AngelsWing => false,
|
||||||
|
MagType::DevilsWing => false,
|
||||||
|
MagType::Elenor => false,
|
||||||
|
MagType::MarkIII => false,
|
||||||
|
MagType::MasterSystem => false,
|
||||||
|
MagType::Genesis => false,
|
||||||
|
MagType::SegaSaturn => false,
|
||||||
|
MagType::Dreamcast => false,
|
||||||
|
MagType::Hamburger => false,
|
||||||
|
MagType::PanzersTail => false,
|
||||||
|
MagType::DevilsTail => false,
|
||||||
|
MagType::Deva => false,
|
||||||
|
MagType::Rati => false,
|
||||||
|
MagType::Savitri => false,
|
||||||
|
MagType::Rukmin => false,
|
||||||
|
MagType::Pushan => false,
|
||||||
|
MagType::Diwari => false,
|
||||||
|
MagType::Sato => false,
|
||||||
|
MagType::Bhima => false,
|
||||||
|
MagType::Nidra => false,
|
||||||
|
MagType::GeungSi => false,
|
||||||
|
MagType::Tellusis => false,
|
||||||
|
MagType::StrikerUnit => false,
|
||||||
|
MagType::Pioneer => false,
|
||||||
|
MagType::Puyo => false,
|
||||||
|
MagType::Moro => false,
|
||||||
|
MagType::Rappy => false,
|
||||||
|
MagType::Yahoo => false,
|
||||||
|
MagType::GaelGiel => false,
|
||||||
|
MagType::Agastya => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum MagCell {
|
||||||
|
CellOfMag502,
|
||||||
|
CellOfMag213,
|
||||||
|
PartsOfRobochao,
|
||||||
|
HeartOfOpaOpa,
|
||||||
|
HeartOfPian,
|
||||||
|
HeartOfChao,
|
||||||
|
HeartOfAngel,
|
||||||
|
HeartOfDevil,
|
||||||
|
KitOfHamburger,
|
||||||
|
PanthersSpirit,
|
||||||
|
KitOfMark3,
|
||||||
|
KitOfMasterSystem,
|
||||||
|
KitOfGenesis,
|
||||||
|
KitOfSegaSaturn,
|
||||||
|
KitOfDreamcast,
|
||||||
|
Tablet,
|
||||||
|
DragonScale,
|
||||||
|
HeavenStrikerCoat,
|
||||||
|
PioneerParts,
|
||||||
|
AmitiesMemo,
|
||||||
|
HeartOfMorolian,
|
||||||
|
RappysBeak,
|
||||||
|
YahoosEngine,
|
||||||
|
DPhotonCore,
|
||||||
|
LibertaKit,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::convert::TryFrom<ToolType> for MagCell {
|
||||||
|
type Error = ();
|
||||||
|
|
||||||
|
fn try_from(tool: ToolType) -> Result<MagCell, ()> {
|
||||||
|
match tool {
|
||||||
|
ToolType::CellOfMag502 => Ok(MagCell::CellOfMag502),
|
||||||
|
ToolType::CellOfMag213 => Ok(MagCell::CellOfMag213),
|
||||||
|
ToolType::PartsOfRobochao => Ok(MagCell::PartsOfRobochao),
|
||||||
|
ToolType::HeartOfOpaOpa => Ok(MagCell::HeartOfOpaOpa),
|
||||||
|
ToolType::HeartOfPian => Ok(MagCell::HeartOfPian),
|
||||||
|
ToolType::HeartOfChao => Ok(MagCell::HeartOfChao),
|
||||||
|
ToolType::HeartOfAngel => Ok(MagCell::HeartOfAngel),
|
||||||
|
ToolType::HeartOfDevil => Ok(MagCell::HeartOfDevil),
|
||||||
|
ToolType::KitOfHamburger => Ok(MagCell::KitOfHamburger),
|
||||||
|
ToolType::PanthersSpirit => Ok(MagCell::PanthersSpirit),
|
||||||
|
ToolType::KitOfMark3 => Ok(MagCell::KitOfMark3),
|
||||||
|
ToolType::KitOfMasterSystem => Ok(MagCell::KitOfMasterSystem),
|
||||||
|
ToolType::KitOfGenesis => Ok(MagCell::KitOfGenesis),
|
||||||
|
ToolType::KitOfSegaSaturn => Ok(MagCell::KitOfSegaSaturn),
|
||||||
|
ToolType::KitOfDreamcast => Ok(MagCell::KitOfDreamcast),
|
||||||
|
ToolType::Tablet => Ok(MagCell::Tablet),
|
||||||
|
ToolType::DragonScale => Ok(MagCell::DragonScale),
|
||||||
|
ToolType::HeavenStrikerCoat => Ok(MagCell::HeavenStrikerCoat),
|
||||||
|
ToolType::PioneerParts => Ok(MagCell::PioneerParts),
|
||||||
|
ToolType::AmitiesMemo => Ok(MagCell::AmitiesMemo),
|
||||||
|
ToolType::HeartOfMorolian => Ok(MagCell::HeartOfMorolian),
|
||||||
|
ToolType::RappysBeak => Ok(MagCell::RappysBeak),
|
||||||
|
ToolType::YahoosEngine => Ok(MagCell::YahoosEngine),
|
||||||
|
ToolType::DPhotonCore => Ok(MagCell::DPhotonCore),
|
||||||
|
ToolType::LibertaKit => Ok(MagCell::LibertaKit),
|
||||||
|
_ => Err(()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum MagAttribute {
|
||||||
|
//Def,
|
||||||
|
Pow,
|
||||||
|
Dex,
|
||||||
|
Mind,
|
||||||
|
}
|
||||||
|
|
||||||
|
// one day I hope to be cool enough to figure how to enforce that each magattribute in sequence must be unique
|
||||||
|
// (to not need the _ in the match)
|
||||||
|
enum MagAttributeOrdering {
|
||||||
|
Sequence(MagAttribute, MagAttribute, MagAttribute),
|
||||||
|
Primary(MagAttribute),
|
||||||
|
MultiPrimary
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MagAttributeOrdering {
|
||||||
|
fn new(pow: u16, dex: u16, mnd: u16) -> MagAttributeOrdering {
|
||||||
|
let primary = if pow > dex && pow > mnd {
|
||||||
|
MagAttribute::Pow
|
||||||
|
}
|
||||||
|
else if dex > pow && dex > mnd{
|
||||||
|
MagAttribute::Dex
|
||||||
|
}
|
||||||
|
else if mnd > pow && mnd > dex {
|
||||||
|
MagAttribute::Mind
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return MagAttributeOrdering::MultiPrimary
|
||||||
|
};
|
||||||
|
|
||||||
|
match primary {
|
||||||
|
MagAttribute::Pow => {
|
||||||
|
match dex.cmp(&mnd) {
|
||||||
|
Greater => MagAttributeOrdering::Sequence(primary, MagAttribute::Dex, MagAttribute::Mind),
|
||||||
|
Equal => MagAttributeOrdering::Primary(primary),
|
||||||
|
Less => MagAttributeOrdering::Sequence(primary, MagAttribute::Mind, MagAttribute::Dex),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
MagAttribute::Dex => {
|
||||||
|
match pow.cmp(&mnd) {
|
||||||
|
Greater => MagAttributeOrdering::Sequence(primary, MagAttribute::Pow, MagAttribute::Mind),
|
||||||
|
Equal => MagAttributeOrdering::Primary(primary),
|
||||||
|
Less => MagAttributeOrdering::Sequence(primary, MagAttribute::Mind, MagAttribute::Pow),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
MagAttribute::Mind => {
|
||||||
|
match pow.cmp(&dex) {
|
||||||
|
Greater => MagAttributeOrdering::Sequence(primary, MagAttribute::Pow, MagAttribute::Dex),
|
||||||
|
Equal => MagAttributeOrdering::Primary(primary),
|
||||||
|
Less => MagAttributeOrdering::Sequence(primary, MagAttribute::Dex, MagAttribute::Pow),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
@ -257,11 +514,12 @@ pub enum MagModifier {
|
|||||||
FeedMag{
|
FeedMag{
|
||||||
food: ItemEntityId,
|
food: ItemEntityId,
|
||||||
},
|
},
|
||||||
BankMag,
|
BankMag, // when putting a mag in the bank it truncates the values which has applications when raising degenerate mags
|
||||||
MagCell(ItemEntityId),
|
MagCell(ItemEntityId),
|
||||||
|
OwnerChange(CharacterClass, SectionID)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone, PartialEq)]
|
#[derive(Debug, Copy, Clone, PartialEq, Deserialize, enum_utils::FromStr)]
|
||||||
pub enum PhotonBlast {
|
pub enum PhotonBlast {
|
||||||
Farlla,
|
Farlla,
|
||||||
Estlla,
|
Estlla,
|
||||||
@ -274,19 +532,38 @@ pub enum PhotonBlast {
|
|||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub struct Mag {
|
pub struct Mag {
|
||||||
pub mag: MagType,
|
pub mag: MagType,
|
||||||
pub def: u16,
|
def: u16,
|
||||||
pub pow: u16,
|
pow: u16,
|
||||||
pub dex: u16,
|
dex: u16,
|
||||||
pub mnd: u16,
|
mnd: u16,
|
||||||
pub synchro: u8,
|
pub synchro: u8,
|
||||||
pub iq: u8,
|
iq: u8,
|
||||||
pub photon_blast: [Option<PhotonBlast>; 3],
|
photon_blast: [Option<PhotonBlast>; 3],
|
||||||
pub color: u8,
|
pub color: u8,
|
||||||
pub modifiers: Vec<MagModifier>,
|
//modifiers: Vec<MagModifier>,
|
||||||
|
pub class: CharacterClass,
|
||||||
|
pub id: SectionID,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
impl Mag {
|
impl Mag {
|
||||||
|
pub fn baby_mag(skin: u16) -> Mag {
|
||||||
|
Mag {
|
||||||
|
mag: MagType::Mag,
|
||||||
|
def: 500,
|
||||||
|
pow: 0,
|
||||||
|
dex: 0,
|
||||||
|
mnd: 0,
|
||||||
|
synchro: 20,
|
||||||
|
iq: 0,
|
||||||
|
photon_blast: [None; 3],
|
||||||
|
color: (skin % 18) as u8,
|
||||||
|
//modifiers: Vec::new(),
|
||||||
|
class: CharacterClass::HUmar,
|
||||||
|
id: SectionID::Viridia,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn as_bytes(&self) -> [u8; 16] {
|
pub fn as_bytes(&self) -> [u8; 16] {
|
||||||
let mut result = [0; 16];
|
let mut result = [0; 16];
|
||||||
result[0..3].copy_from_slice(&self.mag.value());
|
result[0..3].copy_from_slice(&self.mag.value());
|
||||||
@ -355,7 +632,7 @@ impl Mag {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_bytes(data: [u8; 16]) -> Result<Mag, ItemParseError> {
|
pub fn from_bytes(data: [u8; 16]) -> Result<Mag, ItemParseError> {
|
||||||
let m = MagType::parse_type([data[0], data[1], data[2]]);
|
let m = MagType::parse_type([data[0], data[1], data[2]]);
|
||||||
if m.is_ok() {
|
if m.is_ok() {
|
||||||
let mut def = u16::from_le_bytes([data[4], data[5]]);
|
let mut def = u16::from_le_bytes([data[4], data[5]]);
|
||||||
let mut pow = u16::from_le_bytes([data[6], data[7]]);
|
let mut pow = u16::from_le_bytes([data[6], data[7]]);
|
||||||
@ -382,11 +659,516 @@ impl Mag {
|
|||||||
iq: iq,
|
iq: iq,
|
||||||
photon_blast: [None, None, None], // TODO: actually get PBs from bytes
|
photon_blast: [None, None, None], // TODO: actually get PBs from bytes
|
||||||
color: data[15] % 18,
|
color: data[15] % 18,
|
||||||
modifiers: Vec::new(),
|
//modifiers: Vec::new(),
|
||||||
|
class: CharacterClass::HUmar,
|
||||||
|
id: SectionID::Viridia,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
Err(ItemParseError::InvalidMagBytes) // TODO: error handling if wrong bytes are given
|
Err(ItemParseError::InvalidMagBytes) // TODO: error handling if wrong bytes are given
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn def(&self) -> u16 {
|
||||||
|
self.def/100
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn pow(&self) -> u16 {
|
||||||
|
self.pow/100
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn dex(&self) -> u16 {
|
||||||
|
self.dex/100
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn mind(&self) -> u16 {
|
||||||
|
self.mnd/100
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn level(&self) -> u16 {
|
||||||
|
self.def() + self.pow() + self.dex() + self.mind()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn change_mag_type(&mut self, previous_level: u16) {
|
||||||
|
if !self.mag.can_evolve() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.level() >= 10 && previous_level < 10 {
|
||||||
|
match self.class {
|
||||||
|
CharacterClass::HUmar | CharacterClass::HUnewearl | CharacterClass::HUcast | CharacterClass::HUcaseal => {
|
||||||
|
self.mag = MagType::Varuna
|
||||||
|
},
|
||||||
|
CharacterClass::RAmar | CharacterClass::RAmarl | CharacterClass::RAcast | CharacterClass::RAcaseal => {
|
||||||
|
self.mag = MagType::Kalki
|
||||||
|
},
|
||||||
|
CharacterClass::FOmar | CharacterClass::FOmarl | CharacterClass::FOnewm | CharacterClass::FOnewearl => {
|
||||||
|
self.mag = MagType::Vritra
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.level() >= 35 && previous_level < 35 {
|
||||||
|
match self.mag {
|
||||||
|
MagType::Varuna => {
|
||||||
|
if self.pow > self.dex && self.pow > self.mnd {
|
||||||
|
self.mag = MagType::Rudra
|
||||||
|
}
|
||||||
|
else if self.dex > self.pow && self.dex > self.mnd {
|
||||||
|
self.mag = MagType::Marutah
|
||||||
|
}
|
||||||
|
else if self.mnd > self.pow && self.mnd > self.dex {
|
||||||
|
self.mag = MagType::Vayu
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
self.mag = MagType::Rudra
|
||||||
|
}
|
||||||
|
},
|
||||||
|
MagType::Kalki => {
|
||||||
|
if self.pow > self.dex && self.pow > self.mnd {
|
||||||
|
self.mag = MagType::Surya
|
||||||
|
}
|
||||||
|
else if self.dex > self.pow && self.dex > self.mnd {
|
||||||
|
self.mag = MagType::Mitra
|
||||||
|
}
|
||||||
|
else if self.mnd > self.pow && self.mnd > self.dex {
|
||||||
|
self.mag = MagType::Tapas
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
self.mag = MagType::Mitra
|
||||||
|
}
|
||||||
|
},
|
||||||
|
MagType::Vritra => {
|
||||||
|
if self.pow > self.dex && self.pow > self.mnd {
|
||||||
|
self.mag = MagType::Sumba
|
||||||
|
}
|
||||||
|
else if self.dex > self.pow && self.dex > self.mnd {
|
||||||
|
self.mag = MagType::Ashvinau
|
||||||
|
}
|
||||||
|
else if self.mnd > self.pow && self.mnd > self.dex {
|
||||||
|
self.mag = MagType::Namuci
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
self.mag = MagType::Namuci
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.level() >= 50 && self.level() % 5 == 0 {
|
||||||
|
let mag_attr_ordering = MagAttributeOrdering::new(self.pow, self.dex, self.mnd);
|
||||||
|
self.mag = match self.id {
|
||||||
|
SectionID::Viridia | SectionID::Skyly | SectionID::Purplenum | SectionID::Redria | SectionID::Yellowboze => {
|
||||||
|
match self.class {
|
||||||
|
CharacterClass::HUmar | CharacterClass::HUnewearl | CharacterClass::HUcast | CharacterClass::HUcaseal => {
|
||||||
|
match mag_attr_ordering {
|
||||||
|
MagAttributeOrdering::Primary(MagAttribute::Pow) => MagType::Varaha,
|
||||||
|
MagAttributeOrdering::Primary(MagAttribute::Dex) => MagType::Nandin,
|
||||||
|
MagAttributeOrdering::Primary(MagAttribute::Mind) => MagType::Kabanda,
|
||||||
|
MagAttributeOrdering::Sequence(MagAttribute::Pow, MagAttribute::Dex, MagAttribute::Mind) => MagType::Varaha,
|
||||||
|
MagAttributeOrdering::Sequence(MagAttribute::Pow, MagAttribute::Mind, MagAttribute::Dex) => MagType::Bhirava,
|
||||||
|
MagAttributeOrdering::Sequence(MagAttribute::Dex, MagAttribute::Pow, MagAttribute::Mind) => MagType::Ila,
|
||||||
|
MagAttributeOrdering::Sequence(MagAttribute::Dex, MagAttribute::Mind, MagAttribute::Pow) => MagType::Nandin,
|
||||||
|
MagAttributeOrdering::Sequence(MagAttribute::Mind, MagAttribute::Pow, MagAttribute::Dex) => MagType::Kabanda,
|
||||||
|
MagAttributeOrdering::Sequence(MagAttribute::Mind, MagAttribute::Dex, MagAttribute::Pow) => MagType::Ushasu,
|
||||||
|
MagAttributeOrdering::MultiPrimary => {
|
||||||
|
if self.dex >= self.mnd {
|
||||||
|
MagType::Varaha
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
MagType::Bhirava
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => unreachable!()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
CharacterClass::RAmar | CharacterClass::RAmarl | CharacterClass::RAcast | CharacterClass::RAcaseal => {
|
||||||
|
match mag_attr_ordering {
|
||||||
|
MagAttributeOrdering::Primary(MagAttribute::Pow) => MagType::Kama,
|
||||||
|
MagAttributeOrdering::Primary(MagAttribute::Dex) => MagType::Kama,
|
||||||
|
MagAttributeOrdering::Primary(MagAttribute::Mind) => MagType::Varaha,
|
||||||
|
MagAttributeOrdering::Sequence(MagAttribute::Pow, MagAttribute::Dex, MagAttribute::Mind) => MagType::Kama,
|
||||||
|
MagAttributeOrdering::Sequence(MagAttribute::Pow, MagAttribute::Mind, MagAttribute::Dex) => MagType::Bhirava,
|
||||||
|
MagAttributeOrdering::Sequence(MagAttribute::Dex, MagAttribute::Pow, MagAttribute::Mind) => MagType::Bhirava,
|
||||||
|
MagAttributeOrdering::Sequence(MagAttribute::Dex, MagAttribute::Mind, MagAttribute::Pow) => MagType::Kama,
|
||||||
|
MagAttributeOrdering::Sequence(MagAttribute::Mind, MagAttribute::Pow, MagAttribute::Dex) => MagType::Varaha,
|
||||||
|
MagAttributeOrdering::Sequence(MagAttribute::Mind, MagAttribute::Dex, MagAttribute::Pow) => MagType::Apsaras,
|
||||||
|
MagAttributeOrdering::MultiPrimary => {
|
||||||
|
if self.mnd >= self.pow {
|
||||||
|
MagType::Kama
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
MagType::Bhirava
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => unreachable!()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
CharacterClass::FOmar | CharacterClass::FOmarl | CharacterClass::FOnewm | CharacterClass::FOnewearl => {
|
||||||
|
match (mag_attr_ordering, self.def() >= 45) {
|
||||||
|
(MagAttributeOrdering::Primary(MagAttribute::Pow), true) => MagType::Andhaka,
|
||||||
|
(MagAttributeOrdering::Primary(MagAttribute::Dex), true) => MagType::Bana,
|
||||||
|
(MagAttributeOrdering::Primary(MagAttribute::Mind), true) => MagType::Bana,
|
||||||
|
(MagAttributeOrdering::Sequence(MagAttribute::Pow, MagAttribute::Dex, MagAttribute::Mind), true) => MagType::Andhaka,
|
||||||
|
(MagAttributeOrdering::Sequence(MagAttribute::Pow, MagAttribute::Mind, MagAttribute::Dex), true) => MagType::Andhaka,
|
||||||
|
(MagAttributeOrdering::Sequence(MagAttribute::Dex, MagAttribute::Pow, MagAttribute::Mind), true) => MagType::Bana,
|
||||||
|
(MagAttributeOrdering::Sequence(MagAttribute::Dex, MagAttribute::Mind, MagAttribute::Pow), true) => MagType::Bana,
|
||||||
|
(MagAttributeOrdering::Sequence(MagAttribute::Mind, MagAttribute::Pow, MagAttribute::Dex), true) => MagType::Bana,
|
||||||
|
(MagAttributeOrdering::Sequence(MagAttribute::Mind, MagAttribute::Dex, MagAttribute::Pow), true) => MagType::Bana,
|
||||||
|
(MagAttributeOrdering::MultiPrimary, true) => MagType::Bana,
|
||||||
|
(MagAttributeOrdering::Primary(MagAttribute::Pow), false) => MagType::Naraka,
|
||||||
|
(MagAttributeOrdering::Primary(MagAttribute::Dex), false) => MagType::Sita,
|
||||||
|
(MagAttributeOrdering::Primary(MagAttribute::Mind), false) => MagType::Naga,
|
||||||
|
(MagAttributeOrdering::Sequence(MagAttribute::Pow, MagAttribute::Dex, MagAttribute::Mind), false) => MagType::Naraka,
|
||||||
|
(MagAttributeOrdering::Sequence(MagAttribute::Pow, MagAttribute::Mind, MagAttribute::Dex), false) => MagType::Ravana,
|
||||||
|
(MagAttributeOrdering::Sequence(MagAttribute::Dex, MagAttribute::Pow, MagAttribute::Mind), false) => MagType::Ribhava,
|
||||||
|
(MagAttributeOrdering::Sequence(MagAttribute::Dex, MagAttribute::Mind, MagAttribute::Pow), false) => MagType::Sita,
|
||||||
|
(MagAttributeOrdering::Sequence(MagAttribute::Mind, MagAttribute::Pow, MagAttribute::Dex), false) => MagType::Naga,
|
||||||
|
(MagAttributeOrdering::Sequence(MagAttribute::Mind, MagAttribute::Dex, MagAttribute::Pow), false) => MagType::Kabanda,
|
||||||
|
(MagAttributeOrdering::MultiPrimary, false) => {
|
||||||
|
if self.pow >= self.dex {
|
||||||
|
MagType::Naga
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
MagType::Kabanda
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => unreachable!()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
SectionID::Greenill | SectionID::Bluefull | SectionID::Pinkal | SectionID::Oran | SectionID::Whitill => {
|
||||||
|
match self.class {
|
||||||
|
CharacterClass::HUmar | CharacterClass::HUnewearl | CharacterClass::HUcast | CharacterClass::HUcaseal => {
|
||||||
|
match mag_attr_ordering {
|
||||||
|
MagAttributeOrdering::Primary(MagAttribute::Pow) => MagType::Kama,
|
||||||
|
MagAttributeOrdering::Primary(MagAttribute::Dex) => MagType::Yaksa,
|
||||||
|
MagAttributeOrdering::Primary(MagAttribute::Mind) => MagType::Bana,
|
||||||
|
MagAttributeOrdering::Sequence(MagAttribute::Pow, MagAttribute::Dex, MagAttribute::Mind) => MagType::Kama,
|
||||||
|
MagAttributeOrdering::Sequence(MagAttribute::Pow, MagAttribute::Mind, MagAttribute::Dex) => MagType::Apsaras,
|
||||||
|
MagAttributeOrdering::Sequence(MagAttribute::Dex, MagAttribute::Pow, MagAttribute::Mind) => MagType::Garuda,
|
||||||
|
MagAttributeOrdering::Sequence(MagAttribute::Dex, MagAttribute::Mind, MagAttribute::Pow) => MagType::Yaksa,
|
||||||
|
MagAttributeOrdering::Sequence(MagAttribute::Mind, MagAttribute::Pow, MagAttribute::Dex) => MagType::Bana,
|
||||||
|
MagAttributeOrdering::Sequence(MagAttribute::Mind, MagAttribute::Dex, MagAttribute::Pow) => MagType::Soma,
|
||||||
|
MagAttributeOrdering::MultiPrimary => {
|
||||||
|
if self.dex >= self.mnd {
|
||||||
|
MagType::Kama
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
MagType::Apsaras
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => unreachable!()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
CharacterClass::RAmar | CharacterClass::RAmarl | CharacterClass::RAcast | CharacterClass::RAcaseal => {
|
||||||
|
match mag_attr_ordering {
|
||||||
|
MagAttributeOrdering::Primary(MagAttribute::Pow) => MagType::Madhu,
|
||||||
|
MagAttributeOrdering::Primary(MagAttribute::Dex) => MagType::Varaha,
|
||||||
|
MagAttributeOrdering::Primary(MagAttribute::Mind) => MagType::Kabanda,
|
||||||
|
MagAttributeOrdering::Sequence(MagAttribute::Pow, MagAttribute::Dex, MagAttribute::Mind) => MagType::Madhu,
|
||||||
|
MagAttributeOrdering::Sequence(MagAttribute::Pow, MagAttribute::Mind, MagAttribute::Dex) => MagType::Kaitabha,
|
||||||
|
MagAttributeOrdering::Sequence(MagAttribute::Dex, MagAttribute::Pow, MagAttribute::Mind) => MagType::Kaitabha,
|
||||||
|
MagAttributeOrdering::Sequence(MagAttribute::Dex, MagAttribute::Mind, MagAttribute::Pow) => MagType::Varaha,
|
||||||
|
MagAttributeOrdering::Sequence(MagAttribute::Mind, MagAttribute::Pow, MagAttribute::Dex) => MagType::Kabanda,
|
||||||
|
MagAttributeOrdering::Sequence(MagAttribute::Mind, MagAttribute::Dex, MagAttribute::Pow) => MagType::Durga,
|
||||||
|
MagAttributeOrdering::MultiPrimary => {
|
||||||
|
if self.pow > self.mnd {
|
||||||
|
MagType::Kaitabha
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
MagType::Varaha
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => unreachable!()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
CharacterClass::FOmar | CharacterClass::FOmarl | CharacterClass::FOnewm | CharacterClass::FOnewearl => {
|
||||||
|
match (mag_attr_ordering, self.def() >= 45) {
|
||||||
|
(MagAttributeOrdering::Primary(MagAttribute::Pow), true) => MagType::Andhaka,
|
||||||
|
(MagAttributeOrdering::Primary(MagAttribute::Dex), true) => MagType::Bana,
|
||||||
|
(MagAttributeOrdering::Primary(MagAttribute::Mind), true) => MagType::Bana,
|
||||||
|
(MagAttributeOrdering::Sequence(MagAttribute::Pow, MagAttribute::Dex, MagAttribute::Mind), true) => MagType::Andhaka,
|
||||||
|
(MagAttributeOrdering::Sequence(MagAttribute::Pow, MagAttribute::Mind, MagAttribute::Dex), true) => MagType::Andhaka,
|
||||||
|
(MagAttributeOrdering::Sequence(MagAttribute::Dex, MagAttribute::Pow, MagAttribute::Mind), true) => MagType::Bana,
|
||||||
|
(MagAttributeOrdering::Sequence(MagAttribute::Dex, MagAttribute::Mind, MagAttribute::Pow), true) => MagType::Bana,
|
||||||
|
(MagAttributeOrdering::Sequence(MagAttribute::Mind, MagAttribute::Pow, MagAttribute::Dex), true) => MagType::Bana,
|
||||||
|
(MagAttributeOrdering::Sequence(MagAttribute::Mind, MagAttribute::Dex, MagAttribute::Pow), true) => MagType::Bana,
|
||||||
|
(MagAttributeOrdering::MultiPrimary, true) => MagType::Bana,
|
||||||
|
(MagAttributeOrdering::Primary(MagAttribute::Pow), false) => MagType::Marica,
|
||||||
|
(MagAttributeOrdering::Primary(MagAttribute::Dex), false) => MagType::Bhirava,
|
||||||
|
(MagAttributeOrdering::Primary(MagAttribute::Mind), false) => MagType::Kumara,
|
||||||
|
(MagAttributeOrdering::Sequence(MagAttribute::Pow, MagAttribute::Dex, MagAttribute::Mind), false) => MagType::Marica,
|
||||||
|
(MagAttributeOrdering::Sequence(MagAttribute::Pow, MagAttribute::Mind, MagAttribute::Dex), false) => MagType::Naga,
|
||||||
|
(MagAttributeOrdering::Sequence(MagAttribute::Dex, MagAttribute::Pow, MagAttribute::Mind), false) => MagType::Garuda,
|
||||||
|
(MagAttributeOrdering::Sequence(MagAttribute::Dex, MagAttribute::Mind, MagAttribute::Pow), false) => MagType::Bhirava,
|
||||||
|
(MagAttributeOrdering::Sequence(MagAttribute::Mind, MagAttribute::Pow, MagAttribute::Dex), false) => MagType::Kumara,
|
||||||
|
(MagAttributeOrdering::Sequence(MagAttribute::Mind, MagAttribute::Dex, MagAttribute::Pow), false) => MagType::Ila,
|
||||||
|
(MagAttributeOrdering::MultiPrimary, false) => {
|
||||||
|
if self.pow >= self.dex {
|
||||||
|
MagType::Kumara
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
MagType::Ila
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => unreachable!()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.level() >= 100 && self.level() % 5 == 0 {
|
||||||
|
match self.id {
|
||||||
|
SectionID::Skyly | SectionID::Pinkal | SectionID::Yellowboze => {
|
||||||
|
if self.def() + self.pow() == self.dex() + self.mind() {
|
||||||
|
self.mag = match self.class {
|
||||||
|
CharacterClass::HUmar | CharacterClass::HUcast => {
|
||||||
|
MagType::Rati
|
||||||
|
},
|
||||||
|
CharacterClass::HUnewearl | CharacterClass::HUcaseal => {
|
||||||
|
MagType::Savitri
|
||||||
|
},
|
||||||
|
CharacterClass::RAmar | CharacterClass::RAcast => {
|
||||||
|
MagType::Pushan
|
||||||
|
},
|
||||||
|
CharacterClass::RAmarl | CharacterClass::RAcaseal => {
|
||||||
|
MagType::Diwari
|
||||||
|
},
|
||||||
|
CharacterClass::FOmar | CharacterClass::FOnewm => {
|
||||||
|
MagType::Nidra
|
||||||
|
},
|
||||||
|
CharacterClass::FOmarl | CharacterClass::FOnewearl => {
|
||||||
|
MagType::Bhima
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
SectionID::Viridia | SectionID::Bluefull | SectionID::Redria | SectionID::Whitill => {
|
||||||
|
if self.def() + self.dex() == self.pow() + self.mind() {
|
||||||
|
self.mag = match self.class {
|
||||||
|
CharacterClass::HUmar | CharacterClass::HUcast => {
|
||||||
|
MagType::Deva
|
||||||
|
},
|
||||||
|
CharacterClass::HUnewearl | CharacterClass::HUcaseal => {
|
||||||
|
MagType::Savitri
|
||||||
|
},
|
||||||
|
CharacterClass::RAmar | CharacterClass::RAcast => {
|
||||||
|
MagType::Pushan
|
||||||
|
},
|
||||||
|
CharacterClass::RAmarl | CharacterClass::RAcaseal => {
|
||||||
|
MagType::Rukmin
|
||||||
|
},
|
||||||
|
CharacterClass::FOmar | CharacterClass::FOnewm => {
|
||||||
|
MagType::Nidra
|
||||||
|
},
|
||||||
|
CharacterClass::FOmarl | CharacterClass::FOnewearl => {
|
||||||
|
MagType::Sato // best mag
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
SectionID::Greenill | SectionID::Purplenum | SectionID::Oran => {
|
||||||
|
if self.def() + self.mind() == self.pow() + self.dex() {
|
||||||
|
self.mag = match self.class {
|
||||||
|
CharacterClass::HUmar | CharacterClass::HUcast => {
|
||||||
|
MagType::Rati
|
||||||
|
},
|
||||||
|
CharacterClass::HUnewearl | CharacterClass::HUcaseal => {
|
||||||
|
MagType::Savitri
|
||||||
|
},
|
||||||
|
CharacterClass::RAmar | CharacterClass::RAcast => {
|
||||||
|
MagType::Pushan
|
||||||
|
},
|
||||||
|
CharacterClass::RAmarl | CharacterClass::RAcaseal => {
|
||||||
|
MagType::Rukmin
|
||||||
|
},
|
||||||
|
CharacterClass::FOmar | CharacterClass::FOnewm => {
|
||||||
|
MagType::Nidra
|
||||||
|
},
|
||||||
|
CharacterClass::FOmarl | CharacterClass::FOnewearl => {
|
||||||
|
MagType::Bhima
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn assign_photon_blast(&mut self) {
|
||||||
|
MAG_STATS.get(&self.mag).map(|stats| {
|
||||||
|
stats.photon_blast.map(|photon_blast| {
|
||||||
|
if !self.photon_blast.contains(&Some(photon_blast)) {
|
||||||
|
self.photon_blast.iter_mut().find(|k| k.is_none()).map(|pb_slot| {
|
||||||
|
*pb_slot = Some(photon_blast)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn feed(&mut self, tool: ToolType) {
|
||||||
|
let previous_level = self.level();
|
||||||
|
MAG_STATS.get(&self.mag).map(|stats| {
|
||||||
|
MAG_FEEDING_TABLES.get(stats.feed_table).map(|feeding_table| {
|
||||||
|
feeding_table.get(&tool).map(|feed_stats| {
|
||||||
|
self.def = std::cmp::max(std::cmp::max((self.def as i16) + feed_stats.def, 0) as u16, self.def()*100);
|
||||||
|
self.pow = std::cmp::max(std::cmp::max((self.pow as i16) + feed_stats.pow, 0) as u16, self.pow()*100);
|
||||||
|
self.dex = std::cmp::max(std::cmp::max((self.dex as i16) + feed_stats.dex, 0) as u16, self.dex()*100);
|
||||||
|
self.mnd = std::cmp::max(std::cmp::max((self.mnd as i16) + feed_stats.mnd, 0) as u16, self.mind()*100);
|
||||||
|
self.iq = std::cmp::min(((self.iq as i16) + feed_stats.iq as i16) as u8, 200);
|
||||||
|
self.synchro = std::cmp::min(((self.synchro as i8) + feed_stats.syn) as u8, 120);
|
||||||
|
})
|
||||||
|
})
|
||||||
|
});
|
||||||
|
//if previous_level != self.level() {
|
||||||
|
self.change_mag_type(previous_level);
|
||||||
|
self.assign_photon_blast();
|
||||||
|
//}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn change_owner(&mut self, class: CharacterClass, id: SectionID) {
|
||||||
|
self.class = class;
|
||||||
|
self.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn bank(&mut self) {
|
||||||
|
// what is the truncation logic anyway
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: this needs more checks on validity
|
||||||
|
pub fn apply_mag_cell(&mut self, mag_cell: MagCell) {
|
||||||
|
self.mag = match mag_cell {
|
||||||
|
MagCell::CellOfMag502 => {
|
||||||
|
match self.id {
|
||||||
|
SectionID::Viridia | SectionID::Skyly | SectionID::Purplenum | SectionID::Redria | SectionID::Yellowboze => {
|
||||||
|
MagType::Soniti
|
||||||
|
},
|
||||||
|
SectionID::Greenill | SectionID::Bluefull | SectionID::Pinkal | SectionID::Oran | SectionID::Whitill => {
|
||||||
|
MagType::Pitri
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
MagCell::CellOfMag213 => {
|
||||||
|
match self.id {
|
||||||
|
SectionID::Viridia | SectionID::Skyly | SectionID::Purplenum | SectionID::Redria | SectionID::Yellowboze => {
|
||||||
|
MagType::Churel
|
||||||
|
},
|
||||||
|
SectionID::Greenill | SectionID::Bluefull | SectionID::Pinkal | SectionID::Oran | SectionID::Whitill => {
|
||||||
|
MagType::Preta
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
MagCell::PartsOfRobochao => MagType::Robochao,
|
||||||
|
MagCell::HeartOfOpaOpa => MagType::OpaOpa,
|
||||||
|
MagCell::HeartOfPian => MagType::Pian,
|
||||||
|
MagCell::HeartOfChao => MagType::Chao,
|
||||||
|
MagCell::HeartOfAngel => MagType::AngelsWing,
|
||||||
|
MagCell::HeartOfDevil => if self.mag == MagType::DevilsWing {
|
||||||
|
MagType::DevilsTail
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
MagType::DevilsWing
|
||||||
|
},
|
||||||
|
MagCell::KitOfHamburger => MagType::Hamburger,
|
||||||
|
MagCell::PanthersSpirit => MagType::PanzersTail,
|
||||||
|
MagCell::KitOfMark3 => MagType::MarkIII,
|
||||||
|
MagCell::KitOfMasterSystem => MagType::MasterSystem,
|
||||||
|
MagCell::KitOfGenesis => MagType::Genesis,
|
||||||
|
MagCell::KitOfSegaSaturn => MagType::SegaSaturn,
|
||||||
|
MagCell::KitOfDreamcast => MagType::Dreamcast,
|
||||||
|
MagCell::Tablet => MagType::GeungSi,
|
||||||
|
MagCell::DragonScale => MagType::Tellusis,
|
||||||
|
MagCell::HeavenStrikerCoat => MagType::StrikerUnit,
|
||||||
|
MagCell::PioneerParts => MagType::Pioneer,
|
||||||
|
MagCell::AmitiesMemo => MagType::Puyo,
|
||||||
|
MagCell::HeartOfMorolian => MagType::Moro,
|
||||||
|
MagCell::RappysBeak => MagType::Rappy,
|
||||||
|
MagCell::YahoosEngine => MagType::Yahoo,
|
||||||
|
MagCell::DPhotonCore => MagType::GaelGiel,
|
||||||
|
MagCell::LibertaKit => MagType::Agastya,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use super::*;
|
||||||
|
use std::io::Read;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_load_mag_stats() {
|
||||||
|
let mut f = std::fs::File::open("data/item_stats/mag_stats.toml").unwrap();
|
||||||
|
let mut s = String::new();
|
||||||
|
f.read_to_string(&mut s).unwrap();
|
||||||
|
|
||||||
|
let mags: HashMap<String, MagStats> = toml::from_str(&s).unwrap();
|
||||||
|
let _mags = mags.into_iter()
|
||||||
|
.map(|(name, stats)| {
|
||||||
|
(name.parse().unwrap(), stats)
|
||||||
|
})
|
||||||
|
.collect::<HashMap<MagType, MagStats>>();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_load_mag_feed_table() {
|
||||||
|
let mut f = std::fs::File::open("data/item_stats/mag_feed_table.toml").unwrap();
|
||||||
|
let mut s = String::new();
|
||||||
|
f.read_to_string(&mut s).unwrap();
|
||||||
|
|
||||||
|
let mut feed: HashMap<String, Vec<HashMap<String, MagFeedTable>>> = toml::from_str(&s).unwrap();
|
||||||
|
let feed = feed.remove("feedtable".into()).unwrap();
|
||||||
|
let _feed = feed.into_iter()
|
||||||
|
.map(|table| {
|
||||||
|
table.into_iter()
|
||||||
|
.map(|(tool, stats)| {
|
||||||
|
(tool.parse().unwrap(), stats)
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
})
|
||||||
|
.collect::<Vec<HashMap<ToolType, MagFeedTable>>>();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_raise_a_sato() {
|
||||||
|
let mut mag = Mag::baby_mag(0);
|
||||||
|
mag.change_owner(CharacterClass::RAcaseal, SectionID::Whitill);
|
||||||
|
for _ in 0..137 {
|
||||||
|
mag.feed(ToolType::Antidote);
|
||||||
|
}
|
||||||
|
for _ in 0..75 {
|
||||||
|
mag.feed(ToolType::Antiparalysis);
|
||||||
|
}
|
||||||
|
mag.change_owner(CharacterClass::FOmarl, SectionID::Whitill);
|
||||||
|
for _ in 0..51 {
|
||||||
|
mag.feed(ToolType::Antiparalysis);
|
||||||
|
}
|
||||||
|
for _ in 0..284 {
|
||||||
|
mag.feed(ToolType::Dimate);
|
||||||
|
}
|
||||||
|
assert!(mag == Mag {
|
||||||
|
mag: MagType::Sato,
|
||||||
|
def: 507,
|
||||||
|
pow: 5019,
|
||||||
|
dex: 4505,
|
||||||
|
mnd: 0,
|
||||||
|
synchro: 120,
|
||||||
|
iq: 200,
|
||||||
|
photon_blast: [Some(PhotonBlast::Estlla), Some(PhotonBlast::Pilla), Some(PhotonBlast::MyllaYoulla)],
|
||||||
|
color: 0,
|
||||||
|
class: CharacterClass::FOmarl,
|
||||||
|
id: SectionID::Whitill,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_mag_does_not_level_down() {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -44,6 +44,9 @@ pub enum ItemLocation {
|
|||||||
z: f32,
|
z: f32,
|
||||||
},
|
},
|
||||||
Consumed,
|
Consumed,
|
||||||
|
FedToMag {
|
||||||
|
mag: ItemEntityId,
|
||||||
|
}
|
||||||
/*Destroyed {
|
/*Destroyed {
|
||||||
// marks an item that has been consumed in some way
|
// marks an item that has been consumed in some way
|
||||||
},
|
},
|
||||||
|
@ -251,6 +251,42 @@ impl ToolType {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn is_mag_cell(&self) -> bool {
|
||||||
|
match self {
|
||||||
|
ToolType::CellOfMag502 => true,
|
||||||
|
ToolType::CellOfMag213 => true,
|
||||||
|
ToolType::PartsOfRobochao => true,
|
||||||
|
ToolType::HeartOfOpaOpa => true,
|
||||||
|
ToolType::HeartOfPian => true,
|
||||||
|
ToolType::HeartOfChao => true,
|
||||||
|
ToolType::HeartOfAngel => true,
|
||||||
|
ToolType::HeartOfDevil => true,
|
||||||
|
ToolType::KitOfHamburger => true,
|
||||||
|
ToolType::PanthersSpirit => true,
|
||||||
|
ToolType::KitOfMark3 => true,
|
||||||
|
ToolType::KitOfMasterSystem => true,
|
||||||
|
ToolType::KitOfGenesis => true,
|
||||||
|
ToolType::KitOfSegaSaturn => true,
|
||||||
|
ToolType::KitOfDreamcast => true,
|
||||||
|
ToolType::Tablet => true,
|
||||||
|
ToolType::DragonScale => true,
|
||||||
|
ToolType::HeavenStrikerCoat => true,
|
||||||
|
ToolType::PioneerParts => true,
|
||||||
|
ToolType::AmitiesMemo => true,
|
||||||
|
ToolType::HeartOfMorolian => true,
|
||||||
|
ToolType::RappysBeak => true,
|
||||||
|
ToolType::YahoosEngine => true,
|
||||||
|
ToolType::DPhotonCore => true,
|
||||||
|
ToolType::LibertaKit => true,
|
||||||
|
ToolType::CellOfMag0503 => true,
|
||||||
|
ToolType::CellOfMag0504 => true,
|
||||||
|
ToolType::CellOfMag0505 => true,
|
||||||
|
ToolType::CellOfMag0506 => true,
|
||||||
|
ToolType::CellOfMag0507 => true,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn value(&self) -> [u8; 3] {
|
pub fn value(&self) -> [u8; 3] {
|
||||||
match self {
|
match self {
|
||||||
ToolType::Monomate => [0x03, 0x00, 0x00],
|
ToolType::Monomate => [0x03, 0x00, 0x00],
|
||||||
|
@ -3,6 +3,8 @@
|
|||||||
#![feature(maybe_uninit_extra)]
|
#![feature(maybe_uninit_extra)]
|
||||||
#![feature(const_in_array_repeat_expressions)]
|
#![feature(const_in_array_repeat_expressions)]
|
||||||
#![feature(drain_filter)]
|
#![feature(drain_filter)]
|
||||||
|
#![feature(or_patterns)]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -224,21 +224,11 @@ async fn new_character<EG: EntityGateway>(entity_gateway: &mut EG, user: &UserAc
|
|||||||
equipped: true,
|
equipped: true,
|
||||||
}}).await;
|
}}).await;
|
||||||
|
|
||||||
|
let mut mag = Mag::baby_mag(character.appearance.skin);
|
||||||
|
mag.change_owner(character.char_class, character.section_id);
|
||||||
entity_gateway.create_item(
|
entity_gateway.create_item(
|
||||||
NewItemEntity {
|
NewItemEntity {
|
||||||
item: ItemDetail::Mag(
|
item: ItemDetail::Mag(mag),
|
||||||
Mag {
|
|
||||||
mag: MagType::Mag,
|
|
||||||
def: 500,
|
|
||||||
pow: 0,
|
|
||||||
dex: 0,
|
|
||||||
mnd: 0,
|
|
||||||
synchro: 20,
|
|
||||||
iq: 0,
|
|
||||||
photon_blast: [None; 3],
|
|
||||||
color: (character.appearance.skin % 18) as u8,
|
|
||||||
modifiers: Vec::new(),
|
|
||||||
}),
|
|
||||||
location: ItemLocation::Inventory {
|
location: ItemLocation::Inventory {
|
||||||
character_id: character.id,
|
character_id: character.id,
|
||||||
slot: 2,
|
slot: 2,
|
||||||
|
@ -136,18 +136,7 @@ impl RareDropTable {
|
|||||||
})
|
})
|
||||||
},
|
},
|
||||||
RareDropItem::Mag(mag) => {
|
RareDropItem::Mag(mag) => {
|
||||||
ItemDropType::Mag(Mag {
|
ItemDropType::Mag(Mag::baby_mag(rng.gen_range(0, 18)))
|
||||||
mag: mag,
|
|
||||||
def: 500,
|
|
||||||
pow: 0,
|
|
||||||
dex: 0,
|
|
||||||
mnd: 0,
|
|
||||||
iq: 0,
|
|
||||||
synchro: 20,
|
|
||||||
photon_blast: [None; 3],
|
|
||||||
color: rng.gen_range(0, 18),
|
|
||||||
modifiers: Vec::new(),
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@ use thiserror::Error;
|
|||||||
use libpso::character::character;//::InventoryItem;
|
use libpso::character::character;//::InventoryItem;
|
||||||
use crate::entity::item::{ItemEntityId, ItemDetail, ItemType};
|
use crate::entity::item::{ItemEntityId, ItemDetail, ItemType};
|
||||||
use crate::entity::item::tool::Tool;
|
use crate::entity::item::tool::Tool;
|
||||||
|
use crate::entity::item::mag::Mag;
|
||||||
use crate::ship::items::{ClientItemId, BankItem, BankItemHandle};
|
use crate::ship::items::{ClientItemId, BankItem, BankItemHandle};
|
||||||
use crate::ship::items::floor::{IndividualFloorItem, StackedFloorItem};
|
use crate::ship::items::floor::{IndividualFloorItem, StackedFloorItem};
|
||||||
|
|
||||||
@ -20,6 +21,22 @@ pub struct IndividualInventoryItem {
|
|||||||
pub equipped: bool,
|
pub equipped: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl IndividualInventoryItem {
|
||||||
|
pub fn mag(&self) -> Option<&Mag> {
|
||||||
|
match self.item {
|
||||||
|
ItemDetail::Mag(ref mag) => Some(mag),
|
||||||
|
_ => None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn mag_mut(&mut self) -> Option<&mut Mag> {
|
||||||
|
match self.item {
|
||||||
|
ItemDetail::Mag(ref mut mag) => Some(mag),
|
||||||
|
_ => None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct StackedInventoryItem {
|
pub struct StackedInventoryItem {
|
||||||
pub entity_ids: Vec<ItemEntityId>,
|
pub entity_ids: Vec<ItemEntityId>,
|
||||||
@ -57,6 +74,17 @@ pub enum InventoryItemAddToError {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl InventoryItem {
|
impl InventoryItem {
|
||||||
|
pub fn entity_ids(&self) -> Vec<ItemEntityId> {
|
||||||
|
match self {
|
||||||
|
InventoryItem::Individual(individual_inventory_item) => {
|
||||||
|
vec![individual_inventory_item.entity_id]
|
||||||
|
},
|
||||||
|
InventoryItem::Stacked(stacked_inventory_item) => {
|
||||||
|
stacked_inventory_item.entity_ids.clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn item_id(&self) -> ClientItemId {
|
pub fn item_id(&self) -> ClientItemId {
|
||||||
match self {
|
match self {
|
||||||
InventoryItem::Individual(individual_inventory_item) => {
|
InventoryItem::Individual(individual_inventory_item) => {
|
||||||
@ -179,6 +207,13 @@ impl InventoryItem {
|
|||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn individual(&mut self) -> Option<&mut IndividualInventoryItem> {
|
||||||
|
match self {
|
||||||
|
InventoryItem::Individual(ref mut individual_inventory_item) => Some(individual_inventory_item),
|
||||||
|
_ => None
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -365,6 +400,24 @@ impl CharacterInventory {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_equipped_mag_handle<'a>(&'a mut self) -> Option<InventoryItemHandle<'a>> {
|
||||||
|
let (slot, _) = self.items.iter()
|
||||||
|
.enumerate()
|
||||||
|
.filter(|(_, item)| {
|
||||||
|
if let InventoryItem::Individual(individual_inventory_item) = item {
|
||||||
|
if let ItemDetail::Mag(_) = &individual_inventory_item.item {
|
||||||
|
return individual_inventory_item.equipped
|
||||||
|
}
|
||||||
|
}
|
||||||
|
false
|
||||||
|
})
|
||||||
|
.nth(0)?;
|
||||||
|
Some(InventoryItemHandle {
|
||||||
|
inventory: self,
|
||||||
|
slot: slot,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
pub fn get_item_by_id(&self, item_id: ClientItemId) -> Option<&InventoryItem> {
|
pub fn get_item_by_id(&self, item_id: ClientItemId) -> Option<&InventoryItem> {
|
||||||
self.items.iter()
|
self.items.iter()
|
||||||
.filter(|item| {
|
.filter(|item| {
|
||||||
|
@ -5,7 +5,7 @@ use crate::entity::gateway::EntityGateway;
|
|||||||
use crate::entity::character::{CharacterEntity, CharacterEntityId};
|
use crate::entity::character::{CharacterEntity, CharacterEntityId};
|
||||||
use crate::entity::item::{ItemDetail, ItemLocation, BankName};
|
use crate::entity::item::{ItemDetail, ItemLocation, BankName};
|
||||||
use crate::entity::item::{Meseta, NewItemEntity};
|
use crate::entity::item::{Meseta, NewItemEntity};
|
||||||
use crate::entity::item::tool::Tool;
|
use crate::entity::item::tool::{Tool, ToolType};
|
||||||
use crate::ship::map::MapArea;
|
use crate::ship::map::MapArea;
|
||||||
use crate::ship::ship::ItemDropLocation;
|
use crate::ship::ship::ItemDropLocation;
|
||||||
use crate::ship::drops::{ItemDrop, ItemDropType};
|
use crate::ship::drops::{ItemDrop, ItemDropType};
|
||||||
@ -14,6 +14,7 @@ use crate::ship::location::{AreaClient, RoomId};
|
|||||||
use crate::ship::items::bank::*;
|
use crate::ship::items::bank::*;
|
||||||
use crate::ship::items::floor::*;
|
use crate::ship::items::floor::*;
|
||||||
use crate::ship::items::inventory::*;
|
use crate::ship::items::inventory::*;
|
||||||
|
use crate::ship::items::use_tool;
|
||||||
|
|
||||||
|
|
||||||
pub enum TriggerCreateItem {
|
pub enum TriggerCreateItem {
|
||||||
@ -36,6 +37,8 @@ pub enum ItemManagerError {
|
|||||||
NotEnoughTools(Tool, usize, usize), // have, expected
|
NotEnoughTools(Tool, usize, usize), // have, expected
|
||||||
InventoryItemConsumeError(#[from] InventoryItemConsumeError),
|
InventoryItemConsumeError(#[from] InventoryItemConsumeError),
|
||||||
BankFull,
|
BankFull,
|
||||||
|
WrongItemType(ClientItemId),
|
||||||
|
UseItemError(#[from] use_tool::UseItemError),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ItemManager {
|
pub struct ItemManager {
|
||||||
@ -260,6 +263,9 @@ impl ItemManager {
|
|||||||
equipped: false,
|
equipped: false,
|
||||||
}
|
}
|
||||||
).await;
|
).await;
|
||||||
|
if let Some(_) = new_inventory_item.mag() {
|
||||||
|
entity_gateway.change_mag_owner(&new_inventory_item.entity_id, character).await;
|
||||||
|
}
|
||||||
},
|
},
|
||||||
None => {
|
None => {
|
||||||
return Err(ItemManagerError::CouldNotAddToInventory(item_id));
|
return Err(ItemManagerError::CouldNotAddToInventory(item_id));
|
||||||
@ -508,7 +514,7 @@ impl ItemManager {
|
|||||||
character: &CharacterEntity,
|
character: &CharacterEntity,
|
||||||
item_id: ClientItemId,
|
item_id: ClientItemId,
|
||||||
amount: usize)
|
amount: usize)
|
||||||
-> Result<ItemDetail, ItemManagerError> {
|
-> Result<ConsumedItem, ItemManagerError> {
|
||||||
let inventory = self.character_inventory.get_mut(&character.id).ok_or(ItemManagerError::NoCharacter(character.id))?;
|
let inventory = self.character_inventory.get_mut(&character.id).ok_or(ItemManagerError::NoCharacter(character.id))?;
|
||||||
let used_item = inventory.get_item_handle_by_id(item_id).ok_or(ItemManagerError::NoSuchItemId(item_id))?;
|
let used_item = inventory.get_item_handle_by_id(item_id).ok_or(ItemManagerError::NoSuchItemId(item_id))?;
|
||||||
let consumed_item = used_item.consume(amount)?;
|
let consumed_item = used_item.consume(amount)?;
|
||||||
@ -518,7 +524,7 @@ impl ItemManager {
|
|||||||
ItemLocation::Consumed).await;
|
ItemLocation::Consumed).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(consumed_item.item())
|
Ok(consumed_item)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn player_deposits_item<EG: EntityGateway>(&mut self,
|
pub async fn player_deposits_item<EG: EntityGateway>(&mut self,
|
||||||
@ -595,4 +601,155 @@ impl ItemManager {
|
|||||||
|
|
||||||
Ok(inventory_item.0)
|
Ok(inventory_item.0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn player_feeds_mag_item<EG: EntityGateway>(&mut self,
|
||||||
|
entity_gateway: &mut EG,
|
||||||
|
character: &CharacterEntity,
|
||||||
|
mag_id: ClientItemId,
|
||||||
|
tool_id: ClientItemId)
|
||||||
|
-> Result<(), ItemManagerError> {
|
||||||
|
let inventory = self.character_inventory.get_mut(&character.id).ok_or(ItemManagerError::NoCharacter(character.id))?;
|
||||||
|
let consumed_tool = {
|
||||||
|
let item_to_feed = inventory.get_item_handle_by_id(tool_id).ok_or(ItemManagerError::NoSuchItemId(tool_id))?;
|
||||||
|
item_to_feed.consume(1)?
|
||||||
|
};
|
||||||
|
let mut mag_handle = inventory.get_item_handle_by_id(mag_id).ok_or(ItemManagerError::NoSuchItemId(mag_id))?;
|
||||||
|
|
||||||
|
let individual_item = mag_handle.item_mut()
|
||||||
|
.ok_or(ItemManagerError::NoSuchItemId(mag_id))?
|
||||||
|
.individual()
|
||||||
|
.ok_or(ItemManagerError::WrongItemType(mag_id))?;
|
||||||
|
let mag = individual_item
|
||||||
|
.mag_mut()
|
||||||
|
.ok_or(ItemManagerError::WrongItemType(mag_id))?;
|
||||||
|
|
||||||
|
let consumed_tool_type = match &consumed_tool {
|
||||||
|
ConsumedItem::Stacked(stacked_consumed_item) => stacked_consumed_item.tool.tool,
|
||||||
|
_ => return Err(ItemManagerError::WrongItemType(tool_id))
|
||||||
|
};
|
||||||
|
mag.feed(consumed_tool_type);
|
||||||
|
|
||||||
|
for entity_id in consumed_tool.entity_ids() {
|
||||||
|
entity_gateway.feed_mag(&individual_item.entity_id, &entity_id).await;
|
||||||
|
entity_gateway.change_item_location(&entity_id, ItemLocation::FedToMag {
|
||||||
|
mag: individual_item.entity_id,
|
||||||
|
}).await;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pub async fn use_item<EG: EntityGateway>(&mut self,
|
||||||
|
used_item: ConsumedItem,
|
||||||
|
entity_gateway: &mut EG,
|
||||||
|
character: &mut CharacterEntity) -> Result<(), ItemManagerError> {
|
||||||
|
let inventory = self.character_inventory.get_mut(&character.id).ok_or(ItemManagerError::NoCharacter(character.id))?;
|
||||||
|
match &used_item.item() {
|
||||||
|
ItemDetail::Weapon(_w) => {
|
||||||
|
// something like when items are used to combine/transform them?
|
||||||
|
//_ => {}
|
||||||
|
},
|
||||||
|
ItemDetail::Tool(t) => {
|
||||||
|
match t.tool {
|
||||||
|
ToolType::PowerMaterial => {
|
||||||
|
use_tool::power_material(entity_gateway, character).await;
|
||||||
|
},
|
||||||
|
ToolType::MindMaterial => {
|
||||||
|
use_tool::mind_material(entity_gateway, character).await;
|
||||||
|
},
|
||||||
|
ToolType::EvadeMaterial => {
|
||||||
|
use_tool::evade_material(entity_gateway, character).await;
|
||||||
|
},
|
||||||
|
ToolType::DefMaterial => {
|
||||||
|
use_tool::def_material(entity_gateway, character).await;
|
||||||
|
},
|
||||||
|
ToolType::LuckMaterial => {
|
||||||
|
use_tool::luck_material(entity_gateway, character).await;
|
||||||
|
},
|
||||||
|
ToolType::HpMaterial => {
|
||||||
|
use_tool::hp_material(entity_gateway, character).await;
|
||||||
|
},
|
||||||
|
ToolType::TpMaterial => {
|
||||||
|
use_tool::tp_material(entity_gateway, character).await;
|
||||||
|
},
|
||||||
|
ToolType::CellOfMag502 => {
|
||||||
|
use_tool::cell_of_mag_502(entity_gateway, &used_item, inventory).await?;
|
||||||
|
},
|
||||||
|
ToolType::CellOfMag213 => {
|
||||||
|
use_tool::cell_of_mag_213(entity_gateway, &used_item, inventory).await?;
|
||||||
|
},
|
||||||
|
ToolType::PartsOfRobochao => {
|
||||||
|
use_tool::parts_of_robochao(entity_gateway, &used_item, inventory).await?;
|
||||||
|
},
|
||||||
|
ToolType::HeartOfOpaOpa => {
|
||||||
|
use_tool::heart_of_opaopa(entity_gateway, &used_item, inventory).await?;
|
||||||
|
},
|
||||||
|
ToolType::HeartOfPian => {
|
||||||
|
use_tool::heart_of_pian(entity_gateway, &used_item, inventory).await?;
|
||||||
|
},
|
||||||
|
ToolType::HeartOfChao=> {
|
||||||
|
use_tool::heart_of_chao(entity_gateway, &used_item, inventory).await?;
|
||||||
|
},
|
||||||
|
ToolType::HeartOfAngel => {
|
||||||
|
use_tool::heart_of_angel(entity_gateway, &used_item, inventory).await?;
|
||||||
|
},
|
||||||
|
ToolType::KitOfHamburger => {
|
||||||
|
use_tool::kit_of_hamburger(entity_gateway, &used_item, inventory).await?;
|
||||||
|
},
|
||||||
|
ToolType::PanthersSpirit => {
|
||||||
|
use_tool::panthers_spirit(entity_gateway, &used_item, inventory).await?;
|
||||||
|
},
|
||||||
|
ToolType::KitOfMark3 => {
|
||||||
|
use_tool::kit_of_mark3(entity_gateway, &used_item, inventory).await?;
|
||||||
|
},
|
||||||
|
ToolType::KitOfMasterSystem=> {
|
||||||
|
use_tool::kit_of_master_system(entity_gateway, &used_item, inventory).await?;
|
||||||
|
},
|
||||||
|
ToolType::KitOfGenesis => {
|
||||||
|
use_tool::kit_of_genesis(entity_gateway, &used_item, inventory).await?;
|
||||||
|
},
|
||||||
|
ToolType::KitOfSegaSaturn => {
|
||||||
|
use_tool::kit_of_sega_saturn(entity_gateway, &used_item, inventory).await?;
|
||||||
|
},
|
||||||
|
ToolType::KitOfDreamcast => {
|
||||||
|
use_tool::kit_of_dreamcast(entity_gateway, &used_item, inventory).await?;
|
||||||
|
},
|
||||||
|
ToolType::Tablet => {
|
||||||
|
use_tool::tablet(entity_gateway, &used_item, inventory).await?;
|
||||||
|
},
|
||||||
|
ToolType::DragonScale => {
|
||||||
|
use_tool::dragon_scale(entity_gateway, &used_item, inventory).await?;
|
||||||
|
},
|
||||||
|
ToolType::HeavenStrikerCoat => {
|
||||||
|
use_tool::heaven_striker_coat(entity_gateway, &used_item, inventory).await?;
|
||||||
|
},
|
||||||
|
ToolType::PioneerParts => {
|
||||||
|
use_tool::pioneer_parts(entity_gateway, &used_item, inventory).await?;
|
||||||
|
},
|
||||||
|
ToolType::AmitiesMemo => {
|
||||||
|
use_tool::amities_memo(entity_gateway, &used_item, inventory).await?;
|
||||||
|
},
|
||||||
|
ToolType::HeartOfMorolian => {
|
||||||
|
use_tool::heart_of_morolian(entity_gateway, &used_item, inventory).await?;
|
||||||
|
},
|
||||||
|
ToolType::RappysBeak => {
|
||||||
|
use_tool::rappys_beak(entity_gateway, &used_item, inventory).await?;
|
||||||
|
},
|
||||||
|
ToolType::YahoosEngine => {
|
||||||
|
use_tool::yahoos_engine(entity_gateway, &used_item, inventory).await?;
|
||||||
|
},
|
||||||
|
ToolType::DPhotonCore => {
|
||||||
|
use_tool::d_photon_core(entity_gateway, &used_item, inventory).await?;
|
||||||
|
},
|
||||||
|
ToolType::LibertaKit => {
|
||||||
|
use_tool::liberta_kit(entity_gateway, &used_item, inventory).await?;
|
||||||
|
},
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@ mod bank;
|
|||||||
mod floor;
|
mod floor;
|
||||||
mod inventory;
|
mod inventory;
|
||||||
mod manager;
|
mod manager;
|
||||||
|
pub mod use_tool;
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
|
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
|
||||||
pub struct ClientItemId(pub u32);
|
pub struct ClientItemId(pub u32);
|
||||||
|
175
src/ship/items/use_tool.rs
Normal file
175
src/ship/items/use_tool.rs
Normal file
@ -0,0 +1,175 @@
|
|||||||
|
use thiserror::Error;
|
||||||
|
use crate::entity::gateway::EntityGateway;
|
||||||
|
use crate::entity::character::CharacterEntity;
|
||||||
|
use crate::entity::item::{ItemEntityId, ItemDetail};
|
||||||
|
use crate::entity::item::tool::ToolType;
|
||||||
|
use crate::entity::item::mag::MagCell;
|
||||||
|
use crate::ship::items::{ItemManager, ClientItemId, CharacterInventory, ConsumedItem};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#[derive(Error, Debug)]
|
||||||
|
#[error("")]
|
||||||
|
pub enum UseItemError {
|
||||||
|
NoCharacter,
|
||||||
|
ItemNotEquipped,
|
||||||
|
InvalidItem,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//pub fn use_tool()
|
||||||
|
|
||||||
|
pub async fn power_material<EG: EntityGateway>(entity_gateway: &mut EG, character: &mut CharacterEntity) {
|
||||||
|
character.materials.power += 1;
|
||||||
|
entity_gateway.save_character(character).await;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn mind_material<EG: EntityGateway>(entity_gateway: &mut EG, character: &mut CharacterEntity) {
|
||||||
|
character.materials.mind += 1;
|
||||||
|
entity_gateway.save_character(character).await;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn evade_material<EG: EntityGateway>(entity_gateway: &mut EG, character: &mut CharacterEntity) {
|
||||||
|
character.materials.evade += 1;
|
||||||
|
entity_gateway.save_character(character).await;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn def_material<EG: EntityGateway>(entity_gateway: &mut EG, character: &mut CharacterEntity) {
|
||||||
|
character.materials.def += 1;
|
||||||
|
entity_gateway.save_character(character).await;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn luck_material<EG: EntityGateway>(entity_gateway: &mut EG, character: &mut CharacterEntity) {
|
||||||
|
character.materials.luck += 1;
|
||||||
|
entity_gateway.save_character(character).await;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn hp_material<EG: EntityGateway>(entity_gateway: &mut EG, character: &mut CharacterEntity) {
|
||||||
|
character.materials.hp += 1;
|
||||||
|
entity_gateway.save_character(character).await;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn tp_material<EG: EntityGateway>(entity_gateway: &mut EG, character: &mut CharacterEntity) {
|
||||||
|
character.materials.tp += 1;
|
||||||
|
entity_gateway.save_character(character).await;
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn mag_cell<EG: EntityGateway>(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory, mag_cell_type: MagCell) -> Result<(), UseItemError> {
|
||||||
|
let mut mag_handle = inventory.get_equipped_mag_handle().ok_or(UseItemError::ItemNotEquipped)?;
|
||||||
|
let mag_item = mag_handle.item_mut()
|
||||||
|
.ok_or(UseItemError::InvalidItem)?;
|
||||||
|
let actual_mag = mag_item
|
||||||
|
.individual()
|
||||||
|
.ok_or(UseItemError::InvalidItem)?
|
||||||
|
.mag_mut()
|
||||||
|
.ok_or(UseItemError::InvalidItem)?;
|
||||||
|
actual_mag.apply_mag_cell(mag_cell_type);
|
||||||
|
for mag_entity_id in mag_item.entity_ids() {
|
||||||
|
for cell_entity_id in used_cell.entity_ids() {
|
||||||
|
entity_gateway.use_mag_cell(&mag_entity_id, &cell_entity_id).await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn cell_of_mag_502<EG: EntityGateway>(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory) -> Result<(), UseItemError> {
|
||||||
|
mag_cell(entity_gateway, used_cell, inventory, MagCell::CellOfMag502).await
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn cell_of_mag_213<EG: EntityGateway>(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory) -> Result<(), UseItemError> {
|
||||||
|
mag_cell(entity_gateway, used_cell, inventory, MagCell::CellOfMag213).await
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn parts_of_robochao<EG: EntityGateway>(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory) -> Result<(), UseItemError> {
|
||||||
|
mag_cell(entity_gateway, used_cell, inventory, MagCell::PartsOfRobochao).await
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn heart_of_opaopa<EG: EntityGateway>(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory) -> Result<(), UseItemError> {
|
||||||
|
mag_cell(entity_gateway, used_cell, inventory, MagCell::HeartOfOpaOpa).await
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn heart_of_pian<EG: EntityGateway>(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory) -> Result<(), UseItemError> {
|
||||||
|
mag_cell(entity_gateway, used_cell, inventory, MagCell::HeartOfPian).await
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn heart_of_chao<EG: EntityGateway>(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory) -> Result<(), UseItemError> {
|
||||||
|
mag_cell(entity_gateway, used_cell, inventory, MagCell::HeartOfChao).await
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn heart_of_angel<EG: EntityGateway>(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory) -> Result<(), UseItemError> {
|
||||||
|
mag_cell(entity_gateway, used_cell, inventory, MagCell::HeartOfAngel).await
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn kit_of_hamburger<EG: EntityGateway>(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory) -> Result<(), UseItemError> {
|
||||||
|
mag_cell(entity_gateway, used_cell, inventory, MagCell::KitOfHamburger).await
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn panthers_spirit<EG: EntityGateway>(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory) -> Result<(), UseItemError> {
|
||||||
|
mag_cell(entity_gateway, used_cell, inventory, MagCell::PanthersSpirit).await
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn kit_of_mark3<EG: EntityGateway>(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory) -> Result<(), UseItemError> {
|
||||||
|
mag_cell(entity_gateway, used_cell, inventory, MagCell::KitOfMark3).await
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn kit_of_master_system<EG: EntityGateway>(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory) -> Result<(), UseItemError> {
|
||||||
|
mag_cell(entity_gateway, used_cell, inventory, MagCell::KitOfMasterSystem).await
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn kit_of_genesis<EG: EntityGateway>(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory) -> Result<(), UseItemError> {
|
||||||
|
mag_cell(entity_gateway, used_cell, inventory, MagCell::KitOfGenesis).await
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn kit_of_sega_saturn<EG: EntityGateway>(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory) -> Result<(), UseItemError> {
|
||||||
|
mag_cell(entity_gateway, used_cell, inventory, MagCell::KitOfSegaSaturn).await
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn kit_of_dreamcast<EG: EntityGateway>(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory) -> Result<(), UseItemError> {
|
||||||
|
mag_cell(entity_gateway, used_cell, inventory, MagCell::KitOfDreamcast).await
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn tablet<EG: EntityGateway>(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory) -> Result<(), UseItemError> {
|
||||||
|
mag_cell(entity_gateway, used_cell, inventory, MagCell::Tablet).await
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn dragon_scale<EG: EntityGateway>(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory) -> Result<(), UseItemError> {
|
||||||
|
mag_cell(entity_gateway, used_cell, inventory, MagCell::DragonScale).await
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn heaven_striker_coat<EG: EntityGateway>(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory) -> Result<(), UseItemError> {
|
||||||
|
mag_cell(entity_gateway, used_cell, inventory, MagCell::HeavenStrikerCoat).await
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn pioneer_parts<EG: EntityGateway>(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory) -> Result<(), UseItemError> {
|
||||||
|
mag_cell(entity_gateway, used_cell, inventory, MagCell::PioneerParts).await
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn amities_memo<EG: EntityGateway>(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory) -> Result<(), UseItemError> {
|
||||||
|
mag_cell(entity_gateway, used_cell, inventory, MagCell::AmitiesMemo).await
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn heart_of_morolian<EG: EntityGateway>(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory) -> Result<(), UseItemError> {
|
||||||
|
mag_cell(entity_gateway, used_cell, inventory, MagCell::HeartOfMorolian).await
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn rappys_beak<EG: EntityGateway>(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory) -> Result<(), UseItemError> {
|
||||||
|
mag_cell(entity_gateway, used_cell, inventory, MagCell::RappysBeak).await
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn yahoos_engine<EG: EntityGateway>(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory) -> Result<(), UseItemError> {
|
||||||
|
mag_cell(entity_gateway, used_cell, inventory, MagCell::YahoosEngine).await
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn d_photon_core<EG: EntityGateway>(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory) -> Result<(), UseItemError> {
|
||||||
|
mag_cell(entity_gateway, used_cell, inventory, MagCell::DPhotonCore).await
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn liberta_kit<EG: EntityGateway>(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory) -> Result<(), UseItemError> {
|
||||||
|
mag_cell(entity_gateway, used_cell, inventory, MagCell::LibertaKit).await
|
||||||
|
}
|
@ -263,50 +263,9 @@ where
|
|||||||
EG: EntityGateway
|
EG: EntityGateway
|
||||||
{
|
{
|
||||||
let client = clients.get_mut(&id).ok_or(ShipError::ClientNotFound(id))?;
|
let client = clients.get_mut(&id).ok_or(ShipError::ClientNotFound(id))?;
|
||||||
|
|
||||||
let item_used_type = item_manager.player_consumes_tool(entity_gateway, &client.character, ClientItemId(player_use_tool.item_id), 1).await?;
|
let item_used_type = item_manager.player_consumes_tool(entity_gateway, &client.character, ClientItemId(player_use_tool.item_id), 1).await?;
|
||||||
|
|
||||||
match item_used_type {
|
item_manager.use_item(item_used_type, entity_gateway, &mut client.character).await?;
|
||||||
ItemDetail::Weapon(_w) => {
|
|
||||||
// something like when items are used to combine/transform them?
|
|
||||||
//_ => {}
|
|
||||||
},
|
|
||||||
ItemDetail::Tool(t) => {
|
|
||||||
match t.tool {
|
|
||||||
ToolType::PowerMaterial => {
|
|
||||||
client.character.materials.power += 1;
|
|
||||||
entity_gateway.save_character(&client.character).await;
|
|
||||||
},
|
|
||||||
ToolType::MindMaterial => {
|
|
||||||
client.character.materials.mind += 1;
|
|
||||||
entity_gateway.save_character(&client.character).await;
|
|
||||||
},
|
|
||||||
ToolType::EvadeMaterial => {
|
|
||||||
client.character.materials.evade += 1;
|
|
||||||
entity_gateway.save_character(&client.character).await;
|
|
||||||
},
|
|
||||||
ToolType::DefMaterial => {
|
|
||||||
client.character.materials.def += 1;
|
|
||||||
entity_gateway.save_character(&client.character).await;
|
|
||||||
},
|
|
||||||
ToolType::LuckMaterial => {
|
|
||||||
client.character.materials.luck += 1;
|
|
||||||
entity_gateway.save_character(&client.character).await;
|
|
||||||
},
|
|
||||||
ToolType::HpMaterial => {
|
|
||||||
client.character.materials.hp += 1;
|
|
||||||
entity_gateway.save_character(&client.character).await;
|
|
||||||
},
|
|
||||||
ToolType::TpMaterial => {
|
|
||||||
client.character.materials.tp += 1;
|
|
||||||
entity_gateway.save_character(&client.character).await;
|
|
||||||
},
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(Box::new(None.into_iter()))
|
Ok(Box::new(None.into_iter()))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -326,4 +285,25 @@ EG: EntityGateway
|
|||||||
} else {
|
} else {
|
||||||
Err(ShipError::NotEnoughMeseta(id, client.character.meseta))
|
Err(ShipError::NotEnoughMeseta(id, client.character.meseta))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pub async fn player_feed_mag<EG>(id: ClientId,
|
||||||
|
mag_feed: &PlayerFeedMag,
|
||||||
|
entity_gateway: &mut EG,
|
||||||
|
client_location: &ClientLocation,
|
||||||
|
clients: &Clients,
|
||||||
|
item_manager: &mut ItemManager)
|
||||||
|
-> Result<Box<dyn Iterator<Item = (ClientId, SendShipPacket)> + Send>, ShipError>
|
||||||
|
where
|
||||||
|
EG: EntityGateway
|
||||||
|
{
|
||||||
|
let client = clients.get(&id).ok_or(ShipError::ClientNotFound(id))?;
|
||||||
|
item_manager.player_feeds_mag_item(entity_gateway, &client.character, ClientItemId(mag_feed.mag_id), ClientItemId(mag_feed.item_id)).await?;
|
||||||
|
|
||||||
|
let mag_feed = mag_feed.clone();
|
||||||
|
Ok(Box::new(client_location.get_client_neighbors(id).unwrap().into_iter()
|
||||||
|
.map(move |client| {
|
||||||
|
(client.client, SendShipPacket::Message(Message::new(GameMessage::PlayerFeedMag(mag_feed.clone()))))
|
||||||
|
})))
|
||||||
|
}
|
||||||
|
@ -348,6 +348,9 @@ impl<EG: EntityGateway> ShipServerState<EG> {
|
|||||||
GameMessage::PlayerUsedMedicalCenter(player_used_medical_center) => {
|
GameMessage::PlayerUsedMedicalCenter(player_used_medical_center) => {
|
||||||
handler::message::player_used_medical_center(id, &player_used_medical_center, &mut self.entity_gateway, &mut self.clients).await
|
handler::message::player_used_medical_center(id, &player_used_medical_center, &mut self.entity_gateway, &mut self.clients).await
|
||||||
},
|
},
|
||||||
|
GameMessage::PlayerFeedMag(player_feed_mag) => {
|
||||||
|
handler::message::player_feed_mag(id, &player_feed_mag, &mut self.entity_gateway, &mut self.client_location, &mut self.clients, &mut self.item_manager).await
|
||||||
|
},
|
||||||
_ => {
|
_ => {
|
||||||
let cmsg = msg.clone();
|
let cmsg = msg.clone();
|
||||||
Ok(Box::new(self.client_location.get_client_neighbors(id).unwrap().into_iter()
|
Ok(Box::new(self.client_location.get_client_neighbors(id).unwrap().into_iter()
|
||||||
|
210
tests/test_mags.rs
Normal file
210
tests/test_mags.rs
Normal file
@ -0,0 +1,210 @@
|
|||||||
|
use elseware::common::serverstate::{ClientId, ServerState};
|
||||||
|
use elseware::entity::gateway::{EntityGateway, InMemoryGateway};
|
||||||
|
use elseware::entity::item;
|
||||||
|
use elseware::ship::ship::{ShipServerState, RecvShipPacket, SendShipPacket};
|
||||||
|
use elseware::entity::character::{CharacterClass, SectionID};
|
||||||
|
|
||||||
|
use libpso::packet::ship::*;
|
||||||
|
use libpso::packet::messages::*;
|
||||||
|
|
||||||
|
#[path = "common.rs"]
|
||||||
|
mod common;
|
||||||
|
use common::*;
|
||||||
|
|
||||||
|
#[async_std::test]
|
||||||
|
async fn test_mag_feed() {
|
||||||
|
let mut entity_gateway = InMemoryGateway::new();
|
||||||
|
|
||||||
|
let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await;
|
||||||
|
|
||||||
|
entity_gateway.create_item(
|
||||||
|
item::NewItemEntity {
|
||||||
|
item: item::ItemDetail::Mag(
|
||||||
|
item::mag::Mag::baby_mag(0)
|
||||||
|
),
|
||||||
|
location: item::ItemLocation::Inventory {
|
||||||
|
character_id: char1.id,
|
||||||
|
slot: 0,
|
||||||
|
equipped: true,
|
||||||
|
}
|
||||||
|
}).await;
|
||||||
|
for _ in 0..7 {
|
||||||
|
entity_gateway.create_item(
|
||||||
|
item::NewItemEntity {
|
||||||
|
item: item::ItemDetail::Tool(
|
||||||
|
item::tool::Tool {
|
||||||
|
tool: item::tool::ToolType::Monomate,
|
||||||
|
}
|
||||||
|
),
|
||||||
|
location: item::ItemLocation::Inventory {
|
||||||
|
character_id: char1.id,
|
||||||
|
slot: 1,
|
||||||
|
equipped: false,
|
||||||
|
}
|
||||||
|
}).await;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut ship = ShipServerState::builder()
|
||||||
|
.gateway(entity_gateway.clone())
|
||||||
|
.build();
|
||||||
|
log_in_char(&mut ship, ClientId(1), "a1", "a").await;
|
||||||
|
join_lobby(&mut ship, ClientId(1)).await;
|
||||||
|
create_room(&mut ship, ClientId(1), "room", "").await;
|
||||||
|
|
||||||
|
for _ in 0..7 {
|
||||||
|
ship.handle(ClientId(1), &RecvShipPacket::Message(Message::new(GameMessage::PlayerFeedMag(PlayerFeedMag {
|
||||||
|
client: 0,
|
||||||
|
target: 0,
|
||||||
|
mag_id: 0x10000,
|
||||||
|
item_id: 0x10001,
|
||||||
|
})))).await.unwrap().for_each(drop);
|
||||||
|
}
|
||||||
|
|
||||||
|
let p1_items = entity_gateway.get_items_by_character(&char1).await;
|
||||||
|
let mag = p1_items.get(0).unwrap();
|
||||||
|
match &mag.item {
|
||||||
|
item::ItemDetail::Mag(mag) => {
|
||||||
|
assert!(mag.level() == 7);
|
||||||
|
assert!(mag.def() == 5);
|
||||||
|
assert!(mag.pow() == 2);
|
||||||
|
assert!(mag.dex() == 0);
|
||||||
|
assert!(mag.mind() == 0);
|
||||||
|
}
|
||||||
|
_ => panic!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_std::test]
|
||||||
|
async fn test_mag_change_owner() {
|
||||||
|
let mut entity_gateway = InMemoryGateway::new();
|
||||||
|
|
||||||
|
let (_user1, mut char1) = new_user_character(&mut entity_gateway, "a1", "a").await;
|
||||||
|
let (_user2, mut char2) = new_user_character(&mut entity_gateway, "a2", "a").await;
|
||||||
|
char1.char_class = CharacterClass::RAmarl;
|
||||||
|
char1.section_id = SectionID::Redria;
|
||||||
|
entity_gateway.save_character(&char1).await;
|
||||||
|
char2.char_class = CharacterClass::FOmarl;
|
||||||
|
char2.section_id = SectionID::Whitill;
|
||||||
|
entity_gateway.save_character(&char2).await;
|
||||||
|
|
||||||
|
entity_gateway.create_item(
|
||||||
|
item::NewItemEntity {
|
||||||
|
item: item::ItemDetail::Mag(
|
||||||
|
item::mag::Mag::baby_mag(0)
|
||||||
|
),
|
||||||
|
location: item::ItemLocation::Inventory {
|
||||||
|
character_id: char1.id,
|
||||||
|
slot: 0,
|
||||||
|
equipped: true,
|
||||||
|
}
|
||||||
|
}).await;
|
||||||
|
|
||||||
|
let mut ship = ShipServerState::builder()
|
||||||
|
.gateway(entity_gateway.clone())
|
||||||
|
.build();
|
||||||
|
log_in_char(&mut ship, ClientId(1), "a1", "a").await;
|
||||||
|
log_in_char(&mut ship, ClientId(2), "a2", "a").await;
|
||||||
|
join_lobby(&mut ship, ClientId(1)).await;
|
||||||
|
join_lobby(&mut ship, ClientId(2)).await;
|
||||||
|
create_room(&mut ship, ClientId(1), "room", "").await;
|
||||||
|
join_room(&mut ship, ClientId(2), 0).await;
|
||||||
|
|
||||||
|
ship.handle(ClientId(1), &RecvShipPacket::Message(Message::new(GameMessage::PlayerDropItem(PlayerDropItem {
|
||||||
|
client: 0,
|
||||||
|
target: 0,
|
||||||
|
unknown1: 0,
|
||||||
|
map_area: 0,
|
||||||
|
item_id: 0x10000,
|
||||||
|
x: 0.0,
|
||||||
|
y: 0.0,
|
||||||
|
z: 0.0,
|
||||||
|
})))).await.unwrap().for_each(drop);
|
||||||
|
|
||||||
|
ship.handle(ClientId(2), &RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::PickupItem(PickupItem {
|
||||||
|
client: 0,
|
||||||
|
target: 0,
|
||||||
|
item_id: 0x10000,
|
||||||
|
map_area: 0,
|
||||||
|
unknown: [0; 3]
|
||||||
|
})))).await.unwrap().for_each(drop);
|
||||||
|
|
||||||
|
let p2_items = entity_gateway.get_items_by_character(&char2).await;
|
||||||
|
let mag = p2_items.get(0).unwrap();
|
||||||
|
match &mag.item {
|
||||||
|
item::ItemDetail::Mag(mag) => {
|
||||||
|
assert!(mag.class == CharacterClass::FOmarl);
|
||||||
|
assert!(mag.id == SectionID::Whitill);
|
||||||
|
},
|
||||||
|
_ => panic!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[async_std::test]
|
||||||
|
async fn test_mag_cell() {
|
||||||
|
let mut entity_gateway = InMemoryGateway::new();
|
||||||
|
|
||||||
|
let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await;
|
||||||
|
|
||||||
|
let mag = entity_gateway.create_item(
|
||||||
|
item::NewItemEntity {
|
||||||
|
item: item::ItemDetail::Mag(
|
||||||
|
item::mag::Mag::baby_mag(0)
|
||||||
|
),
|
||||||
|
location: item::ItemLocation::Inventory {
|
||||||
|
character_id: char1.id,
|
||||||
|
slot: 0,
|
||||||
|
equipped: true,
|
||||||
|
}
|
||||||
|
}).await.unwrap();
|
||||||
|
|
||||||
|
for _ in 0..1000 {
|
||||||
|
let fed_tool = entity_gateway.create_item(
|
||||||
|
item::NewItemEntity {
|
||||||
|
item: item::ItemDetail::Tool (
|
||||||
|
item::tool::Tool {
|
||||||
|
tool: item::tool::ToolType::Monomate,
|
||||||
|
}
|
||||||
|
),
|
||||||
|
location: item::ItemLocation::FedToMag {
|
||||||
|
mag: mag.id,
|
||||||
|
}
|
||||||
|
}).await.unwrap();
|
||||||
|
entity_gateway.feed_mag(&mag.id, &fed_tool.id).await;
|
||||||
|
}
|
||||||
|
entity_gateway.create_item(
|
||||||
|
item::NewItemEntity {
|
||||||
|
item: item::ItemDetail::Tool(
|
||||||
|
item::tool::Tool {
|
||||||
|
tool: item::tool::ToolType::CellOfMag502,
|
||||||
|
}
|
||||||
|
),
|
||||||
|
location: item::ItemLocation::Inventory {
|
||||||
|
character_id: char1.id,
|
||||||
|
slot: 1,
|
||||||
|
equipped: false,
|
||||||
|
}
|
||||||
|
}).await;
|
||||||
|
|
||||||
|
let mut ship = ShipServerState::builder()
|
||||||
|
.gateway(entity_gateway.clone())
|
||||||
|
.build();
|
||||||
|
log_in_char(&mut ship, ClientId(1), "a1", "a").await;
|
||||||
|
join_lobby(&mut ship, ClientId(1)).await;
|
||||||
|
create_room(&mut ship, ClientId(1), "room", "").await;
|
||||||
|
|
||||||
|
ship.handle(ClientId(1), &RecvShipPacket::Message(Message::new(GameMessage::PlayerUseItem(PlayerUseItem {
|
||||||
|
client: 0,
|
||||||
|
target: 0,
|
||||||
|
item_id: 0x10001,
|
||||||
|
})))).await.unwrap().for_each(drop);
|
||||||
|
|
||||||
|
let p1_items = entity_gateway.get_items_by_character(&char1).await;
|
||||||
|
let mag = p1_items.get(0).unwrap();
|
||||||
|
match &mag.item {
|
||||||
|
item::ItemDetail::Mag(mag) => {
|
||||||
|
assert!(mag.mag == item::mag::MagType::Soniti);
|
||||||
|
}
|
||||||
|
_ => panic!()
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user