Author Topic: Weapon Switching Exploit  (Read 1238 times)

Legacy_Madasahatter

  • Full Member
  • ***
  • Posts: 214
  • Karma: +0/-0
Weapon Switching Exploit
« on: August 27, 2015, 08:32:45 pm »


               

Is there anyway to stop players using the weapon switching exploit in combat using a script ? if so can anyone help.


 


Thanks in Advance



               
               

               
            

Legacy_Pstemarie

  • Hero Member
  • *****
  • Posts: 4368
  • Karma: +0/-0
Weapon Switching Exploit
« Reply #1 on: August 27, 2015, 08:46:38 pm »


               

You could modify the equip and unequip events to abort if the PC is in combat and attempts to swap weapons.



               
               

               
            

Legacy_Shadooow

  • Hero Member
  • *****
  • Posts: 7698
  • Karma: +0/-0
Weapon Switching Exploit
« Reply #2 on: August 27, 2015, 08:51:24 pm »


               

Imo the best way to stop it is ClearAllActions(); anytime item is unequipped/equipped.



               
               

               
            

Legacy_Thayan

  • Sr. Member
  • ****
  • Posts: 435
  • Karma: +0/-0
Weapon Switching Exploit
« Reply #3 on: August 27, 2015, 08:55:03 pm »


               

This was from the old NWVault, and I can't seem to find it on the new vault so I don't know who to give credit for it. But this should work (although I haven't tested it now in probably a few years) -


 


Put this or merge this into the Module OnEquip:



//stopswap_onequ
 
#include "stopswap_inc"
 
void main()
{
  object oItem = GetPCItemLastEquipped();
  object oPC   = GetPCItemLastEquippedBy();

  //Stop Swapping of weapons in combat with no penalties (see stopswap_XXX scripts for more details)
  int nSlot = GetRestictedInventorySlot(oItem);
  if (GetLocalObject(oPC, VAR_SLOT_KEY + IntToString(nSlot)) == oItem) {
    // unlock the slot
    DeleteLocalInt(oPC, VAR_SLOT_LOCK + IntToString(nSlot));
    DeleteLocalObject(oPC, VAR_SLOT_KEY + IntToString(nSlot));
  }
}

Put this or merge this into the Module OnUnequip:



//stopswap_onunequ

#include "stopswap_inc"

// -----------------------------------------------------------------------------
//  MAIN
// -----------------------------------------------------------------------------

// module event - OnPlayerUnEquipItem
// file name - stopswap_onunequ  v1.3 (added tag based scripting)
void main()
{
  object oItem = GetPCItemLastUnequipped();
  object oPC = GetPCItemLastUnequippedBy();

  // pre-emptive abort: if the PC's appearance is not a standard PC appearance type the PC is/has just
  // polymorphed which merges inventory slots  so no need for restrictions on swapping items

  if(GetAppearanceType(oPC) > LAST_PC_APPEARANCE_TYPE && GetSubRace(oPC) == "") return;
  if(GetCurrentHitPoints(oPC) <= 1) return; //If the PC is dying or dead, let them unequip (usually forced by the module)

  // Check if PC is in combat & within the unsafe distance, & if they equip a
  // melee or ranged weapon if so, create an attack of opportunity
  if(GetWasWeaponUnequippedInMelee(oPC, oItem) && UNEQUIP_WEAPON_PROVOKES_AOO && !GetLocalInt(oPC, "SwappedWeapons")) {
    ActionStepBackwards(oPC, 2.5);
    SendMessageToPC(oPC, "It takes you a moment to switch weapons while in melee combat!");
    SetLocalInt(oPC, "SwappedWeapons", 1);
    DelayCommand(0.1, DeleteLocalInt(oPC, "SwappedWeapons"));
    DelayCommand(0.1, AssignCommand(oPC, ClearAllActions(TRUE)));
    DelayCommand(0.1, ApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectCutsceneParalyze(), oPC, 1.5));
  }
  else if(GetIsOkayToUnequip(oPC, oItem) == FALSE) {
    int nSlot = GetRestictedInventorySlot(oItem);

    // lock the slot and note the key
    SetLocalInt(oPC, VAR_SLOT_LOCK + IntToString(nSlot), TRUE);
    SetLocalObject(oPC, VAR_SLOT_KEY + IntToString(nSlot), oItem);

    // force the PC to re-equip the item
    AssignCommand(oPC, ActionEquipItem(oItem, nSlot));
    SendMessageToPC(oPC, "You can't unequip " + GetName(oItem) + " in melee combat!");
  }
}

And finally, create an include script called stopswap_inc with this in it:



// file name - stopswap_inc v1.3

#include "x2_inc_itemprop"

// -----------------------------------------------------------------------------
//  CONSTANTS
// -----------------------------------------------------------------------------

const float SAFE_DISTANCE             = 4.0;  // Set safe distance to equip items during combat
const int LAST_PC_APPEARANCE_TYPE     = 6;    // Last standard racial type
const int UNEQUIP_WEAPON_PROVOKES_AOO = TRUE; // TRUE or FALSE

