Seikan

A question about scrips and items

Recommended Posts

Hello everyone, i've never really know anything about scripting, but i was wondering something, is it theoretically possible to use a script to make an item apply an effect depending on the appearance of the one using it, something like detecting the appearance of the character and triggering an effect in response?

Share this post


Link to post
Share on other sites

Hmmm thanks for the answer, though just to be sure i want to give some more details on to what I was thinking, since maybe i was misunderstood, if not then sorry for keep this going x)

 

I don't want an item that allows to activate a script by "using" it like an armband or any kind of usable item in a game, so instead of using an item to trigger a scrip having a scrip that triggers when you equip an item which I think on paper might have more chances to work with the limitations of the game.

 

The use i imagine for it would be to work around some of the limitations of the game regarding appearance.2da, so the way i thought (of course only assuming it'd be possible to trigger a script by equipping a certain piece of equipment) was to create duplicate rows in the appearance.2da for each playable character (only for one the three classes should be enough), and use items that disguise you into the duplicate appearance corresponding to your character's base appearance which would look exactly the same except one aspect of it: you could change all the body models to simulate new armor classes, by using a duplicate of your character's appearance you'd double the number of armor models you could use and would allow to much more variety and compatibility between mods instead of having to replace the existing armor models each time you want a new armor type and have people being able to choose only one mod amonst many because they all replace the same body model.

Another use to it could be like i did for my mod's helmets disguising you into a new appearance with a head fitting inside but instead of like I did having to make an item for males and one for females have a script differentiate your character's gender to assign the correct appearance.

 

I know it's very unlikely that it works and people might have thought of it already, but i thought it would be a shame not to give it a try and ask for the opinion of people more knowledgeable on the matter, since i myself don't know the limits of scripting when it comes to kotor.

Share this post


Link to post
Share on other sites

I've just checked, and apart from modifying the OnHeartbeat script and using checks for the object, tag, and a global boolean, you wouldn't be able to do what you want to do.

 

For modifying the OnHeartbeat, you'd need to do something like this:

 

 

void main()

{

    // Normal OnHeartbeat code here.

 

    if(GetTag(OBJECT_SELF) == "Carth")

    {

        if (GetGlobalBoolean("SEI_CAR_DIS") == 0 &&

            GetTag(GetItemInSlot(, OBJECT_SELF)) == "")

        {

            SetGlobalBoolean("SEI_CAR_DIS", 1);

            ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectDisguise(), OBJECT_SELF);

       }

       else if (GetGlobalBoolean("SEI_CAR_DIS") == 1 &&

                  GetTag(GetItemInSlot(, OBJECT_SELF)) == "")

        {

            // Do nothing, since it's already been done.

        }

        else if (GetGlobalBoolean("SEI_CAR_DIS") == 1 &&

                   GetTag(GetItemInSlot(, OBJECT_SELF)) != "")

        {

            // Carth has been disguised, but the item is no longer equipped. Remove the disguise.

            effect eEffect = GetFirstEffect(OBJECT_SELF);

 

            while(GetIsEffectValid(eEffect))

            {

                if (GetEffectType(eEffect) == EFFECT_TYPE_DISGUISE)

                {

                    RemoveEffect(OBJECT_SELF, eEffect);

                    break;

                }

                eEffect = GetNextEffect(OBJECT_SELF);

            }

        }

    }

}

 

 

That would have to be done for every party member, and in the case of the player, you'd see GetTag equaled "", since the player has no tag. The only real cons here are the following:

 

1. This depends on the Heartbeat, which fires every six seconds, so there could easily be a delay between the item being equipped and the effect happening.

2. This is done by an Effect, and despite it being DURATION_TYPE_PERMANENT, this effect can be removed with ClearAllEffects. This could be worked around a bit by this:

 

 

Changing this

 

       else if (GetGlobalBoolean("SEI_CAR_DIS") == 1 &&

                  GetTag(GetItemInSlot(, OBJECT_SELF)) == "")

        {

            // Do nothing, since it's already been done.

        }

 

to this

 

       else if (GetGlobalBoolean("SEI_CAR_DIS") == 1 &&

                  GetTag(GetItemInSlot(, OBJECT_SELF)) == "")

        {

            int iHaveEffect = 0;

            effect eEffect = GetFirstEffect(OBJECT_SELF);

 

            while(GetIsEffectValid(eEffect))

            {

                if (GetEffectType(eEffect) == EFFECT_TYPE_DISGUISE)

                {

                    iHaveEffect = 1;

                    break;

                }

                eEffect = GetNextEffect(OBJECT_SELF);

            }

 

            if(iHaveEffect == 0)

            {

                ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectDisguise(), OBJECT_SELF);

            }

        }

 

Share this post


Link to post
Share on other sites

Sounds like it's almost possible, i actually did think about something like what the OnHeartBeat script does (a check every X time), the delay wouldn't be that much of a problem if it opened new possibilities, I think the modification you propose would work great on party members (even if it might be quite the cumbersome script) but doesn't look like it would work on the player itself since you'd be disguised to the same appearance no matter what the player base appearance is.

 

