Aller au contenu

Photo

Editing Beholder AI


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

#1
Gem Hound

Gem Hound
  • Members
  • 118 messages

This is a monster. I've been fighting with this for a week, and so far all I have for my efforts is causing the player to shapeshift into a mindflayer, cast eldritch cone at the beholder-kin, and then cast fireburst on itself. This was when I replaced the snippet of code below to access my version of x2_s1_beholdatt. It is either that or I stay with the same rays. This is for a server that also has beholders, so I named the script called x2_s1_beholdray to x2_s1_gauthray. Now. I need to know how to access this spell to see what makes it tick:

ActionCastSpellAtObject(736,oIntruder,METAMAGIC_ANY,TRUE,0,PROJECTILE_PATH_TYPE_DEFAULT,TRUE);

736 is blank in Spells.2da, yet somehow points to all the beholder rays.

 

Now. I have 2 other questions. 

 

How would I go about replacing the deleted spell repulsion(for monster use only), and also adding a temporary dweomer drain to the beholder's Anti-magic ray?

 

The spell repulsion is important since it is one of the eye stalk powers of the beholder-kin I am making. 

 

This beholderkin is very focused on damage, speed, and it feeds on magic. Not only can it dispel your abilities, but it can also drain your item enchantments. It is completely immune to magic. 

 

Monster Manual on Beholderkin - the beholderkin is a Gauth.



#2
kevL

kevL
  • Members
  • 4 056 messages

I need to know how to access this spell to see what makes it tick:

ActionCastSpellAtObject(736,oIntruder,METAMAGIC_ANY,TRUE,0,PROJECTILE_PATH_TYPE_DEFAULT,TRUE);
736 is blank in Spells.2da, yet somehow points to all the beholder rays.


looks here like the stock Spells.2da has #736

Label: Beholder_Special_Spell_AI
ImpactScript: x2_s1_beholdatt


caveat: I'm am not really wanting to go through beholder-mania myself, but here are stock scripts that seem relevant:

x2_ai_behold.nss
x2_inc_beholder.nss
x2_s1_beholdray.nss

as well as the impact script.

[edit]
more in Spells.2da:

#727 Beholder_Anti_Magic_Cone, 'x2_s1_beantimag'
#776+ Beholder_Node_1 .. _10, 'x2_s1_beholdray'
  • Gem Hound aime ceci

#3
Gem Hound

Gem Hound
  • Members
  • 118 messages

Hmm, odd. My spells.2da doesn't have it even though the beholders still work(or at least its blanked out). I do not have 736 or any of the other beholder rays in Spells.2da. I know this because I combed through it for 3 hours last night after getting it organized by number.

 

I have already been monkeying around with all 4 of those scripts. They all compile nicely and actually run somewhat ingame, just need to connect them together.

 

Thankyou though. Maybe my toolset is acting up.

 

Now, about the other two questions. Do you know of a way to forcibly move a pc(if they fail a saving throw) if they enter a certain radius around another creature?

 

Also: Do you know of a way to get an item's magical properties and put them in an array?



#4
kevL

kevL
  • Members
  • 4 056 messages

Hmm, odd. My spells.2da doesn't have it even though the beholders still work(or at least its blanked out). I do not have 736 or any of the other beholder rays in Spells.2da. I know this because I combed through it for 3 hours last night after getting it organized by number.


WHAT HAVE YOU DONE jk.
honestly, i don't know what you mean "organized by number" ...

I don't know if you're using a custom .2da from the server, but i suggest taking a look in your <install>NwN2/Data folder and checking the Spells.2da there.

... Maybe my toolset is acting up.

- an external .2da editor is bonus


Do you know of a way to forcibly move a pc(if they fail a saving throw) if they enter a certain radius around another creature?


create an entry in Vfx_persistent.2da, and use its onEnter script ...


Also: Do you know of a way to get an item's magical properties and put them in an array?


no Array. Got to do it on the fly. First get the Item, then examine it with GetFirst/NextItemProperty()
  • Gem Hound aime ceci

#5
Gem Hound

Gem Hound
  • Members
  • 118 messages

Thankyou, you have been alot of help. :D  I might have more questions though if I hit another 2 day roadblock.



#6
kevL

kevL
  • Members
  • 4 056 messages

sounds bout right   :)_~



#7
Gem Hound

Gem Hound
  • Members
  • 118 messages