const string VAR_SLOT_KEY   = "SLOT_KEY_";
const string VAR_SLOT_LOCK  = "SLOT_LOCK_";

// -----------------------------------------------------------------------------
//  PROTOTYPES
// -----------------------------------------------------------------------------

int GetIsRestrictedSlot(int nSlot);

int GetRestictedInventorySlot(object oItem);

int GetRestrictedInventorySlotByType(int nType);

// Check if PC is in combat & within the unsafe distance,
// & if they equip a melee or ranged weapon if so,
// create an attack of opportunity
// oPC   - Player
// oItem - Check if melee or ranged weapon
int GetWasWeaponUnequippedInMelee(object oPC, object oItem);

int GetIsOkayToUnequip(object oPC, object oItem);

void ActionStepBackwards(object oCreature, float fDistance);

// -----------------------------------------------------------------------------
//  FUNCTIONS
// -----------------------------------------------------------------------------

int GetIsRestrictedSlot(int nSlot)
{
    return nSlot > -1;
}

int GetRestictedInventorySlot(object oItem)
{
    return GetRestrictedInventorySlotByType(GetBaseItemType(oItem));
}

int GetRestrictedInventorySlotByType(int nType)
{
    int nRet = -1;
    switch (nType)
    {
        case BASE_ITEM_AMULET:      nRet = INVENTORY_SLOT_NECK;  break;
        case BASE_ITEM_BELT:        nRet = INVENTORY_SLOT_BELT;  break;
        case BASE_ITEM_BOOTS:       nRet = INVENTORY_SLOT_BOOTS; break;
        case BASE_ITEM_CLOAK:       nRet = INVENTORY_SLOT_CLOAK; break;
        case BASE_ITEM_BRACER:
        case BASE_ITEM_GLOVES:      nRet = INVENTORY_SLOT_ARMS;  break;
        case BASE_ITEM_HELMET:      nRet = INVENTORY_SLOT_HEAD;  break;
        case BASE_ITEM_LARGESHIELD:
        case BASE_ITEM_SMALLSHIELD:
        case BASE_ITEM_TOWERSHIELD: nRet = INVENTORY_SLOT_LEFTHAND; break;
    }

    return nRet;
}

int GetWasWeaponUnequippedInMelee(object oPC, object oItem)
{
    // is it a weapon?
    if(IPGetIsMeleeWeapon(oItem) || IPGetIsRangedWeapon(oItem))
    {
        // is the PC in combat?
        if(GetIsInCombat(oPC))
        {
            // is the nearest enemy in striking range?
            object oEnemy = GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, oPC);
            if(GetDistanceBetween(oPC, oEnemy) < SAFE_DISTANCE)
            {
                return TRUE;
            }
        }
    }
    return FALSE;
}

int GetIsOkayToUnequip(object oPC, object oItem)
{
    int nSlot = GetRestictedInventorySlot(oItem);

    // is the slot locked?
    // NOTE: if we are trying to unequip something from a locked slot then it
    // is the system doing the unequipping
    if(GetLocalInt(oPC, VAR_SLOT_LOCK + IntToString(nSlot)))
    {
        return TRUE;
    }

    // is it a restricted slot?
    if(GetIsRestrictedSlot(nSlot))
    {
        // is PC in combat
        if(GetIsInCombat(oPC))
        {
            // is enemy too close
            object oEnemy = GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, oPC);
            if(GetDistanceBetween(oPC, oEnemy) < SAFE_DISTANCE)
            {
                return FALSE;
            }
        }
    }

    // at least one condition was not met so it is okay to unequip
    return TRUE;
}

void ActionStepBackwards(object oCreature, float fDistance)
{
    // decompose the creature's current location
    object oArea = GetArea(oCreature);
    vector vPosition = GetPosition(oCreature);
    float fFacing = GetFacing(oCreature);

    // generate a position behind the creature
    float fX = fDistance * cos(fFacing + 180.0);
    float fY = fDistance * sin(fFacing + 180.0);
    vector vBackwards = Vector(fX, fY);

    // generate a location behind the creature
    location lBackwards = Location(oArea, vPosition + vBackwards, fFacing);

    // force the creature to run there
    AssignCommand(oCreature, ClearAllActions());
    AssignCommand(oCreature, ActionMoveToLocation(lBackwards, TRUE));
}


Editted becaues these boards suck for formatting code.



               
               

               
            

Legacy_Madasahatter

  • Full Member
  • ***
  • Posts: 214
  • Karma: +0/-0
Weapon Switching Exploit
« Reply #4 on: August 27, 2015, 09:03:06 pm »


               

Thanks for the quick reply's


 


Shadooow


How and where would I add ClearAllActions(); ?


 


Thanks



               
               

               
            

Legacy_meaglyn

  • Hero Member
  • *****
  • Posts: 1451
  • Karma: +0/-0
Weapon Switching Exploit
« Reply #5 on: August 27, 2015, 09:27:20 pm »


               

That's Sir Elric's stopswap code I believe.



               
               

               
            

Legacy_Madasahatter

  • Full Member
  • ***
  • Posts: 214
  • Karma: +0/-0
Weapon Switching Exploit
« Reply #6 on: August 28, 2015, 08:39:38 am »


               

