Added crafting method for modular weapons.

This commit is contained in:
Sam 2021-11-04 22:28:01 -04:00
parent b7aa0a7a9f
commit 00649f8ebb
4 changed files with 133 additions and 2 deletions
common/src
server/src/events

View File

@ -98,6 +98,11 @@ pub enum CraftEvent {
slots: Vec<(u32, InvSlotId)>,
},
Salvage(InvSlotId),
// TODO: Maybe look at making this more general when there are more modular recipes?
ModularWeapon {
damage_component: InvSlotId,
held_component: InvSlotId,
},
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]

View File

@ -355,6 +355,11 @@ fn make_mod_comp_dir_def(tool: ToolKind, mod_kind: ModularComponentKind) -> Stri
)
}
/// Creates initial item for a modular weapon
pub fn initialize_modular_weapon(toolkind: ToolKind) -> Item {
Item::new_from_asset_expect(&make_weapon_def(toolkind).0)
}
/// Creates a random modular weapon when provided with a toolkind, material, and
/// optionally the handedness
pub fn random_weapon(tool: ToolKind, material: super::Material, hands: Option<Hands>) -> Item {
@ -372,7 +377,7 @@ pub fn random_weapon(tool: ToolKind, material: super::Material, hands: Option<Ha
let msm = Default::default();
// Initialize modular weapon
let mut modular_weapon = Item::new_from_asset_expect(&make_weapon_def(tool).0);
let mut modular_weapon = initialize_modular_weapon(tool);
// Load recipe book (done to check that material is valid for a particular
// component)

View File

@ -2,7 +2,7 @@ use crate::{
assets::{self, AssetExt, AssetHandle},
comp::{
inventory::slot::InvSlotId,
item::{modular, tool::AbilityMap, ItemDef, ItemTag, MaterialStatManifest},
item::{modular, tool::AbilityMap, ItemDef, ItemKind, ItemTag, MaterialStatManifest},
Inventory, Item,
},
terrain::SpriteKind,
@ -193,6 +193,87 @@ pub fn try_salvage(
}
}
pub enum ModularWeaponError {
InvalidSlot,
ComponentMismatch,
DifferentTools,
DifferentHands,
}
pub fn modular_weapon(
inv: &mut Inventory,
damage_component: InvSlotId,
held_component: InvSlotId,
ability_map: &AbilityMap,
msm: &MaterialStatManifest,
) -> Result<Item, ModularWeaponError> {
use modular::{ModularComponent, ModularComponentKind};
// Closure to get inner modular component info from item in a given slot
let unwrap_modular = |slot| -> Option<&ModularComponent> {
if let Some(ItemKind::ModularComponent(mod_comp)) = inv.get(slot).map(|item| &item.kind) {
Some(mod_comp)
} else {
None
}
};
// Checks if both components are comptabile, and if so returns the toolkind to
// make weapon of
let compatiblity = if let (Some(damage_component), Some(held_component)) = (
unwrap_modular(damage_component),
unwrap_modular(held_component),
) {
// Checks that damage and held component slots each contain a damage and held
// modular component respectively
if matches!(damage_component.modkind, ModularComponentKind::Damage)
&& matches!(held_component.modkind, ModularComponentKind::Held)
{
// Checks that both components are of the same tool kind
if damage_component.toolkind == held_component.toolkind {
// Checks that if both components have a hand restriction, they are the same
let hands_check = damage_component.hand_restriction.map_or(true, |hands| {
held_component
.hand_restriction
.map_or(true, |hands2| hands == hands2)
});
if hands_check {
Ok(damage_component.toolkind)
} else {
Err(ModularWeaponError::DifferentHands)
}
} else {
Err(ModularWeaponError::DifferentTools)
}
} else {
Err(ModularWeaponError::ComponentMismatch)
}
} else {
Err(ModularWeaponError::InvalidSlot)
};
match compatiblity {
Ok(tool_kind) => {
// Remove components from inventory
let damage_component = inv
.take(damage_component, ability_map, msm)
.expect("Expected component to exist");
let held_component = inv
.take(held_component, ability_map, msm)
.expect("Expected component to exist");
// Initialize modular weapon
let mut modular_weapon = modular::initialize_modular_weapon(tool_kind);
// Insert components into modular weapon item
modular_weapon.add_component(damage_component, ability_map, msm);
modular_weapon.add_component(held_component, ability_map, msm);
Ok(modular_weapon)
},
Err(err) => Err(err),
}
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct RecipeBook {
recipes: HashMap<String, Recipe>,

View File

@ -660,6 +660,46 @@ pub fn handle_inventory(server: &mut Server, entity: EcsEntity, manip: comp::Inv
None
}
},
CraftEvent::ModularWeapon {
damage_component,
held_component,
} => {
let sprite = craft_sprite
.filter(|pos| {
let entity_cylinder = get_cylinder(state, entity);
if !within_pickup_range(entity_cylinder, || {
Some(find_dist::Cube {
min: pos.as_(),
side_length: 1.0,
})
}) {
debug!(
?entity_cylinder,
"Failed to craft recipe as not within range of required \
sprite, sprite pos: {}",
pos
);
false
} else {
true
}
})
.and_then(|pos| state.terrain().get(pos).ok().copied())
.and_then(|block| block.get_sprite());
if matches!(sprite, Some(SpriteKind::CraftingBench)) {
recipe::modular_weapon(
&mut inventory,
damage_component,
held_component,
ability_map,
&msm,
)
.ok()
.map(|item| vec![item])
} else {
None
}
},
};
// Attempt to insert items into inventory, dropping them if there is not enough