Aller au contenu

Photo

HELP!!!! My module is wrecking people's save games.


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

#1
mutantspicy

mutantspicy
  • Members
  • 467 messages
Hello, 

I have a mod called Oracle.  Its a basic armor add mod.  I recently added some significant Event handling script in order to use Event_Type_Equip / Unequip.  In order create a special event script that does the following.

When boot of speed are equipped, set appearance = to a custom apr GDA which double movement rate.
When boots of speed are unequipped set appearance normal.

The Script compiles, the mod works flawlessly..

The problem

When you uninstall the mod, the game and/or save game files become corrupted.
 
Things like.

Can't use certain skills like herbalism, weopons won't do damage, major health regeneration, can't exit combat mode.

Now reinstall the mod, or copy my event handling script into the override.  The game is back to normal.

So how is it possible that when my mod is uninstalled, the game become corrupt and requires my event handler to function properly.

Is there some module property I need to set to prevent this or is there a way to reset the game back using its own event handler upon uninstall?

See next post for the scripts in question.

#2
mutantspicy

mutantspicy
  • Members
  • 467 messages
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);


}

Modifié par mutantspicy, 11 octobre 2010 - 12:43 .


#3
FollowTheGourd

FollowTheGourd
  • Members
  • 572 messages
Just a wild guess, but what happens if you make an "uninstall script" like
"for each follower and the player: SetEventScript(oPC_or_oFollower, RESOURCE_SCRIPT_PLAYER_CORE)"? Maybe the player is getting left without a valid default event handler?

Modifié par FollowTheGourd, 11 octobre 2010 - 04:18 .


#4
mutantspicy

mutantspicy
  • Members
  • 467 messages
Actually thats what I've been working on. As of now the only way I can figure to do it is to have a item with a unique power that SetEventScript(oPc,"") if you set oPc to Resource_Script_Player_Core, then you end up with events that double fire. Things happen like when you level up, when you add attribute points, instead of 1 point you get 2. That said, I haven't been able to find any kind of Event_Types like module exit or uninstalled. I guess I'm not sure how you'd make an uninstall script. I've been using DAO Modmanager or just the Bioware checkbox to uninstall, but haven't found any event types that are related to uninstalling a mod.

I've found out that in the save game file, there's a string under playerchar called OBJECT_EVENTSCRIPT.  It should be blank , but using SetEventScript fills it in with my event handler.  oracle_speed_event_handler.  So when that is not installed.  The game is looking for it, buts its not there.  So You thoughts on the right track.  I just don't know how to go about an uninstall script. 

Modifié par mutantspicy, 11 octobre 2010 - 05:51 .


#5
FollowTheGourd

FollowTheGourd
  • Members
  • 572 messages
