2h, Shield visibility and Dual-Handed Weapons

Sure thing:

public void EquipShield (ShieldConfig shield) {
            currentShield = shield;
            currentEquippedShield.value = AttachShield(shield);
        }

And AttachShield… (I’m trying to get to the point where I either see a call to spawn or worse, an Equipment.AddItem)

I also added ‘DestroyOffHandItem()’ as a bonus :stuck_out_tongue_winking_eye: :

private Shield AttachShield(ShieldConfig shield) {
            return shield.SpawnEquipableItem(rightHandTransform, leftHandTransform);
        }

        private void DestroyOffHandItem() {
            Shield offHandWeapon = leftHandTransform.GetComponentInChildren<Shield>();
            if (offHandWeapon == null) return;
            Destroy(offHandWeapon.gameObject);
        }

Jokes aside, quick question on the fly:

In ‘InventorySlotUI.TryEquipWeapon()’, why are we removing the body equipment?

Because sometimes Intellisense types the rung dings.

:rofl: :rofl: :rofl: :rofl: - Not gonna lie though, I slowly got used to Intellisense, and would probably struggle to attempt my own code without it telling me what to do lel

Ok, I have NO idea why the shield would be saved across saves… excepting that if there’s no shield equipped in equipment, then Fighter will, of course, set the nothingburger shield as the current shield on a restore, but it shouldn’t ever appear in equipment.

I reversed all changes in ‘Equipment’, didn’t help… I’ll have a second look at what should I do though (although I’m probably more clueless than you tbh)

Something is… wrong with the code. Apparently double clicking, at a high spam rate (I’ll revert that to 0.001f) permanently erases items from the game completely. Assuming spam is fixed, clicking on non-2h items, or non shield stuff, doesn’t equip the items anymore (apologies)

OK shield issue aside, the code works. Thanks Brian :slight_smile: (only difference is that your “HandleDoubleClick()” is named “TryHandleRightClick()” in my project). Tomorrow morning I’ll preview this entire thing again, so I understand what’s going on. For now though, the shield issue will be my priority

And one last thing for anyone who reads this later down the line: Introduce an ‘equipment’ variable, as follows, otherwise NREs will attack you like a beehive after their queen:

private Equipment equipment;

private void Awake() {
equipment = Inventory.GetPlayerInventory().GetComponent<Equipment>();
}

(I’m out of edits, so I apologize for the large number of comments in advance)

Hey Brian, apologies for the nuisance today, but this statement:

has conflicted with my skill-checking part of the ‘TryHandleDoubleClick()’ function, which means now my player can equip stuff he’s not qualified for just yet, as my “EquipableItem” part of my “InventorySlotUI.TryHandleDoubleClick()” function looks like this:

if (item is EquipableItem equipableItem) {


                if (equipableItem is WeaponConfig weapon)
                {
                    TryEquipWeapon(weapon);
                    return;
                }

                if (equipableItem is ShieldConfig shield)
                {
                    TryEquipShield(shield);
                    return;
                }

                Equipment equipment = inventory.GetComponent<Equipment>();
                EquipableItem equippedItem = equipment.GetItemInSlot(equipableItem.GetAllowedEquipLocation());
                // if (!equipableItem.CanEquip(equipableItem.GetAllowedEquipLocation(), equipment)) return;    // The line solely responsible for checking for Predicate conditions, prior to being able to wield a weapon (if you're not high enough of a level, you can't wield that)
                
                // Test: Check 'Equipment.MaxAcceptable()' to confirm if a weapon is 2-handed or not:
                if (equipment.MaxAcceptable(equipableItem.GetAllowedEquipLocation(), equipableItem) == 0) return;

                equipment.RemoveItem(equipableItem.GetAllowedEquipLocation());
                equipment.AddItem(equipableItem.GetAllowedEquipLocation(), equipableItem);
                RemoveItems(1);

                if (equippedItem != null)
                {
                    AddItems(equippedItem, 1);
                }

            }

Do I just shift that line to the top, or…? (still working on my shield issue in the meanwhile)

(I’m out of edits, promise this is my last question for now):

Does the shield initialization, in ‘Fighter.Awake()’, have anything to do with this by chance?