Just got back home and found it. Thank you very much, I can have this creature running in a few days now hopefully.



#8
Gem Hound

Gem Hound
  • Members
  • 118 messages

Now this I just wrote up out of the blue. Do you think it would be a good way to strip item enhancements? Or do you think I can do it in an even better way?

Spoiler
///edited in previous post


#9
Dann-J

Dann-J
  • Members
  • 3 161 messages

Now this I just wrote up out of the blue. Do you think it would be a good way to strip item enhancements? Or do you think I can do it in an even better way?

Spoiler

 

That script won't work, as you're trying to compare an effect variable with an integer variable (the constants). Therefore they'll never equal each other, and no properties will ever be removed.

 

You'll need to use something like GetEffectType() to set an integer to compare with the constants. Even then, that script will permanently remove item properties rather than temporarily. You can add a delayed command that re-adds the property after a certain amount of time though.


  • Gem Hound aime ceci

#10
Gem Hound

Gem Hound
  • Members
  • 118 messages

That script won't work, ...

Thanks, I hadn't even noticed you had posted yet sorry. I'll see what I can do with that. Hmm, another issue with that though, where would I save the item effects? 



#11
kevL

kevL
  • Members
  • 4 056 messages

Do you really want to remove all ip's of every item?

And then restore them because the removal was only temporary??

incl. things like weight reduction on magic bags??? I mean, i think there's unforeseen ramifications here .....


Ok back up a step. The only 'easy' way I can think of to maintain integrity of an original item is to CopyItem() to someplace safe, like a chest in an otherwise inaccessable area before IPs get removed.

