Aller au contenu

Photo

Custom effects on weapons


  • Veuillez vous connecter pour répondre
30 réponses à ce sujet

#1
Serlith_

Serlith_
  • Members
  • 72 messages

Hi. I wrote a quick script that's meant to apply visual effects on weapons, but the custom (the most important, too) part refuses to work.
I'll be grateful for any help with debugging that part.

#include "x2_inc_itemprop"

void main(string sWeaponVisual){

	object oDM = OBJECT_SELF;
	object oPC = GetPlayerCurrentTarget(oDM);
	object oItem = GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oPC);
	if (!GetIsObjectValid(oItem)) return;
	
	itemproperty ipLoop=GetFirstItemProperty(oItem); 
	SendMessageToPC(oDM, "ItemPropertyValid?");

	while (GetIsItemPropertyValid(ipLoop))
		{ 
			SendMessageToPC(oDM, "Checking if the effect is visual");
			if (GetItemPropertyType(ipLoop)==ITEM_PROPERTY_VISUALEFFECT)
			{ 
				RemoveItemProperty(oItem, ipLoop);
				SendMessageToPC(oDM, "Removing the effect");   
			}
			ipLoop=GetNextItemProperty(oItem);
		}
	
	if (sWeaponVisual =="clear")
		return;
		
	if (sWeaponVisual == "0" 
		|| sWeaponVisual == "1" 
		|| sWeaponVisual == "2" 
		|| sWeaponVisual == "3" 
		|| sWeaponVisual == "4" 
		|| sWeaponVisual == "5" 
		|| sWeaponVisual == "6" 
		|| sWeaponVisual == "7") 
        {
		int nStockWeaponVisual = StringToInt(sWeaponVisual);
		itemproperty ipAdd = ItemPropertyVisualEffect(nStockWeaponVisual);
		IPSafeAddItemProperty(oItem, ipAdd);
		SendMessageToPC(oDM, "Base visual effect applied");   

	}
	else {
		SendMessageToPC(oDM, "Attempting to apply a custom effect: "+sWeaponVisual);   
		effect eEffect = EffectNWN2SpecialEffectFile(sWeaponVisual, oItem);
		ApplyEffectToObject(DURATION_TYPE_PERMANENT, eEffect, oItem);
	}
	return;
}


#2
kevL

kevL
  • Members
  • 4 052 messages
I don't think ApplyEffectToObject() can apply a SpecialEffectFile directly to an item.

have you got something that says different?

#3
Serlith_

Serlith_
  • Members
  • 72 messages
The EffectNWN2SpecialEffectFile function is a constructor that returns an effect.
Which is what ApplyEffectToObject takes as argument. It is exactly the opposite of applying the sef file directly.

#4
kevL

kevL
  • Members
  • 4 052 messages
can you point me to code that does that IG ?

#5
Serlith_

Serlith_
  • Members
  • 72 messages

I'm lost. What do you mean? Are you asking me for the function documentation? It's here:
http://nwn2.wikia.co...ecialEffectFile

It's literally all it does. Takes a .sef file and (allegedly) returns an effect that is seen as normal by the ApplyEffectToObject function. If you couldn't apply the function's return value, the script would not compile, which it does.



#6
kevL

kevL
  • Members
  • 4 052 messages
i was asking for an actual example of code. You know, complete, compilable script that I could run, that uses an SEF + ApplyEffectToObject() ... and works ofc. [edit, on an *item* ]

That link suggests it is possible but I'm skeptical. The only code that I've seen, that works, that combines SEF + ApplyEffectToObect() to create a weapon visual *applies the SEF to the creature holding the weapon*. (not the weapon itself)

The SEF file requires a "node" attachment, and gets into modelling stuff i'm unfamiliar with.

Hence my statement that an SEF with ApplyEffectToObject cannot be directly used on an -item- ... but can be used indirectly when applying an SEF with a hand-node attachment (or whatever) but applying it to the -creature-

( "object" is a regretably inexact term in NwScripting ...) Anyway, from that link:
 

It is important to note that you cannot use this function to apply visual effects to items or to valid objects when the .sef has no associated part to the object that you're attempting to apply the effect to.


Notice that in the example then given, to get a visual effect on the example baton, the effect construction is applied to "oPC" !
 