currentShield = defaultShield;
        currentEquippedShield = new LazyValue<Shield>(null);
  1. “My Shield issue” is extremely confusing… as we’re talking about equipping shields… so don’t say “My Shield Issue” without being very explicit.
  2. While I’ve implemented the methods I posted in SpellboundHunter, (which does not use skills), I do have pre-conditions (Level, traits) before equipping any items. Here’s how I manage it:
            if (GetItem() is EquipableItem equipableItem)
            {
                if (equipment)
                {
                    InventoryItem currentItem = equipment.GetItemInSlot(equipableItem.GetAllowedEquipLocation());
                    //Prevent equipping items not qualified.
                    if (stats.GetLevel() < equipableItem.GetLevel()) return;
                    if (!equipableItem.TestRequirements(stats.gameObject)) return;
                    //Handle if weapon
                    if (equipableItem is WeaponConfig weaponConfig)
                    {
                        TryEquipWeapon(weaponConfig);
                        return;
                    }
                    //Handle if shield
                    if (equipableItem is ShieldConfig shieldConfig)
                    {
                        TryEquipShield(shieldConfig);
                        return;
                    }
                    //Everything else
                    equipment.RemoveItem(equipableItem.GetAllowedEquipLocation());
                    equipment.AddItem(equipableItem.GetAllowedEquipLocation(), equipableItem);
                    RemoveItems(GetNumber());
                    if (currentItem) AddItems(currentItem, 1);
                }
            }

OK umm, I’m still trying to identify why when I restore my shield from a save function, it shows up as a Base Shield item, something it’s not supposed to do :sweat_smile: (and I’m guessing it’ll probably have something to do with the JSON Capture and Restore States somewhere)

I’m still going through this. It has some functions in locations that my game doesn’t have (for example, I don’t have an ‘equipableItem.TestRequirements()’ in “EquipableItem.cs”, and I’m using “skilStore.GetSkillLevel()” instead of “stats.GetLevel()”, etc… a tad bit confusing :stuck_out_tongue_winking_eye: )

The idea is that’s where you test for skills, before moving on to equipping

Is it showing up in EQUIPMENT as a base shield?

AHH… The problem was DUMBER than I thought it was, I just found out what went so wrong:

When I was creating the Base Shield, a REPLICA of the wooden shield in the inspector, I forgot to erase the Unique ID for the computer to re-generate a new one, and this baffled all 3 of us (me, you and Unity) for a while. Apologies for the mess :sweat_smile:

ANYWAY, I’ll go give your challenge a go :slight_smile:

OK I got it to work, and somehow… MaxAcceptable() was causing more issues than help (so I eliminated that), but the TryEquipWeapon() and TryEquipShield() functions saved the day, thanks Brian :slight_smile:

Off to the Dual-Handed Weapons, I’ll give this one some thought as well

Edit: OK after some thought, here’s how I want to approach the dual-wield task:

  1. Create a Boolean in the inspector under ‘WeaponConfig.cs’, name it ‘isDualWielded’
  2. If that boolean is true, we place a new variable called ‘partnerWeapon’ or something… something that basically acts as a weapon, but places the weapon into the shield slot, and replaces anything there
  3. Similar to the Quiver system, if the weapon in that shield slot does not match the weapon it is partnered to, or if it does not have a partner at all, and the player attempts to use it to engage in combat, Automatically Unequip that weapon

I’ll go try start working on this. What sort of pitfalls can I expect on this one?

OK so I’m trying the ‘Dual Hand Weapon’ coding on my own, something that basically checks for two things:

  1. If the weapon is labelled as ‘isDualHand’, and it was placed in another weapon’s ‘dualHandWeapon’ slot it gets equipped in the shield slot (although both swords are individual items, on their own)
  2. If it does not match the weapon in the weapon slot, it automatically strips the weapon equipment slot from whatever it has on it

So here are my steps:

  1. in ‘WeaponConfig.cs’, I introduced a boolean called ‘isDualHandedWeapon’, which must be ticked by both the main and off hand weapon, along with a ‘Weapon’ slot for the dual hand weapon, as follows:
public bool isTwoHanded = false;    // for dual-handed weapons
[SerializeField] WeaponConfig dualHandWeapon; // the second weapon, for the shield slot
  1. In ‘fighter.cs’, I introduced these variables and functions, to equip off-hand weapons:
        // ----------------------------------------------- OUT OF COURSE CONTENT: Off-Hand Weapon Visibility Variables --------------------
        WeaponConfig defaultOffHandWeapon;
        WeaponConfig currentOffHandWeapon;
        LazyValue<Weapon> currentEquippedOffHandWeapon;
        // --------------------------------------------------------------------------------------------------------------------------------


// in void Awake():

        // ------------------------------------ MORE OUT OF COURSE CONTENT: Off-Hand Weapons -----------------
        currentOffHandWeapon = defaultOffHandWeapon;
        currentEquippedOffHandWeapon = new LazyValue<Weapon>(null);
        // ---------------------------------------------------------------------------------------------------

// Attaching and Equipping functions:

