sitting script
#1
Posté 18 décembre 2014 - 12:12
#2
Posté 18 décembre 2014 - 12:29
The NWN1 sitting scripts don't work in NWN2, and there's not a built-in script you can call for it. You can get a replacement sitting system on the Vault, or you can just play any of the sitting animations directly and jump the character to the location of a chair, which you can get by a unique tag, or by getting the nearest object with a chair-type tag you choose, etc. Just keep the sitting animation playing in the character's heartbeat.
You can see several sitting animations and sittable chairs in use in my campaign if you want an example (there's one in the starting room, and many downstairs in the inn), and check out the scripts on them.
#3
Posté 18 décembre 2014 - 12:38
You might like my commoner ai package. http://neverwinterva...ric-commoner-ai
videos of it in action:
defenders getting up to protect the pc, then sitting back down in their chairs once combat is over
day/night schedules, including selecting a home for the night.
#4
Posté 18 décembre 2014 - 12:58
#5
Posté 18 décembre 2014 - 01:02
What are the sitting animations called and where do I find them?
may as well give you the list of animations for reference.
http://nwn2.wikia.co...t_of_animations
#6
Posté 18 décembre 2014 - 01:30
#7
Posté 18 décembre 2014 - 03:20
You don't need a prefix for those. Use the PlayCustomAnimation function and just pass in the name of the animation in that list, such as "sitidle". Keep that list handy. I have a copy saved.
#8
Posté 19 décembre 2014 - 01:23
#9
Posté 19 décembre 2014 - 01:25
#10
Posté 19 décembre 2014 - 01:28
#11
Posté 19 décembre 2014 - 01:30
#12
Posté 19 décembre 2014 - 01:43
yes.
if you put "PlayCustomAnimation" into Script Assist filter, and click 'functions' (or whatever it is), this should come up:
// FAK - OEI 5/16/05 // Returns TRUE if it found an object to play a custom animation one // oObject is the object to play the animation on // sAnimationName is the name of the gr2 to play // nLooping is 0 for one-off, 1 for loop // fSpeed is the playback speed: 1.0 is default, < 0 is backwards int PlayCustomAnimation( object oObject, string sAnimationName, int nLooping, float fSpeed = 1.0f );
eg:
PlayCustomAnimation(oNPC, "sitidle", 1);
(there might be tricks needed, like writing a wrapper if you want to delay the command, or using "*" before the anim-string when using a combat related animation - see the link )
#13
Posté 19 décembre 2014 - 01:47
once you've assigned a looping animation, you *might* not have to recall PlayCustomAnimation each heartbeat
instead, when the animation should stop, call the function again and use "%" as the string - I think that means 'no animation'
#14
Posté 19 décembre 2014 - 02:07
I didn't know that about the "no animation" string. I'd been telling it to play "idle" when I want the custom animation to stop. ![]()
You don't need to call PlayCustomAnimation each heartbeat if it's looping, unless something interrupts the playback. For instance, walking past the NPC and bumping it, or perhaps talking to it (assuming nodes are set to the default "idle" animation). Or if it senses a hostile creature nearby. Some of these things are solved by making the NPC unbumpable, immobile, and setting them not to turn to face the PC on dialogue.
#15
Posté 19 décembre 2014 - 05:14
For what it's use, here's a heartbeat script I used for seated bar patrons.
// ms_pub_sit_hb
/*
This is a custom heartbeat script adopted from
3030_fplace_dwarf_hb in the original campaign.
It is used by seated, non-bark stringing NPCs.
*/
// 25apr12 RJH
#include "ginc_misc"
#include "ginc_math"
#include "ginc_wp"
const string CURR_ANIM = "CurrAnim";
const int ANIM_IDLE = 0;
const int ANIM_DRINK = 1;
const int ANIM_TALK = 2;
void PlayCustomLoopingAnimation(object oObject, string sAnimationName)
{
PlayCustomAnimation(oObject, sAnimationName, 1);
}
void PlayCustomOneShotAnimation(object oObject, string sAnimationName)
{
PlayCustomAnimation(oObject, sAnimationName, 0);
}
// Perform an animation of the same type
void RepeatAnim( object oActor )
{
int nLastAnim = GetLocalInt( oActor, CURR_ANIM );
switch ( nLastAnim ) {
case ANIM_IDLE:
default:
if ( d2(1) == 1 ) {
PlayCustomLoopingAnimation(oActor, "sitidle");
} else {
PlayCustomLoopingAnimation(oActor, "sitfidget");
}
break;
case ANIM_DRINK:
if ( d2(1) == 1 ) {
PlayCustomLoopingAnimation(oActor, "sitdrink");
} else {
PlayCustomLoopingAnimation(oActor, "sitdrinkidle");
}
break;
case ANIM_TALK:
if ( d2(1) == 1 ) {
PlayCustomLoopingAnimation(oActor, "sittalk01");
} else {
PlayCustomLoopingAnimation(oActor, "sittalk02");
}
break;
}
}
// Perform a random animation
void RandomAnim( object oActor )
{
int nNextAnim = ANIM_IDLE;
int nRandom = d10(1);
switch( nRandom ) {
case 0:
PlayCustomLoopingAnimation(oActor, "sitidle");
break;
case 1:
PlayCustomLoopingAnimation(oActor, "sitfidget");
break;
case 2:
case 3:
PlayCustomLoopingAnimation(oActor, "sitdrink");
nNextAnim = ANIM_DRINK;
break;
case 4:
case 5:
PlayCustomLoopingAnimation(oActor, "sitdrinkidle");
nNextAnim = ANIM_DRINK;
break;
case 6:
case 7:
PlayCustomLoopingAnimation(oActor, "sittalk01");
nNextAnim = ANIM_TALK;
break;
case 8:
case 9:
PlayCustomLoopingAnimation(oActor, "sittalk02");
nNextAnim = ANIM_TALK;
break;
default:
PlayCustomLoopingAnimation(oActor, "sitidle");
break;
}
SetLocalInt( oActor, CURR_ANIM, nNextAnim );
}
void main()
{
if (GetAILevel(OBJECT_SELF) == AI_LEVEL_VERY_LOW)
{
return;
}
object oActor = OBJECT_SELF;
if (GetLocalInt(oActor, "SetDefaultAnimation") == 0)
{
AssignCommand(oActor, PlayCustomLoopingAnimation(oActor, "sitidle"));
SetLocalInt(oActor, "SetDefaultAnimation", 1);
}
if ( d10(1) < 6 ) {
RepeatAnim( oActor );
} else {
RandomAnim( oActor );
}
}
Probably redundant at this point.
#16
Posté 19 décembre 2014 - 08:05
instead, when the animation should stop, call the function again and use "%" as the string - I think that means 'no animation'
I found a comment in a script (but I can't remember if that was custom or stock) explaining
percent sign to set the looping animations to defaults
#17
Posté 19 décembre 2014 - 09:30
#18
Posté 19 décembre 2014 - 12:29
void main()
{
object oMrDrunk = OBJECT_SELF;
PlayCustomAnimation(oMrDrunk, "sitdrink", 1);
}see what i did thar?
that doesn't mean it'll work, but you should really look up some NwScript tutorials/ basics.
#19
Posté 20 décembre 2014 - 12:57
#20
Posté 20 décembre 2014 - 01:21
For what it's use, here's a heartbeat script I used for seated bar patrons.
// ms_pub_sit_hb /* This is a custom heartbeat script adopted from 3030_fplace_dwarf_hb in the original campaign. It is used by seated, non-bark stringing NPCs. */ // 25apr12 RJH #include "ginc_misc" #include "ginc_math" #include "ginc_wp" const string CURR_ANIM = "CurrAnim"; const int ANIM_IDLE = 0; const int ANIM_DRINK = 1; const int ANIM_TALK = 2; void PlayCustomLoopingAnimation(object oObject, string sAnimationName) { PlayCustomAnimation(oObject, sAnimationName, 1); } void PlayCustomOneShotAnimation(object oObject, string sAnimationName) { PlayCustomAnimation(oObject, sAnimationName, 0); } // Perform an animation of the same type void RepeatAnim( object oActor ) { int nLastAnim = GetLocalInt( oActor, CURR_ANIM ); switch ( nLastAnim ) { case ANIM_IDLE: default: if ( d2(1) == 1 ) { PlayCustomLoopingAnimation(oActor, "sitidle"); } else { PlayCustomLoopingAnimation(oActor, "sitfidget"); } break; case ANIM_DRINK: if ( d2(1) == 1 ) { PlayCustomLoopingAnimation(oActor, "sitdrink"); } else { PlayCustomLoopingAnimation(oActor, "sitdrinkidle"); } break; case ANIM_TALK: if ( d2(1) == 1 ) { PlayCustomLoopingAnimation(oActor, "sittalk01"); } else { PlayCustomLoopingAnimation(oActor, "sittalk02"); } break; } } // Perform a random animation void RandomAnim( object oActor ) { int nNextAnim = ANIM_IDLE; int nRandom = d10(1); switch( nRandom ) { case 0: PlayCustomLoopingAnimation(oActor, "sitidle"); break; case 1: PlayCustomLoopingAnimation(oActor, "sitfidget"); break; case 2: case 3: PlayCustomLoopingAnimation(oActor, "sitdrink"); nNextAnim = ANIM_DRINK; break; case 4: case 5: PlayCustomLoopingAnimation(oActor, "sitdrinkidle"); nNextAnim = ANIM_DRINK; break; case 6: case 7: PlayCustomLoopingAnimation(oActor, "sittalk01"); nNextAnim = ANIM_TALK; break; case 8: case 9: PlayCustomLoopingAnimation(oActor, "sittalk02"); nNextAnim = ANIM_TALK; break; default: PlayCustomLoopingAnimation(oActor, "sitidle"); break; } SetLocalInt( oActor, CURR_ANIM, nNextAnim ); } void main() { if (GetAILevel(OBJECT_SELF) == AI_LEVEL_VERY_LOW) { return; } object oActor = OBJECT_SELF; if (GetLocalInt(oActor, "SetDefaultAnimation") == 0) { AssignCommand(oActor, PlayCustomLoopingAnimation(oActor, "sitidle")); SetLocalInt(oActor, "SetDefaultAnimation", 1); } if ( d10(1) < 6 ) { RepeatAnim( oActor ); } else { RandomAnim( oActor ); } }Probably redundant at this point.
This is useful. I want to do something like this. Now I'm trying to figure out how to get him to grab a chair.
#21
Posté 20 décembre 2014 - 02:03
This is useful. I want to do something like this. Now I'm trying to figure out how to get him to grab a chair.
In my commoner AI, they can establish an origin and facing on their first heartbeat. They will then return to their origin, facing, and activity automatically if they are not busy doing something else (seen for instance in the video where the elf returns to his seat once his combat is over). I did this all in heartbeat to make it as easy as possible for an inexperience builder to implement, you could also set up the origin point etc in the OnSpawn script. My ai assumes the chairs are environmental objects, they are not active objects for the player to use, however the npc is in the spot so the pc can't walk through the environmental chair, as the pc bumps into the npc who is in that space. It may not do exactly what you want, but feel free to pillage from it (with attribution of course :-) ).
#22
Posté 20 décembre 2014 - 07:52
#23
Posté 20 décembre 2014 - 08:31
You can set him to be unbumpable in his character properties. If/when you get more comfortable with scripting, you can toggle whether he's bumpable or not, for instance to make him unbumpable only when he's in the chair.
The chair doesn't have to be (and shouldn't be) usable if you intend to have the NPC in that chair all the time, or else the PC may accidentally click on the chair instead of the NPC. It would need to be a placeable and not an environmental object if you want to refer to it by its tag in a script, in which case the chair should be set to "walkable" in its properties so that the NPC can occupy the same space as the chair and sit in it.
There are dozens of different ways of handling sitting in a chair, and we're all giving you methods that work, but which may not necessarily work together.
#24
Posté 20 décembre 2014 - 08:34
take 2: assumes you're placing the NPC in the toolset (not spawning).
- place him in the chair with proper orientation
- on his Properties page:
- give him an int_variable "NX2_NO_ORIENT_ON_DIALOG", set it to TRUE ( or "1")
- make him unbumpable, in the Bumpable dropdown
you might want to clear some/most of his AI script-slots, so he just sits there drinking.*
* not the onSpawn or onHB, but pretty much all the others can be blank
#25
Posté 20 décembre 2014 - 10:49
* not the onSpawn or onHB, but pretty much all the others can be blank
Should keep the On Conversation, too, if you want to talk to him.





Retour en haut