How many copies of the armour are there in your game? Could you do something like "uninstall" the event handler if the player chooses to remove it from their inventory (destroys it or puts it in a container) and then "reinstall" if it goes back in to the inventory (presuming that's not bypassed before being equipped)? You'd still have people complaining who don't read instructions, but it would provide a simple way without needing to use the console to run a script, if that'd work.

Modifié par FollowTheGourd, 11 octobre 2010 - 08:02 .


#6
mutantspicy

mutantspicy
  • Members
  • 467 messages
Once again you've responded to my freakishness with some pretty good ideas. Thanks.

#7
mutantspicy

mutantspicy
  • Members
  • 467 messages
As of now, I'm able to reset the savegame info thru use of an extra item with an activated unique ability. I called it panic button for lack of a better name. It essentially resets player character and follower event scripts back to default. Like we are talking.  Thanks for your thoughts it helped me to sort this out.

I tried to do it with an EVENT_TYPE_INVENTORY_REMOVED but I didn't have much luck, it seemed to break the rest of my event handler. I don't know why really. Maybe thats another one that needs to be turned on with enablevevents.  The panic button idea does the samething really, but I would to look at doing it through removing the items.  It seems more natural, but I needed something that works right now and panic button did the trick.  I felt horrible for corrupting people's savegames. 

Either way the bigger concern I have; is if this command (SetEventScript) behaves this way it seems to me that if you were to have multiple mods that use seteventscript for the PC or Followers, then things would just completely break. There needs to be a better way of basically Setting the Event script just temporarily while you need it. And then quickly resetting the script back to default so other mods would be able to do there thing as well. On second thought, why is this information even stored in the savegame file to begin with? It just seems very limiting/Dangerous.

Modifié par mutantspicy, 12 octobre 2010 - 01:36 .


#8
mutantspicy

mutantspicy
  • Members
  • 467 messages
DDDDDDDouble

Modifié par mutantspicy, 12 octobre 2010 - 01:31 .


#9
TimelordDC

TimelordDC
  • Members
  • 923 messages
You could try using Anakin's Event Manager to handle your EVENT_TYPE_EQUIP and EVENT_TYPE_UNEQUIP and see if it works. That way, you would not need to set your own event script and it would co-exist peacefully with other mods that do the same thing.

#10
mutantspicy

mutantspicy
  • Members
  • 467 messages
Well Anakin kinda disapeered. So he wasn't available for comments or suggestions. And I really just couldn't figure that thing out. I tried it and didn't get anywhere. That said, after going thru all of this, I do understand the event system better, and maybe now his event manager would actually make sense to me. At the time I created this mod. That thing didn't make any sense, I couldn't tell if it was doing anything or not.

#11
mutantspicy

mutantspicy
  • Members
  • 467 messages
Well excellent. I decided to give anakin's event manager another go. This time it worked like a charm. Totally skirts the issue of setting event scripts. I think the difference this time was the event type equip/unequip are actually enabled, with the enablevevent command. The first time around, I hadn't figure that part out yet, and therefor nothing I did worked. So yeah. Eventmanager does the trick. SWEET.

#12
TimelordDC

TimelordDC
  • Members
  • 923 messages
Glad it worked. No more panic button :D

#13
mutantspicy

mutantspicy
  • Members
  • 467 messages
Well I still need it for those who already installed the mod. The panic button is the only way short of opening the savegame files in the toolset, of cleaning up the mess SetEventScript leaves behind.

#14
mutantspicy

mutantspicy
  • Members
  • 467 messages
The interesting thing about the Eventmanager and I'll have to test it out to be sure. Is I think I can override those events with multiple override scripts. So idea would be having multiple items that add spell like affects. Boots of Speed, Robe of Rock Armor, Gloves of Spell Wisp, and so on. So I'll have to experiment with using multiple overrides to see how this goes with Event Manager, but it seems like it should work since each override has its own ID.

#15
TimelordDC

TimelordDC
  • Members
  • 923 messages
Why would you need multiple overrides? You can use the switch statement inside the events to apply the effects you want based on the item.



For those already using the mod, you could release an update that sets back the scripts to the default and bundle the Event Manager code in to get rid of the panic button. Just an idea.

#16
mutantspicy

mutantspicy
  • Members
  • 467 messages
Because I suck at scripting. :)

Just to keep my events small and tidy. 

Modifié par mutantspicy, 12 octobre 2010 - 04:39 .


#17
TimelordDC

TimelordDC
  • Members
  • 923 messages