I really don't know much at all about scripting so i wouldn't dare take to much of your time with this, I was just wondering if it would work to get around some of the limitations of the game in general for everyone, i don't really have the time to get into it myself at this time (it'd mean learning some scripting basics while i have to prepare for moving abroad), but I thank you for your time, and perhaps my idea flies over there and someone finds an use to it, who knows.

Share this post


Link to post
Share on other sites

I've given this some thought before. It's totally possible with the heartbeat script, just not... practical. But if you do want to go with that option, there is an alternative to the disguise effect. You could script the heartbeat to remove and replace the item, depending on whoever is wearing it, and then make multiple copies of the item, each with the right disguise property. However, you wouldn't be able to include those items in the upgrade system, since you'd be destroying the upgrade parts every time the item was equipped. That couldn't be removed through ClearAllEffects and as a bonus the disguise would be removed immediately when the item is removed.

 

If you want to retain each character's head though, that's much trickier. There is a function for that, DuplicateHeadAppearance, but it requires two spawned objects in order to compare their heads. You can't just input head numbers. It might be possible to implement, but because it would be so convoluted I never attempted it. It would go something along the lines of...

 

Equip item -> Heartbeat script fires -> get the item user's current appearance, before the disguise item -> apply the disguise item -> spawn a creature, any creature (ideally somewhere the player can't see) -> apply the desired disguise effect to that creature -> DuplicateHeadAppearance with the spawned creature and the item user (assuming it gets the right head) -> delete the spawned creature -> item user now has the desired head and body combination.

 

There are a number of potential issues I can imagine. You'd probably have to set a boolean for whether the item has been equipped or not, to make sure the script is fired when the item is equipped but also when it is removed to fix everything, and also to account for area transitions, party members being sent away and then summoned again, etc. You might also have to store the player's appearance as a numeric so you can call it again later. I'm not sure if simply removing the item would set everything back to normal, so you might have to repeat the spawning and duplicating procedure, or apply a disguise effect using the player's original appearance, or maybe apply any other disguise effect and then clear it... I could go on and on. Like I said, convoluted.

 

But it may be possible. And it's tempting.

Share this post


Link to post
Share on other sites

I think the modification you propose would work great on party members (even if it might be quite the cumbersome script) but doesn't look like it would work on the player itself since you'd be disguised to the same appearance no matter what the player base appearance is.

Actually, that's not the case.

 

You can use GetAppearanceType(OBJECT_SELF) to figure out the appearance.2da row the player is using. And each player in K1 uses one of three rows to account for the different class heights.

 

So, the first female asian player uses rows 91-93. So if GetAppearanceType(OBJECT_SELF) returned 91, 92, or 93, you'd know the player had the first female asian head (row 26 or heads.2da).

 

Equip item -> Heartbeat script fires -> get the item user's current appearance, before the disguise item -> apply the disguise item -> spawn a creature, any creature (ideally somewhere the player can't see) -> apply the desired disguise effect to that creature -> DuplicateHeadAppearance with the spawned creature and the item user (assuming it gets the right head) -> delete the spawned creature -> item user now has the desired head and body combination.

 

There are a number of potential issues I can imagine. You'd probably have to set a boolean for whether the item has been equipped or not, to make sure the script is fired when the item is equipped but also when it is removed to fix everything, and also to account for area transitions, party members being sent away and then summoned again, etc. You might also have to store the player's appearance as a numeric so you can call it again later. I'm not sure if simply removing the item would set everything back to normal, so you might have to repeat the spawning and duplicating procedure, or apply a disguise effect using the player's original appearance, or maybe apply any other disguise effect and then clear it... I could go on and on. Like I said, convoluted.

 

So you'd have them equip an item only to equip another item over that later? Besides that, the approach you've described is used in Antonia's Disguise mod for K1.

 

The boolean and effect and all that was why I opted for the EffectDisguise route, but if you wanted to be really sure of things, you could take all of the code I posted above and move it to a custom function. Then you could use the following to remove most of the delay and keep the effect current between effect-removals:

 

 (for the following, let's assume I moved all the code into a new function named DisguiseCheck and pass OBJECT_SELF to it)

 

DisguiseCheck(OBJECT_SELF);

DelayCommand(1.0, DisguiseCheck(OBJECT_SELF));

DelayCommand(2.0,DisguiseCheck(OBJECT_SELF));

DelayCommand(3.0,DisguiseCheck(OBJECT_SELF));

DelayCommand(4.0,DisguiseCheck(OBJECT_SELF));

DelayCommand(5.0,DisguiseCheck(OBJECT_SELF));

Share this post


Link to post
Share on other sites

@ JCarter:

Yeah i suspected it would require quite a convoluted process, but as you say it is tempting, if someone manages to pull it off it could be used as a modder's resource that would open the door for other modders who might use the new models available for new skins, helmets (It could be useful for Xander's masks "retexture" to avoid clipping of his new helmets for example) , etc...

 

