Name: lib_weight (plus
examples, tr_enter_weight and tr_exit_weight)
What it does: An include library to give you some weighing
functions, with values taken from the PHB and MM (except where NWN
differs, in which case NWN wins for consistency's sake). Functions
include:
(list)
(*)int GetCreatureWeight(object oCritter);
(*)int GetInventoryWeight( object oToWeigh );
(*)float GetItemWeight( object oItem );
(*)int GetSphereWeight(location center, float radius, int threshold);
(*)int GetCubeWeight(location center, float halfSide, int threshold);
(/list-incomplete)
Notes: Documented in the script itself. Note also:
(list)
(*)I've left debug comments in the GetInventoryWeight() function.
(*)GetInventoryWeight() includes the weight of equipped items
(*)NWN takes care of Magic bags for me
(*)There's also a GetShapeWeight, but I don't recommend you use it...
the GetCube and GetSphere functions just wrap it.
(*)tr_enter_weight automatically adds the weight of the entering object,
but the GetSphere with a low radius doesn't seem to pick other critters
as I would expect. I fear that's because they somehow fall outside the
sphere. I wanted to use GetNearestCreatureToLocation(), and check its
distance from the center, but I couldn't quite get it to work as I
expected. Which is a bummer. I'll keep trying, though.
(/list-incomplete)
How to use: I wrote this because someone PMed me asking about
pressure plates. Looking at the Pressure Plate placeables, I figured
that they didn't, by default, have the smarts to do 'real' pressure
plate logic, and would probably need to have their inventories filled or
something naff like that. I wanted a pressure plate that a PC would
have to leave something heavy on to hold a door open. Like 100lbs
worth of heavy - another PC, a couple of suits of Full Plate, whatever -
it should be hard. When populating dungeons, I want to be able to
include triggers that a player or party has to reason about, rather than
accept the prevailing game paradigm of "Look, a glowing thing called
'Pressure Plate', and it's got an inventory! Look! A rock! Hmmm... let's
put the rock in the Pressure Plate's inventory... Bingo!".
Hence the library. Here's how I've used it in my experimental dungeon:
- (Optional) Paint a round Pressure Plate into your area. I made
mine usable, but with no inventory, so it glows on mouse hover, but
you can't open it and 'fill' it with junk.
- Paint a Generic Trigger around the pressure plate. If you zoom
right in, and the plate's in the right spot, you can form a decent
octagon that fits exactly right.
- There's a door nearby. I have two scripts called open_door and
close_door that tell it to open and close. When it closes, it locks
itself. (There's also open_door_time that's on a trigger on the other
side of the door from the pressure plate. It's timed to shut the door,
trapping the PC in the room with the plate).
- Put the tr_enter_weight script in the trigger's onEnter event
- Put the tr_exit_weight script in the trigger's onEnter event
- EDIT BOTH SCRIPTS - there are things you MUST change to get it to
work
- That should be it, really.
lib_weight(b)
NWScript:
int GetCreatureWeight( object oCritter);
float GetItemWeight( object oToWeigh );
int GetInventoryWeight( object oToWeigh );
int GetSphereWeight( location center, float radius, int threshold);
int GetCubeWeight(location center, float halfSide, int threshold);
int GetShapeWeight( location center, float radius, int threshold, int iShape);
void debug(string sMsg);
int GetSphereWeight( location center, float radius, int threshold) {
return GetShapeWeight( center, radius, threshold, SHAPE_SPHERE);
}
int GetCubeWeight( location center, float halfSide, int threshold) {
return GetShapeWeight( center, halfSide, threshold, SHAPE_CUBE);
}
int GetShapeWeight( location center, float radius, int threshold, int iShape) {
float iWeightSoFar = 0.0;
int iObjType = OBJECT_TYPE_CREATURE|OBJECT_TYPE_ITEM;
object oOnPlate = GetFirstObjectInShape( iShape, radius, center, FALSE, iObjType);
while (OBJECT_INVALID != oOnPlate) {
switch (GetObjectType( oOnPlate ) ){
case OBJECT_TYPE_CREATURE :
iWeightSoFar += IntToFloat( GetCreatureWeight( oOnPlate ) );
break;
case OBJECT_TYPE_ITEM :
iWeightSoFar += GetItemWeight( oOnPlate );
break;
default:
}
if ( threshold && FloatToInt( iWeightSoFar ) > threshold) break;
if (GetHasInventory( oOnPlate ) ) {
iWeightSoFar += GetInventoryWeight( oOnPlate );
}
oOnPlate = GetNextObjectInShape( iShape, radius, center, FALSE, iObjType);
}
return FloatToInt( iWeightSoFar );
}
int GetCreatureWeight( object oCritter) {
if ( GetObjectType( oCritter ) != OBJECT_TYPE_CREATURE ) {
debug("Object is not a creature");
return 0;
}
switch ( GetRacialType( oCritter ) ) {
case RACIAL_TYPE_DWARF:
if (GetGender( oCritter ) == GENDER_MALE ) return 135;
return 105;
case RACIAL_TYPE_ELF:
if (GetGender( oCritter ) == GENDER_MALE ) return 105;
return 100;
case RACIAL_TYPE_GNOME:
if (GetGender( oCritter ) == GENDER_MALE ) return 45;
return 40;
case RACIAL_TYPE_HALFELF:
if (GetGender( oCritter ) == GENDER_MALE ) return 145;
return 125;
case RACIAL_TYPE_HALFLING:
if (GetGender( oCritter ) == GENDER_MALE ) return 35;
return 30;
case RACIAL_TYPE_HALFORC:
if (GetGender( oCritter ) == GENDER_MALE ) return 205;
return 185;
case RACIAL_TYPE_HUMAN:
if (GetGender( oCritter ) == GENDER_MALE ) return 195;
return 180;
default:
switch ( GetCreatureSize( oCritter ) ) {
case CREATURE_SIZE_HUGE:
return 4000;
case CREATURE_SIZE_LARGE:
return 500;
case CREATURE_SIZE_MEDIUM:
return 155;
case CREATURE_SIZE_SMALL:
return 34;
case CREATURE_SIZE_TINY:
return 5;
case CREATURE_SIZE_INVALID:
default:
return 0;
}
}
return 0;
}
float GetItemWeight( object oToWeigh ) {
if (GetObjectType( oToWeigh ) != OBJECT_TYPE_ITEM) return 0.0;
float iWeight = 0.0f;
switch ( GetBaseItemType( oToWeigh ) ) {
case BASE_ITEM_DOUBLEAXE :
iWeight = 25.0;
break;
case BASE_ITEM_HEAVYFLAIL :
case BASE_ITEM_GREATAXE :
iWeight = 20.0;
break;
case BASE_ITEM_TOWERSHIELD :
iWeight = 19.4;
break;
case BASE_ITEM_GREATSWORD :
case BASE_ITEM_HALBERD :
iWeight = 15.0;
break;
case BASE_ITEM_DIREMACE :
case BASE_ITEM_SCYTHE :
iWeight = 12.0;
break;
case BASE_ITEM_BASTARDSWORD :
case BASE_ITEM_LARGESHIELD :
case BASE_ITEM_KATANA :
iWeight = 10.0;
break;
case BASE_ITEM_HEAVYCROSSBOW :
iWeight = 9.0;
break;
case BASE_ITEM_MORNINGSTAR :
case BASE_ITEM_WARHAMMER :
iWeight = 8.0;
break;
case BASE_ITEM_BATTLEAXE :
iWeight = 7.0;
break;
case BASE_ITEM_LIGHTMACE :
case BASE_ITEM_LIGHTCROSSBOW :
iWeight = 6.0;
break;
case BASE_ITEM_SHORTSPEAR :
case BASE_ITEM_HANDAXE :
case BASE_ITEM_LIGHTFLAIL :
case BASE_ITEM_SMALLSHIELD :
iWeight = 5.0;
break;
case BASE_ITEM_TWOBLADEDSWORD :
iWeight = 4.4;
break;
case BASE_ITEM_QUARTERSTAFF :
case BASE_ITEM_THROWINGAXE :
case BASE_ITEM_LONGSWORD :
case BASE_ITEM_SCIMITAR :
case BASE_ITEM_MAGICSTAFF :
iWeight = 4.0;
break;
case BASE_ITEM_CLUB :
case BASE_ITEM_SICKLE :
case BASE_ITEM_RAPIER :
case BASE_ITEM_SHORTSWORD :
case BASE_ITEM_LONGBOW :
case BASE_ITEM_KUKRI :
iWeight = 3.0;
break;
case BASE_ITEM_LIGHTHAMMER :
case BASE_ITEM_SHORTBOW :
case BASE_ITEM_HELMET :
case BASE_ITEM_MAGICROD :
iWeight = 2.0;
break;
case BASE_ITEM_KAMA :
case BASE_ITEM_GLOVES :
case BASE_ITEM_DAGGER :
case BASE_ITEM_MAGICWAND :
case BASE_ITEM_BELT :
case BASE_ITEM_BOOK :
case BASE_ITEM_BRACER :
case BASE_ITEM_LARGEBOX :
iWeight = 1.0;
break;
case BASE_ITEM_AMULET :
case BASE_ITEM_BOOTS :
case BASE_ITEM_HEALERSKIT :
case BASE_ITEM_MISCMEDIUM :
case BASE_ITEM_MISCLARGE :
case BASE_ITEM_THIEVESTOOLS :
case BASE_ITEM_TRAPKIT :
iWeight = 0.5;
break;
case BASE_ITEM_MISCSMALL :
iWeight = 0.3;
break;
case BASE_ITEM_TORCH :
case BASE_ITEM_POTIONS :
case BASE_ITEM_RING :
case BASE_ITEM_KEY :
case BASE_ITEM_SCROLL :
case BASE_ITEM_SPELLSCROLL :
case BASE_ITEM_DART :
iWeight = 0.1;
break;
case BASE_ITEM_ARMOR :
switch ( GetItemACValue( oToWeigh ) ) {
case 8 :
case 7 :
iWeight = 50.0;
break;
case 6 :
iWeight = 45.0;
break;
case 5 :
iWeight = 40.0;
break;
case 4 :
iWeight = 30.0;
break;
case 3 :
iWeight = 15.0;
break;
case 2 :
iWeight = 10.0;
break;
case 1 :
iWeight = 5.0;
break;
case 0 :
default: iWeight = 1.0;
}
break;
case BASE_ITEM_BULLET :
case BASE_ITEM_SHURIKEN :
case BASE_ITEM_BOLT :
case BASE_ITEM_ARROW :
case BASE_ITEM_CREATUREITEM :
case BASE_ITEM_CSLASHWEAPON :
case BASE_ITEM_CPIERCWEAPON :
case BASE_ITEM_CBLUDGWEAPON :
case BASE_ITEM_CSLSHPRCWEAP :
case BASE_ITEM_SLING :
case BASE_ITEM_GEM :
case BASE_ITEM_GOLD :
case BASE_ITEM_MISCTALL :
case BASE_ITEM_MISCWIDE :
default:
iWeight = 0.0;
}
return iWeight * IntToFloat( GetNumStackedItems( oToWeigh ) );
}
int GetInventoryWeight( object oToWeigh ) {
float iTotalWeight = 0.0;
object oItem;
int iSlot;
for ( iSlot = 0; iSlot < NUM_INVENTORY_SLOTS; iSlot++ ) {
oItem = GetItemInSlot( iSlot, oToWeigh);
if ( OBJECT_INVALID != oItem ) {
debug( GetName( oItem ) + " weighs " + FloatToString( GetItemWeight( oItem ) ) );
iTotalWeight += GetItemWeight( oItem );
}
}
oItem = GetFirstItemInInventory( oToWeigh );
while ( OBJECT_INVALID != oItem ) {
debug( GetName( oItem ) + " weighs " + FloatToString( GetItemWeight( oItem ) ) );
iTotalWeight += GetItemWeight( oItem );
oItem = GetNextItemInInventory( oToWeigh );
}
return FloatToInt( iTotalWeight );
}
void debug(string sMsg) {
SendMessageToPC(GetFirstPC(),sMsg);
SendMessageToAllDMs(sMsg);
}
(b)tr_enter_weight
NWScript:
#include "lib_weight"
void say(string sMessage);
int GetPlateWeight();
float fRadius = 0.5f;
int iThreshold = 100;
int iOldWeight = 0;
location lSource;
vector vCenter;
object oIntruder;
void main()
{
oIntruder = GetEnteringObject();
lSource = GetLocation( OBJECT_SELF);
vCenter = GetPositionFromLocation( lSource) + Vector(0.5f, -0.5f, 0.0f);
lSource = Location( GetAreaFromLocation(lSource), vCenter,0.0f);
iOldWeight = GetLocalInt( OBJECT_SELF, "weighted");
int iNew = GetPlateWeight();
SetLocalInt( OBJECT_SELF, "weighted", iNew);
if (iOldWeight >= iThreshold) return;
if ( (iNew >= iThreshold) && (iOldWeight < iThreshold) ) {
ExecuteScript( "open_door", OBJECT_SELF);
effect eVis = EffectVisualEffect( VFX_FNF_SMOKE_PUFF);
ApplyEffectAtLocation( DURATION_TYPE_TEMPORARY, eVis, lSource);
}
}
int GetPlateWeight() {
int iWeightSoFar = GetCreatureWeight( oIntruder );
iWeightSoFar += GetInventoryWeight( oIntruder );
iWeightSoFar += GetSphereWeight( lSource, fRadius, iThreshold);
return iWeightSoFar;
}
void say(string sMsg) {
SendMessageToPC( GetFirstPC(),sMsg);
SendMessageToAllDMs( GetFirstPC(),sMsg);
}
tr_exit_weight
NWScript:
#include "lib_weight"
void say(string sMessage);
float fRadius = 0.5f;
int iThreshold = 100;
int iOldWeight = 0;
int bExited = FALSE;
int bChanged = FALSE;
location lSource;
vector vCenter;
void main()
{
lSource = GetLocation( OBJECT_SELF);
vCenter = GetPositionFromLocation( lSource) + Vector(0.5f, -0.5f, 0.0f);
lSource = Location( GetAreaFromLocation(lSource), vCenter,0.0f);
iOldWeight = GetLocalInt( OBJECT_SELF, "weighted");
int iNew = GetSphereWeight( lSource, fRadius, iThreshold);
SetLocalInt(OBJECT_SELF, "weighted", iNew);
bChanged = (((iOldWeight >= iThreshold) && (iNew < iThreshold)) ||
((iOldWeight < iThreshold) && (iNew >= iThreshold)));
if ( bChanged ) {
if (iOldWeight >= iThreshold) {
ExecuteScript("close_door", OBJECT_SELF);
}
if (iOldWeight < iThreshold) {
ExecuteScript("open_door", OBJECT_SELF);
}
effect eVis = EffectVisualEffect( VFX_FNF_SMOKE_PUFF);
ApplyEffectAtLocation( DURATION_TYPE_TEMPORARY, eVis, lSource);
}
}
void say(string sMsg) {
object oSpeaker = GetNearestObject( OBJECT_TYPE_CREATURE, OBJECT_SELF );
if ( (GetDistanceBetweenLocations( GetLocation( oSpeaker ), lSource ) < 3 * fRadius) && GetIsObjectValid( oSpeaker) )
FloatingTextStringOnCreature( sMsg, oSpeaker, FALSE );
else {
SendMessageToPC( GetFirstPC(),sMsg);
AssignCommand( GetObjectByTag( "plateDoorOpen"),
ActionSpeakString( sMsg, TALKVOLUME_TALK));
}
}
Cheers,
Iskander
________________
Simple Quest Creation Walkthrough - no scripting required
Korak's NWNScript reference
|