I have been tinkering with the NWN2 toolset for the past five years without any scripting experience in hopes of creating a JRPG-style turn-based combat mod. It has been a labor of love and pain. The entire battle system is being developed as a conversation in the conversation editor. I rely entirely on the built in conversation action and condition scripts, GC_, GA_ to make everything work. I have seen other attempts to do turn-based battling, but what I am building is not based on Dungeons and Dragons rulesets so the conversation editor really allows for a lot of flexibility.
I hit a roadblock a few years that made me want to give up, though a few hours of messing with the script editor and looking at the forums last night has inspired me to ask for help.
Is there a community expansion pack of GC_ and GA_ scripts? (Examples of ones I have implemented so far from the community include Sunjammerâs check_items and item count scripts, apply visual effect scripts, as well as ga_do_damage by DannJ)
My main issue is with the limited parameters of the scripts. In particular, many of the scripts check the PC or the PC party instead of a tag-based sTarget. I canât perform skill checks, saving throw checks (reflex, will, fortitude), inventory checks, or gift items to Non-PCs, but that is how I am building the system. I need to change the PC parameter to sTarget and I canât for the life of me figure out how to successfully compile a script with those modifications.
My immediate need is for:
A. ga_give_item script that can give an item to an sTarget instead of a PC and
B. for a script that can check if an item is in the inventory of an sTarget instead of a PC/Party.
C. Is there a way to modify the ga_floating_text script to display floaty text over an sTarget instead of the PC?
Beyond that, I am very interested in the ways that the community has expanded this noob-friendly conversation based scripting library and any of you would be willing to share your work.
// ga_give_item_npc
/*
Give an item to an NPC
*/
#include "ginc_param_const"
void CreateItemsOnObject(string sItemResRef, object oTarget = OBJECT_SELF, int nQuantity = 1);
void main(string sTarget, string sItemResRef, int nQuantity)
{
// sanity check: have any parameters been left empty?
if (sTarget == "" || sItemResRef == "" || nQuantity == 0)
{
PrintString("ERROR: empty parameter(s) passed to ga_give_item_npc");
return;
}
object oTarget = GetTarget(sTarget);
if (GetIsObjectValid(oTarget))
{
CreateItemsOnObject(sItemResRef, oTarget, nQuantity);
}
}
void CreateItemsOnObject(string sItemResRef, object oTarget = OBJECT_SELF, int nQuantity = 1)
{
int i = 1;
while (i <= nQuantity)
{
CreateItemOnObject(sItemResRef, oTarget, 1);
i++;
}
}
B. gc_check_item_npc:
// gc_check_item_npc
/*
This script checks to see if the NPC has an item in their inventory
*/
#include "ginc_param_const"
int CountItems(object oTarget, string sItemTag);
int StartingConditional(string sTarget, string sItemTag, int nQuantity)
{
// sanity check: have any parameters been left empty?
if (sTarget == "" || sItemTag == "" || nQuantity == 0)
{
PrintString("ERROR: empty parameter(s) passed to gc_check_item_npc");
return FALSE;
}
int nCount = 0;
object oTarget = GetTarget(sTarget);
if (GetIsObjectValid(oTarget))
{
// sanity check: ensure target has one of this item before checking all items
if (GetIsObjectValid(GetItemPossessedBy(oTarget, sItemTag)))
{
nCount += CountItems(oTarget, sItemTag);
}
}
return nCount >= nQuantity;
}
int CountItems(object oTarget, string sItemTag)
{
int nCount;
object oItem;
oItem = GetFirstItemInInventory(oTarget);
while (GetIsObjectValid(oItem))
{
if (GetTag(oItem) == sItemTag)
{
nCount += GetItemStackSize(oItem);
}
oItem = GetNextItemInInventory(oTarget);
}
int nSlot;
for (nSlot = 0; nSlot < NUM_INVENTORY_SLOTS; nSlot++)
{
oItem = GetItemInSlot(nSlot, oTarget);
if (GetTag(oItem) == sItemTag)
{
nCount += GetItemStackSize(oItem);
}
}
return nCount;
}
C. ga_floating_text_npc:
// ga_floating_text_npc
/*
Do floaty text on NPC
*/
#include "ginc_param_const"
void main(string sTarget, string sText)
{
// sanity check: have any parameters been left empty?
if (sTarget == "" || sText == "")
{
PrintString("ERROR: empty parameter(s) passed to ga_floating_text_npc");
return;
}
object oTarget = GetTarget(sTarget);
if (GetIsObjectValid(oTarget))
{
AssignCommand(oTarget, SpeakString(sText));
}
}
You are surely a Wizard sent to Middle Earth to help noobs like me.
Perhaps there is a bit more you can help withâŚ
At one point I stumbled upon a GC_ script that performed a DC roll on a Creature (sTarget) that checked itâs reflex, fortitude and/or will scores. Since these are the only âstatsâ that I am aware of that are not hard-coded to cap per D&D rules, I wanted to be able to use them for my battle system to calculate things like evasion chance etc. The script used to be on the vault somewhere but it is gone now
Additionally, it would be cool if the GC_ skill roll checks could apply to an NPC target instead of the PC/Party.
Thanks again! I am so excited to get working on this again.
When an item with an inventory (such as a bag of holding) is returned using the GetFirstItemInInventory and GetNextItemInInventory functions, the next call to GetNextItemInInventory will start to look inside the nested inventory (e.g. the bag of holdingâs inventory).
In my testing the item appears to be stacking past the 10 stack limit (possibly by adding items to an additional inventory slot). I made an alternate version of this script provided by @ Aqvilinus that removes items from NPCs. For some reason, the script does not remove as specified the quantity of items indicated, instead it overrides the quantity to be less than whatever is specified for the stack. So I added 11 items (max stack of 10). When I asked the script to remove 1 it removed all 10. If I ask it to remove by 1 it makes whatever the quantity of the stack is less than 1 (0). Any ideas on how to fix!
// ga_take_item_npc
/*
Take an item from an NPC
*/
#include âginc_param_constâ
void main(string sTarget, string sItemTag, int nQuantity)
{
// sanity check: have any parameters been left empty?
if (sTarget == ââ || sItemTag == ââ || nQuantity == 0)
{
PrintString("");
return;
}
object oTarget = GetTarget(sTarget);
if (GetIsObjectValid(oTarget))
TakeNumItems (oTarget,sItemTag,nQuantity);
// gc_save_dc(string sTarget, int nSavingThrow, int nDC, int nSaveType, string sTargetVersus)
/*
Parameters:
string sTarget = target NPC being checked (see Target's note)
int nSavingThrow = saving throw int to check
int nDC = difficulty class to beat
int nSaveType = int describing saving throw type
string sTargetVersus = target creature or object to save against (default: OBJECT_SELF)
Remarks:
saving throw ints
1 Fortitude saving throw.
2 Reflex saving throw.
3 Will saving throw.
saving throw type ints
0 No saving throw type.
1 Against mind affecting spells.
2 Against poison.
3 Against disease.
4 Against fear.
5 Against sound based effects.
6 Against acid.
7 Against fire.
8 Against electical based effects.
9 Against positive effects.
10 Against negative effects.
11 Against death effects.
12 Against cold based effects.
13 Against divine effects.
14 Against trap type effects.
15 Against spells.
16 Against good effects.
17 Against evil effects.
18 Against law effects.
19 Against chaos effects.
*/
#include "ginc_param_const"
int StartingConditional(string sTarget, int nSavingThrow, int nDC, int nSaveType, string sTargetVersus)
{
// sanity checks
if (sTarget == "" || nSavingThrow < 1 || nSavingThrow > 3 || nSaveType < 0 || nSaveType > 19)
{
PrintString("ERROR: invalid parameter(s) passed to gc_save_dc");
return FALSE;
}
// sanity checks to prevent wrapping around
if (nDC < 1)
{
nDC = 1;
}
else if (nDC > 255)
{
nDC = 255;
}
if (sTargetVersus == "" || !GetIsObjectValid(GetTarget(sTargetVersus)))
sTargetVersus = TARGET_OBJECT_SELF;
object oTarget = GetTarget(sTarget);
object oSaveVersus = GetTarget(sTargetVersus);
if (GetIsObjectValid(oTarget))
{
if (nSavingThrow == SAVING_THROW_FORT)
{
if (FortitudeSave(oTarget, nDC, nSaveType, oSaveVersus) > 0)
{
return TRUE;
}
}
else if (nSavingThrow == SAVING_THROW_REFLEX)
{
if (ReflexSave(oTarget, nDC, nSaveType, oSaveVersus) > 0)
{
return TRUE;
}
}
else if (nSavingThrow == SAVING_THROW_WILL)
{
if (WillSave(oTarget, nDC, nSaveType, oSaveVersus) > 0)
{
return TRUE;
}
}
}
return FALSE;
}
// gc_skill_dc_npc(string sTarget, int nSkill, int nDC)
/*
Determine if NPC's skill roll is successful.
Parameters:
string sTarget = target NPC being checked (see Target's note).
int nSkill = skill int to check
int nDC = difficulty class to beat
Remarks:
skill ints
0 APPRAISE
1 BLUFF
2 CONCENTRATION
3 CRAFT ALCHEMY
4 CRAFT ARMOR
5 CRAFT WEAPON
6 DIPLOMACY
7 DISABLE DEVICE
8 DISCIPLINE
9 HEAL
10 HIDE
11 INTIMIDATE
12 LISTEN
13 LORE
14 MOVE SILENTLY
15 OPEN LOCK
16 PARRY
17 PERFORM
18 RIDE
19 SEARCH
20 CRAFT TRAP
21 SLEIGHT OF HAND
22 SPELL CRAFT
23 SPOT
24 SURVIVAL
25 TAUNT
26 TUMBLE
27 USE MAGIC DEVICE
*/
#include "ginc_param_const"
int StartingConditional(string sTarget, int nSkill, int nDC)
{
// sanity check: have any parameters been left empty?
if (sTarget == "")
{
PrintString("ERROR: invalid target passed to gc_skill_dc_npc");
return FALSE;
}
object oTarget = GetTarget(sTarget);
if (GetIsObjectValid(oTarget))
{
int nSkillVal = GetSkillConstant(nSkill);
if (GetIsSkillSuccessful(oTarget, nSkillVal, nDC))
{
return TRUE;
}
}
return FALSE;
}
// gc_skill_rank_npc(string sTarget, int nSkill, int nRank)
/*
Determine if NPC has sufficient rank in a particular skill.
Parameters:
string sTarget = target NPC being checked (see Target's note).
int nSkill = skill int to check
int nRank = minimum rank to return TRUE
Remarks:
skill ints
0 APPRAISE
1 BLUFF
2 CONCENTRATION
3 CRAFT ALCHEMY
4 CRAFT ARMOR
5 CRAFT WEAPON
6 DIPLOMACY
7 DISABLE DEVICE
8 DISCIPLINE
9 HEAL
10 HIDE
11 INTIMIDATE
12 LISTEN
13 LORE
14 MOVE SILENTLY
15 OPEN LOCK
16 PARRY
17 PERFORM
18 RIDE
19 SEARCH
20 CRAFT TRAP
21 SLEIGHT OF HAND
22 SPELL CRAFT
23 SPOT
24 SURVIVAL
25 TAUNT
26 TUMBLE
27 USE MAGIC DEVICE
*/
// BMA-OEI 9/02/05
#include "ginc_param_const"
int StartingConditional(string sTarget, int nSkill, int nRank)
{
// sanity check
if (sTarget == "")
{
PrintString("ERROR: invalid target passed to gc_skill_rank_npc");
return FALSE;
}
object oTarget = GetTarget(sTarget);
if (GetIsObjectValid(oTarget))
{
int nSkillVal = GetSkillConstant(nSkill);
if (GetSkillRank(nSkillVal, oTarget) >= nRank)
{
return TRUE;
}
}
return FALSE;
}
Dear Scripting Gods, Is there a ga_script that can modify a creatureâs tag? Something that retrieves the tag of the creature (Get STarget by Tag) then changes the Tag to a new string. The idea is to use the script to toggle who the âtargetâ is and reduce the number of nodes in my convo by changing the tag of the enemy instead of having a dozen paths in my conversation file. Support is greatly appreciated!!!
a clearcut situation would be helpful, and a desired result
usually you donât want to modify a creatureâs tag ⌠instead, perhaps, you might want a script to find a target-creature (whatever its tag is), and work with the creature-object directly
Maybe the best way to explain this is by looking at the ga_create_obj script. The script retrieves the ResRef of the Object, then gives the option to create a NewTag for the object (different than the one that corresponds to the Blueprint.) Similarly, I want to retrieve the tag of a creature, letâs say the tag is âEnemy_Leaderâ, then change that creatureâs tag to a new tag, âEnemy_Targetâ. This will then allow me to use âEnemy_Targetâ in the Speaker or Listener nodes and for Camera placement purposes in the Conversation editor. I am designing a turn-based battling system that is a conversation file. If I canât change the creatureâs tag with a conversational action script, then I will have to have separate branching paths for all the Enemies in the formation by tag to get the cameras and effects to fire (Leader, LGuard, RGuard, LWing, RWing, SupportLead, RSupport, LSupport). I hope that makes sense!
So in review, I want a ga_ script that asks for the String of the Creatureâs tag and then asks for a new string for the creatureâs new tag. I want to change the creatureâs tag.
// ga_change_tag
/*
Finds the object with the specified tag and changes its tag to a new one.
If there are several objects with the same tag, the first one closest
to the conversation owner will be chosen in that case.
*/
#include "ginc_param_const"
void main(string sCurrentTag, string sNewTag)
{
if (sCurrentTag == "" || sNewTag == "")
{
PrintString("ERROR: empty parameter(s) passed to ga_change_tag");
return;
}
object oTarget = GetTarget(sCurrentTag);
if (GetIsObjectValid(oTarget))
{
SetTag(oTarget, sNewTag);
}
}