Kissing Animation, Ability Increase Script, Pelvis Modification in game

@NeverKnight It’s not so much how it works but how it looks. It might not be what you want. That’s why I gave you the links. 1st grab the pdf version of the readme that I did (it’s at the end of that review) and have a read. Then follow the link at the top of that review and download the package and give the demo module a try. Only then will you know if it suits your needs.

TR

I was corresponding and working with NinjaWeaselMan at the time, so I know a bit about what happened with that. Intimate Animations was released first. He’d packaged and released it so that others could use it as an add-on hak, and was upset that it was more or less immediately taken and subsumed into a number of other systems without what he felt was proper permission or credit. This was back in the days of the old IGN Vault, at a time when CC authors were first fighting to be able to mark content to not be automatically treated as “open,” and to have those wishes respected. His disillusionment with how all of that worked out at the time was what led him to decide not to release the RAS as a separate hak at all, but instead to make it part of Project Q (which was not open at the time). He pretty much disappeared from the NWN community after that.

@Tarot_Redhand: I’ve read the pdf. It’s intended for multiplayer? I’m developing a single player module.

I’ve downloaded tiamat’s Ultimate Animations pack from the link given by @xorbaxian.

It’s just when I use the following script:

//Jump and butt wiggle

void main()
{
object oPC = GetPCSpeaker();
object oGuy = GetObjectByTag(“Adam”);

ClearAllActions();

ActionJumpToObject(GetObjectByTag(“WP_Him”));
ActionPlayAnimation(ANIMATION_LOOPING_CUSTOM1, 1.0, 999.0);

AssignCommand(oPC, ClearAllActions());
AssignCommand(oPC, ActionJumpToObject(GetObjectByTag(“WP_Her”)));
AssignCommand(oPC, ActionPlayAnimation(ANIMATION_LOOPING_CUSTOM2, 1.0, 999.0));
}

The animations won’t play when I tested them. So I was wondering, is there something wrong about the script above? Did I miss something?

New question,

Is there an on death script to make sure that the PC stays dead if they’re killed and cannot respawn?

there are actually lots of possible reasons this could be failing. here are some things you could check :

  • what you’ve written will theoretically cause the npc speaking to the pc to perform the actions. is this what you want ? i ask because although i see you’ve instanced the variable oHim, it’s never used anywhere, so if ‘adam’ is the one you want to be wiggling and jiggling, your script won’t do that.
  • are you sure the waypoints exist and have those tags ?
  • are you sure you’ve added the hak pack ?

you might want to test the animations to make sure that they can be executed in a simple situation before you integrate them into more complicated situations. one way to do this is by calling them up ‘from the command line’ [i.e., using player chat]. write a simple test script that you can call from the chat bar ; go to Edit => module properties and enter the name of a script you want to use :
chat

copy/paste this into the script :

void main()
{
    object pc = GetPCChatSpeaker();
    int anim = StringToInt(GetPCChatMessage());

    if (anim < 1 || anim > 20) {
        SendMessageToPC(pc, "type a number 1-20 only");
        return;
    }

    AssignCommand(pc, ClearAllActions());
    AssignCommand(pc, ActionPlayAnimation(ANIMATION_LOOPING_CUSTOM1 + anim - 1, 1.0, RoundsToSeconds(1)));
}

when you fire up your mod, hit the carriage return to put your cursor into the chat bar, then type a number 1-20 followed by carriage return. your character should perform the custom animation you selected. if not, there’s a problem w/the hak.

sure. once again on the module properties window, edit the OnPlayerDeath script. if you’re using the vanilla templates, just clear out everything in there, it’s all geared to the oc anyway. then write your script to do what you want when the pc dies. you’ll want to use the command PopUpDeathGUIPanel(). season to taste.

@xorbaxian : Thanks a lot for the help, it works. Only the first two animations don’t play.

Now I really need help with the local variables stored on items. I’ve tested my script, but when I exported the character to the next module, the game still couldn’t read the local variables from the previous module. I think I need another script to read all the local variables stored on items.

Any help would be much appreciated.

where did you store the variables specifically ?  common practice is to store them on the pc hide, using the routines in x3_inc_skin. if that’s what you did, it’s normal that you can’t read the variables, because the game is set up to start w/a fresh skin whenever your exported pc starts a new module. in this case, you’ve got two possibilities :

  1. save the variables to an inventory plot item [in which case you should say something in the description like ‘don’t throw this item away! it’s needed for the game’].
  2. save the variables to the campaign database. this is actually easier than it might sound and, imho, ‘the best’ approach. read up on SetCampaignInt(), GetCampaignInt(), etc. i personally prefer this approach because it doesn’t clutter up the pc’s inventory w/‘meta-items’ and the interface is more straightforward, but that’s just me.

otoh if you already are storing your variables on an inventory item rather than the skin :

  • make sure you’re storing the variables correctly in the first module. take note of the item’s tag and whether there are multiple items w/this same tag.
  • make sure you’re accessing the same item in the 2nd module. check for tag/duplications as above.