@Fair Strides:

 

Another thing I was wondering, if you wanted to apply exactly the same effect to different characters (in the case of helmets for example, where you'd only need one male and one female appearance, do you have to make a script for every single male companion and male player appearance or would it be possible to add multiple variables on the "if(GetTag(OBJECT_SELF) == "")" so that there is a single script for all the male characters and one for females ones?

Share this post


Link to post
Share on other sites

@ JCarter:

Yeah i suspected it would require quite a convoluted process, but as you say it is tempting, if someone manages to pull it off it could be used as a modder's resource that would open the door for other modders who might use the new models available for new skins, helmets (It could be useful for Xander's masks "retexture" to avoid clipping of his new helmets for example) , etc...

 

i really gave that some thought, but i decided to just make them a disguise with either male or female, and it has to be with a suit of armor that matches the helmet, and it will be an add on to the masks later. Of course for that i think i will just make it a new texture completely, and forego the separate helmet, and make it more like a creature body, where the head is attached to the body, so it wont need a new head.

 

If it was more like the canderous mandalorian items, then yes i would go ahead and do that since it is just one suit and helmet, but there are three, and i wanted them to be wearable by any gender, except maybe zaalbar or mission, who will get their own stuff to compensate for not being able to wear the disguises.

 

as tempting as it was, i realized it was convoluted as well, and so it might be better used for another mod later down the road where it is more suitable. Such as one that needs to have different mix and match robes or armor and helmets.

Share this post


Link to post
Share on other sites

i really gave that some thought, but i decided to just make them a disguise with either male or female, and it has to be with a suit of armor that matches the helmet, and it will be an add on to the masks later. Of course for that i think i will just make it a new texture completely, and forego the separate helmet, and make it more like a creature body, where the head is attached to the body, so it wont need a new head.

 

If it was more like the canderous mandalorian items, then yes i would go ahead and do that since it is just one suit and helmet, but there are three, and i wanted them to be wearable by any gender, except maybe zaalbar or mission, who will get their own stuff to compensate for not being able to wear the disguises.

 

as tempting as it was, i realized it was convoluted as well, and so it might be better used for another mod later down the road where it is more suitable. Such as one that needs to have different mix and match robes or armor and helmets.

 

I don't know why, but every time i see you post about the disguise option you give me the impression you believe that the disguise property limits the armors you can wear (but maybe i'm wrong), i did the disguise option with helmets before:

 

post-10880-0-52215400-1466110376_thumb.jpgpost-10880-0-40754000-1466110380_thumb.jpg

 

Here they are with matching armor for sake of aesthetics and because i actually made the matching armors, but they are completely apart from the helmet, i can get my character in underwear, or with any other armor in the game while keeping the helmet on as i would normally do without the helmet, the only issue as you say is that you've gotta make a female and a male version of the item which is annoying.

So sure some helmets are hard to match with other stuff, like the sith helmet is way too shiny for most armors, but many other masks like black ones, Mandalore's  etc can easily match different armors without you making a specific armor for them

 

In this case managing such a scrip as we're talking about would only serve to unify both items into a single unisex item in the case of your mod, and the mod wouldn't have that much of an issue without it, looking for such a convoluted method for a single mod wouldn't be worth it, but if such a script could be done and understood then many mods like yours could take advantage of it like any other modding tool.

Share this post


Link to post
Share on other sites
@Fair Strides:

 

