Is there anyway to stop players using the weapon switching exploit in combat using a script ? if so can anyone help.
Thanks in Advance
Is there anyway to stop players using the weapon switching exploit in combat using a script ? if so can anyone help.
Thanks in Advance
You could modify the equip and unequip events to abort if the PC is in combat and attempts to swap weapons.
Imo the best way to stop it is ClearAllActions(); anytime item is unequipped/equipped.
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.
Thanks for the quick reply's
Shadooow
How and where would I add ClearAllActions(); ?
Thanks
That's Sir Elric's stopswap code I believe.
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
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.
Shadooow's is definitely the simplest way to do it ![]()
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).
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.
Ok, Thanks shadooow
I just used ClearAllActions and its doing what I need
Thanks to everone for all the help and support
Regards
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.
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.
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.
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.
Just a quick thought....
Since SetBaseAttackBonus() doesn't work on PCs, would this function work to reduce the PC's attacks to 1 for one round?
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.
as mad poet said, in DnD you wouldnt be allowed to do this anyway, the problem I see is something I encountered on epic action loot server both as DM and player
most players carry at least 10 items they are swapping by situation, thats all right when it comes to the weapons etc. but then there are players that have over 40 such items, and they change the whole equip in one second, hell even I am doing that, my main char has 6 rings Im swapping by situations, one for sneak attack, 3 to get resist 30 on one element, +6 saves one and +4 regeneration. Then 3 amulets, my main one, one with +20 taunt, and +7 saves one. Im also swapping bracers, usually going with HIPS bracers, swappng for damage reduction 10/+5, +30 concentration and then bracers with blind fight- And thats my wiz/AA build where I cant really swap weapon as I can fight only with bow, bards and WMs really utilizing around 30 such items and they are able to change 15 of them just when fighting boss creature for no penalty, as the server in question doesnt even use clearallactions. This is not okay in my opinion. Its too beneficial, and some of the cases are really ridiculous like when this bard goes with improved expertise, then swap cloak for +30 perform, then curse enemies, then swap back for charisma cloak, then use divine shield and cancel expertise, then swap cloak to the one he uses normally ie. regen, then swap weapon with MD onhit to dispel enemies divine favor they casted, then swap on main weapon, then swap bracers that gives him disarm and disarms their weapons, then he swap for strength bracers and equip chaotic shield as now they dont do damage. Repeat for every encounter lol.
Just a quick thought....
Since SetBaseAttackBonus() doesn't work on PCs, would this function work to reduce the PC's attacks to 1 for one round?
void ReduceAttacks(object oTarget){int nAttacks = GetBaseAttackBonus(oTarget);int nModify = 0 - (nAttacks -1);effect eAttack = EffectModifyAttacks(nModify);ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eAttack, oTarget, 1.0);}
it does work for players
from readme to the CP 1.71: Note for SetBaseAttackBonus function corrected to inform it does works for PC actually.
Shadooow so the coding would look something like this for the OnEquip and OnUnEquip events?
....
SetBaseAttackBonus(oPC, 1);
DelayCommand(6.0, RestoreBaseAttackBonus(oPC)));
....
Shadooow so the coding would look something like this for the OnEquip and OnUnEquip events?
....
SetBaseAttackBonus(oPC, 1);
DelayCommand(6.0, RestoreBaseAttackBonus(oPC)));
....
yes that should work, just need to use restorebaseattackbonus also in OnClientEnter to fix players who logged off during the 6.0 delay
yes that should work, just need to use restorebaseattackbonus also in OnClientEnter to fix players who logged off during the 6.0 delay
Thanks, didn't think of that.
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.
This is not okay in my opinion. Its too beneficial, and some of the cases are really ridiculous like when this bard goes with improved expertise, then swap cloak for +30 perform, then curse enemies, then swap back for charisma cloak, then use divine shield and cancel expertise, then swap cloak to the one he uses normally ie. regen, then swap weapon with MD onhit to dispel enemies divine favor they casted, then swap on main weapon, then swap bracers that gives him disarm and disarms their weapons, then he swap for strength bracers and equip chaotic shield as now they dont do damage. Repeat for every encounter lol.
Again, this goes back to my original statement: find a solution that doesn't hurt people playing legitimately.
Hence, my "solution" opted to just reduce attacks to one for one round and includes a module switch to bypass the "solution" for those Builders that don't like it.
BTW, that is an excellent example you give, but it doesn't really address the original point of just "...how much can you do in 6 seconds?" in NWN. In your example the archers dropped their bows then took up mallets (which were lying all along their line or just behind it) - an action that would have approximated to more than one round in DnD terms (i.e drop bow, move to mallet, pickup mallet, ready weapon, attack enemy). In NWN, characters don't drop weapons when they are unequipped, they are placed in inventory, and continue to be readily available. However, the exploit allows you to do way more in that 6 seconds then the game was intended to allow - hence, its an exploit.
Where did I even mention four attacks? I'm talking about a low level character with 1 attack per round. He fires a shot, sees that the enemy will be in melee range soon, and spends the next few seconds switching weapons. According to Shadow he should be flatfooted for 1+ rounds -- meaning he'll go a minimum of 12 seconds between attacks.
0: Fire bow
1: decide to switch, become flat footed
4: enemy enters melee range, still flat footed
6: would do a melee swing now but still flat footed
7: flat footed wears off but have to wait until start of next combat round to attack since enemy is meleeing him
12: first melee swing
.........
As you say it is an approximation. DnD generally assumes your character swings a sword way more than 1 time in a six second span. Only one of those attacks are counted in actual combat. No one is going to swing once, wait six seconds, swing again. As your level, and thus your skill, increases you gain more attacks, approximating ones skill increasing in combat.
Carrying 11 greatswords... well... it depends on how you play PnP. Characters should only be able to carry one greatsword logically. I've seen DM's handle this differently. My way is just by saying you can carry up to 25 lbs of weapons on you at any one time. I find it the easiest method as it allows a player to carry two different greatswords and a dagger, which I think is more than enough for one player. Another DM I played with allowed only one weapon on the back, two on the flanks (one-handed only), and four small weapons anywhere else. That worked fine too. I've played games where the DM let players carry 11 greatswords.... they were likely VERY encumbered considering that is 132 lbs of sword... but that's another issue.
Regardless of how many weapons you have any weapon that is not in your hands at the start of combat is considered not drawn and at the ready. Requires a move action to ready that weapon. To put a weapon away to be drawn later is a move action (sheathing, or whatever method you want to use), and it draws an attack of opportunity. Dropping a weapon on the floor is a free action. So if you want to put a weapon into your 'Inventory' and draw another weapon it would take 2 move actions, or basically require all of your actions for that turn. Simply drop the weapon in hand and draw the next and you can make one attack. Either way you will not get a full attack action, which limits you to only one attack in that round.
Clearing all actions and leaving them flat-footed for a moment is more than fair considering the PnP way of putting away a weapon and drawing another would keep them from attacking at all and invoke an AoO.
Like I said though, many people consider trying to match PnP methods in NWN a bad idea. I'm not attached to them, but I feel it is better to default there unless someone comes up with a better idea.
Hence, my "solution" opted to just reduce attacks to one for one round and includes a module switch to bypass the "solution" for those Builders that don't like it.
In NWN, characters don't drop weapons when they are unequipped, they are placed in inventory, and continue to be readily available. However, the exploit allows you to do way more in that 6 seconds then the game was intended to allow - hence, its an exploit.
As you say it is an approximation. DnD generally assumes your character swings a sword way more than 1 time in a six second span. Only one of those attacks are counted in actual combat. No one is going to swing once, wait six seconds, swing again. As your level, and thus your skill, increases you gain more attacks, approximating ones skill increasing in combat.
My way is just by saying you can carry up to 25 lbs of weapons on you at any one time. I find it the easiest method as it allows a player to carry two different greatswords and a dagger, which I think is more than enough for one player.
Simply drop the weapon in hand and draw the next and you can make one attack. Either way you will not get a full attack action, which limits you to only one attack in that round.
Like I said though, many people consider trying to match PnP methods in NWN a bad idea. I'm not attached to them, but I feel it is better to default there unless someone comes up with a better idea.