There will be a number of checks to see wether the player misses or hits, a reflex save for the target, and finally a strength check to see wether the snowball knocks the target down or not. The targeting mechanism of NWN forces the player to move within an 8 metre radius, so there's no snowball sniping unfortunately... Also, there's no visual snowball because there are simply no a models which could be used for that. Fake spells do cast a white blob at players, but that requires a conjure animation and sounds, which look odd in my opinion...
This part is finished, but there will be gaming elements, e.g. number of headshots, hits, misses, etc. Have fun

---
Create a custom gauntlet, and give it a tag, I used "SnowGloves".
In your module's OnActivateItem, place the lines
Code: Select all
#include "snowfight"
if(GetTag(GetItemActivated()) == "SnowGloves") CheckReady(GetItemActivator());
Code: Select all
/*
September 16, 2003 - Eric Ettes - Raiko - zeiren@hotmail.com
A simple snowball throwing game
Please do not modify
*/
void AttackMoan(object oPlayer){
switch(d3()){
case 1 : AssignCommand(oPlayer, PlayVoiceChat(VOICE_CHAT_GATTACK1));
case 2 : AssignCommand(oPlayer, PlayVoiceChat(VOICE_CHAT_GATTACK2));
case 3 : AssignCommand(oPlayer, PlayVoiceChat(VOICE_CHAT_GATTACK3));
}
}
void Moan(object oPlayer){
switch(d3()){
case 1 : AssignCommand(oPlayer, PlayVoiceChat(VOICE_CHAT_PAIN1));
case 2 : AssignCommand(oPlayer, PlayVoiceChat(VOICE_CHAT_PAIN2));
case 3 : AssignCommand(oPlayer, PlayVoiceChat(VOICE_CHAT_PAIN3));
}
}
int FrontBack(float fPlayerFacing, float fTargetFacing){
if((fPlayerFacing + 90.0) > fTargetFacing && (fPlayerFacing - 90.0) < fTargetFacing){
return 2;
}
return 1;
}
void Impact(object oPlayer, int Type){
ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_IMP_FROST_L), oPlayer);
switch(Type){
case 1 : AssignCommand(oPlayer, ActionPlayAnimation(ANIMATION_LOOPING_DEAD_BACK, 1.0, 0.5)); break;
case 2 : AssignCommand(oPlayer, ActionPlayAnimation(ANIMATION_LOOPING_DEAD_FRONT, 1.0, 0.5)); break;
case 3 : break;
}
}
void FireSnowball(object oPlayer, object oTarget){
int iDistance = FloatToInt(GetDistanceBetween(oPlayer, oTarget));
int iSize = GetCreatureSize(oTarget);
int iStr = GetAbilityScore(oPlayer, ABILITY_STRENGTH);
int iDex = GetAbilityScore(oPlayer, ABILITY_DEXTERITY);
int iHitPercentage = ((iDex - iDistance) * iSize) * GetAbilityModifier(ABILITY_DEXTERITY, oPlayer);
int iHit = d100();
int iDC = iStr + iSize - iDistance;
int iReflexSave;
if(iHitPercentage > 100) iHitPercentage = 100;
iReflexSave = ReflexSave(oTarget, iDC, SAVING_THROW_TYPE_COLD);
if(iHit <= iHitPercentage){
if(iReflexSave == 0){
if(d20() + iStr >= 30){
Impact(oTarget, FrontBack(GetFacing(oPlayer), GetFacing(oTarget)));
AssignCommand(oPlayer, ActionSpeakString("*Hits " + GetName(oTarget) + " where it hurts*"));
AssignCommand(oTarget, PlayVoiceChat(VOICE_CHAT_DEATH));
}
else
if(d20() + iStr < 30){
Impact(oTarget, 3);
AssignCommand(oPlayer, ActionSpeakString("*Hits " + GetName(oTarget) + "*"));
Moan(oTarget);
}
}
else
if(iReflexSave == 1){
AssignCommand(oTarget, ActionSpeakString("*Dodges " + GetName(oPlayer) + "'s snowball*"));
AssignCommand(oTarget, ActionPlayAnimation(ANIMATION_FIREFORGET_DODGE_SIDE, 1.0));
AssignCommand(oTarget, PlayVoiceChat(VOICE_CHAT_LAUGH));
}
else
if(iReflexSave == 2){
SendMessageToPC(oPlayer, "Your target is immune to cold.");
AssignCommand(oTarget, ActionSpeakString("*Dodges " + GetName(oPlayer) + "'s snowball*"));
AssignCommand(oTarget, PlayVoiceChat(VOICE_CHAT_LAUGH));
}
}
else if(iHit > iHitPercentage){
AssignCommand(oPlayer, ActionSpeakString("*Misses " + GetName(oTarget) + "*"));
AssignCommand(oTarget, PlayVoiceChat(VOICE_CHAT_LAUGH));
}
}
void AimAndFire(object oPlayer, object oTarget){
AssignCommand(oPlayer, ActionSpeakString("*Picks up some snow for a snowball*"));
AssignCommand(oPlayer, ActionPlayAnimation(ANIMATION_LOOPING_GET_LOW, 1.0, 1.0));
AssignCommand(oPlayer, ActionPlayAnimation(ANIMATION_LOOPING_CONJURE1, 1.0, 3.0));
DelayCommand(3.5, AssignCommand(oPlayer, ActionSpeakString("*Aims for " + GetName(oTarget) + "*")));
DelayCommand(5.2, AssignCommand(oPlayer, ActionPlayAnimation(ANIMATION_FIREFORGET_SALUTE, 1.0)));
DelayCommand(5.3, AttackMoan(oPlayer));
DelayCommand(5.5, FireSnowball(oPlayer, oTarget));
}
void CheckReady(object oPlayer){
if(GetWeather(GetArea(oPlayer)) != WEATHER_SNOW){
SendMessageToPC(oPlayer, "There's no snow to throw around with.");
return;
}
if(GetTag(GetItemInSlot(INVENTORY_SLOT_ARMS, oPlayer)) != "SnowGloves"){
SendMessageToPC(oPlayer, "You should equip the snowgloves to be able to use them.");
return;
}
AimAndFire(GetItemActivator(), GetItemActivatedTarget());
}