Aller au contenu

Photo

OK, we have many ways to handle NPC Creatures events, but how to handle Hero/Party events?


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

#1
Nattfodd

Nattfodd
  • Members
  • 321 messages
After the examination of many scripts of the toolset, Wikies, threads etc., i can't understand yet how to manage events/commands/actions performed by my PC and party followers via scripting.

The only way is to replace the player_core and rules_core scripts?

If someone knows other ways (maybe .GDAs?) , i'll gladly welcome his/her suggestions.

Thanks.

#2
Challseus

Challseus
  • Members
  • 1 032 messages
Just make your own player_core (i.e. roe_player_core), like so:

void main()
{
    event ev = GetCurrentEvent();
    int nEventType = GetEventType(ev);
    // Setting this to true will prevent the script from invoking rules_core
    int bEventHandled = FALSE;
    switch(nEventType)
    {
        case EVENT_TYPE_DAMAGED:
            break;
    }
    if (!bEventHandled) //If this event wasn't handled by this script, let the core script try
    {
        HandleEvent(ev, RESOURCE_SCRIPT_PLAYER_CORE);
    }
}

Then, for the PC, you call the function, SetEventScript and pass in the player object (GetHero()), as well as the name of your script (roe_player_core.nss) that overrides player_core.nss. One thing to remember is that not all PC events are fired to this new script automatically, you'll need to specify them yourself using the function, EnablevEvent.

So for instance, to catch EVENT_TYPE_DAMAGED, you would do:

EnablevEvent(GetHero(), TRUE, EVENT_TYPE_DAMAGED);

For party members, just stick the overriding script as their core script via the creature editor.

Finally, as to where to call these functions, I personally call them at the module level, with the event, EVENT_MODULE_START. All my initialization functionality goes there.

Hope this helps.

Modifié par Challseus, 30 septembre 2010 - 01:07 .

  • sapphim aime ceci

#3
Proleric

Proleric
  • Members
  • 2 346 messages
That's a really helpful post - thanks!

A pitfall to be aware of is that both the follower tutorial on the wiki and the wrapper function WR_SetFollowerState reset the follower script to RESOURCE_SCRIPT_PLAYER_CORE under some circumstances. Obviously, you don't want that to happen if you're overriding the default script.

#4
Challseus

Challseus
  • Members
  • 1 032 messages

Proleric1 wrote...

That's a really helpful post - thanks!

A pitfall to be aware of is that both the follower tutorial on the wiki and the wrapper function WR_SetFollowerState reset the follower script to RESOURCE_SCRIPT_PLAYER_CORE under some circumstances. Obviously, you don't want that to happen if you're overriding the default script.


Ah yes, thanks for reminding me about that! Now, my particular situation may be different, but I gutted the hell out of the standard hiring scripts, and only kept what I needed. So, I have something like so:

AddPartyMember(object oPartyMember, resource rScript = RESOURCE_SCRIPT_ROE_PLAYER_CORE)
{    
    //bail out if already in party
    if (IsFollower(oPartyMember))
        return;

    //NOTE: This is gutted from UT_HireFollower. Currently, script does a lot of
    //hardcoded stuff, like preventing party members from leveling up, and other things I don't care about
    SetGroupId(oPartyMember, GetGroupId(GetPartyLeader()));
    WR_SetFollowerState(oPartyMember, FOLLOWER_STATE_ACTIVE, FALSE, 0, FALSE);
    SetEventScript(oPartyMember, rScript);
}

So, whenever I add a party member, I'll always be using my player core script. Or, I can pass the function a party member specific core script as well. Now, this function won't be useful for everyone, it's sort of tailored after what I need for my own module. For instance, this gets around the party member being auto-leveled when they join the team, as well as some other things I can't remember, but know I didn't care about at the time.

But yeah, good find, Proleric. That's one of the biggest gotchas around.

Modifié par Challseus, 30 septembre 2010 - 06:22 .


#5
Nattfodd

Nattfodd
  • Members
  • 321 messages
Very useful informations.