this works ok in a test mod but not in the full mod, I may need help merging it into my current equip / unequip scripts.


 


any help would be great thanks



               
               

               
            

Legacy_Shadooow

  • Hero Member
  • *****
  • Posts: 7698
  • Karma: +0/-0
Weapon Switching Exploit
« Reply #7 on: August 28, 2015, 08:50:26 am »


               


Thanks for the quick reply's


 


Shadooow


How and where would I add ClearAllActions(); ?


 


Thanks




just add


 


AssignCommand(oPC, ClearAllActions()); somewhere in the top of your OnEquip and OnUnEquip scripts.


               
               

               
            

Legacy_meaglyn

  • Hero Member
  • *****
  • Posts: 1451
  • Karma: +0/-0
Weapon Switching Exploit
« Reply #8 on: August 28, 2015, 02:00:00 pm »


               

Shadooow's is definitely the simplest way to do it '<img'>


 


But if you want the features of the above posted system and you have those scripts named as above you can add



ExecuteScript("stopswap_onequ", OBJECT_SELF);

to the body of your existing onequp handler. And



ExecuteScript("stopswap_onunequ", OBJECT_SELF);

to the unequip handler.  This is the simple way to "merge" multiple event handlers. It assumes there is no real overlap in what the handlers do (which is probably the case here).


               
               

               
            

Legacy_leo_x

  • Sr. Member
  • ****
  • Posts: 403
  • Karma: +0/-0
Weapon Switching Exploit
« Reply #9 on: August 28, 2015, 04:39:03 pm »


               

Another alternative I picked up from an old FunkySwerve post is applying EffectMissChance(100) for a round or so when a weapon is swapped.  It's nice if you don't want to force a player flat-footed, etc.



               
               

               
            

Legacy_Madasahatter

  • Full Member
  • ***
  • Posts: 214
  • Karma: +0/-0
Weapon Switching Exploit
« Reply #10 on: August 29, 2015, 10:27:25 am »


               

Ok, Thanks shadooow


 


I just used ClearAllActions and its doing what I need


 


Thanks to everone for all the help and support


 


Regards



               
               

               
            

Legacy_Shadooow

  • Hero Member
  • *****
  • Posts: 7698
  • Karma: +0/-0
Weapon Switching Exploit
« Reply #11 on: August 29, 2015, 08:45:42 pm »


               


Another alternative I picked up from an old FunkySwerve post is applying EffectMissChance(100) for a round or so when a weapon is swapped.  It's nice if you don't want to force a player flat-footed, etc.




Well yes of course, but the problem here is that in some cases which I don't want to specify more, weapon swap can result in creature not attacking at all for entire duration of the combat. Unless you will clear all actions, you won't prevent this.


 


Plus I myself consider the ClearAllAction be too soft actually. Any player that knows about this will be ready to click on his target again and won't be flatfooted at all. Personally I would like to delay all equip/unequip calls and make player flatfooted doing some action for 1+ rounds at least. Item swapping in combat is too powerful possibility already.



               
               

               
            

Legacy_Pstemarie

  • Hero Member
  • *****
  • Posts: 4368
  • Karma: +0/-0
Weapon Switching Exploit
« Reply #12 on: August 29, 2015, 09:38:31 pm »


               

Not sure if its possible, but what about reducing attacks by one just for that round? In effect the swap takes the place of an attack.



               
               

               
            

Legacy_MagicalMaster

  • Hero Member
  • *****
  • Posts: 2712
  • Karma: +0/-0
Weapon Switching Exploit
« Reply #13 on: August 30, 2015, 08:45:57 pm »


               


Personally I would like to delay all equip/unequip calls and make player flatfooted doing some action for 1+ rounds at least. Item swapping in combat is too powerful possibility already.




 


Really?  So if an orc is charging at me and I shoot at it with a bow until it reaches melee range and then I pull out a sword and shield, you think I should be effectively stunned for 6+ seconds?


 


I thought the concern here was people getting extra attacks that they shouldn't, through a method I'm trying not to elaborate on here.  But it seems to me at least that not punishing people who *aren't* trying to exploit should be one of the main priorities.



               
               

               
            

Legacy_The Mad Poet

  • Hero Member
  • *****
  • Posts: 715
  • Karma: +0/-0
Weapon Switching Exploit
« Reply #14 on: August 30, 2015, 08:57:35 pm »


               

I know a lot of people don't run strict according to DnD rules when it concerns NWN, but according to 3.5, and 3.0 I suspect, drawing a weapon or readying a shield (pulling it out for use in combat when it was not in the hands before) is each a move action. Move actions don't allow Full Attack actions, so essentially you would be limited to a single attack in that round. So losing all your other attacks in that round for switching equipment sounds perfectly reasonable to me. A round is six seconds. How much can one person reasonably do in six seconds? I doubt make four attacks, ready a shield, and sheathe (cause they don't drop them) a previously held weapon, and draw a new one. Too much.


 


On that note it might be great do have it that if a player changes weapons in combat they drop whatever weapon they were previously holding on the ground to make it a bit more realistic. Also annoying enough that players might not want to do it very often.