Another thing I was wondering, if you wanted to apply exactly the same effect to different characters (in the case of helmets for example, where you'd only need one male and one female appearance, do you have to make a script for every single male companion and male player appearance or would it be possible to add multiple variables on the "if(GetTag(OBJECT_SELF) == "")" so that there is a single script for all the male characters and one for females ones?

Ideally, you'd have it setup like this (I was just giving an example with Carth and the player):

 

 

 

void DisguiseCheck(object oSelf);

 

void main()

{

    // Original Heartbeat script

    DisguiseCheck(OBJECT_SELF);

    DelayCommand(1.0, DisguiseCheck(OBJECT_SELF));

    DelayCommand(2.0, DisguiseCheck(OBJECT_SELF));

    DelayCommand(3.0, DisguiseCheck(OBJECT_SELF));

    DelayCommand(4.0, DisguiseCheck(OBJECT_SELF));

    DelayCommand(5.0, DisguiseCheck(OBJECT_SELF));

}

 

void DisguiseCheck(object oSelf)

{

    string sTag = GetTag(oSelf);

    string sItemTag = ;

    string sGlobal; // This will be used for the global boolean later.

 

    int iAppNumber = 0;

    int iSlotNumber = ; // This is the Inventory slot the to check.

    // iSlotNumber will need to be one of the following:

   

// INVENTORY_SLOT_HEAD        = 0;

// INVENTORY_SLOT_BODY        = 1;

// INVENTORY_SLOT_HANDS       = 3;

// INVENTORY_SLOT_RIGHTWEAPON = 4;

// INVENTORY_SLOT_LEFTWEAPON  = 5;

// INVENTORY_SLOT_LEFTARM     = 7;

// INVENTORY_SLOT_RIGHTARM    = 8;

// INVENTORY_SLOT_IMPLANT     = 9;

// INVENTORY_SLOT_BELT        = 10;

// INVENTORY_SLOT_CWEAPON_L   = 14;

// INVENTORY_SLOT_CWEAPON_R   = 15;

// INVENTORY_SLOT_CWEAPON_B   = 16;

// INVENTORY_SLOT_CARMOUR     = 17;

 

    if (sTag == "Bastila")

    {

        iAppNumber = ;

        sGlobal = "BAS";

    }

    else if (sTag == "Carth")

    {

        iAppNumber = ;

        sGlobal = "CAR";

    }

    else if (sTag == "Canderous")

    {

        iAppNumber = ;

        sGlobal = "CAN";

    }

    else if (sTag == "Jolee")

    {

        iAppNumber = ;

        sGlobal = "JOL";

    }

    else if (sTag == "Juhani")

    {

        iAppNumber = ;

        sGlobal = "JUH";

    }

    else if (sTag == "Mission")

    {

        iAppNumber = ;

        sGlobal = "MIS";

    }

    else if(sTag == "")

    {

        int iPlayerApp = GetAppearanceType(OBJECT_SELF);

 

        if(iPlayerApp >= 91 && iPlayerApp

        {

            // Player is female

            iAppNumber = ;

            sGlobal = "PCF";

        }

        else if (iPlayerApp >= 136 && iPlayerApp

        {

            // Player is male

            iAppNumber = ;

            sGlobal = "PCM";

        }

    }

 

    if(iAppNumber > 0)

    {

        if (GetGlobalBoolean("SEI_" + sGlobal + "_DIS") == 0 &&

            GetTag(GetItemInSlot(iSlotNumber, oSelf)) == sItemTag)

        {

            SetGlobalBoolean("SEI_" + sGlobal + "_DIS", 1);

            ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectDisguise(iAppNumber), oSelf);

       }

       else if (GetGlobalBoolean("SEI_" + sGlobal + "_DIS") == 1 &&

                  GetTag(GetItemInSlot(iSlotNumber, oSelf)) == sItemTag)

        {

            int iHaveEffect = 0;

            effect eEffect = GetFirstEffect(oSelf);

 

            while(GetIsEffectValid(eEffect))

            {

                if (GetEffectType(eEffect) == EFFECT_TYPE_DISGUISE)

                {

                    iHaveEffect = 1;

                    break;

                }

                eEffect = GetNextEffect(oSelf);

            }

 

            if(iHaveEffect == 0)

            {

                ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectDisguise(iAppNumber), oSelf);

            }

        }

        else if (GetGlobalBoolean("SEI_" + sGlobal + "_DIS") == 1 &&

                   GetTag(GetItemInSlot(iSlotNumber, oSelf)) != sItemTag)

        {

            // The person has been disguised, but the item is no longer equipped. Remove the disguise.

            effect eEffect = GetFirstEffect(oSelf);

 

            while(GetIsEffectValid(eEffect))

            {

                if (GetEffectType(eEffect) == EFFECT_TYPE_DISGUISE)

                {

                    RemoveEffect(oSelf, eEffect);

                    break;

                }

                eEffect = GetNextEffect(oSelf);

            }

        }

    }

}

 

Share this post


Link to post
Share on other sites

So you'd have them equip an item only to equip another item over that later? Besides that, the approach you've described is used in Antonia's Disguise mod for K1.

I haven't taken a look at that mod, but that's basically it, yeah. In an ideal situation, the item you actually equip would have no disguise property, then the heartbeat script would fire and replace it with the disguise one. And then similarly swap out any in the inventory with the dummy version.

 

The boolean and effect and all that was why I opted for the EffectDisguise route, but if you wanted to be really sure of things, you could take all of the code I posted above and move it to a custom function.

Disguise effect wouldn't preserve the head, though. All that nonsense is just to preserve the head. You shouldn't need booleans if we're talking about mask items. The heartbeat script would only need to check if the item doesn't have the correct disguise property, which could be handled through the item tag.

 

 

Yeah i suspected it would require quite a convoluted process, but as you say it is tempting, if someone manages to pull it off it could be used as a modder's resource that would open the door for other modders who might use the new models available for new skins, helmets (It could be useful for Xander's masks "retexture" to avoid clipping of his new helmets for example) , etc...

 

Mm, like I said I've thought about doing it before too... I've just never had a reason to try it. If I have time I might write up some generic code at least as a starting point.

Share this post


Link to post
Share on other sites

Disguise effect wouldn't preserve the head, though. All that nonsense is just to preserve the head. You shouldn't need booleans if we're talking about mask items. The heartbeat script would only need to check if the item doesn't have the correct disguise property, which could be handled through the item tag.

 