... for the present there is no known way to attach a tail effect to an item. (my emphasis)



#7
Serlith_

Serlith_
  • Members
  • 72 messages

Ah. Then IIRC NWN2 implementation of Tome of Battle uses this function on weapon temporary effects and (I think) critical hit animations, it works properly there.

EDIT: It's applied to a character as well. Damn.

Workaround idea: Apply an effect/function to a weapon that... Applies the effect every time a character picks it up? 

 

I take it there's no way to convert an effect type to an itemproperty type?



#8
kevL

kevL
  • Members
  • 4 052 messages
nope. :\

workaround: ( yah you could use tag-based, or onEquip/Unequip events or what have ya .... )

I don't want to sound defeatist ('cause who knows what's possible in script), but i suspect that whatever workaround you might come up with won't be as general or straightforward as the original idea, in your script above.

#9
kamal_

kamal_
  • Members
  • 5 238 messages

Well, you certainly can have custom vfx on weapons. Alas I don't remember how I did it, but I don't remember it being particularly complicated or requiring scripting.

http://kamalpoe.blog...s-out-area.html



#10
kevL

kevL
  • Members
  • 4 052 messages
so apparently there's a way to attach an SEF to an item .. I've read four places that suggest as such, and two of them go on to attach the SEF to the creature instead. ( But they say that only *trail* special effects cannot be attached to items. )

assumption: the item has to have a "node" to attach to
assumption: all weapons have at least a "hand-node"
belief: the method -- whatever it is -- does not use ApplyEffectToObject()

... this would be a lot simpler if someone just came out and said it.

#11
kamal_

kamal_
  • Members
  • 5 238 messages
I've tried to remember and I think it was that only certain types of vfx could be applied. Something like you couldnt apply a creature vfx, but you could apply area vfx. If you checked what type of vfx I used for that blog post I bet it could be figured out. Since the post mentions I did it in response to a request there must be a thread somewhere from that time. I probably would have posted those pics to the forum so a google image search for them might turn up a link that goes to the pic in a thread here. The ringed weapon is probably the key to searching.

#12
kevL

kevL
  • Members
  • 4 052 messages
in Toolset, the item's Properties sheet, Appearance -> "fx_dryad_leaves"

unfortunately neither RemoveSEFFromObject(oItem) nor ApplyEffectToObject(oItem) appear to affect this.


looks like lawyers + executive ego borked us again ...

#13
Lance Botelle

Lance Botelle
  • Members
  • 1 480 messages
Hi,
 
There are some effects that can be applied direct to a weapon from within the toolset: E.g. "fx_magical_1", which I have used and they work in-game. I use them for my own "magikal" weapons.

This also works:
 
IPSafeAddItemProperty(oWeapon, ItemPropertyVisualEffect(ITEM_VISUAL_HOLY), 0.0, X2_IP_ADDPROP_POLICY_KEEP_EXISTING,TRUE,TRUE);
NOTE: There are only a few ITEM specific effects. (ACID/COLD/ELECTRICAL/EVIL/FIRE/HOLY and SONIC.) Perhaps there is a way to see how these effects differ from some of the others. I suspect what KevL says about nodes in models tying in with "effect nodes"? is the key.

Cheers,
Lance

#14
Serlith_

Serlith_
  • Members
  • 72 messages

Yeah, this works in my script as well. The point was to be able to add custom effects onto weapons on the fly. For now, we figured we can do it in the toolset as long as the weapon is not going through the crafting system afterwards, since it strips these off.

The function was meant to be called from the console to add th custom stuff on the fly ingame. Which is, well, impossible. When applying the FX through the character, you can't access the weapon's FX nodes which makes it all pointless. 