But copying all items, especially containers with contents, is not trivial. So i suggest rethinking the Dweomer, perhaps to affect only equipped items (which ergo won't be containers), and/or filter the IPs that are affected, and/or make the loss permanent as a last resort.

You might end up doing a fair bit of data-tracking; storing the original items in the chest and as local_objects, associating those with specific characters, etc.


ps. personally I'd use Random() as an additional condition, sprinkle it here & there, to check if an item gets affected, and then if an IP gets affected -- only then check if an item has already been affected, if it needs to be deleted, replaced, and updated at the chest,

- do a check to see if an item even has IPs that can be affected ......


  • Gem Hound aime ceci

#12
Dann-J

Dann-J
  • Members
  • 3 161 messages

Instead of storing the effects, you can simply put a delayed command right beneath IPSafeRemoveItemProperty() that adds that same item property back again after a given amount of time.

 

I don't know what'd happen if you saved and quit the game while the item properties were removed but hadn't yet come back. Would the delayed commands still happen when you next reloaded?


  • Gem Hound aime ceci

#13
kevL

kevL
  • Members
  • 4 056 messages

Instead of storing the effects, you can simply put a delayed command right beneath IPSafeRemoveItemProperty() that adds that same item property back again after a given amount of time.


that'd be convenient. In fact ... setting up a pseudo-heartbeat with that data strikes me as way more convenient than storing items & locals. This way, do a check every X-seconds on the pseudo-HB, whether to see if the beholder is still in range or if perhaps duration has expired, and if true then let it replace the lost IP(s) and kill the p-HB.

*but* i'm not so sure that GetFirst/NextItemProperty() actually retrieves a complete IP. tests required

if it does, yeh just transfer the 'itemproperty' into a heartbeat and keep it cycling, ready to reapply.


I don't know what'd happen if you saved and quit the game while the item properties were removed but hadn't yet come back. Would the delayed commands still happen when you next reloaded?


uh, yeh, right. No, they wouldn't. ( so back to item-chests & locals )

(Unless the IPs are automatically reapplied on game save/exit and, on reloading, the Dweomer instantly removes them again, but what if program crashes etc)
  • Gem Hound aime ceci

#14
Gem Hound

Gem Hound
  • Members
  • 118 messages
Now this, is what I have for deleting the temporary effects(permanently), just incase someone wants to use it for something else in the future. 
void DoRemoveTempProperties(object oTarget)
{
object itemCur = GetFirstItemInInventory(oTarget);
while (itemCur != OBJECT_INVALID)
{
IPRemoveAllItemProperties(itemCur, DURATION_TYPE_TEMPORARY);
itemCur = GetNextItemInInventory(oTarget);
}
}
 
Now, about what you guys have said: The server is BGTSCC, as far as I know, there are no magical bags on the server, so I don't need to worry about that. Just about health kits, traps, weight reduction, etc.
They would hate me for doing it via your way kevL, and the creature would never get into the server. Too many items.
Now, the delayed command... That sounds really good, just to figure out how to write one. I believe the server restores items back to their original statistics when you log on again, but I could be terribly wrong. 
 
A Heartbeat script now, I have never made one.


#15
kevL

kevL
  • Members
  • 4 056 messages

ok here's the basic idea to a pseudo-heartbeat.

defender gets hit with anti-magic, fails save (or whatever)

in the script where the save is failed, call:


void DoRemoveAllProperties(object oTarget)
{
    object itemCur = GetFirstItemInInventory(oTarget);
    while (itemCur != OBJECT_INVALID)
    {
        itemproperty ip = GetFirstItemProperty(itemCur);
        while (GetIsItemPropertyValid(ip))
        {
            if (GetItemPropertyDurationType(ip) == DURATION_TYPE_PERMANENT) // kiss.
            {
                AntiMagicBeat(itemCur, ip); // <- pseudoHB start.
            }

            ip = GetNextItemProperty(itemCur);
        }


        IPRemoveAllItemProperties(itemCur, DURATION_TYPE_PERMANENT);
        IPRemoveAllItemProperties(itemCur, DURATION_TYPE_TEMPORARY);

        itemCur = GetNextItemInInventory(oTarget);
    }
}


// runs a pseudo-heartbeat per itemproperty (!!!)
void AntiMagicBeat(object oTarget, itemproperty ip)
{
    if ( /*conditions for restoring ip are met*/
        /* or a safety is triggered */ )
    {
        AddItemProperty(DURATION_TYPE_PERMANENT, ip, oTarget);
        return;
    }

    // else
    DelayCommand(6.f, AntiMagicBeat(oTarget, ip)); // 6 second delay till next check.
}


this is extremely basic ofc. And i suspect you'll have to compromise on something before a thing like this is acceptable to the administration. Perhaps by limiting the number of IPs that can be removed and hence run a pHB. Naturally, extra care need be taken that players won't lose their +5 Holy Axe of Balrog Whacking if -- read, when -- a sunflare eg. hits the pacific northwest and the burds head south. Or billy gets called to dinner and june decides she wants to play whakamole NOW. To make a long story short i wouldn't do it without a copy of the item *before ips are removed* /shrug.

ps, while you could group ips, to a pre-defined limit, 'member we don't get vector-arrays.


oh, and as I was looking at this .. a previous issue of whether or not GetFirst/NextItemProperty() returns a complete ip hasn't been addressed; that is, the code above assumes that it does,

#16
Gem Hound

Gem Hound
  • Members
  • 118 messages

Hmm, could I also do it with a delaycommand like this?

DelayCommand(fDelay, AddItemProperty(DURATION_TYPE_PERMANENT, ip, oTarget, fDuration));

fDelay == the distance between the Gauth and the player

 

fDuration == the time the effects for the other parts of the spell wear off

 

Also, no +5 hackmasters on this server, maximum magic is +4 and it is actually a relatively low magic setting considering its in the Forgotten Realms. :D

 

Once I actually get a working prototype, I have another player that is willing to help me playtest everything with a fully decked out char. Only thing we will not be able to test is what will happen if the server resets or the player leaves.

 

Or should I have an on area enter script that saves all the items to an inventory somewhere and somehow get the items to seamlessly replace the drained ones when the effects wear off? I'll have to check to see if that would work though with the area designers.



#17
kevL

kevL
  • Members
  • 4 056 messages
you could do it like Dj originally suggested,
 
void DoRemoveAllProperties(object oTarget)
{
    object itemCur = GetFirstItemInInventory(oTarget);
    while (itemCur != OBJECT_INVALID)
    {
        itemproperty ip = GetFirstItemProperty(itemCur);
        while (GetIsItemPropertyValid(ip))
        {
            if (GetItemPropertyDurationType(ip) == DURATION_TYPE_PERMANENT)
            {
                float fDelay = ANTIMAGIC_DURATION;
                DelayCommand(fDelay, AddItemProperty(DURATION_TYPE_PERMANENT, ip, oTarget));
            }

            ip = GetNextItemProperty(itemCur);
        }


        IPRemoveAllItemProperties(itemCur, DURATION_TYPE_PERMANENT);
        IPRemoveAllItemProperties(itemCur, DURATION_TYPE_TEMPORARY);

        itemCur = GetNextItemInInventory(oTarget);
    }
}
but the reason i didn't jump on it is because i figured you'd want distance to be the condition for restoring IPs.
Ie, this doesn't make sense:
 

fDelay == the distance between the Gauth and the player


( unless you really want it to ...)
 

fDuration == the time the effects for the other parts of the spell wear off


fDuration in AddItemProperty() is how long a DURATION_TYPE_TEMPORARY ip lasts ....

 

Once I actually get a working prototype, I have another player that is willing to help me playtest everything with a fully decked out char. Only thing we will not be able to test is what will happen if the server resets or the player leaves.


aye, yer gonna have to discuss it w/ a script-aware admin eventually
 

Or should I have an on area enter script that saves all the items to an inventory somewhere and somehow get the items to seamlessly replace the drained ones when the effects wear off? I'll have to check to see if that would work though with the area designers.


that's similar to the way I'd do it, except if you stick to the script then i believe it's more efficient to do CopyItem() only on items that check TRUE for one or more Permanent IPs ( players can just say bye to temporaries ) -- a lot less items for the server to track this way. But the loop'd have to be a tad more intricate ...
  • Gem Hound aime ceci

#18
Gem Hound

Gem Hound
  • Members
  • 118 messages

Sorry, I was basing that off of what was already in the script, I'm sort of a noob to NWScript. I'm not a noob to other languages though, so I have a basic understanding of what is going on, just I know nothing about what function does what in the fine print.



#19
kevL

kevL
  • Members
  • 4 056 messages

y I gather that, i just learned c++ a year ago but have been have been jabbing poking twisting NwScript for over a decade.


  • Gem Hound aime ceci

#20
Gem Hound

Gem Hound
  • Members
  • 118 messages

I have not been programming for a decade.

 

So now, back to this. 

 

Which do you think would cause less lag, the heartbeat script, or the hidden chest with items in it? Also, with this hidden chest, would there be a way to automatically return items to their proper equipment slots?



#21
kevL

kevL
  • Members
  • 4 056 messages
Which do you think would cause less lag, the heartbeat script, or the hidden chest with items in it?


less lag? probably the HB script. the item-structs* don't get copied, and there's less risk of a chug happening as items got re-equipped in their proper slots, the other way. But this method could suffer the 'unexpected event sydrome'

* if that's what they are.
 

 

Also, with this hidden chest, would there be a way to automatically return items to their proper equipment slots?


i don't think it can be done seamlessly; the only function I'm finding for it is ActionEquipItem(), which as an "action" takes 6 seconds per. ( edit: maybe not, but it's that -clunk- you hear )



You need to talk to the boys & gals at the other end. I'm starting to side more towards a HB. If the server goes down without saving state, things should revert to its last save either way (but there is a critical time between the anti-magic getting applied, and dissipating, a time that would be covered by CopyItem). And I really don't know what happens when a player's PC goes down vis-a-vis the GameWorld.

What i think might be best, now, is a combination of the two: Copy the items, let the server save state or not, but rely primarily on a p-HB to restore IPs. That way if something crashes either the server resets to a previous state, or at least the original items can be retrieved from the chest.

eh?



#22
Dann-J

Dann-J
  • Members
  • 3 161 messages

Ginc_item has a function that stores the equipped slots of items as local variables on them (RememberEquippedItems(object oOwner)). There is another function that restores them to their 'remembered' slots again (RestoreEquippedItems(object oOwner, int bReset=TRUE))


  • Gem Hound aime ceci

#23
kevL

kevL
  • Members
  • 4 056 messages

the Restore counterpart uses

AssignCommand(oOwner, ActionEquipItem(oInventoryItem, iSlot));


ActionEquipItem() might put everything back lickety split, but atm I'm imagining *clunk*clunk*clunk*clunk*clunk*clunk*clunk*

lol


... but yeah it has insight on how to track the owner and items w/ local ints & objects

#24
Gem Hound

Gem Hound
  • Members
  • 118 messages

Thanks to you both, I'll crack down on the code and see what I come up with on Saturday(day off).



#25
Tchos

Tchos
  • Members
  • 5 042 messages

Those functions didn't work well for me.


  • Gem Hound aime ceci