dizietemblesssma Posted February 21, 2021 Share Posted February 21, 2021 I have the following in an MCM menu: Event OnKeyDown(Int code) If code == ess_hotkey && !Utility.IsInMenuMode() ;debug.messagebox("essential toggle pressed") scriptRef_things = (Game.GetFormFromFile(0x00000800, "dz_little_things.esp") as dz_little_things_script) scriptRef_hfclean = (Game.GetFormFromFile(0x00000801, "dz_hearthfire_cleanup.esp") as dz_hearthfire_cleanup_script) debug.messagebox(scriptRef_hfclean) debug.messagebox(scriptRef_things) ;scriptRef_things.dz_essential_toggle() EndIf EndEvent the onkeydown is working because I get a message box with the result of scriptRef_hfcleanbut the messagebox for scriptRef_things just says NONEhowever both esp names are correct, both scriptnames are correct and both lower order formids are correct.both esps are active and at the beginning of the script I have: dz_hearthfire_cleanup_script scriptRef_hfclean dz_little_things_script scriptRef_things there must be something else, perhaps outside the script that makes one work and not the other,any suggestions? diziet Link to comment Share on other sites More sharing options...
dizietemblesssma Posted February 21, 2021 Author Share Posted February 21, 2021 Well I found the cause, except it makes no sense to me.The script dz_little_things_script extended Actor, I changed it to extend ObjectReference and things worked.But I don't understand why GetFormFromFile won't work in the former case. diziet Link to comment Share on other sites More sharing options...
IsharaMeradin Posted February 21, 2021 Share Posted February 21, 2021 scriptRef_things = (Game.GetFormFromFile(0x00000800, "dz_little_things.esp") as dz_little_things_script) With this line you are telling papyrus to go fetch the form with the ID 0x00000800 within the ESP dz_little_things and then cast it to the script. You discovered that it will only work when the script extends ObjectReference rather than Actor. Why? The form with the ID 0x00000800 is most likely pointing to an ObjectReference form (i.e. a pre-placed actor). If you had cast the returning form into the appropriate type(s) then you would not have needed to change the script. For example:scriptRef_things = (((Game.GetFormFromFile(0x00000800,"dz_little_things.esp") as ObjectReference) as Actor) as dz_little_things_script) Link to comment Share on other sites More sharing options...
dizietemblesssma Posted February 21, 2021 Author Share Posted February 21, 2021 Put like that it makes sense, but leaves me wondering why it ever worked before since, in both cases: scriptRef_things = (Game.GetFormFromFile(0x00000800, "dz_little_things.esp") as dz_little_things_script) scriptRef_hfclean = (Game.GetFormFromFile(0x00000801, "dz_hearthfire_cleanup.esp") as dz_hearthfire_cleanup_script) the intent is to run a function or access a variable that are on the scripts, in each case the esps may or may not exist e.g. scriptRef_hfclean = (Game.GetFormFromFile(0x00000801, "dz_hearthfire_cleanup.esp") as dz_hearthfire_cleanup_script) scriptRef_hfclean.dz_state_windstad(toggle_cleanup_windstad) If scriptRef_hfclean.wind_first_run == False ShowMessage("$haven't_finished_quest",False) toggle_cleanup_windstad = False EndIf so the form will be that of an xmarker in each esp to which one of the scripts is attached: So I'm not sure how I would follow your example of casting multiple times.Fortunately I have managed to get my dz_little_things_script to compile extending Objectreference, so at the moment it's an academic confusion for me:) Thanks for replying. diziet Link to comment Share on other sites More sharing options...
IsharaMeradin Posted February 21, 2021 Share Posted February 21, 2021 The hfclean works because it is pointing to an ObjectReference (a pre-placed object). Same reason that the actor one ended up working when the script was changed to extend ObjectReference. Script wise ObjectReference does extend Form, so casting would typically be: SomeForm as ObjectReference. But because pre-placed objects have their own formID already, fetching that with GetFormFromFile will yield the object reference form and it can then be cast into the script without explicitly casting into ObjectReference beforehand. The same line with casting would appear as:scriptRef_hfclean = ((Game.GetFormFromFile(0x00000801, "dz_hearthfire_cleanup.esp") as ObjectReference) as dz_hearthfire_cleanup_script) Now because the mod may or may not exist, it might be smarter to not cast directly to the script but first check that the mod exists. Cause while GetFormFromFile will fail without in-game issue, the code following doesn't even need to try running (which it will) if the mod does not exist. An adjustment as an example: ObjectReference Ref_hfclean = (Game.GetFormFromFile(0x00000801, "dz_hearthfire_cleanup.esp") as ObjectReference If Ref_hfclean ;if a valid object - the mod exists scriptRef_hfclean = Ref_hfclean as dz_hearthfire_cleanup_script scriptRef_hfclean.dz_state_windstad(toggle_cleanup_windstad) If scriptRef_hfclean.wind_first_run == False ShowMessage("$haven't_finished_quest",False) toggle_cleanup_windstad = False EndIf EndIf Link to comment Share on other sites More sharing options...
dizietemblesssma Posted February 23, 2021 Author Share Posted February 23, 2021 the line:scriptRef_hfclean = (Game.GetFormFromFile(0x00000801, "dz_hearthfire_cleanup.esp") as dz_hearthfire_cleanup_script)appears in an mcm menu that only appears if a check for the mod's existence succeedsmisc_menus_script ScriptName dz_misc_mcm_menu_script Extends SKI_ConfigBase import FissFactory String[] page_names Actor Property PlayerRef Auto ;;;variables for diziet's drafting table remover mod mcm menu;;; Bool toggle_cleanup_lakeview ;enable/disable draftint tables Bool toggle_cleanup_heljarchen ;enable/disable draftint tables Bool toggle_cleanup_windstad ;enable/disable draftint tables dz_hearthfire_cleanup_script scriptRef_hfclean ;access diziet's drafting table remover mod script ;;;----------------------------------------------------------;;; ;;;variables for diziet's little things;;; Int ess_hotkey = 24 Int null_key = -1 dz_little_things_script scriptRef_things ;access diziet's little things script Float carry ;;;----------------------------------------------------------;;; Int Function GetVersion() ;version function Return 2 ; Default version EndFunction Event OnConfigInit() EndEvent Event OnConfigOpen() ;;;max number of supported mods is two;;; ;;;hearthfire cleanup aka Diziet's Drafting Table Remover;;; page_names = New String[3] ;max size of page_names array ;;;test for number of installed diziet misc mods;;; Int i = 0 If Game.IsPluginInstalled("dz_hearthfire_cleanup.esp") ;check for diziet's drafting table remover mod page_names[i] = "Drafting Tables" i += 1 EndIf If Game.IsPluginInstalled("dz_little_things.esp") ;check for diziet's little things carry = PlayerRef.GetActorValue("CarryWeight") as Float RegisterForKey(ess_hotkey) page_names[i] = "Little Things" i += 1 EndIf ;;;number of menu pages needed is i;;; If i == 1 Pages = New String[1] ElseIf i == 2 Pages = New String[2] EndIf ;;;set the names of the pages;;; Int k = 0 While k < i Pages[k] = page_names[k] k +=1 EndWhile EndEvent Event OnVersionUpdate(Int a_version) If (a_version >= 2 && CurrentVersion < 2) Debug.Trace(self + ": Updating Diziet's Misc MCM Menus script to version 2") Debug.Notification("Diziet's Misc MCM Menus updating to Version 2") EndIf EndEvent Event OnPageReset(String a_page) If a_page == "" ;exit if page is "" ;ShowMessage("a_page = \"\" Returning",False) Return EndIf If a_page == "Drafting Tables" ;/ AddHeaderOption("Options for Diziet's Drafting Table Remover") AddEmptyOption() AddEmptyOption() /; SetCursorFillMode(TOP_TO_BOTTOM) ;fill the page with toggles etc. AddEmptyOption() AddHeaderOption("$Lakeview_Cleanup") AddToggleOptionST("state_lakeview_cleanup","$cleanup_lakeview?",toggle_cleanup_lakeview) AddEmptyOption() AddHeaderOption("$Heljarchen_Cleanup") AddToggleOptionST("state_heljarchen_cleanup","$cleanup_heljarchen?",toggle_cleanup_heljarchen) AddEmptyOption() AddHeaderOption("$Windstad_Cleanup") AddToggleOptionST("state_windstad_cleanup","$cleanup_windstad?",toggle_cleanup_windstad) EndIf If a_page == "Little Things" SetCursorFillMode(TOP_TO_BOTTOM) ;fill the page with toggles etc. AddHeaderOption("$select_key_essential") AddKeyMapOptionST("state_essential_hotkey","$set_essential_hotkey",ess_hotkey) AddToggleOptionST("state_null_essential_hotkey","$null_essential_hotkey",False) AddEmptyOption() AddEmptyOption() AddHeaderOption("$carryweight_cheat") AddSliderOptionST("state_carry_slider", "$choose_the_carryweight", carry) EndIf EndEvent ;;;the following states apply to the mod Diziet's Drafting Table Remover;;; State state_lakeview_cleanup Event OnSelectST() toggle_cleanup_lakeview = !toggle_cleanup_lakeview scriptRef_hfclean = (Game.GetFormFromFile(0x00000801, "dz_hearthfire_cleanup.esp") as dz_hearthfire_cleanup_script) scriptRef_hfclean.dz_state_lakeview(toggle_cleanup_lakeview) If scriptRef_hfclean.lake_first_run == False ShowMessage("$haven't_finished_quest",False) toggle_cleanup_lakeview = False EndIf SetToggleOptionValueST(toggle_cleanup_lakeview) EndEvent Event OnDefaultST() toggle_cleanup_lakeview = False SetToggleOptionValueST(toggle_cleanup_lakeview) EndEvent Event OnHighlightST() SetInfoText("$remove_exterior_crafting_table_from_lakeview_manor") EndEvent EndState State state_heljarchen_cleanup Event OnSelectST() toggle_cleanup_heljarchen = !toggle_cleanup_heljarchen scriptRef_hfclean = (Game.GetFormFromFile(0x00000801, "dz_hearthfire_cleanup.esp") as dz_hearthfire_cleanup_script) scriptRef_hfclean.dz_state_heljarchen(toggle_cleanup_heljarchen) If scriptRef_hfclean.helj_first_run == False ShowMessage("$haven't_finished_quest",False) toggle_cleanup_heljarchen = False EndIf SetToggleOptionValueST(toggle_cleanup_heljarchen) EndEvent Event OnDefaultST() toggle_cleanup_heljarchen = False SetToggleOptionValueST(toggle_cleanup_heljarchen) EndEvent Event OnHighlightST() SetInfoText("$remove_exterior_crafting_table_from_heljarchen_hall") EndEvent EndState State state_windstad_cleanup Event OnSelectST() toggle_cleanup_windstad = !toggle_cleanup_windstad scriptRef_hfclean = (Game.GetFormFromFile(0x00000801, "dz_hearthfire_cleanup.esp") as dz_hearthfire_cleanup_script) scriptRef_hfclean.dz_state_windstad(toggle_cleanup_windstad) If scriptRef_hfclean.wind_first_run == False ShowMessage("$haven't_finished_quest",False) toggle_cleanup_windstad = False EndIf SetToggleOptionValueST(toggle_cleanup_windstad) EndEvent Event OnDefaultST() toggle_cleanup_windstad = False SetToggleOptionValueST(toggle_cleanup_windstad) EndEvent Event OnHighlightST() SetInfoText("$remove_exterior_crafting_table_from_windstad_manor") EndEvent EndState ;;;end of states for Diziet's Drafting Table Remover;;; ;;;the following states and functions apply to Diziet's Little Things;;; State state_essential_hotkey Event OnKeyMapChangeST(Int keyCode, String conflictControl, String conflictName) Bool continue = True If (conflictControl != "") String msg If (conflictName != "") msg = "$KeyMapConflict{" + conflictControl + "}{" + conflictName + "}" Else msg = "$KeyMapConflict{" + conflictControl + "}" EndIf continue = ShowMessage(msg, True, "$Yes_text", "$No_text") EndIf If (continue) ess_hotkey = keyCode SetKeyMapOptionValueST(keyCode) EndIf RegisterForKey(keyCode) EndEvent EndState State state_null_essential_hotkey Event OnSelectST() ess_hotkey = null_key SetKeyMapOptionValueST(null_key,False,"state_essential_hotkey") EndEvent EndState State state_carry_slider Event OnSliderOpenST() SetSliderDialogStartValue(carry) SetSliderDialogDefaultValue(300) SetSliderDialogRange(100,10000) SetSliderDialogInterval(10) EndEvent Event OnSliderAcceptST(float a_value) carry = a_value PlayerRef.SetActorValue("CarryWeight", carry) SetSliderOptionValueST(carry) EndEvent Event OnDefaultST() carry = 300 SetSliderOptionValueST(carry) EndEvent Event OnHighlightST() SetInfoText("$carry_slide_info") EndEvent EndState ;;;the following functions are for FISSES;;; ;;;save function for Diziet's Little Things Function dz_save_fiss_little_things() ;;;get a reference to the FISS Interface;;; FISSInterface fiss = FISSFactory.getFISS() ;;;check if FISS is installed;;; If !fiss debug.messageBox("FISS not installed. Saving disabled") Return EndIf ;;;save variables;; fiss.beginSave("diziets_little_things\\fiss.xml","little_things") fiss.saveInt("ESSKEY", ess_hotkey) String saveResult = fiss.endSave() ;;;check the result;;; If saveResult != "" debug.Trace(saveResult) EndIf EndFunction Function dz_load_fiss_little_things() ;;;get a reference to the FISS Interface;;; FISSInterface fiss = FISSFactory.getFISS() ;;;check if FISS is installed;;; If !fiss debug.messageBox("FISS not installed. Loading disabled") Return EndIf ;;;load variables;;; fiss.beginLoad("diziets_little_things\\fiss.xml") ess_hotkey = fiss.loadInt("ESSKEY") EndFunction ;;;end of states and functions for Diziet's Little Things ;;;the following keydown events apply to all;;; Event OnKeyDown(Int code) If code == ess_hotkey ;debug.messagebox("essential toggle pressed") scriptRef_things = (Game.GetFormFromFile(0x00000800, "dz_little_things.esp") as dz_little_things_script) ;scriptRef_hfclean = (Game.GetFormFromFile(0x00000801, "dz_hearthfire_cleanup.esp") as dz_hearthfire_cleanup_script) ;debug.messagebox(scriptRef_hfclean) ;debug.messagebox(scriptRef_things) If scriptRef_things.secondpress == False scriptRef_things.dz_essential_toggle() ElseIf scriptRef_things.secondpress == True scriptRef_things.dz_setessential() EndIf EndIf EndEvent hearthfire_cleanup_script Scriptname dz_hearthfire_cleanup_script Extends ObjectReference;;this mod will be controlled by my misc mcm menus mod ;dz_misc_mcm_menu_script Property dz_mcm Auto;;;insert objects as properties here;;;---------------------;;;ObjectReference Property dz_new_lake_xmarker Auto ObjectReference Property dz_new_helj_xmarker Auto ObjectReference Property dz_new_wind_xmarker Auto;;;has this script been run before on any of the homes?;;; Bool Property lake_first_run Auto Bool Property helj_first_run Auto Bool Property wind_first_run AutoFunction dz_state_lakeview(Bool cleanup)ObjectReference lake_xmarker = (Game.getForm(0x0300307b) as ObjectReference) ;vanilla game xmarker If cleanup == True && lake_xmarker.IsDisabled() Return ;since you can't clean up a non-existent table) ElseIf cleanup == True && !lake_xmarker.IsDisabled() ;we wish to clean up and the marker is enabled lake_xmarker.Disable() ;disable the marker dz_new_lake_xmarker.Enable() ;enable our marker to keep chopping block present and prevent disabled trees etc. from coming back lake_first_run = True ElseIf cleanup == False && !lake_xmarker.IsDisabled() Return ElseIf cleanup == False && lake_xmarker.IsDisabled() && lake_first_run == True lake_xmarker.Enable() EndIf EndFunctionFunction dz_state_heljarchen(Bool cleanup)ObjectReference helj_xmarker = (Game.getForm(0x0300C3C6) as ObjectReference) ;vanilla game xmarker If cleanup == True && helj_xmarker.IsDisabled() Return ;since you can't clean up a non-existent table) ElseIf cleanup == True && !helj_xmarker.IsDisabled() ;we wish to clean up and the marker is enabled helj_xmarker.Disable() ;disable the marker dz_new_helj_xmarker.Enable() ;enable our marker to keep chopping block present and prevent disabled trees etc. from coming back helj_first_run = True ElseIf cleanup == False && !helj_xmarker.IsDisabled() Return ElseIf cleanup == False && helj_xmarker.IsDisabled() && helj_first_run == True helj_xmarker.Enable() EndIf EndFunctionFunction dz_state_windstad(Bool cleanup)ObjectReference wind_xmarker = (Game.getForm(0x0300A50E) as ObjectReference) ;vanilla game xmarker If cleanup == True && wind_xmarker.IsDisabled() Return ;since you can't clean up a non-existent table) ElseIf cleanup == True && !wind_xmarker.IsDisabled() ;we wish to clean up and the marker is enabled wind_xmarker.Disable() ;disable the marker dz_new_wind_xmarker.Enable() ;enable our marker to keep chopping block present and prevent disabled trees etc. from coming back wind_first_run = True ElseIf cleanup == False && !wind_xmarker.IsDisabled() Return ElseIf cleanup == False && wind_xmarker.IsDisabled() && wind_first_run == True wind_xmarker.Enable() EndIf EndFunction little_things_script ScriptName dz_little_things_script Extends Actor import Actor ;;;this mod will be controlled by my misc mcm menus mod;;;these GMST variables control daylight/night;;; ;fTimeSpanAfternoonEnd ;fTimeSpanAfternoonStart ;fTimeSpanEveningEnd ;fTimeSpanEveningStart ;fTimeSpanMidnightEnd ;fTimeSpanMidnightStart ;fTimeSpanMorningEnd ;fTimeSpanMorningStart ;fTimeSpanNightEnd ;fTimeSpanNightStart ;fTimeSpanSunriseEnd ;fTimeSpanSunriseStart ;fTimeSpanSunsetEnd ;fTimeSpanSunsetStart;Int Property ess_keycode = 24 Auto Bool Property secondpress Auto ;to keep track of messagebox open Bool ess_bool;;;to toggle the NPC under the crosshair to essential/non-essential;;; ;;;press hotkey once for status, a second time to toggle while message still displays;;; Function dz_essential_toggle() ;debug.notification("essential toggle pressed")Actor NPCRef = Game.GetCurrentCrosshairRef() as Actor ;the actor under the crosshair If !NPCRef debug.messagebox("There is no NPC under the crosshair") Return EndIf String actorname = NPCRef.GetBaseObject().Getname() ;the actor's name ;debug.notification("NPC is "+actorname) ess_bool = NPCRef.IsEssential() ;is the actor essential? Bool prot_bool = NPCRef.GetActorBase().IsProtected() ;is the actor protected? String ess_status ;message about essentual status String prot_status ;message about protected status If ess_bool == True ess_status = "essential" Else ess_status = "non-essential" EndIf If prot_bool == True prot_status = "protected" Else prot_status = "not protected" EndIf ;String msg = "$status_msg" String msg = "press the key again within five seconds to change the essential status." debug.messagebox(actorname+ " is "+ess_status+ "\n and "+prot_status+" \n"+msg) secondpress = True ;while this is true a second press is diverted to dz_setessential() function ;debug.notification("secondpress is "+secondpress) Utility.WaitMenumode(5.0) secondpress = False ;debug.notification("secondpress is "+secondpress) Int ActKey = Input.GetMappedKey("Activate") Input.TapKey(ActKey) ;Send 'Enter' to close messageboxEndFunctionFunction dz_setessential() Int ActKey = Input.GetMappedKey("Activate") Input.TapKey(ActKey) ;Send 'Enter' to close messagebox secondpress = False ;debug.notification("secondpress is "+secondpress) Actor NPCRef = Game.GetCurrentCrosshairRef() as Actor String actorname = NPCRef.GetBaseObject().Getname() ;the actor's name ;is messagebox open? ess_bool = !ess_bool ;toggle essential status debug.notification("setting essential status") If ess_bool == True NPCRef.GetActorBase().SetEssential(True) ;need to use GetActorBase here If NPCRef.IsEssential() debug.messagebox(actorname+" is now essential") EndIf Utility.WaitMenumode(1) Input.TapKey(Actkey) Else NPCRef.GetActorBase().SetEssential(False) If !NPCRef.IsEssential() debug.messagebox(actorname+" is no longer essential") EndIf Utility.WaitMenumode(1) Input.TapKey(Actkey) EndIf ;debug.notification("setting function") EndFunction perhaps I'm confusing myself but in both the lines:scriptRef_things = (Game.GetFormFromFile(0x00000800, "dz_little_things.esp") as dz_little_things_script)scriptRef_hfclean = (Game.GetFormFromFile(0x00000801, "dz_hearthfire_cleanup.esp") as dz_hearthfire_cleanup_script) the form is an xmarker, both markers have the relevant script attached with a function I wish to run e.g scriptRef_x.the_function hence my difficulty in seeing the functional difference. As I said I did rewrite the one script to compile and work, so this isn't currently a 'live' issue:) diziet Link to comment Share on other sites More sharing options...
IsharaMeradin Posted February 23, 2021 Share Posted February 23, 2021 You may be confusing yourself. Just remember that if the target of GetFormFromFile is a pre-placed ObjectReference (i.e. has its own formID) and the attached script extends ObjectReference then you can cast to the script without casting to ObjectReference. But if the target script extends a child class such as Actor then you'll need to cast to Actor before trying to cast to the script. Also, the screenshot shows a plugin local formID of 00001801 for the xmarker rather than 00000801. Is there a mistake somewhere? Link to comment Share on other sites More sharing options...
dizietemblesssma Posted February 24, 2021 Author Share Posted February 24, 2021 Also, the screenshot shows a plugin local formID of 00001801 for the xmarker rather than 00000801. Is there a mistake somewhere? That's just xedit isn't it? the esp is the first esl flagged file loaded so xedit adds a 1 as in FE001 for the mod order loading. in the esp the low order form id is still 801, if loaded later the full id in xedit might be 00002801. diziet Link to comment Share on other sites More sharing options...
IsharaMeradin Posted February 24, 2021 Share Posted February 24, 2021 If that is the case, I did not know. I haven't delved too much into light plugins. I certainly haven't converted any that were targets of GetFormFromFile. Another approach to consider is SKSE mod events. I actually find them to be a little more useful. But if you don't have control over the other mod, then you cannot register for the event and run the code when your script sends the event. In that case, you're still stuck with using GetFormFromFile. Link to comment Share on other sites More sharing options...
Recommended Posts