And since I am unable to work within the engine (and doubt nwnx would help on this one) to somehow convert Effect types to Itemproperty ones (Seriously, WHY ISN'T THIS A FEATURE), I guess I have to let this idea go.



#15
kevL

kevL
  • Members
  • 4 052 messages
Serlith,
you could ofc revamp the "custom effect" part of the script, point the target back to the PC, and for convenience use a Look-up table ( referencing a variety of input-strings to (string)SEF-outputs ) -- to attach an effect to the creature. (think ToB style)

And work that backwards, so to speak, for the removal of a weapon-SEF. Or even maintain a string-variable on the PC that holds its current sef-weapon-effect ....


--
unrelated note: looking at "fx_dryad_leaves" in the TS visual effects editor, it uses ATTACH_INVALID ... so do the "fx_defaultitem_*" SEF's. But don't see anything other that might mean this-is-for-an-item effect ... :\

#16
Serlith_

Serlith_
  • Members
  • 72 messages

Could you elaborate? I got lost at the look-up table. I blame lack of sleep.

And overall, wouldn't keeping that variable on the PC mean all weapons getting that SFX unless I delete/clear it with OnUnequip?
And #2, how should I create the call to the function? On the item (somehow?). When it comes to storing variables/function calls I know next to nothing. 



#17
kevL

kevL
  • Members
  • 4 052 messages
http://pastebin.myrror.net/2773

has a bunch of holes and may not result in the behavior you're looking for in all cases, but it is a proof of concept.

- intended to be run by a DM from the console
- only 1 SEF per weapon per character; ip-visuals will however stick to each weapon


the most noticeable hole I notice is that if a character gets an SEF for a weapon, then puts that weapon down and gets another SEF for a different weapon, but picks the first weapon up again, the SEF from the second weapon will display on both weapons.

All this assumes that onEquip/Unequip scripts handle weapon-switching appropriately. The basic checks would go like this:

[warning, no distinction has been made here between left & right weapons, yet that distinction *is* made in the application script ...]


// onEquip
if (GetLocalInt(oEquipItem, "weapon_effect_target") == ObjectToInt(oEquipper))
{
    string sVis = GetLocalString(oEquipper, "weapon_effect");
    effect eVis = EffectNWN2SpecialEffectFile(sVis);
    ApplyEffectToObject(DURATION_TYPE_PERMANENT, eVis, oEquipper);
}

// onUnequip
if (GetLocalInt(oUnequipItem, "weapon_effect_target") == ObjectToInt(oUnequipper))
{
    RemoveSEFFromObject(oUnequipper, GetLocalString(oUnequipper, "weapon_effect"));
}
[edit] I just noticed that the weapon-effect string should probably be put on the item as well ....

that might allow each weapon to have its own related SEF.

#18
kevL

kevL
  • Members
  • 4 052 messages
yeah it's looking like storing the SEF-string on the item simplifies matters greatly ...

#19
kevL

kevL
  • Members
  • 4 052 messages
much better
 
//
// - sWeaponVisual: string  "0" = ITEM_VISUAL_ACID
//                          "1" = ITEM_VISUAL_COLD
//                          "2" = ITEM_VISUAL_ELECTRICAL
//                          "3" = ITEM_VISUAL_FIRE
//                          "4" = ITEM_VISUAL_SONIC
//                          "5" = ITEM_VISUAL_HOLY
//                          "6" = ITEM_VISUAL_EVIL
//                          "<shortcut>" - uses lookup table to find SEF file
//                          "clear" - clears visual effects


#include "x2_inc_itemprop"

// Varname on item that holds current SEF (file w/out extension) of the weapon-visual.
const string WEAPON_EFFECT = "weapon_effect";

// Look-up table that converts an input-string to an SEF file string.
// This is for convenience at the console as well as denoting the SEF's that
// are allowable.
string getSef(string sShort);


//__________
// * MAIN **
void main(string sWeaponVisual)
{
    object oTarget = GetPlayerCurrentTarget(OBJECT_SELF);
    if (GetIsObjectValid(oTarget)
        && GetObjectType(oTarget) == OBJECT_TYPE_CREATURE
        && GetIsObjectValid(GetFactionLeader(oTarget)))
    {
        object oItem = GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oTarget);
        if (GetIsObjectValid(oItem)
            && IPGetIsMeleeWeapon(oItem))
        {
            // NOTE: no check has been done to ensure a valid input-string
            // before all vis (both SEF and IP) are removed.
            RemoveSEFFromObject(oTarget, GetLocalString(oItem, WEAPON_EFFECT));

            itemproperty ipVis = GetFirstItemProperty(oItem);
            while (GetIsItemPropertyValid(ipVis))
            {
                if (GetItemPropertyType(ipVis) == ITEM_PROPERTY_VISUALEFFECT)
                    RemoveItemProperty(oItem, ipVis);

                ipVis = GetNextItemProperty(oItem);
            }

            if (   sWeaponVisual == "0"
                || sWeaponVisual == "1"
                || sWeaponVisual == "2"
                || sWeaponVisual == "3"
                || sWeaponVisual == "4"
                || sWeaponVisual == "5"
                || sWeaponVisual == "6")
            {
                ipVis = ItemPropertyVisualEffect(StringToInt(sWeaponVisual));
                IPSafeAddItemProperty(oItem, ipVis);
            }
            else if (sWeaponVisual != "clear")
            {
                sWeaponVisual = getSef(sWeaponVisual);
                if (sWeaponVisual != "")
                {
                    SetLocalString(oItem, WEAPON_EFFECT, sWeaponVisual);

                    effect eVis = EffectNWN2SpecialEffectFile(sWeaponVisual);
                    ApplyEffectToObject(DURATION_TYPE_PERMANENT, eVis, oTarget);
                }
            }
        }
    }
}

