Implement WeaponLevelUp

This commit is contained in:
xeon 2025-06-11 20:46:47 +03:00
parent a7a2747eba
commit 19b54b04df
5 changed files with 195 additions and 63 deletions

View file

@ -7,7 +7,7 @@ pub use equip::EquipItem;
use num_enum::{IntoPrimitive, TryFromPrimitive}; use num_enum::{IntoPrimitive, TryFromPrimitive};
pub use weapon::WeaponItem; pub use weapon::WeaponItem;
#[derive(Debug, PartialEq, Eq, TryFromPrimitive, IntoPrimitive)] #[derive(Debug, PartialEq, Eq, Clone, Copy, TryFromPrimitive, IntoPrimitive)]
#[repr(u32)] #[repr(u32)]
pub enum EItemType { pub enum EItemType {
Currency = 1, Currency = 1,
@ -18,6 +18,7 @@ pub enum EItemType {
Equip = 7, Equip = 7,
Buddy = 8, Buddy = 8,
AvatarLevelUpMaterial = 12, AvatarLevelUpMaterial = 12,
WeaponLevelUpMaterial = 13,
} }
#[derive(Debug, PartialEq, Eq, TryFromPrimitive, IntoPrimitive)] #[derive(Debug, PartialEq, Eq, TryFromPrimitive, IntoPrimitive)]

View file

@ -1664,6 +1664,23 @@ pub struct WeaponUnDressScRsp {
pub retcode: i32, pub retcode: i32,
} }
#[derive(Clone, PartialEq, ::proto_derive::Message, ::proto_derive::NetCmd)] #[derive(Clone, PartialEq, ::proto_derive::Message, ::proto_derive::NetCmd)]
#[cmd_id(6184)]
pub struct WeaponLevelUpCsReq {
#[prost(uint32, tag = "15", xor = "9837")]
pub weapon_uid: u32,
#[prost(map = "uint32, uint32", tag = "4")]
pub exp_materials: ::std::collections::HashMap<u32, u32>,
}
#[derive(Clone, PartialEq, ::proto_derive::Message, ::proto_derive::NetCmd)]
#[derive(::proto_derive::NetResponse)]
#[cmd_id(9680)]
pub struct WeaponLevelUpScRsp {
#[prost(int32, tag = "3", xor = "8188")]
pub retcode: i32,
#[prost(message, repeated, tag = "5")]
pub return_item_list: ::prost::alloc::vec::Vec<ItemRewardInfo>,
}
#[derive(Clone, PartialEq, ::proto_derive::Message, ::proto_derive::NetCmd)]
#[cmd_id(3101)] #[cmd_id(3101)]
pub struct TalentSwitchCsReq { pub struct TalentSwitchCsReq {
#[prost(uint32, tag = "5", xor = "10791")] #[prost(uint32, tag = "5", xor = "10791")]

View file

@ -63,20 +63,11 @@ impl AvatarHandler {
item_util::use_item(context.player, id, count); item_util::use_item(context.player, id, count);
}); });
let added_exp = request let added_exp = item_util::materials_to_exp(
.exp_materials &request.exp_materials,
.iter() EItemType::AvatarLevelUpMaterial,
.filter_map(|(&id, &count)| { context.resources,
let template = context );
.resources
.templates
.item_template_tb()
.find(|tmpl| tmpl.id() == id)?;
(template.class() == EItemType::AvatarLevelUpMaterial.into())
.then(|| template.parameters().unwrap().get(0) * count)
})
.sum::<u32>();
let avatar = context let avatar = context
.player .player
@ -112,50 +103,24 @@ impl AvatarHandler {
avatar.level += 1; avatar.level += 1;
} }
let mut rsp = AvatarLevelUpScRsp::default(); AvatarLevelUpScRsp {
retcode: 0,
if avatar.level == max_level { return_item_list: if avatar.level == max_level {
while avatar.exp > 0 { item_util::exp_to_materials(
let Some(return_material) = context &mut avatar.exp,
.resources EItemType::AvatarLevelUpMaterial,
.templates context.resources,
.item_template_tb() )
.filter(|tmpl| { .into_iter()
tmpl.class() == EItemType::AvatarLevelUpMaterial.into() .map(|(item_id, amount)| {
&& tmpl.parameters().unwrap().get(0) <= avatar.exp item_util::add_item(context.player, item_id, amount);
}) ItemRewardInfo { item_id, amount }
.max_by_key(|tmpl| tmpl.parameters().unwrap().get(0)) })
else { .collect()
avatar.exp = 0; } else {
break; Vec::new()
}; },
let exp_amount = return_material.parameters().unwrap().get(0);
rsp.return_item_list.push(ItemRewardInfo {
item_id: return_material.id(),
amount: avatar.exp / exp_amount,
});
let cur = context
.player
.item_model
.item_count_map
.get(&return_material.id())
.copied()
.unwrap_or_default();
context
.player
.item_model
.item_count_map
.insert(return_material.id(), cur + (avatar.exp / exp_amount) as i32);
avatar.exp %= exp_amount;
}
} }
rsp
} }
pub fn on_weapon_dress_cs_req( pub fn on_weapon_dress_cs_req(

View file

@ -1,10 +1,12 @@
use yixuan_codegen::{handlers, required_state}; use yixuan_codegen::{handlers, required_state};
use yixuan_logic::item::EItemType;
use yixuan_proto::{ use yixuan_proto::{
GetEquipDataCsReq, GetEquipDataScRsp, GetItemDataCsReq, GetItemDataScRsp, GetWeaponDataCsReq, GetEquipDataCsReq, GetEquipDataScRsp, GetItemDataCsReq, GetItemDataScRsp, GetWeaponDataCsReq,
GetWeaponDataScRsp, GetWishlistDataCsReq, GetWishlistDataScRsp, GetWeaponDataScRsp, GetWishlistDataCsReq, GetWishlistDataScRsp, ItemRewardInfo,
WeaponLevelUpCsReq, WeaponLevelUpScRsp,
}; };
use crate::sync::SyncType; use crate::{sync::SyncType, util::item_util};
use super::NetContext; use super::NetContext;
@ -55,4 +57,103 @@ impl ItemHandler {
.sync_helper .sync_helper
.remove_sync_response(SyncType::BasicData) .remove_sync_response(SyncType::BasicData)
} }
pub fn on_weapon_level_up_cs_req(
context: &mut NetContext,
request: WeaponLevelUpCsReq,
) -> WeaponLevelUpScRsp {
if !context
.player
.item_model
.weapon_map
.contains_key(&request.weapon_uid)
{
return WeaponLevelUpScRsp {
retcode: 1,
..Default::default()
};
}
if !request
.exp_materials
.iter()
.all(|(&id, &count)| item_util::has_enough_items(context.player, id, count))
{
return WeaponLevelUpScRsp {
retcode: 1,
..Default::default()
};
}
request.exp_materials.iter().for_each(|(&id, &count)| {
item_util::use_item(context.player, id, count);
});
let added_exp = item_util::materials_to_exp(
&request.exp_materials,
EItemType::WeaponLevelUpMaterial,
context.resources,
);
let weapon = context
.player
.item_model
.weapon_map
.get_mut(&request.weapon_uid)
.unwrap();
weapon.exp += added_exp;
let weapon_rarity = context
.resources
.templates
.item_template_tb()
.find(|tmpl| tmpl.id() == weapon.id)
.map(|tmpl| tmpl.rarity())
.unwrap();
let max_level = context
.resources
.templates
.weapon_star_template_tb()
.find(|tmpl| tmpl.rarity() == weapon_rarity && tmpl.star() == weapon.star)
.unwrap()
.max_level();
while weapon.level < max_level {
let required_exp = context
.resources
.templates
.weapon_level_template_tb()
.find(|tmpl| tmpl.rarity() == weapon_rarity && tmpl.level() == weapon.level)
.unwrap()
.exp();
if weapon.exp < required_exp {
break;
}
weapon.exp -= required_exp;
weapon.level += 1;
}
WeaponLevelUpScRsp {
retcode: 0,
return_item_list: if weapon.level == max_level {
item_util::exp_to_materials(
&mut weapon.exp,
EItemType::WeaponLevelUpMaterial,
context.resources,
)
.into_iter()
.map(|(item_id, amount)| {
item_util::add_item(context.player, item_id, amount);
ItemRewardInfo { item_id, amount }
})
.collect()
} else {
Vec::new()
},
}
}
} }