Well, it should be easy enough to do. A quick example, if you are interested (switch statement accepts only integers so I'm switching by race ID) -
            
case EVENT_TYPE_EQUIP:
{
    object oItem = GetEventObject(ev,0);
    object oEquipper = GetEventCreator(ev);
    int nRace = GetCreatureRacialType(oEquipper);

    switch(nRace)
    {
        case 2:
        {
            if (oItem = GetObjectByTag("boots_spd"))
            {
                SetAppearanceType(oEquipper,65010,TRUE);
            }
            else if (oItem = GetObjectByTag("robe_rck_armr")) 
            {
                SetAppearanceType(oEquipper, APR_ID_FOR_ROBE, TRUE);
            }
            break;
        }

        case 3:
        {
            if (oItem = GetObjectByTag("boots_spd")) 
            {
                SetAppearanceType(oEquipper,65011,TRUE);
            }
            else if (oItem = GetObjectByTag("robe_rck_armr")) 
            {
                SetAppearanceType(oEquipper, APR_ID_FOR_ROBE, TRUE);
            }
            break;
        }
    }
    break;
}


#18
mutantspicy

mutantspicy
  • Members
  • 467 messages
hmm. I thought I responded to this yesterday, but its not here.



Thanks. I didn't realize you could use a switch command like that, I thought it was some special function for switching event case. Not a generic integer switch. Very cool.

#19
mutantspicy

mutantspicy
  • Members
  • 467 messages
Actually, since you seem pretty knowledgeable.



I like to use arrays for my item names so this way I can add multiple variations of items easily, later on.



The problem becomes, I would know need some logic to determine item type. It seems to me the ID's in the Bitem. xls is the way to do this. However, in the toolset 2da consts, not all of the item types in the bitem.xls are set to const. So I was using GetBaseItemType(oitems[x]) to return the bitm ID row. But it not really working. Do I need to set the those items to constant? Or perhaps do you know of a list of armor items types.



BASE_ITEM_GLOVES_LIGHT, ""_BOOTS_LIGHT, etc.

#20
TimelordDC

TimelordDC
  • Members
  • 923 messages
Only the following are defined as constants -
const int BASE_ITEM_TYPE_SHORTBOW = 19;
const int BASE_ITEM_TYPE_LONGBOW = 20;
const int BASE_ITEM_TYPE_ARMOR_LIGHT = 9;
const int BASE_ITEM_TYPE_ARMOR_MEDIUM = 10;
const int BASE_ITEM_TYPE_ARMOR_HEAVY = 11;
const int BASE_ITEM_TYPE_ARMOR_MASSIVE = 12;
const int BASE_ITEM_TYPE_ARMOR_SUPERMASSIVE = 22;
const int BASE_ITEM_TYPE_STAFF = 16;
const int BASE_ITEM_TYPE_QUICK = 39;
const int BASE_ITEM_TYPE_GIFT = 109;
...and only because these are used in the core/single player scripts to do certain things like setting tutorial plot flags (armor types for fatigue) or calculating damage (when main weapon is staff), etc.

What do you get when you run the function against your items?

#21
mutantspicy

mutantspicy
  • Members
  • 467 messages
woohoo. Success. Apparently GetBaseItemType does return the bitm ID integers.

Just when I added this to my script, I forgot to check if event item = item array first. So things went whacko.

So now that I got the logic right, it does turn out that GetBaseItemType does in fact return the bitm id's.
Cool.

heres the working script

    // Boots
    rFileNames[0] = R"bts_spd_a.uti";
    rFileNames[1] = R"bts_spd_b.uti";

    //Robes
    rFileNames[2] = R"robe_rock_armor.uti";
    rFileNames[3] = R"oracle_rock_armor.uti";


    //Gloves
    rFileNames[4] = R"glvs_spl_wisp_a.uti";
    rFileNames[5] = R"glvs_spl_wisp_b.uti";

                case 1:
                {
                    int x;
                    for(x = 0; x < GetArraySize(rFileNames); x++)
                    {
                    sTags[x] = ResourceToTag(rFileNames[x]); //gets all the tags from your file names
                    oItems[x] = GetObjectByTag(sTags[x]); //turns the tags into objects
                        if(oItem == oItems[x])
                        {
                            if(GetBaseItemType(oItems[x])==1)  // looks for light boot types
                            {
                            SetAppearanceType(oEquipper,65022,TRUE);   // speed increase
                            }
                            else if(GetBaseItemType(oItems[x])==38)   // looks for clothing types
                            {
                            AddAbility(oEquipper,400022);
                            command cSpell = CommandUseAbility(400022,oEquipper);  // casts rock armor
                            WR_AddCommand(oEquipper,cSpell);
                            Ability_SubtractAbilityCost(oEquipper,400022);
                            }
                            else if(GetBaseItemType(oItems[x])==32)    // looks for glove types
                            {
                            AddAbility(oEquipper,400023);
                            command cSpell = CommandUseAbility(400023,oEquipper);    //casts spell wisp
                            WR_AddCommand(oEquipper,cSpell);
                            Ability_SubtractAbilityCost(oEquipper,400023);
                            }
                        }

                    }
                break;
                }

Modifié par mutantspicy, 13 octobre 2010 - 05:48 .


#22
mutantspicy

mutantspicy
  • Members
  • 467 messages
Just an update I figured out why I couldn't get two seperate overrides happening. I needed to set the eventmanager gda to listen type 2 and eliminate the Handleevent command from my handler. I'm not exactly sure how it works, but I suspect its the eventmanager script is doing the handleevent, and queuing it up by m2da ID number.