private static void OnPlayerPickedUpWeapon(IPlayer player, PlayerWeaponAddedArg arg)
        {
            if (!m_weapons.ContainsKey(arg.SourceObjectID) && !m_queuedPowerups.ContainsKey(player.UniqueID))
            {
                return;
            }

            GetOrCreatePlayerWeapon(player);

            // TODO: gibbed player doesn't fire OnPlayerDropped, so calling m_weapons.GetItem() will throw
            // wait for gurt to fix and remove this line:
            // https://www.mythologicinteractiveforums.com/viewtopic.php?f=18&t=3999&p=23441#p23441
            if (arg.SourceObjectID != 0 && !m_weapons.ContainsKey(arg.SourceObjectID))
            {
                return;
            }

            var weaponInfo = arg.SourceObjectID == 0 ?
                             (PowerupInfo)m_queuedPowerups[player.UniqueID].Where(wi => wi.Weapon == arg.WeaponItem).FirstOrDefault() :
                             (PowerupInfo)m_weapons[arg.SourceObjectID].WeaponInfo;

            if (weaponInfo == null)
            {
                return;
            }

            var createRangedWeapon = new Func <RangeWpn>(
                () => RangeWeaponFactory.Create(player, arg.WeaponItem, weaponInfo.RangedPowerup));

            switch (arg.WeaponItemType)
            {
            case WeaponItemType.Melee:
                // TODO: create power melee weapon with factory if implement one
                m_owners[player.UniqueID].Melee.Add(arg.WeaponItem, weaponInfo.MeleePowerup);
                break;

            case WeaponItemType.Rifle:
                m_owners[player.UniqueID].Primary = createRangedWeapon();
                break;

            case WeaponItemType.Handgun:
                m_owners[player.UniqueID].Secondary = createRangedWeapon();
                break;

            case WeaponItemType.Thrown:
                m_owners[player.UniqueID].Throwable = createRangedWeapon();
                break;
            }

            if (arg.SourceObjectID == 0)
            {
                m_queuedPowerups[player.UniqueID].Remove((WeaponInfo)weaponInfo);
            }
            else
            {
                m_weapons.Remove(arg.SourceObjectID);
            }
        }
        private static void OnPlayerDroppedWeapon(IPlayer player, PlayerWeaponRemovedArg arg)
        {
            // ID == 0 means no weapon was dropped. For example: Activating instant powerup will make it disappeared, not dropped
            if (arg.TargetObjectID == 0)
            {
                return;
            }

            // player argument may be a null object if the weapon drops right after the player was gibbed
            if (player.UniqueID == 0)
            {
                return;
            }

            // dropped weapons dont not always have IObjectWeaponItem type. For example thrown grenades have IObject type
            var weaponObject = Game.GetObject(arg.TargetObjectID) as IObjectWeaponItem;

            if (weaponObject == null)
            {
                return;
            }

            var oldPlayerWpn  = GetOrCreatePlayerWeapon(player);
            var newWeaponInfo = new WeaponObjectInfo()
            {
                Weapon = weaponObject
            };

            switch (weaponObject.WeaponItemType)
            {
            case WeaponItemType.Melee:
                newWeaponInfo.MeleePowerup = oldPlayerWpn.Melee.Powerup;
                m_owners[player.UniqueID].Melee.Remove();
                // TODO: add null object
                break;

            case WeaponItemType.Rifle:
                newWeaponInfo.RangedPowerup = oldPlayerWpn.Primary.Powerup;
                m_owners[player.UniqueID].Primary.Remove();
                m_owners[player.UniqueID].Primary = RangeWeaponFactory.Create(player, WeaponItem.NONE, RangedWeaponPowerup.None);
                break;

            case WeaponItemType.Handgun:
                newWeaponInfo.RangedPowerup = oldPlayerWpn.Secondary.Powerup;
                m_owners[player.UniqueID].Secondary.Remove();
                m_owners[player.UniqueID].Secondary = RangeWeaponFactory.Create(player, WeaponItem.NONE, RangedWeaponPowerup.None);
                break;

            case WeaponItemType.Thrown:
                newWeaponInfo.RangedPowerup = oldPlayerWpn.Throwable.Powerup;
                m_owners[player.UniqueID].Throwable.Remove();
                m_owners[player.UniqueID].Throwable = RangeWeaponFactory.Create(player, WeaponItem.NONE, RangedWeaponPowerup.None);
                break;
            }

            m_weapons.Add(weaponObject.UniqueID, new Weapon(newWeaponInfo));
        }