// --------------------------------- TEST OUT OF COURSE CONTENT: Equipping Off-Hand Content ------------------------------

        public void EquipOffHandWeapon(WeaponConfig offHandWeapon) {
            currentOffHandWeapon = offHandWeapon;
            currentEquippedOffHandWeapon.value = AttachOffHandWeapon(offHandWeapon);
        }

        private Weapon AttachOffHandWeapon(WeaponConfig offHandWeapon) {
            Animator animator = GetComponent<Animator>();
            return offHandWeapon.Spawn(rightHandTransform, leftHandTransform, animator);
        }

        // ------------------------------------------------------------------------------------------------------------------

// in 'UpdateWeapon()':

        var offHandWeapon = equipment.GetItemInSlot(EquipLocation.Shield) as WeaponConfig;

        // TEST (Delete if failed): Equipping off-hand weapons:
        EquipOffHandWeapon(offHandWeapon);

  1. In ‘InventorySlotUI.TryHandleRightClick()’ (‘HandleDoubleClick()’ for you), I added the following:
// TEST (Delete if failed): Equipping dual hand weapons into the shield slot:
                if (equipableItem is WeaponConfig dualHandWeapon) 
                {
                    TryEquipDualHandWeapon(dualHandWeapon);
                    return;
                }

And then I created these two functions, also in ‘InventorySlotUI.cs’:

private void TryEquipDualHandWeapon(WeaponConfig dualHandWeapon) {

            Fighter fighter = Inventory.GetPlayerInventory().GetComponent<Fighter>();

            RemoveItems(1);
            WeaponConfig otherDualHandWeapon = (WeaponConfig) equipment.GetItemInSlot(EquipLocation.Shield);    // for other dual-handed weapons possibly in the players' hands
            WeaponConfig mainWeapon = (WeaponConfig) equipment.GetItemInSlot(EquipLocation.Weapon);     // to check for whether the main weapon matches with the DH-Weapon assigned, or not
            ShieldConfig otherShield = (ShieldConfig) equipment.GetItemInSlot(EquipLocation.Shield);         // checks for any shields in the players' hands

            if (otherDualHandWeapon != null || otherShield != null) {

                equipment.RemoveItem(EquipLocation.Shield);
                if (otherDualHandWeapon) AddItems(otherDualHandWeapon, 1);
                if (otherShield) AddItems(otherShield, 1); 

            }
            else if (mainWeapon) {
                // If it's not the main hand weapon's companion, keep the item in the inventory
                if (!mainWeapon.isDualHandWeapon) {
                    UnequipDualHandWeapons(mainWeapon, otherDualHandWeapon);
                    return;
                }
                else {
                    // If they match, delete whatever is in the players' shield slot, and place the new weapon
                    equipment.RemoveItem(EquipLocation.Shield);
                    // If you had a weapon on, put that in the inventory. Otherwise if it was a shield, put that in the inventory as well
                    if (equipment.GetItemInSlot(EquipLocation.Shield) == otherDualHandWeapon) AddItems(otherDualHandWeapon, 1);
                    if (equipment.GetItemInSlot(EquipLocation.Shield) == otherShield) AddItems(otherShield, 1);
                }
            }

            equipment.AddItem(EquipLocation.Shield, dualHandWeapon);

        }

        private void UnequipDualHandWeapons(WeaponConfig mainWeapon, WeaponConfig otherWeapon) {
            
            AddItems(mainWeapon, 1);    // Visual
            AddItems(otherWeapon, 1);   // Visual
            inventory.AddToFirstEmptySlot(mainWeapon, 1);   // Actual
            inventory.AddToFirstEmptySlot(otherWeapon, 1);  // Actual
            equipment.RemoveItem(EquipLocation.Weapon); // Actual
            equipment.RemoveItem(EquipLocation.Shield); // Actual

        }

Next up, I created two new weapons to test the off-hand system, but that failed… quite badly, giving me an NRE which tells me that my ‘Fighter.AttachOffHandWeapon()’ was a complete mess.

In that test, my off-hand weapon was set the opposite hand to its counterpart, labelled ‘isDualHanded’ and given the main weapon as its counter-part, as shown below:

And my Main Hand Weapon had the following setup:

I’ll swap the animator overrides, prefabs and tune both weapons accordingly later on down the line. For now, I’m just trying to get this system to work. As for how will I deal damage for dual-handed weapons? I plan to use the solution we did for implementing ‘Hit()’ on an imported animation before, to call hit twice during the animation

I wasn’t expecting this to work from the first try anyway, but I tried because I needed guidance (and a break… I’ll admit, I need a break after this one, for a bit). How do we go around this? I definitely got lost down the line somewhere