That is why i was thinking of using the script to figure the appearance used by the player (with GetAppearanceType(OBJECT_SELF) as Fair Strides proposed) and have an appearance row for the disguise with the same head as the appearance detected by the script, of course it would mean having a duplicate appearance row for every single playable appearance (ignoring the 3 classes differences and using only one would be enough imho), but if it is possible to do, that would be less convoluted that your method and avoid the complication of having to figure out a way to restore the normal appearance since it would dissipate once the disguise effect is removed. There might be some issues to overcome but probably less than the head swapping which has so many steps it could easily go wrong at one of them.

Share this post


Link to post
Share on other sites

That wouldn't be compatible with any head mods, though. And would be a fair bit more work with setting up all the 2DAs, and you'd also have to directly map each appearance to each new appearance in the script, which would mean using the TSL Patcher for the script too. But sure, that is an option in theory.

  • Like 1

Share this post


Link to post
Share on other sites

kinda why i gave up on the helmet style mask option with every armor in the game. I guess i could try it, but im leery about making it incompatible with other mods. Dont mind tsl patcher, but the other stuff is too labor intensive on the scripting for me just yet.

 

I think for now it would be just fine to get the helmet versions of a few masks in the game with its own armor or robe, one disguise for each gender. Now for helmets i want to mix and match with armor i would have to use a dummy head replacer like the squashed face one, as long as it doesnt have to be in the head selection menu.

 

i did a mockup of one that i never tested and it basically cuts everything off from the bottom lip up since the rest is hidden anyway. textured it to be like the stormtrooper turtleneck sort of. but then that would take some multiple texture editing in the Uiti i believe as well to match armor colors. Thats kind of why i have so many mods on hold, one reason is to secure permissions, and the other is to think about it for a minute before i proceed and make it too ridiculous.

Share this post


Link to post
Share on other sites

I did some testing that answered a few questions I had. And I've confirmed that my convoluted head process should work. The spawning procedure is still needed for the initial appearance change, though. And I've yet to determine the best way of spawning the creature somewhere the player won't be able to see them. Every module's coordinates different, so I'm not sure how to go about this. Also it would probably be unavoidable in small modules anyway. As such, I decided not to write the head duplicating function yet. The following code should work work for masks and such, however:

 

/* jc_d_test    K2 VERSION



   This allows for the extension of body model slots through the use of disguise items.

   When the item is equipped, the heartbeat script will replace that item with a copy that

   has the desired disguise property.    The disguise effect can vary based on the user's

   gender and phenotype. The character may also retain their original head or be given a

   new one through the disguise; however, this has not yet been implemented.



   In the K2 version of the script, feedback is hidden, phenotype is disabled by default,

   and everything is contained in in one script.

*/





// This sets the string for gender



string JC_SET_GENDER(object oUser) {



/* 0 = Male

   1 = Female

   2 = Both

   3 = Other

   4 = None

*/



string sGender;

int nGender = GetGender(oUser);



if(nGender == 0 ) sGender = "_m";

else if(nGender == 1 ) sGender = "_f";

else if(nGender == 2 ) sGender = "_m";

else if(nGender == 3 ) sGender = "_m";

else if(nGender == 4 ) sGender = "_m";

else sGender = "_m";



return sGender;



}





// This sets the string for phenotype



string JC_SET_PHENO(object oUser) {



/* Small - Scoundrel, Jedi Consular, Jedi Master, Sith Lord

   Medium - Scout, Jedi Sentinel, Jedi Watchman, Sith Assassin, and default

   Large - Soldier, Jedi Guardian, Jedi Weapon Master, Sith Marauder

*/



string sPheno;

int nClass = GetClassByPosition(1, oUser);



if( nClass == 0 || nClass == 3 || nClass == 11 || nClass == 14 ){

  sPheno = "_l";

  }

else if( nClass == 2 || nClass == 4 || nClass == 12 || nClass == 15 ){

  sPheno = "_s";

  }

else sPheno = "_m";



return sPheno;



}





// This cycles through the inventory to replace disguise items with the dummy item.



void JC_SWAP_INVENTORY_CYCLE(string sItemBase, string sDisguise, object oUser) {



object oItem = GetFirstItemInInventory(oUser);



while( oItem != OBJECT_INVALID ) {

  string sTag = GetTag(oItem);

  if( sTag == sDisguise ) {

    DestroyObject(oItem, 0.0, TRUE, 0.0, TRUE);

    CreateItemOnObject(sItemBase, oUser, 1, TRUE);

    }

  oItem = GetNextItemInInventory(oUser);

  }



}





//This just runs the above subroutine for every possible disguise item name.