@xorbaxian : There are three scripts that I’m using.

First one (module_inc_debug):

// Functions for sending the player debug/error messages with a fancier look.
// Sends Message To PC, starting with "DEBUG: ",
// only if "Module_DEBUG" int variable is set.

void Module_DebugMessage(string sMessage);

// Sends Message To PC, starting with "DEBUG: ",
// only if "Module_DEBUG" int variable is set AND bDebugLocal != 0.

// (Set this var at the top of a script file and forward it to the function,
// to be able to receive only selected debug messages without having to delete the unwanted ones that might still be needed later)
void Module_DebugMessageLocal(string sMessage, int bDebugLocal);

// Sends Message To PC, starting with "ERROR: ",
// regardless of Module_DEBUG (warning about something that isn't supposed to happen!)
void Module_ErrorMessage(string sMessage);

/////////////////////////////////////////
/////////////////////////////////////////

void Module_DebugMessage(string sMessage)
{
    object oPC = GetFirstPC();
    if (GetLocalInt(oPC, "Module_DEBUG"))
    {
        string sDebugMessage = "DEBUG: " + sMessage;
        SendMessageToPC(oPC, sDebugMessage);
    }
}


void Module_DebugMessageLocal(string sMessage, int bDebugLocal)
{
    object oPC = GetFirstPC();
    if (bDebugLocal && GetLocalInt(oPC, "Module_DEBUG"))
    {
        string sDebugMessage = "DEBUG: " + sMessage;
        SendMessageToPC(oPC, sDebugMessage);
    }
}


void Module_ErrorMessage(string sMessage)
{
    object oPC = GetFirstPC();
    string sErrorMessage = "ERROR: " + sMessage;
    SendMessageToPC(oPC, sErrorMessage);
}



//void main() {}

Second one (local_variables):

/*

Important Variables, for determining game progress, PC personal traits, etc.

Includes functions for creating module token inside container and setting variables on it.

*/

#include "module_inc_debug"


void GiveTok(object oPI) // give to container
{
    object oI = CreateItemOnObject("module_token", oPI);
    DelayCommand(2.0, SetLocalInt(oI, "MyTestVariable", 3));
}

void CreatemoduleTokenOnPC(object oPC)
{
    object oPI = CreateItemOnObject("module_plotitem", oPC);
    DelayCommand(2.0, GiveTok(oPI));
}

void module_SetSingleVar(string sVar, object oO, object oPC)
{
    SetLocalInt(oO, sVar, GetLocalInt(oPC, sVar));
}


void module_SetSingleStringVar(string sVar, object oO, object oPC)
{
    SetLocalString(oO, sVar, GetLocalString(oPC, sVar));
}



/* -------------------------------------- */
/* THE VARIABLES THAT WILL BE TRANSFERRED */
/* -------------------------------------- */

void SetVariables(object oO)
{
    object oPC = GetFirstPC();



    /* PC Traits */

    module_SetSingleVar("PCLovesHim", oO, oPC); 
    module_SetSingleVar("PCLovesHer", oO, oPC); 
    module_SetSingleVar("PCIsMean", oO, oPC); 
    module_SetSingleVar("PCIsKind", oO, oPC); 
    
 }

Third one (Export_to_Chap1):

// give token inside container, transfer all variables to it
// then export and exit

#include "local_variables"

void main()
{
    // I'm giving the module token upon area entry just in case someone is
    // impatient and exports manually, so here is a check if the item is already there
    object oPC = GetFirstPC();
    object oCont = GetItemPossessedBy(oPC, "module_plotitem");
    object oTok;
    if (!GetIsObjectValid(oCont))
        CreateModuleTokenOnPC(oPC); // gives container + token, with 2.0 delay!!!
    else {
        oTok = GetItemPossessedBy(oCont, "module_token");
        if (!GetIsObjectValid(oTok))
            GiveTok(oCont);
    }

    // assume that PC now has the token after at most 3.0 seconds

    // set variables (just in case, it attempts to do this on area enter, too)
    DelayCommand(3.0, SetVariables(oTok));

    // export character
    DelayCommand(6.0, ExportSingleCharacter(GetFirstPC()));

    DelayCommand(9.0, StartNewModule ("The Next Module"));

    DelayCommand(0.5, FloatingTextStringOnCreature("Please wait 3...", oPC));
    DelayCommand(2.33, FloatingTextStringOnCreature("2...", oPC));
    DelayCommand(4.16, FloatingTextStringOnCreature("1...", oPC));

}

I was wondering, if there’s an easier script (without having to use three different scripts) where I can just store all those local variables in one single item?
And will I need another script ‘to read’ all the local variables stored on that one particular item in the next module?

well !   it looks like all that was written by someone who certainly enjoys coding.

personally i favour a different approach. try this and see if it works for you.

