mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Enforced certain invariants in how an item was equipped into the loadout:
- a 2h weapon can only be equipped in a mainhand slot if the offhand slot is empty - a 1h weapon can only be equipped in an offhand slot if the mainhand slot has a 1h weapon - 2h weapons can never be equipped in an offhand slot Fixed some tests
This commit is contained in:
parent
9173dca03f
commit
6b153bcf47
@ -1,6 +1,6 @@
|
|||||||
use crate::comp::{
|
use crate::comp::{
|
||||||
inventory::{
|
inventory::{
|
||||||
item::ItemKind,
|
item::{tool, ItemKind},
|
||||||
slot::{ArmorSlot, EquipSlot},
|
slot::{ArmorSlot, EquipSlot},
|
||||||
InvSlot,
|
InvSlot,
|
||||||
},
|
},
|
||||||
@ -173,10 +173,10 @@ impl Loadout {
|
|||||||
// Check if items can go in the other slots
|
// Check if items can go in the other slots
|
||||||
if item_a
|
if item_a
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.map_or(true, |i| equip_slot_b.can_hold(&i.kind()))
|
.map_or(true, |i| self.slot_can_hold(equip_slot_b, &i.kind()))
|
||||||
&& item_b
|
&& item_b
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.map_or(true, |i| equip_slot_a.can_hold(&i.kind()))
|
.map_or(true, |i| self.slot_can_hold(equip_slot_a, &i.kind()))
|
||||||
{
|
{
|
||||||
// Swap
|
// Swap
|
||||||
self.swap(equip_slot_b, item_a).unwrap_none();
|
self.swap(equip_slot_b, item_a).unwrap_none();
|
||||||
@ -197,7 +197,7 @@ impl Loadout {
|
|||||||
let mut suitable_slots = self
|
let mut suitable_slots = self
|
||||||
.slots
|
.slots
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|s| s.equip_slot.can_hold(item_kind));
|
.filter(|s| self.slot_can_hold(s.equip_slot, item_kind));
|
||||||
|
|
||||||
let first = suitable_slots.next();
|
let first = suitable_slots.next();
|
||||||
|
|
||||||
@ -217,7 +217,7 @@ impl Loadout {
|
|||||||
) -> impl Iterator<Item = &Item> {
|
) -> impl Iterator<Item = &Item> {
|
||||||
self.slots
|
self.slots
|
||||||
.iter()
|
.iter()
|
||||||
.filter(move |s| s.equip_slot.can_hold(&item_kind))
|
.filter(move |s| self.slot_can_hold(s.equip_slot, &item_kind))
|
||||||
.filter_map(|s| s.slot.as_ref())
|
.filter_map(|s| s.slot.as_ref())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -296,21 +296,73 @@ impl Loadout {
|
|||||||
/// If no slot is available the item is returned.
|
/// If no slot is available the item is returned.
|
||||||
#[must_use = "Returned item will be lost if not used"]
|
#[must_use = "Returned item will be lost if not used"]
|
||||||
pub(super) fn try_equip(&mut self, item: Item) -> Result<(), Item> {
|
pub(super) fn try_equip(&mut self, item: Item) -> Result<(), Item> {
|
||||||
if let Some(loadout_slot) = self
|
/* if let Some(loadout_slot) = self
|
||||||
.slots
|
.slots
|
||||||
.iter_mut()
|
.iter_mut()
|
||||||
.find(|s| s.slot.is_none() && s.equip_slot.can_hold(item.kind()))
|
.find(|s| s.slot.is_none() && self.slot_can_hold(s.equip_slot, item.kind()))
|
||||||
{
|
{
|
||||||
loadout_slot.slot = Some(item);
|
loadout_slot.slot = Some(item);
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
Err(item)
|
Err(item)
|
||||||
|
} */
|
||||||
|
// TODO: Get XVar to see if there better way to handle mutability issues
|
||||||
|
let loadout_slot = self
|
||||||
|
.slots
|
||||||
|
.iter()
|
||||||
|
.find(|s| s.slot.is_none() && self.slot_can_hold(s.equip_slot, item.kind()))
|
||||||
|
.map(|s| s.equip_slot);
|
||||||
|
if let Some(slot) = self
|
||||||
|
.slots
|
||||||
|
.iter_mut()
|
||||||
|
.find(|s| Some(s.equip_slot) == loadout_slot)
|
||||||
|
{
|
||||||
|
slot.slot = Some(item);
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(item)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn items(&self) -> impl Iterator<Item = &Item> {
|
pub(super) fn items(&self) -> impl Iterator<Item = &Item> {
|
||||||
self.slots.iter().filter_map(|x| x.slot.as_ref())
|
self.slots.iter().filter_map(|x| x.slot.as_ref())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Checks that a slot can hold a given item
|
||||||
|
pub(super) fn slot_can_hold(&self, equip_slot: EquipSlot, item_kind: &ItemKind) -> bool {
|
||||||
|
// Checks if item can be equipped in a mainhand slot
|
||||||
|
let mainhand_check = |offhand_slot| {
|
||||||
|
// Allows item to be equipped if itemkind is a tool and...
|
||||||
|
matches!(item_kind, ItemKind::Tool(mainhand) if {
|
||||||
|
if let Some(ItemKind::Tool(offhand)) = self.equipped(offhand_slot).map(|i| i.kind()) {
|
||||||
|
// if offhand is 1 handed, only if mainhand is also 1 handed
|
||||||
|
matches!(offhand.hands, tool::Hands::One) && matches!(mainhand.hands, tool::Hands::One)
|
||||||
|
} else {
|
||||||
|
// else there is no tool equipped in offhand, so only if slot can normally hold this item
|
||||||
|
equip_slot.can_hold(item_kind)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
// Checks if item can be equipped in an offhand slot
|
||||||
|
let offhand_check = |mainhand_slot| {
|
||||||
|
// Allows item to be equipped if itemkind is a tool and...
|
||||||
|
matches!(item_kind, ItemKind::Tool(offhand) if {
|
||||||
|
// if offhand weapon is 1 handed...
|
||||||
|
matches!(offhand.hands, tool::Hands::One)
|
||||||
|
// and if mainhand has a 1 handed weapon...
|
||||||
|
&& matches!(self.equipped(mainhand_slot).map(|i| i.kind()), Some(ItemKind::Tool(mainhand)) if matches!(mainhand.hands, tool::Hands::One))
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
match equip_slot {
|
||||||
|
EquipSlot::ActiveMainhand => mainhand_check(EquipSlot::ActiveOffhand),
|
||||||
|
EquipSlot::ActiveOffhand => offhand_check(EquipSlot::ActiveMainhand),
|
||||||
|
EquipSlot::InactiveMainhand => mainhand_check(EquipSlot::InactiveOffhand),
|
||||||
|
EquipSlot::InactiveOffhand => offhand_check(EquipSlot::InactiveMainhand),
|
||||||
|
_ => equip_slot.can_hold(item_kind),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
@ -744,12 +744,12 @@ impl Inventory {
|
|||||||
/// account whether there will be free space in the inventory for the
|
/// account whether there will be free space in the inventory for the
|
||||||
/// loadout item once any slots that were provided by it have been
|
/// loadout item once any slots that were provided by it have been
|
||||||
/// removed.
|
/// removed.
|
||||||
|
#[allow(clippy::blocks_in_if_conditions)]
|
||||||
pub fn can_swap(&self, inv_slot_id: InvSlotId, equip_slot: EquipSlot) -> bool {
|
pub fn can_swap(&self, inv_slot_id: InvSlotId, equip_slot: EquipSlot) -> bool {
|
||||||
// Check if loadout slot can hold item
|
// Check if loadout slot can hold item
|
||||||
if !self
|
if !self.get(inv_slot_id).map_or(true, |item| {
|
||||||
.get(inv_slot_id)
|
self.loadout.slot_can_hold(equip_slot, &item.kind())
|
||||||
.map_or(true, |item| equip_slot.can_hold(&item.kind()))
|
}) {
|
||||||
{
|
|
||||||
trace!("can_swap = false, equip slot can't hold item");
|
trace!("can_swap = false, equip slot can't hold item");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -231,23 +231,29 @@ fn unequip_items_both_hands() {
|
|||||||
|
|
||||||
let sword = Item::new_from_asset_expect("common.items.weapons.sword.steel-8");
|
let sword = Item::new_from_asset_expect("common.items.weapons.sword.steel-8");
|
||||||
|
|
||||||
inv.replace_loadout_item(EquipSlot::Mainhand, Some(sword.duplicate(ability_map, msm)));
|
inv.replace_loadout_item(
|
||||||
inv.replace_loadout_item(EquipSlot::Offhand, Some(sword.duplicate(ability_map, msm)));
|
EquipSlot::ActiveMainhand,
|
||||||
|
Some(sword.duplicate(ability_map, msm)),
|
||||||
|
);
|
||||||
|
inv.replace_loadout_item(
|
||||||
|
EquipSlot::InactiveMainhand,
|
||||||
|
Some(sword.duplicate(ability_map, msm)),
|
||||||
|
);
|
||||||
|
|
||||||
// Fill all inventory slots except one
|
// Fill all inventory slots except one
|
||||||
fill_inv_slots(&mut inv, 17);
|
fill_inv_slots(&mut inv, 17);
|
||||||
|
|
||||||
let result = inv.unequip(EquipSlot::Mainhand);
|
let result = inv.unequip(EquipSlot::ActiveMainhand);
|
||||||
// We have space in the inventory, so this should have unequipped
|
// We have space in the inventory, so this should have unequipped
|
||||||
assert_eq!(None, inv.equipped(EquipSlot::Mainhand));
|
assert_eq!(None, inv.equipped(EquipSlot::ActiveMainhand));
|
||||||
assert_eq!(18, inv.populated_slots());
|
assert_eq!(18, inv.populated_slots());
|
||||||
assert_eq!(true, result.is_ok());
|
assert_eq!(true, result.is_ok());
|
||||||
|
|
||||||
let result = inv.unequip(EquipSlot::Offhand).unwrap_err();
|
let result = inv.unequip(EquipSlot::InactiveMainhand).unwrap_err();
|
||||||
assert_eq!(SlotError::InventoryFull, result);
|
assert_eq!(SlotError::InventoryFull, result);
|
||||||
|
|
||||||
// There is no more space in the inventory, so this should still be equipped
|
// There is no more space in the inventory, so this should still be equipped
|
||||||
assert_eq!(&sword, inv.equipped(EquipSlot::Offhand).unwrap());
|
assert_eq!(&sword, inv.equipped(EquipSlot::InactiveMainhand).unwrap());
|
||||||
|
|
||||||
// Verify inventory
|
// Verify inventory
|
||||||
assert_eq!(inv.slots[17], Some(sword));
|
assert_eq!(inv.slots[17], Some(sword));
|
||||||
|
@ -13,7 +13,7 @@ use std::time::{Duration, Instant};
|
|||||||
#[test]
|
#[test]
|
||||||
fn maps_wield_while_equipping() {
|
fn maps_wield_while_equipping() {
|
||||||
let loadout = LoadoutBuilder::new()
|
let loadout = LoadoutBuilder::new()
|
||||||
.active_item(Some(Item::new_from_asset_expect(
|
.active_mainhand(Some(Item::new_from_asset_expect(
|
||||||
"common.items.weapons.axe.starter_axe",
|
"common.items.weapons.axe.starter_axe",
|
||||||
)))
|
)))
|
||||||
.build();
|
.build();
|
||||||
@ -40,7 +40,7 @@ fn maps_wield_while_equipping() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn maps_unwield() {
|
fn maps_unwield() {
|
||||||
let loadout = LoadoutBuilder::new()
|
let loadout = LoadoutBuilder::new()
|
||||||
.active_item(Some(Item::new_from_asset_expect(
|
.active_mainhand(Some(Item::new_from_asset_expect(
|
||||||
"common.items.weapons.bow.starter",
|
"common.items.weapons.bow.starter",
|
||||||
)))
|
)))
|
||||||
.build();
|
.build();
|
||||||
@ -62,7 +62,7 @@ fn maps_unwield() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn maps_basic_melee() {
|
fn maps_basic_melee() {
|
||||||
let loadout = LoadoutBuilder::new()
|
let loadout = LoadoutBuilder::new()
|
||||||
.active_item(Some(Item::new_from_asset_expect(
|
.active_mainhand(Some(Item::new_from_asset_expect(
|
||||||
"common.items.weapons.axe.starter_axe",
|
"common.items.weapons.axe.starter_axe",
|
||||||
)))
|
)))
|
||||||
.build();
|
.build();
|
||||||
@ -104,7 +104,7 @@ fn maps_basic_melee() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn matches_ability_stage() {
|
fn matches_ability_stage() {
|
||||||
let loadout = LoadoutBuilder::new()
|
let loadout = LoadoutBuilder::new()
|
||||||
.active_item(Some(Item::new_from_asset_expect(
|
.active_mainhand(Some(Item::new_from_asset_expect(
|
||||||
"common.items.weapons.sword.starter",
|
"common.items.weapons.sword.starter",
|
||||||
)))
|
)))
|
||||||
.build();
|
.build();
|
||||||
@ -163,7 +163,7 @@ fn matches_ability_stage() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn ignores_different_ability_stage() {
|
fn ignores_different_ability_stage() {
|
||||||
let loadout = LoadoutBuilder::new()
|
let loadout = LoadoutBuilder::new()
|
||||||
.active_item(Some(Item::new_from_asset_expect(
|
.active_mainhand(Some(Item::new_from_asset_expect(
|
||||||
"common.items.weapons.axe.starter_axe",
|
"common.items.weapons.axe.starter_axe",
|
||||||
)))
|
)))
|
||||||
.build();
|
.build();
|
||||||
|
Loading…
Reference in New Issue
Block a user