void JC_SWAP_INVENTORY(string sItemBase, object oUser ){



JC_SWAP_INVENTORY_CYCLE(sItemBase, sItemBase + "_m", oUser);

JC_SWAP_INVENTORY_CYCLE(sItemBase, sItemBase + "_m" + "_s", oUser);

JC_SWAP_INVENTORY_CYCLE(sItemBase, sItemBase + "_m" + "_m", oUser);

JC_SWAP_INVENTORY_CYCLE(sItemBase, sItemBase + "_m" + "_l", oUser);

JC_SWAP_INVENTORY_CYCLE(sItemBase, sItemBase + "_f", oUser);

JC_SWAP_INVENTORY_CYCLE(sItemBase, sItemBase + "_f" + "_s", oUser);

JC_SWAP_INVENTORY_CYCLE(sItemBase, sItemBase + "_f" + "_m", oUser);

JC_SWAP_INVENTORY_CYCLE(sItemBase, sItemBase + "_f" + "_l", oUser);

JC_SWAP_INVENTORY_CYCLE(sItemBase, sItemBase + "_s", oUser);

JC_SWAP_INVENTORY_CYCLE(sItemBase, sItemBase + "_l", oUser);

JC_SWAP_INVENTORY_CYCLE(sItemBase, sItemBase + "_d", oUser);



}





void JC_SWAP_EQUIP(string sDisguise, int nSlot, object oUser, string sScript) {



int nGame = 2;



object oEquip = GetItemInSlot(nSlot, oUser);



ActionUnequipItem(oEquip, TRUE);

DestroyObject(oEquip, 0.0, TRUE, 0.0, TRUE);

object oItem = CreateItemOnObject(sDisguise, oUser, 1, TRUE);



if( nGame == 1 ) {

  CreateItemOnObject(sDisguise, oUser, 1, TRUE);

  ExecuteScript(sScript, oUser, -1);

  }



else {

  DelayCommand(0.1, AssignCommand(oUser, ActionEquipItem(CreateItemOnObject(sDisguise, oUser, 1, TRUE), nSlot, TRUE)));

  }



}









void JC_SWAP_HEARTBEAT() {



/* Open variables



  - sItemBase:        File name of the item that the user can equip.

            This item should have no disguise properties on it.

            The name must be 12 characters or fewer.

  - sScript:        New script to fire equip the disguise.

            This has to be in a new script file for K1 due to a bug in the script compiler.

  - nCheckHead:        Whether we want to keep the user's original head.

  - nCheckGender:    Whether we want to change appearance based on gender.

  - nCheckPheno:    Whether we want to change appearance based on character class.

  - nSlot:        Which inventory slot the item goes in.

            0 = Head

            1 = Body

            4 = Right Weapon

            6 = Left Weapon

            7 = Left Arm

            8 = Right Arm

            9 = Implant

            10 = Belt

            See NWScript for more details.

  - nB:            Boolean used to check if the creature has put the item on.

            This is currently Boolean 64, but I've left it open for compatibility reasons.

*/



string sItemBase = "jc_d_test";

string sScript = "";

int nCheckHead = TRUE;

int nCheckGender = TRUE;

int nCheckPheno = FALSE;

int nSlot = 1;

int nB = 64;





/* Other variables (don't touch)



  - oUser:    The creature that uses the item. But since this is going in the heartbeat script, it should be OBJECT_SELF.

  - sGender:    Suffix to add to the disguise item name, for gender.

  - sPheno    Suffix to add to the disguise item name, for phenotype.

  - sDisguise:    Disguise item name. It's either item base plus the suffixes, or plus "_d" if there are none.

        For example...

        Item base         = jc_example

        Disguise (male, small)     = jc_example_m_s

        Disguise (just female)     = jc_example_f

        Disguise (just large)     = jc_example_l

        Disguise (no qualifiers) = jc_example_d

        Item names and tags should be assigned accordingly in the UTI files.

  - oEquip:    The item currently equipped in nSlot.

  - sEquip:    Tag of oEquip.

*/



object oUser = OBJECT_SELF;



string sGender = "";

if( nCheckGender == TRUE ) sGender = JC_SET_GENDER(oUser);



string sPheno = "";

if( nCheckPheno == TRUE ) sPheno = JC_SET_PHENO(oUser);



string sDisguise = sItemBase + sGender + sPheno;

if( sDisguise == sItemBase ) sDisguise = sItemBase + "_d";



object oEquip = GetItemInSlot(nSlot, oUser);

string sEquip = GetStringLeft(GetTag(oEquip), GetStringLength(sItemBase));





//This will clear the player's inventory of any disguise items, replacing them with dummy copies.



JC_SWAP_INVENTORY(sItemBase, GetFirstPC());





//This will replace the dummy item with the proper disguise item if equipped.



if( !GetLocalBoolean(oUser, nB) && sEquip == sItemBase ) {

  SetLocalBoolean(oUser, nB, TRUE);

  JC_SWAP_EQUIP(sDisguise, nSlot, oUser, sScript);

  }



}



void main() {



int i;

for( i = 0; i < 30; i++ ) {

  DelayCommand(IntToFloat(i) * 0.2, JC_SWAP_HEARTBEAT());

  }



}

 