So is it better to call the SetEventScript() and EnableEvent() funcions in the EVENT_MODULE_START?

EnableEvent() can be called more times in sequence for each Event i want to redirect to my_player_core.nss?

The reset of the core script happens only to followers or also to the PC?

#6
Challseus

Challseus
  • Members
  • 1 032 messages

Nattfodd wrote...
So is it better to call the SetEventScript() and EnableEvent() funcions in the EVENT_MODULE_START?

 
It's really up to you, and how you want to do it. I just chose this, as it's the most logical place for me, since I do all my initialization related things in there. I look at it like this: I have events I need to have my custom script catch, so might as well get it going as soon as the module is started, versus at some other point, where events may have already started hitting the default script.

Nattfodd wrote...
EnableEvent() can be called more times in sequence for each Event i want to redirect to my_player_core.nss?


Indeed. I'm calling it about 8 times in a row for various events.

Nattfodd wrote...
The reset of the core script happens only to followers or also to the PC?


If you happen to remove the PC from the party (assuming someone else is in your party), and then add them back, yes, it will reset it. As an aside, I love the fact that you can remove the PC from the party.

#7
Proleric

Proleric
  • Members
  • 2 346 messages

Challseus wrote...
... I love the fact that you can remove the PC from the party.

If you can spare the time, it would be great to know how you're handling this.

Amongst other things, IIRC there was a developer post in the early days that recommended using GetPartyLeader in some circumstances, rather than GetHero. I guess this is one of those times?

#8
Nattfodd

Nattfodd
  • Members
  • 321 messages

Challseus wrote...
If you happen to remove the PC from the party (assuming someone else is in your party), and then add them back, yes, it will reset it. As an aside, I love the fact that you can remove the PC from the party.


Thanks and... i agree with you ;)

#9
Challseus

Challseus
  • Members
  • 1 032 messages

Proleric1 wrote...

Challseus wrote...
... I love the fact that you can remove the PC from the party.

If you can spare the time, it would be great to know how you're handling this.

Amongst other things, IIRC there was a developer post in the early days that recommended using GetPartyLeader in some circumstances, rather than GetHero. I guess this is one of those times?


So, in a nutshell, I currently remove the PC from the party upon death. I have this custom death system where dead party members become ghosts that walk the earth. The player should not be able to control them, so I simply remove them from the party, and this includes the PC.

So, if the PC dies, and they need to be made into a ghost, I do the following:

1) Remove them from the party. I have gutted out UT_FireFollower, but it essentially calls SetFollowerState(oPartyMember, FOLLOWER_STATE_AVAILABLE), along with some other module specific stuff.

2) Next, I need to promote another party member to party leader. I wrote this real simple function that handles that:
/**
 * This will take the first party member in the list, and make them the party leader.
 */
void PromoteNewPartyLeader()
{
    object[] partyMembers = GetPartyList();
    if (GetArraySize(partyMembers) > 0)
        SetPartyLeader(partyMembers[0]);
}

3) You are correct, you need to be calling GetPartyLeader in instances like this when you want to reference the head of the group. I imagine this is what Bioware used during the scene where party members had to break out the PC and Alistair from jail.

4) When I add the PC back to the party, I like to make them party leader again, so I just make a call to SetPartyLeader(GetHero()).

----------------------------------------------------------------------

Hope this helps.

Modifié par Challseus, 02 octobre 2010 - 05:19 .


#10
Proleric

Proleric
  • Members
  • 2 346 messages
Thanks!

#11
mutantspicy

mutantspicy
  • Members
  • 467 messages
hmm. I'm actually doing something very similar to this. In order capture Event_TYPE_EQUIP/UNEQUIP.  But have ran into some save game corruption when uninstalling my mod / event handlers.  I think it has something to do with SetEventScript.

Event_Handler (Module Script)
#include "log_h"
#include "utility_h"
#include "wrappers_h"
#include "events_h"