View file

@ -2,9 +2,9 @@ use std::collections::HashMap;
use config::WeaponTemplate; use config::WeaponTemplate;
use rand::{RngCore, seq::IteratorRandom}; use rand::{RngCore, seq::IteratorRandom};
use yixuan_logic::item::WeaponItem; use yixuan_logic::item::{EItemType, WeaponItem};
use crate::player::Player; use crate::{player::Player, resources::NapResources};
pub fn add_items_on_first_login(player: &mut Player) { pub fn add_items_on_first_login(player: &mut Player) {
player.item_model.item_count_map.insert(10, 10_000_000); player.item_model.item_count_map.insert(10, 10_000_000);
@ -139,7 +139,7 @@ pub fn add_weapon(player: &mut Player, template: &WeaponTemplate) -> u32 {
id: template.item_id(), id: template.item_id(),
level: 0, level: 0,
exp: 0, exp: 0,
star: 1, star: 0,
refine_level: 0, refine_level: 0,
lock: false, lock: false,
}, },
@ -190,3 +190,51 @@ pub fn use_item(player: &mut Player, item_id: u32, amount: u32) -> bool {
false false
} }
} }
pub fn materials_to_exp(
materials: &HashMap<u32, u32>,
material_type: EItemType,
res: &NapResources,
) -> u32 {
materials
.iter()
.filter_map(|(&id, &count)| {
let template = res
.templates
.item_template_tb()
.find(|tmpl| tmpl.id() == id)?;
(template.class() == material_type.into())
.then(|| template.parameters().unwrap().get(0) * count)
})
.sum()
}
pub fn exp_to_materials(
exp: &mut u32,
material_type: EItemType,
res: &NapResources,
) -> HashMap<u32, u32> {
let mut materials = HashMap::new();
while *exp > 0 {
let Some(return_material) = res
.templates
.item_template_tb()
.filter(|tmpl| {
tmpl.class() == material_type.into() && tmpl.parameters().unwrap().get(0) <= *exp
})
.max_by_key(|tmpl| tmpl.parameters().unwrap().get(0))
else {
*exp = 0;
break;
};
let exp_amount = return_material.parameters().unwrap().get(0);
materials.insert(return_material.id(), *exp / exp_amount);
*exp %= exp_amount;
}
materials
}