It's untested but it compiles properly so I assume there aren't huge problems with it. This the K2 version. A script for K1 would have to be adjusted slightly, but I didn't feel like doing it all yet.

 

So if anyone wants to test it, I'd be very interested in seeing the results.

Share this post


Link to post
Share on other sites

That wouldn't be compatible with any head mods, though. And would be a fair bit more work with setting up all the 2DAs, and you'd also have to directly map each appearance to each new appearance in the script, which would mean using the TSL Patcher for the script too. But sure, that is an option in theory.

 

Well, any head mod from an active modder could easily get a compatibility patch, but it's true that it would have a different set of obstacles.

 

Regarding your script i'm not sure how to test it since i've never worked with scripts, but if you have the time to fill me in the tweaks to get it into the game and proper items i'd be happy to test it out (just gotta reinstall tsl) for you in case no one better suited is willing to.

Share this post


Link to post
Share on other sites

There are notes in the script, but I can summarize.

 

First you go down to the open variables section:

string sItemBase = "jc_d_test";

string sScript = "";

int nCheckHead = TRUE;

int nCheckGender = TRUE;

int nCheckPheno = FALSE;

int nSlot = 1;

int nB = 64;

(those are all the open variables, don't change any others unless you know what you're doing) and change the item name from "jc_d_test" to whatever you want your item to be called (12 characters or fewer). You make an item with this name and tag, and the description you want and so on, but with no disguise property on the item. Let's say I change this to "jc_example".

 

Then set the gender and phenotype booleans based on how you want the appearance to vary. By default, only gender is enabled, since K2 doesn't use phenotype.

 

Then you duplicate this item to apply the disguise property you want, changing the item's tag, template, and file name. The naming convention is the original item base name, plus a suffix for gender and phenotype. If you just want a male version and a female version, then going by my example, the new items would be "jc_example_m" and "jc_example_f". If you are using phenotype as well, then you would have "jc_example_m_s" and "jc_example_f_m" for male, small and female, medium, and so on. A full list would be:

 

jc_example

jc_example_m_s

jc_example_m_m

jc_example_m_l

jc_example_f_s

jc_example_f_m

jc_example_f_l

 

If you set both gender and phenotype to false, then the disguise item should have the suffix "_d" instead; in my example this would be "jc_example_d".

 

You can also change the inventory slot the item will use. By default I've gone with armor, but you could change this to a mask or whatever. I've included an index in the script comments.

 

The last one is the local boolean that's used to check if the creature has put the item on or not. I've left this as an open variable for compatibility reasons but you shouldn't need to change it.

 

So change those and only those, then save it. Then execute it through the heartbeat script like this:

 

//:: k_hen_heartbt01

/*

    Heartbeat for the non-active party members.

*/

//:: Created By:

//:: Copyright (c) 2002 Bioware Corp.



#include "k_inc_debug"

#include "k_inc_switch"



void main()

{

    ExecuteScript("k_ai_master", OBJECT_SELF, KOTOR_HENCH_EVENT_ON_HEARTBEAT);

    /*

    object oEnemy = GetNearestCreature(CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN, OBJECT_SELF, 1, CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY);

    //GN_SetSpawnInCondition(SW_FLAG_SHOUTED_AT, FALSE);



    if(!GN_GetSpawnInCondition(SW_FLAG_AI_OFF) && !GetSoloMode())

    {

        if(GetPartyMemberByIndex(0) != OBJECT_SELF)

        {

            if(IsObjectPartyMember(OBJECT_SELF) &&  //Note that this check replaces GetIsObjectValid(oMaster)

               //GetCurrentAction(OBJECT_SELF) != ACTION_FOLLOW &&

               GetCurrentAction(OBJECT_SELF) != ACTION_MOVETOPOINT &&

               //GetCurrentAction(OBJECT_SELF) != ACTION_WAIT &&

               GetCurrentAction(OBJECT_SELF) != ACTION_FOLLOWLEADER &&

               !GetIsConversationActive() &&

               //GetDistanceBetween(OBJECT_SELF, GetPartyMemberByIndex(0)) > 4.5 &&

               !GN_GetSpawnInCondition(SW_FLAG_SPECTATOR_STATE) &&

               GetCommandable())

            {

                //Db_PostString(GetTag(OBJECT_SELF) + " HEARTBEAT CHECK 1 PASS", 4, 10, 2.0);

                if(!GN_GetIsFighting(OBJECT_SELF) && !GetIsObjectValid(oEnemy))

                {

                    //Db_PostString(GetTag(OBJECT_SELF) + " HEARTBEAT CHECK 2 PASS", 4, 12, 2.0);

                    //The distance checking is now down in the script fired from AI Action Update - Leave 5m Radius of party leader.

                    ClearAllActions();

                    ActionFollowLeader();

                }

            }

        }

    }



    ...



    else if(GetSoloMode() && GetCurrentAction(OBJECT_SELF) == ACTION_FOLLOWLEADER)

    {

        ClearAllActions();

    }

    if(GN_GetSpawnInCondition(SW_FLAG_EVENT_ON_HEARTBEAT))

    {

        SignalEvent(OBJECT_SELF, EventUserDefined(1001));

    }

    */

 
ExecuteScript("jc_d_test", OBJECT_SELF, -1);

   

}

 