void main()
{
    event ev = GetCurrentEvent();
    int nEventType = GetEventType(ev);
    string sDebug;
    object [] oPartyList = GetPartyPoolList();
    int nEventHandled = FALSE;
    object oPc = GetHero();
    string sTag = "boots_spd";
    object oBoots = GetObjectByTag(sTag);
    {
    PrintToLog("my module handler :event "+IntToString(nEventType)+" from "+GetName(GetEventCreator(ev)));
    switch(nEventType)
        {
        case EVENT_TYPE_MODULE_START:
        case EVENT_TYPE_MODULE_LOAD:
        case EVENT_TYPE_PARTYMEMBER_ADDED:
        case EVENT_TYPE_PARTYMEMBER_DROPPED:

            {
            PrintToLog("event mod party drop");
             //assign custom event handler to each member of the party
            int i;
            for (i = 0; i < GetArraySize(oPartyList); i++)
                {
                PrintToLog("assign event handler to " + GetName(oPartyList[i]));
                EnablevEvent(oPartyList[i],TRUE,EVENT_TYPE_EQUIP);
                EnablevEvent(oPartyList[i],TRUE,EVENT_TYPE_UNEQUIP);
                SetEventScript(oPartyList[i],R"oracle_speed_event_handler.ncs");
                }
            nEventHandled = TRUE; //set this if no further action is required for this event
            break;
            }


        }
        if (!nEventHandled)
            {
            HandleEvent(ev, RESOURCE_SCRIPT_PLAYER_CORE);
            }
    }
}


The actual event script is :
//speed event handler

#include "log_h"
#include "utility_h"
#include "wrappers_h"
#include "events_h"

void main()
{
    event ev = GetCurrentEvent();
    int nEventType = GetEventType(ev);
    string sDebug;
    object oUser = OBJECT_SELF;

    switch(nEventType)
    {
        case EVENT_TYPE_EQUIP:
        {
            object oItem = GetEventObject(ev,0);
PrintToLog("event equip: "+GetName(oUser)+" - "+GetName(oItem));

            object oEquipper = GetEventCreator(ev);
            int nRace = GetCreatureRacialType(oEquipper);
            string sTag = "boots_spd";
            object oBoots = GetObjectByTag(sTag);
            {
            if(oItem == oBoots)
                {
                    if(nRace == 2)
                    {
                    SetAppearanceType(oEquipper,65010,TRUE);
                    }
                    else if(nRace == 3)
                    {
                    SetAppearanceType(oEquipper,65011,TRUE);
                    }
                 }
            }
            break;
        }

        case EVENT_TYPE_UNEQUIP:
        {
            object oItem = GetEventObject(ev,0);
PrintToLog("event unequip: "+GetName(oUser)+" - "+GetName(oItem));
            object oEquipper = GetEventCreator(ev);
            int nRace = GetCreatureRacialType(oEquipper);
            string sTag = "boots_spd";
            object oBoots = GetObjectByTag(sTag);
            {
            if(oItem == oBoots)
                {
                if(nRace == 2)
                    {
                    SetAppearanceType(oEquipper,2,TRUE);
                    }
                else if(nRace == 3)
                    {
                    SetAppearanceType(oEquipper,15,TRUE);
                    }
                }
            }
            break;
        }


    }
    //always let the default event handlers process the rest of the event otherwise things will break
     HandleEvent(ev, RESOURCE_SCRIPT_PLAYER_CORE);


}





Now this works great. Essentially what it does is change the appearance of the object equipper so that the movement rate is doubled.

The problem is. When you uninstall the MOD. it corrupts the game engine. The only way to fix it is then to copy these two scripts into the override. So I think somehow the SetEventScript is setting the default event handler to my event handler. And then when my mod is removed the game is still looking for my event handler. When its not there wierd things begin to happen.  Have any you, who seem to be doing something similar to my mod had similar problems and if so what did you do to fix it. Is there a way to reset the default Event handler back to Core Resources.


Examples of corruption :

-Once you enter combat mode.  combat mode will not exit when enemies are all dead.
-Can't use certain skills like herbalism (hero only, followers unaffected)
-mage staff won't do damage (hero only, followers unaffected)
-hero recieves major health regeneration.