The simplest duel weapon solution is to treat it like a 2H weapon with two models…

This provides you with an instant Dual weapon solution (that requires very little extra coding, just instantiating the 2nd model). The cost, of course, is the loss in flexibility in being able to wield different things like “I have this fantastic Mace that I want to use with this cool Sword I just found.” You’re restricted to whatever you have defined as the two weapons in your dual wield set.

To actually wield two different WeaponConfigs at the same time requires a bit of a tear down of the system. You have a number of issues to worry about:

  • Different animations for the different weapons… Most dual wield animations out there assume a particular pairing (two swords, two daggers, for example)
  • Different damage amounts for the different weapons… (Can be solved by using different events for the main and off hand weapon or adding an optional parameter to the event when set up in the animation)
  • More corner cases (those TryEquipWeapon and TryEquipShield were examples of handling corner cases, things that don’t fit the simple “Unequip this and equip this” model).
  • Equipment locations, especially if a weapon could be a main hand or off hand weapon like a short sword or dagger
  • Coordinating attack delays
  • Handling any effects (sound, visual) that may occur when a hit happens.

Looking over your code, it looks like your intention IS that a weapon and it’s compliment are linked…
This makes the easiest solution to include a 2nd weapon model in the WeaponConfig and spawn it if it exists, treating the weapon as a 2 Handed weapon.

[SerializeField] bool isTwoHanded; //using public variables directly is bad karma
//[SerializeField] WeaponConfig dualHandWeapon;
[SerializeField] Weapon offHandPrefab;
//By making this a property, it can still be used by our corner case code to handle 
//equipping and unequipping (note the case change, however, which may require some refactor
public bool IsTwoHanded =>isTwoHanded || offHandPrefab!=null;

In Spawn, test to see if there is an offHandPrefab (before testing for left/right handedness, because at this point, if it has an offHandPrefab, it doesn’t matter, the main weapon is right hand, the off hand left)
If it has an offHandPrefab, equip the main to the right, the offHand to the left and return the Main.

Ultimately, a refactor of this would return a Tuple --(Weapon, Weapon) instead of simply returning a Weapon. This will require a bit of reworking in Fighter, and I’ll get to that later.

You’ll need a good set of dual hand animations, and you’ll need to add Hit events to both points.

More to follow, as I think, as long as we use the matched pair method of dual wield, this can be wrapped up fairly easily.

As I said, for mix and match dual wield, this is a train wreck waiting to happen. Very large teams of Blizzard coders make this work in World of Warcraft, and even then, they took dual wield away from every class except Rogues… and eliminated scores of bugs…

Now that I think of it, I think restrictions are important, but we can be a little bit flexible about it. I don’t expect a direct answer about this, but how about we create a list of compatible main-hand weapons to dual hand weapons? For example, this “cool mace” can fit with this “awesome fire sword”, or maybe this “sword of wind” would do the trick side by side with this weapon… how about this “axe of water”? That list would go on both the main hand and dual hand weapons, to ensure everyone knows who they’re compatible with (I’m sure an axe of water and a mace of fire won’t be nice together).

We can also give off the idea that these off-hand weapons can work as stand-alone weapons, in shield slots. They are literally normal weapons in the shield slot. The ‘off-hand weapons’ will definitely be individual components of their own, but similar to the quiver and 2h systems, if you try to wield a weapon that doesn’t suit the main-hand weapon or the 2h-weapon, automatically take the OFF-HAND weapon off the players’ shield config slot

The point is, we would still restrict how weapons mix and match, to obviously avoid bad conflicts, but to also give the players flexibility of what works with what. Needless to say, none of this will work with 2-handed weapons, as this is an independent system in and of itself

In the end, visibility is also important, so handling imported animations will also be important for this one, based on what type of system we currently have on us (I.E: if its one handed, use this animator overrider. If it’s two handed, use this one… Is that even possible?)

Again, if this sounds a bit too wild, is a bit fictional or will demand too much work or help, we can scrap this idea and go for a basic system. If it’s possible, it doesn’t sound too bad :stuck_out_tongue_winking_eye: (again, no pressure)

I recently bought an animation pack from Kevin Iglesias on the Unity Asset Store. I think he has that covered

As for the suggested changes in the code, I did a few:

For this one, I changed it to a Serializable Field, and then used a getter function to access this variable in ‘Equipment.cs’ and ‘InventorySlotUI.cs’, through the function. So far it doesn’t seem to be causing a ton of trouble, but I need to thoroughly check my systems again, through play-testing

This one should be fine

Privacy & Terms