...replacing "jc_d_test" with your script name, of course. Recompile k_hen_heartbt01 and you should be all set.

Share this post


Link to post
Share on other sites

Alright, i tested it out at it's simplest and it does work, the item is correctly replaced, disguise applied, and disguise item replaced by the normal one when removed, doesn't seems to be anything wrong with it :P (for both genders)

Share this post


Link to post
Share on other sites

Yay! That's probably the first time a script ever worked on the first try in the history of everything ever. There's still the matter of retaining the head, but I haven't had any new ideas on that front. It's really a critical flaw that DuplicateHeadAppearance requires objects and can't do with just numbers.

Share this post


Link to post
Share on other sites

Yeah, at first it failed, but it wasn't the script, i suspect that it was the fact that bao-dur doesn't like jedi robes and i didn't account for it when i choose it as the disguise for males. Regarding spawning i don't know how it works in kotor, but the first idea that would come to my mind to keep it from sight would be to spawn it under the module's mesh (as when you glitch in many games and fall off the world....) but dunno if that's possible, regarding the coordinates, would it be possible to spawn it in relation to the player instead of the global coordinates of the module?

Share this post


Link to post
Share on other sites

vector vPCPos = GetPosition(GetFirstPC()); // Get PC's XYZ

float fPCFace = GetFacing(GetFirstPC());    // Get PC's directional facing (0 - 359)

 

vPCPos.x = vPCPos.x - 1.5; // Now we're 1.5 meters behind the PC's X-coordinate

vPCPos.y = vPCPos.y - 1.5; // Now we're 1.5 meters behind the PC's Y-coordinate

                                             // (effectively 1.5 meters diagonally away from the PC)

 

location lPCLoc = (vPCPos, fPCFace); // Our new location, which could then be used

                                                             // in CreateObject to spawn something.

Share this post


Link to post
Share on other sites

Yeah, at first it failed, but it wasn't the script, i suspect that it was the fact that bao-dur doesn't like jedi robes and i didn't account for it when i choose it as the disguise for males. Regarding spawning i don't know how it works in kotor, but the first idea that would come to my mind to keep it from sight would be to spawn it under the module's mesh (as when you glitch in many games and fall off the world....) but dunno if that's possible, regarding the coordinates, would it be possible to spawn it in relation to the player instead of the global coordinates of the module?

 

Under the module might work... I'm not sure if it would work with every module, though. I thought about doing it in relation to the player's location, but the problem is there's still no way to tell where in the module the player is.

 

 

vector vPCPos = GetPosition(GetFirstPC()); // Get PC's XYZ

float fPCFace = GetFacing(GetFirstPC());    // Get PC's directional facing (0 - 359)

 

vPCPos.x = vPCPos.x - 1.5; // Now we're 1.5 meters behind the PC's X-coordinate

vPCPos.y = vPCPos.y - 1.5; // Now we're 1.5 meters behind the PC's Y-coordinate

                                             // (effectively 1.5 meters diagonally away from the PC)

 

location lPCLoc = (vPCPos, fPCFace); // Our new location, which could then be used

                                                             // in CreateObject to spawn something.

 

To spawn them outside of the player's field of vision, right? The problem is if the player is at the very edge of the module and facing towards the other end, there is nowhere behind the player and the creature could end up spawning right next to them.

 

Then again, the creature only has to exist for a fraction of a second, so it's not a huge issue. And it's possible to put in a few different options, depending on what works best. For example, getting the location of whatever object is farthest away from the player, and if that's not far enough away then to try some other option.

Share this post


Link to post
Share on other sites

Then again, the creature only has to exist for a fraction of a second, so it's not a huge issue. And it's possible to put in a few different options, depending on what works best. For example, getting the location of whatever object is farthest away from the player, and if that's not far enough away then to try some other option.

 

In that case, you can use the Player's position and the position of the farthest object away and make good use of the HasLineOfSight function:

 

"// 820

// RWT-OEI 04/06/04

// This returns TRUE or FALSE if there is a clear line of sight from

// the source vector to the target vector. This is used in the AI to

// help the creatures using ranged weapons find better places to shoot

// when the player moves out of sight.

 

int HasLineOfSight( vector vSource, vector vTarget, object oSource = OBJECT_INVALID, object oTarget = OBJECT_INVALID );"

Share this post


Link to post
Share on other sites

Yeah, I might try that... Maybe cycle through each creature until there's no line of sight, and if that doesn't work spawn behind the player outside their field of vision, with an extreme negative Z value to try to force them below the module if possible.

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.