Close DDD refactor and remove generated asset proxy
This commit is contained in:
@@ -7,6 +7,22 @@ use crate::commands::{StoryContinueInput, StorySessionInput, normalize_optional_
|
||||
use crate::domain::{INITIAL_STORY_SESSION_VERSION, StorySessionSnapshot, StorySessionStatus};
|
||||
use crate::errors::StorySessionFieldError;
|
||||
use crate::events::{StoryEventKind, StoryEventSnapshot};
|
||||
use module_combat::{BattleStateSnapshot, CombatOutcome};
|
||||
use module_inventory::{
|
||||
GrantInventoryItemInput, InventoryEquipmentSlot, InventoryItemRarity, InventoryItemSnapshot,
|
||||
InventoryItemSourceKind, InventoryMutation, InventoryMutationInput,
|
||||
generate_inventory_mutation_id, generate_inventory_slot_id,
|
||||
};
|
||||
use module_progression::{
|
||||
ChapterProgressionLedgerInput, PlayerProgressionGrantInput, PlayerProgressionGrantSource,
|
||||
};
|
||||
use module_quest::{
|
||||
QuestRecordSnapshot, QuestRewardEquipmentSlot, QuestRewardItem, QuestRewardItemRarity,
|
||||
};
|
||||
use module_runtime_item::{
|
||||
RuntimeItemEquipmentSlot, RuntimeItemRewardItemRarity, RuntimeItemRewardItemSnapshot,
|
||||
TreasureRecordSnapshot, build_inventory_item_snapshot_from_reward_item,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use shared_kernel::format_timestamp_micros;
|
||||
#[cfg(feature = "spacetime-types")]
|
||||
@@ -68,6 +84,17 @@ pub struct StorySessionStateRecord {
|
||||
pub events: Vec<StoryEventRecord>,
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "spacetime-types", derive(SpacetimeType))]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct RpgGameplaySettlementPlan {
|
||||
/// 背包写入计划。adapter 只负责读取当前槽位并执行 mutation,不再拼奖励物品字段。
|
||||
pub inventory_mutations: Vec<InventoryMutationInput>,
|
||||
/// 玩家经验入账计划。章节账本需要依赖执行后的等级结果,所以单独保留。
|
||||
pub progression_grant: Option<PlayerProgressionGrantInput>,
|
||||
/// 章节实际收益账本计划。若章节预算尚未初始化,adapter 会跳过而不阻断主链。
|
||||
pub chapter_ledger: Option<ChapterProgressionLedgerInput>,
|
||||
}
|
||||
|
||||
pub fn build_story_session_snapshot(input: StorySessionInput) -> StorySessionSnapshot {
|
||||
StorySessionSnapshot {
|
||||
story_session_id: input.story_session_id,
|
||||
@@ -165,3 +192,272 @@ pub fn build_story_session_state_record(
|
||||
.collect::<Vec<_>>(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn build_combat_victory_settlement_plan(
|
||||
snapshot: &BattleStateSnapshot,
|
||||
) -> RpgGameplaySettlementPlan {
|
||||
// 非胜利结果不触发战利品、敌对经验或章节 hostile 账本,避免逃脱/切磋混入击杀收益。
|
||||
if snapshot.last_outcome != CombatOutcome::Victory {
|
||||
return empty_settlement_plan();
|
||||
}
|
||||
|
||||
let inventory_mutations = snapshot
|
||||
.reward_items
|
||||
.iter()
|
||||
.cloned()
|
||||
.enumerate()
|
||||
.map(|(index, reward_item)| {
|
||||
let seed = build_reward_seed(snapshot.updated_at_micros, index);
|
||||
InventoryMutationInput {
|
||||
mutation_id: generate_inventory_mutation_id(seed),
|
||||
runtime_session_id: snapshot.runtime_session_id.clone(),
|
||||
story_session_id: Some(snapshot.story_session_id.clone()),
|
||||
actor_user_id: snapshot.actor_user_id.clone(),
|
||||
mutation: InventoryMutation::GrantItem(GrantInventoryItemInput {
|
||||
slot_id: generate_inventory_slot_id(seed),
|
||||
item: build_inventory_item_snapshot_from_battle_reward_item(
|
||||
&snapshot.battle_state_id,
|
||||
reward_item,
|
||||
),
|
||||
}),
|
||||
updated_at_micros: snapshot.updated_at_micros,
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let progression_grant = (snapshot.experience_reward > 0).then(|| PlayerProgressionGrantInput {
|
||||
user_id: snapshot.actor_user_id.clone(),
|
||||
amount: snapshot.experience_reward,
|
||||
source: PlayerProgressionGrantSource::HostileNpc,
|
||||
updated_at_micros: snapshot.updated_at_micros,
|
||||
});
|
||||
|
||||
let chapter_ledger =
|
||||
progression_grant
|
||||
.as_ref()
|
||||
.and_then(|_| match snapshot.chapter_id.as_deref() {
|
||||
Some(chapter_id) if !chapter_id.trim().is_empty() => {
|
||||
Some(ChapterProgressionLedgerInput {
|
||||
user_id: snapshot.actor_user_id.clone(),
|
||||
chapter_id: chapter_id.trim().to_string(),
|
||||
granted_quest_xp: 0,
|
||||
granted_hostile_xp: snapshot.experience_reward,
|
||||
hostile_defeat_increment: 1,
|
||||
level_at_exit: None,
|
||||
updated_at_micros: snapshot.updated_at_micros,
|
||||
})
|
||||
}
|
||||
_ => None,
|
||||
});
|
||||
|
||||
RpgGameplaySettlementPlan {
|
||||
inventory_mutations,
|
||||
progression_grant,
|
||||
chapter_ledger,
|
||||
}
|
||||
}
|
||||
|
||||
/// 任务交付后只生成结算计划,不在领域层直接写背包、成长或章节表。
|
||||
pub fn build_quest_turn_in_settlement_plan(
|
||||
snapshot: &QuestRecordSnapshot,
|
||||
) -> RpgGameplaySettlementPlan {
|
||||
let inventory_mutations = snapshot
|
||||
.reward
|
||||
.items
|
||||
.iter()
|
||||
.cloned()
|
||||
.enumerate()
|
||||
.map(|(index, reward_item)| {
|
||||
let seed = build_reward_seed(snapshot.updated_at_micros, index);
|
||||
InventoryMutationInput {
|
||||
mutation_id: generate_inventory_mutation_id(seed),
|
||||
runtime_session_id: snapshot.runtime_session_id.clone(),
|
||||
story_session_id: snapshot.story_session_id.clone(),
|
||||
actor_user_id: snapshot.actor_user_id.clone(),
|
||||
mutation: InventoryMutation::GrantItem(GrantInventoryItemInput {
|
||||
slot_id: generate_inventory_slot_id(seed),
|
||||
item: build_inventory_item_snapshot_from_quest_reward_item(
|
||||
&snapshot.quest_id,
|
||||
reward_item,
|
||||
),
|
||||
}),
|
||||
updated_at_micros: snapshot.updated_at_micros,
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let reward_experience = snapshot.reward.experience.unwrap_or(0);
|
||||
let progression_grant = (reward_experience > 0).then(|| PlayerProgressionGrantInput {
|
||||
user_id: snapshot.actor_user_id.clone(),
|
||||
amount: reward_experience,
|
||||
source: PlayerProgressionGrantSource::Quest,
|
||||
updated_at_micros: snapshot.updated_at_micros,
|
||||
});
|
||||
|
||||
let chapter_ledger =
|
||||
progression_grant
|
||||
.as_ref()
|
||||
.and_then(|_| match snapshot.chapter_id.as_deref() {
|
||||
Some(chapter_id) if !chapter_id.trim().is_empty() => {
|
||||
Some(ChapterProgressionLedgerInput {
|
||||
user_id: snapshot.actor_user_id.clone(),
|
||||
chapter_id: chapter_id.trim().to_string(),
|
||||
granted_quest_xp: reward_experience,
|
||||
granted_hostile_xp: 0,
|
||||
hostile_defeat_increment: 0,
|
||||
level_at_exit: None,
|
||||
updated_at_micros: snapshot.updated_at_micros,
|
||||
})
|
||||
}
|
||||
_ => None,
|
||||
});
|
||||
|
||||
RpgGameplaySettlementPlan {
|
||||
inventory_mutations,
|
||||
progression_grant,
|
||||
chapter_ledger,
|
||||
}
|
||||
}
|
||||
|
||||
/// 宝箱记录由 `module-runtime-item` 建模,这里只把奖励转成 story gameplay 的背包写入计划。
|
||||
pub fn build_treasure_settlement_plan(
|
||||
snapshot: &TreasureRecordSnapshot,
|
||||
) -> Result<RpgGameplaySettlementPlan, StorySessionFieldError> {
|
||||
let inventory_mutations = snapshot
|
||||
.reward_items
|
||||
.iter()
|
||||
.cloned()
|
||||
.enumerate()
|
||||
.map(
|
||||
|(index, reward_item)| -> Result<InventoryMutationInput, StorySessionFieldError> {
|
||||
Ok(InventoryMutationInput {
|
||||
mutation_id: build_treasure_inventory_mutation_id(
|
||||
&snapshot.treasure_record_id,
|
||||
index,
|
||||
),
|
||||
runtime_session_id: snapshot.runtime_session_id.clone(),
|
||||
story_session_id: Some(snapshot.story_session_id.clone()),
|
||||
actor_user_id: snapshot.actor_user_id.clone(),
|
||||
mutation: InventoryMutation::GrantItem(GrantInventoryItemInput {
|
||||
slot_id: build_treasure_inventory_slot_id(
|
||||
&snapshot.treasure_record_id,
|
||||
index,
|
||||
),
|
||||
item: build_inventory_item_snapshot_from_reward_item(
|
||||
&snapshot.treasure_record_id,
|
||||
reward_item,
|
||||
)
|
||||
.map_err(|_| StorySessionFieldError::InvalidGameplayReward)?,
|
||||
}),
|
||||
updated_at_micros: snapshot.updated_at_micros,
|
||||
})
|
||||
},
|
||||
)
|
||||
.collect::<Result<Vec<_>, _>>()?;
|
||||
|
||||
Ok(RpgGameplaySettlementPlan {
|
||||
inventory_mutations,
|
||||
progression_grant: None,
|
||||
chapter_ledger: None,
|
||||
})
|
||||
}
|
||||
|
||||
fn empty_settlement_plan() -> RpgGameplaySettlementPlan {
|
||||
RpgGameplaySettlementPlan {
|
||||
inventory_mutations: Vec::new(),
|
||||
progression_grant: None,
|
||||
chapter_ledger: None,
|
||||
}
|
||||
}
|
||||
|
||||
fn build_inventory_item_snapshot_from_battle_reward_item(
|
||||
battle_state_id: &str,
|
||||
reward_item: RuntimeItemRewardItemSnapshot,
|
||||
) -> InventoryItemSnapshot {
|
||||
InventoryItemSnapshot {
|
||||
item_id: reward_item.item_id,
|
||||
category: reward_item.category,
|
||||
name: reward_item.item_name,
|
||||
description: reward_item.description,
|
||||
quantity: reward_item.quantity,
|
||||
rarity: map_runtime_reward_item_rarity(reward_item.rarity),
|
||||
tags: reward_item.tags,
|
||||
stackable: reward_item.stackable,
|
||||
stack_key: reward_item.stack_key,
|
||||
equipment_slot_id: reward_item
|
||||
.equipment_slot_id
|
||||
.map(map_runtime_reward_equipment_slot),
|
||||
source_kind: InventoryItemSourceKind::CombatDrop,
|
||||
source_reference_id: Some(battle_state_id.to_string()),
|
||||
}
|
||||
}
|
||||
|
||||
fn build_inventory_item_snapshot_from_quest_reward_item(
|
||||
quest_id: &str,
|
||||
reward_item: QuestRewardItem,
|
||||
) -> InventoryItemSnapshot {
|
||||
InventoryItemSnapshot {
|
||||
item_id: reward_item.item_id,
|
||||
category: reward_item.category,
|
||||
name: reward_item.name,
|
||||
description: reward_item.description,
|
||||
quantity: reward_item.quantity,
|
||||
rarity: map_quest_reward_item_rarity(reward_item.rarity),
|
||||
tags: reward_item.tags,
|
||||
stackable: reward_item.stackable,
|
||||
stack_key: reward_item.stack_key,
|
||||
equipment_slot_id: reward_item
|
||||
.equipment_slot_id
|
||||
.map(map_quest_reward_equipment_slot),
|
||||
source_kind: InventoryItemSourceKind::QuestReward,
|
||||
source_reference_id: Some(quest_id.to_string()),
|
||||
}
|
||||
}
|
||||
|
||||
fn map_quest_reward_item_rarity(rarity: QuestRewardItemRarity) -> InventoryItemRarity {
|
||||
match rarity {
|
||||
QuestRewardItemRarity::Common => InventoryItemRarity::Common,
|
||||
QuestRewardItemRarity::Uncommon => InventoryItemRarity::Uncommon,
|
||||
QuestRewardItemRarity::Rare => InventoryItemRarity::Rare,
|
||||
QuestRewardItemRarity::Epic => InventoryItemRarity::Epic,
|
||||
QuestRewardItemRarity::Legendary => InventoryItemRarity::Legendary,
|
||||
}
|
||||
}
|
||||
|
||||
fn map_runtime_reward_item_rarity(rarity: RuntimeItemRewardItemRarity) -> InventoryItemRarity {
|
||||
match rarity {
|
||||
RuntimeItemRewardItemRarity::Common => InventoryItemRarity::Common,
|
||||
RuntimeItemRewardItemRarity::Uncommon => InventoryItemRarity::Uncommon,
|
||||
RuntimeItemRewardItemRarity::Rare => InventoryItemRarity::Rare,
|
||||
RuntimeItemRewardItemRarity::Epic => InventoryItemRarity::Epic,
|
||||
RuntimeItemRewardItemRarity::Legendary => InventoryItemRarity::Legendary,
|
||||
}
|
||||
}
|
||||
|
||||
fn map_quest_reward_equipment_slot(slot: QuestRewardEquipmentSlot) -> InventoryEquipmentSlot {
|
||||
match slot {
|
||||
QuestRewardEquipmentSlot::Weapon => InventoryEquipmentSlot::Weapon,
|
||||
QuestRewardEquipmentSlot::Armor => InventoryEquipmentSlot::Armor,
|
||||
QuestRewardEquipmentSlot::Relic => InventoryEquipmentSlot::Relic,
|
||||
}
|
||||
}
|
||||
|
||||
fn map_runtime_reward_equipment_slot(slot: RuntimeItemEquipmentSlot) -> InventoryEquipmentSlot {
|
||||
match slot {
|
||||
RuntimeItemEquipmentSlot::Weapon => InventoryEquipmentSlot::Weapon,
|
||||
RuntimeItemEquipmentSlot::Armor => InventoryEquipmentSlot::Armor,
|
||||
RuntimeItemEquipmentSlot::Relic => InventoryEquipmentSlot::Relic,
|
||||
}
|
||||
}
|
||||
|
||||
fn build_reward_seed(updated_at_micros: i64, index: usize) -> i64 {
|
||||
updated_at_micros.saturating_add(index as i64 + 1)
|
||||
}
|
||||
|
||||
fn build_treasure_inventory_slot_id(treasure_record_id: &str, reward_index: usize) -> String {
|
||||
format!("invslot_{}_{}", treasure_record_id, reward_index)
|
||||
}
|
||||
|
||||
fn build_treasure_inventory_mutation_id(treasure_record_id: &str, reward_index: usize) -> String {
|
||||
format!("invmut_{}_{}", treasure_record_id, reward_index)
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ pub enum StorySessionFieldError {
|
||||
MissingNarrativeText,
|
||||
MissingEventId,
|
||||
InvalidVersion,
|
||||
InvalidGameplayReward,
|
||||
}
|
||||
|
||||
impl fmt::Display for StorySessionFieldError {
|
||||
@@ -29,6 +30,7 @@ impl fmt::Display for StorySessionFieldError {
|
||||
Self::MissingNarrativeText => f.write_str("story_event.narrative_text 不能为空"),
|
||||
Self::MissingEventId => f.write_str("story_event.event_id 不能为空"),
|
||||
Self::InvalidVersion => f.write_str("story_session.version 必须大于 0"),
|
||||
Self::InvalidGameplayReward => f.write_str("RPG 结算奖励字段非法"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,6 +13,11 @@ pub use events::*;
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use module_quest::{
|
||||
QuestNarrativeBindingSnapshot, QuestNarrativeOrigin, QuestNarrativeType,
|
||||
QuestObjectiveKind, QuestObjectiveSnapshot, QuestRecordSnapshot, QuestRewardEquipmentSlot,
|
||||
QuestRewardItem, QuestRewardItemRarity, QuestRewardSnapshot, QuestStatus,
|
||||
};
|
||||
|
||||
#[test]
|
||||
fn validate_story_session_input_accepts_minimal_contract() {
|
||||
@@ -200,4 +205,172 @@ mod tests {
|
||||
assert_eq!(next.version, INITIAL_STORY_SESSION_VERSION + 1);
|
||||
assert_eq!(event.event_kind, StoryEventKind::StoryContinued);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn combat_victory_settlement_plan_grants_items_xp_and_chapter_ledger() {
|
||||
let plan = build_combat_victory_settlement_plan(&module_combat::BattleStateSnapshot {
|
||||
battle_state_id: "battle_001".to_string(),
|
||||
story_session_id: "storysess_001".to_string(),
|
||||
runtime_session_id: "runtime_001".to_string(),
|
||||
actor_user_id: "user_001".to_string(),
|
||||
chapter_id: Some("chapter_01".to_string()),
|
||||
target_npc_id: "npc_bandit".to_string(),
|
||||
target_name: "山匪".to_string(),
|
||||
battle_mode: module_combat::BattleMode::Fight,
|
||||
status: module_combat::BattleStatus::Resolved,
|
||||
player_hp: 20,
|
||||
player_max_hp: 30,
|
||||
player_mana: 6,
|
||||
player_max_mana: 10,
|
||||
target_hp: 0,
|
||||
target_max_hp: 18,
|
||||
experience_reward: 35,
|
||||
reward_items: vec![module_runtime_item::RuntimeItemRewardItemSnapshot {
|
||||
item_id: "iron_token".to_string(),
|
||||
category: "material".to_string(),
|
||||
item_name: "铁制信物".to_string(),
|
||||
description: Some("山匪随身携带的旧信物。".to_string()),
|
||||
quantity: 1,
|
||||
rarity: module_runtime_item::RuntimeItemRewardItemRarity::Uncommon,
|
||||
tags: vec!["quest".to_string()],
|
||||
stackable: true,
|
||||
stack_key: "iron_token".to_string(),
|
||||
equipment_slot_id: None,
|
||||
}],
|
||||
turn_index: 2,
|
||||
last_action_function_id: Some("battle_use_skill".to_string()),
|
||||
last_action_text: Some("破阵一击".to_string()),
|
||||
last_result_text: Some("战斗结束。".to_string()),
|
||||
last_damage_dealt: 18,
|
||||
last_damage_taken: 0,
|
||||
last_outcome: module_combat::CombatOutcome::Victory,
|
||||
version: 3,
|
||||
created_at_micros: 100,
|
||||
updated_at_micros: 200,
|
||||
});
|
||||
|
||||
assert_eq!(plan.inventory_mutations.len(), 1);
|
||||
assert_eq!(
|
||||
plan.progression_grant.as_ref().map(|input| input.amount),
|
||||
Some(35)
|
||||
);
|
||||
assert_eq!(
|
||||
plan.chapter_ledger
|
||||
.as_ref()
|
||||
.map(|input| input.granted_hostile_xp),
|
||||
Some(35)
|
||||
);
|
||||
|
||||
let module_inventory::InventoryMutation::GrantItem(input) =
|
||||
&plan.inventory_mutations[0].mutation
|
||||
else {
|
||||
panic!("combat victory should grant inventory item");
|
||||
};
|
||||
assert_eq!(
|
||||
input.item.source_reference_id.as_deref(),
|
||||
Some("battle_001")
|
||||
);
|
||||
assert_eq!(
|
||||
input.item.source_kind,
|
||||
module_inventory::InventoryItemSourceKind::CombatDrop
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn quest_turn_in_settlement_plan_grants_reward_items_and_quest_xp() {
|
||||
let plan = build_quest_turn_in_settlement_plan(&QuestRecordSnapshot {
|
||||
quest_id: "quest_001".to_string(),
|
||||
runtime_session_id: "runtime_001".to_string(),
|
||||
story_session_id: Some("storysess_001".to_string()),
|
||||
actor_user_id: "user_001".to_string(),
|
||||
issuer_npc_id: "npc_scout".to_string(),
|
||||
issuer_npc_name: "斥候".to_string(),
|
||||
scene_id: None,
|
||||
chapter_id: Some("chapter_01".to_string()),
|
||||
act_id: None,
|
||||
thread_id: None,
|
||||
contract_id: None,
|
||||
title: "寻找信物".to_string(),
|
||||
description: "找回遗失的信物。".to_string(),
|
||||
summary: "信物已找到。".to_string(),
|
||||
objective: QuestObjectiveSnapshot {
|
||||
kind: QuestObjectiveKind::InspectTreasure,
|
||||
target_hostile_npc_id: None,
|
||||
target_npc_id: None,
|
||||
target_scene_id: Some("scene_ruin".to_string()),
|
||||
target_item_id: None,
|
||||
required_count: 1,
|
||||
},
|
||||
progress: 1,
|
||||
status: QuestStatus::TurnedIn,
|
||||
completion_notified: true,
|
||||
reward: QuestRewardSnapshot {
|
||||
affinity_bonus: 0,
|
||||
currency: 0,
|
||||
experience: Some(40),
|
||||
items: vec![QuestRewardItem {
|
||||
item_id: "scout_badge".to_string(),
|
||||
category: "trinket".to_string(),
|
||||
name: "斥候徽记".to_string(),
|
||||
description: None,
|
||||
quantity: 1,
|
||||
rarity: QuestRewardItemRarity::Rare,
|
||||
tags: vec!["badge".to_string()],
|
||||
stackable: false,
|
||||
stack_key: "scout_badge".to_string(),
|
||||
equipment_slot_id: Some(QuestRewardEquipmentSlot::Relic),
|
||||
}],
|
||||
intel: None,
|
||||
story_hint: None,
|
||||
},
|
||||
reward_text: "获得斥候徽记。".to_string(),
|
||||
narrative_binding: QuestNarrativeBindingSnapshot {
|
||||
origin: QuestNarrativeOrigin::FallbackBuilder,
|
||||
narrative_type: QuestNarrativeType::Retrieval,
|
||||
dramatic_need: String::new(),
|
||||
issuer_goal: String::new(),
|
||||
player_hook: String::new(),
|
||||
world_reason: String::new(),
|
||||
followup_hooks: Vec::new(),
|
||||
},
|
||||
steps: Vec::new(),
|
||||
active_step_id: None,
|
||||
visible_stage: 1,
|
||||
hidden_flags: Vec::new(),
|
||||
discovered_fact_ids: Vec::new(),
|
||||
related_carrier_ids: Vec::new(),
|
||||
consequence_ids: Vec::new(),
|
||||
created_at_micros: 100,
|
||||
updated_at_micros: 300,
|
||||
completed_at_micros: Some(200),
|
||||
turned_in_at_micros: Some(300),
|
||||
});
|
||||
|
||||
assert_eq!(plan.inventory_mutations.len(), 1);
|
||||
assert_eq!(
|
||||
plan.progression_grant.as_ref().map(|input| input.amount),
|
||||
Some(40)
|
||||
);
|
||||
assert_eq!(
|
||||
plan.chapter_ledger
|
||||
.as_ref()
|
||||
.map(|input| input.granted_quest_xp),
|
||||
Some(40)
|
||||
);
|
||||
|
||||
let module_inventory::InventoryMutation::GrantItem(input) =
|
||||
&plan.inventory_mutations[0].mutation
|
||||
else {
|
||||
panic!("quest turn-in should grant inventory item");
|
||||
};
|
||||
assert_eq!(input.item.source_reference_id.as_deref(), Some("quest_001"));
|
||||
assert_eq!(
|
||||
input.item.equipment_slot_id,
|
||||
Some(module_inventory::InventoryEquipmentSlot::Relic)
|
||||
);
|
||||
assert_eq!(
|
||||
input.item.source_kind,
|
||||
module_inventory::InventoryItemSourceKind::QuestReward
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user