Modifié par mutantspicy, 10 octobre 2010 - 10:50 .


#12
mutantspicy

mutantspicy
  • Members
  • 467 messages
A little more info.

I've found by opening savegames in the toolset that it is indeed the savegame files that get corrupted when using SetEventScript.

Under player char there is a String called
SAVEGAME_OBJECT_EVENTSCRIPT the value of this string should be blank when you are not using it. But for some reason, it doesn't get reset. So anytime you use SetEventScript this gets overwritten with your custom event handler that you are calling. It also shouldn't be set to player_core because that will cause double firing of certain events. So just a heads up some of you guys may run into this if you use SetEventScript. We need to find a way to reset this when uninstalling our projects.

My only thoughts on a solution.

Would be to find an event or create a custom event such as

EVENT_TYPE_MODULE_EXIT
SetEventScript (oPc,"")

Except there is no such Event.  So I dunno and I haven't tried creating custom events.

Modifié par mutantspicy, 11 octobre 2010 - 02:28 .


#13
Nattfodd

Nattfodd
  • Members
  • 321 messages
Are you sure that the problems you are getting are related to corrupted savegames. Are they really corrupted or having the SVEGAME OBJECT_EVENTSCRIPT with a value is a normal thing?



Have you tried without setting the "nEventHandled = TRUE" in the script that handle the EVENT_TYPE_MODULE_START, EVENT_TYPE_MODULE_LOAD, EVENT_TYPE_PARTYMEMBER_ADDED, EVENT_TYPE_PARTYMEMBER_DROPPED events?

#14
mutantspicy

mutantspicy
  • Members
  • 467 messages
Yeah the script originally didn't have the nEventHandled = TRUE in it. I added it to see if that would cure the problem. It seems to have no impact either way.

And yeah I'm sure the savegames are storing this value. Corrupting is the wrong word, because the savegames themselves are fine, but because the SAVEGAME_OBJECT_EVENTSCRIPT is storing whatever script from SetEventScript, whenever you remove your module and the subsequent Event Script is removed the player character and followers are left with an event handler that no longer exists.

So I've come to realize this command SetEventScript is dangerous. Consider the possibility of having two mods installed that set the PC event script to two different handlers. Which one gets used and when, or does it just simply break both mods.

So now I'm trying avoid this all together. Instead of Setting Event Scripts I'm overriding EngineEvents.GDA with Anakins Event manager that seems to be working very well. It allows you override events with a unique m2da ID. A very clever design. At least with the few test I've done in past day or two it works quite well.

Modifié par mutantspicy, 12 octobre 2010 - 02:56 .


#15
Nattfodd

Nattfodd
  • Members
  • 321 messages
Let me know if intercepting events with engineevents.gda works. I tried but i have not been able to intercept many events.

#16
TimelordDC

TimelordDC
  • Members
  • 923 messages
Hi Nattfold, you should check out Anakin's Event Manager. I think he does the same (setting the scripts) but on a temporary basis only - when that event is intercepted.

#17
Nattfodd

Nattfodd
  • Members
  • 321 messages
I'll try that tool, thanks for the advice.

#18
mutantspicy

mutantspicy
  • Members
  • 467 messages
@Nattfodd

The event manager is working quite well on my end. You basically do same process as above, but just leave out the seteventscript function. Then use your override to override those events. The event manager is not that well documented though, so if you have any questions on how to use it just ask. The documentation makes it seem way more complicated than it actually is. It took me bit to figure out what all was needed to be added to the override folders.


I had tried it about 6 months ago and couldn't get it to do anything, it seems the trick was enabling the events., In the module script.  Once I got that, the eventmanager worked like a charm.

Modifié par mutantspicy, 13 octobre 2010 - 06:32 .


#19
Nattfodd

Nattfodd
  • Members
  • 321 messages
@mutantspicy



I having troubles on using eventmanager:

Can you tell me the steps i have to follow?



The eventmanager can intercept only the events listed in engineevents.gda? No solutions for other events?