// Look-up table that converts an input-string to an SEF file string.
// This is for convenience at the console as well as denoting the SEF's that
// are allowable.
// - sShort: short form of an allowable SEF file
// - return: full SEF file w/out extension or blank if input is invalid.
string getSef(string sShort)
{
    // this data could be put in a custom 2da file instead although code-only is faster.
    if (sShort == "lich")
        return "fx_lich_eyes";

    // etc...

    return "";
}
//on Equip
    string sWeaponFX = GetLocalString(GetPCItemLastEquipped(), "weapon_effect");
    if (sWeaponFX != "")
    {
        effect eVis = EffectNWN2SpecialEffectFile(sWeaponFX);
        ApplyEffectToObject(DURATION_TYPE_PERMANENT, eVis, GetPCItemLastEquippedBy());
    }
//on Unequip
    string sWeaponFX = GetLocalString(GetPCItemLastUnequipped(), "weapon_effect");
    if (sWeaponFX != "")
    {
        RemoveSEFFromObject(GetPCItemLastUnequippedBy(), sWeaponFX);
    }
[edit] edits

#20
Serlith_

Serlith_
  • Members
  • 72 messages

That's awesome! Thanks a lot, I'll play with it and see how it works. 



#21
kevL

kevL
  • Members
  • 4 052 messages
great. Feel free to tweak it up or do whatever ofc

#22
Serlith_

Serlith_
  • Members
  • 72 messages

Doing a second glance at the code, I see that it applies the FX to the character's body. I take it I cannot somehow soemhow reference the weapon's "nodes" without some shenanigans with the .sef file?

 

The worst thing is, if you apply the effect from the Toolset it WORKS properly. So why does the function not work when called from the script level...

 

 

Anyway, I'll get to it tomorrow. It's 2am here.



#23
kevL

kevL
  • Members
  • 4 052 messages
k,

the Appearance slot in properties isn't accessible by script ...

we're borked on that one. Yet that's where SEF's should go: like fx_defaultitem_* effects (by the way, the defaultitem* SEF's are the ones that get referenced by the ITEM_VISUAL_* constants)

And I really don't believe that slot is changeable by script. You'd have to make blueprints for all weapons with each effect pre-slotted, and swap items in and out ......


So if you want swappable visual effects via SEF, they have to be a different league of SEF file. These need attachment-nodes (the others do not) and they need to be applied to a creature-object. One or the other

Now, i don't know what stock SEFs, if any, represent weapon effects of the second sort. Except for the Silver Sword in the OC. it has special weapon effects as SEFs that apply to the character.


one thing still nags me though: The ITEM_VISUAL_* constants sure appear to use the 'defaultitem' SEF's for definitions, and they get converted to itemproperties .... This might be hard-coded, it might not,

#24
Serlith_

Serlith_
  • Members
  • 72 messages

Yep. That's the most mind-boggling thing about it. The ONLY hard-coded 2da and it HAS to reference SEF files. Bah, the custom effects I want to add are BASED on these .sefs. Argh. Why, anonymous Obsidian dev. Why.



#25
kevL

kevL
  • Members
  • 4 052 messages
get me the name of one of those .Sef that you want to use

the stock file, so I can tinker with it