put the following in a script that will be run at the conclusion of your first module :

    SetCampaignInt("mycampaign", "PCLovesHim", GetLocalInt(oPC, "PCLovesHim"), oPC);
    SetCampaignInt("mycampaign", "PCLovesHer", GetLocalInt(oPC, "PCLovesHer"), oPC);
    SetCampaignInt("mycampaign", "PCIsMean", GetLocalInt(oPC, "PCIsMean"), oPC);
    SetCampaignInt("mycampaign", "PCIsKind", GetLocalInt(oPC, "PCIsKind"), oPC);
    ExportAllCharacters();

put the following in a script run at the beginning of your second module, such as your module’s OnClientEnter script :

    SetLocalInt(oPC, "PCLovesHim", GetCampaignInt("mycampaign", "PCLovesHim", oPC));
    SetLocalInt(oPC, "PCLovesHer", GetCampaignInt("mycampaign", "PCLovesHer", oPC));
    SetLocalInt(oPC, "PCIsMean", GetCampaignInt("mycampaign", "PCIsMean", oPC));
    SetLocalInt(oPC, "PCIsKind", GetCampaignInt("mycampaign", "PCIsKind", oPC));

no need for ‘tokens’ or meta-items of any sort.

for further info :

@NWShacker : I’ve tested this code…

void main()
{
    itemproperty ipBonus = ItemPropertyAbilityBonus(ABILITY_INTELLIGENCE, 1);
    object oSkin = GetItemInSlot(INVENTORY_SLOT_CARMOUR, GetFirstPC());
    AddItemProperty(DURATION_TYPE_PERMANENT, ipBonus, oSkin);
}

It doesn’t work. Nothing changes. The ability stays the same. Any solution?

@xorbaxian It works! Thanks a lot. Now I’m wondering if I can do the same for phenotype?

So I found the following script:

void main()
{
    // Get the PC to change
    object oPC = GetPCSpeaker();
 
    // Set the phenotype
    SetPhenoType(PHENOTYPE_BIG, oPC);
}

If my phenotype.2da looks like this:

  Label      Name       DefaultPhenoType   

0 Normal 2223 0
1 Skinny **** ****
2 Large 2225 0
3 Normal_M 111015 0
4 **** **** 0
5 Large_M 111016 2
6 N_Joust_M 111017 0
7 **** **** 0
8 L_Joust_M 111018 2
9 **** **** ****
10 Dancer 2223 0
11 Normal_M 111015 0
12 Large_M 111016 2
13 N_Joust_M 111017 0
14 Centaur_W 110916 0
15 Centaur_G 110929 0
16 Centaur_S 110942 0
17 Centaur_B 110955 0
18 **** **** 0
19 Pranger 5737 0
20 Folter 5741 0
21 **** **** 0
22 **** **** 0
23 Floor 16815223 0

What should I type if I want to change the phenotype of the PC from Normal to Folter or Floor?

Do I replace PHENOTYPE_BIG with PHENOTYPE_FLOOR or simply numbers like PHENOTYPE_23?

Definitely not written by me, lol. I just copy-pasted someone else’s script.

Thank you so much, it works perfectly fine, just they way I want them to be, they’re both much simpler scripts.

I have another question, what to do with the NPCs keep looking at the invisible PC during cutscene?

in fact, these are just numbers. you can see them in the script nwscript.nss. so you’d just use the number of the pheno you want – e.g. Folter would be 20 :

	SetPhenoType(20, oPC);

CAVEAT - not all appearances have models for all phenotypes.
_

well, what do you want them to do ? :wink:
if it’s just a question of facing a different direction, you could try SetFacingPoint. for more complicated things, see if gestalt’s cutscene package will help you to get where you want to go.

Thanks, @xorbaxian, I’ll give it a try.

Can anyone help me with the following code to increase ability permanently:

void main()
{
    itemproperty ipBonus = ItemPropertyAbilityBonus(ABILITY_INTELLIGENCE, 1);
    object oSkin = GetItemInSlot(INVENTORY_SLOT_CARMOUR, GetFirstPC());
    AddItemProperty(DURATION_TYPE_PERMANENT, ipBonus, oSkin);
}

I’ve tested it. The script doesn’t work on Neverwinter Nights: Enhanced Edition.

Is oSkin a valid object?? Check that.

What event is calling the script?

If it’s OnClientEnter, some working code:

  // Create or update creature skin as necessary on PC for Player Tool 01 and 10 feats
  // (creates radial feat which runs custom menu script x3_pltool_01).
  // This relies on the Bioware code to equip the skin if necessary, owing
  // to timing issues.

  oSkin = GetItemInSlot(INVENTORY_SLOT_CARMOUR, oPC);

  if (!GetIsObjectValid(oSkin))
    oSkin=GetItemPossessedBy(oPC, "x3_it_pchide");

  if (!GetIsObjectValid(oSkin))
    oSkin = CreateItemOnObject("x3_it_pchide", oPC);

  if (!GetHasFeat(FEAT_PLAYER_TOOL_01, oPC))
    AddItemProperty(DURATION_TYPE_PERMANENT, ItemPropertyBonusFeat(IP_CONST_FEAT_PLAYER_TOOL_01), oSkin);

This code adds a feat, but the principal is the same.