Jump to content

Q. about setup for a script involving a map marker


Recommended Posts

So - the only behavioural difference between your mapmarkers and regular ones is you don't want yours to appear on the compass until discovered. I think the only way you could perhaps do that without scripting is to add a set of your own markers, with either an empty or non-existent 'undiscovered' versions for the compass. However, even if that could work it would need a fair bit of mucking about with shockwave .swf files, which the UI uses - I don't recommend!

As scorrp10 says, the onLocationChange approach would work, but this might not be fine-grained enough to trigger the discovery exactly when you want it to.

Now, if you really wanted to, you could do a regular poll, eg once every second. You could have a player alias with a 'registerforupdate', and check every 'poll' if the player has walked into a zone less than a given amount away from each of your mapmarkers. Though this is sort of the wrong way around, and uses scripting time when it's not necessary - I still think you'd be better off with the trigger boxes as they don't use up resources until needed, and trigger exactly when entered, not up to a second off (or whatever your polling time is). Even if there's hundreds of them, there's no additional game overhead.

Btw, I think the trigger box you'd want to use is... defaultEnableDisableLinkedRef

Edited by dafydd99
Link to comment
Share on other sites

11 hours ago, csbx said:

EDIT: I've checked this and unless I'm mistaken, if someone tells you about the Shrine of Azura, the map marker becomes visible (but can't fast travel) and the only way to stop that is to disable that location marker beforehand. If I don't want any hint of a marker on my map for a location, disabling seems to be the only feasible way to do that. Radiant quests are pretty aggressive about getting their map markers on the map !

Not quite so.   Let's look more at the  'Visit the Shrine of Azura' (DA01Intro)  quest.    The dialogue info for it (Have you seen the Shrine of Azura) has a script fragment:

GetOwningQuest().SetStage(10)
MapMarker.AddToMap()

Where MapMarker property is filled with  SrineofAzuraMapMarkerREF   in ShrineofAzuraExterior01 cell.    The AddToMap() call is what actually makes the shrine marker visible on the world map.    If you do not want that happening, you just don't put that line of code  in.   The marker is still there, active, and is dicoverable via normal 'travel the world' means.

The other part of it is the quest  objective marker.  (The 'arrow')   
Speciically for this quest, the quest alias is Aranea (the NPC) , the quest objective (10) has her alias as TargetRef, and quest stage 10 fragment is:

SetObjectiveDisplayed(10, 1)

So when you get the objective (and make the quest active) you get the quest marker where Aranea is.   If you don't want that, just don't specify TargetRef on the objective.  Then there is no quest marker.

Link to comment
Share on other sites

32 minutes ago, scorrp10 said:

Not quite so.   Let's look more at the  'Visit the Shrine of Azura' (DA01Intro)  quest.    The dialogue info for it (Have you seen the Shrine of Azura) has a script fragment:

GetOwningQuest().SetStage(10)
MapMarker.AddToMap()

Where MapMarker property is filled with  SrineofAzuraMapMarkerREF   in ShrineofAzuraExterior01 cell.    The AddToMap() call is what actually makes the shrine marker visible on the world map.    If you do not want that happening, you just don't put that line of code  in.   The marker is still there, active, and is dicoverable via normal 'travel the world' means.

The other part of it is the quest  objective marker.  (The 'arrow')   
Speciically for this quest, the quest alias is Aranea (the NPC) , the quest objective (10) has her alias as TargetRef, and quest stage 10 fragment is:

SetObjectiveDisplayed(10, 1)

So when you get the objective (and make the quest active) you get the quest marker where Aranea is.   If you don't want that, just don't specify TargetRef on the objective.  Then there is no quest marker.

The scope of my mod includes modded locations but also vanilla quests like Azura. Maybe all radiant quests. Would you agree that it's not wise or efficient to muck around with making those adjustments across some  large number of vanilla quests ? Isn't disabling the marker (an option the mod Atlas Map Markers offers, btw) the way to efficiently get that outcome ? That part works. It's the re-enabling that I'm working on.

7 hours ago, dafydd99 said:

So - the only behavioural difference between your mapmarkers and regular ones is you don't want yours to appear on the compass until discovered. I think the only way you could perhaps do that without scripting is to add a set of your own markers, with either an empty or non-existent 'undiscovered' versions for the compass. However, even if that could work it would need a fair bit of mucking about with shockwave .swf files, which the UI uses - I don't recommend!

As scorrp10 says, the onLocationChange approach would work, but this might not be fine-grained enough to trigger the discovery exactly when you want it to.

Now, if you really wanted to, you could do a regular poll, eg once every second. You could have a player alias with a 'registerforupdate', and check every 'poll' if the player has walked into a zone less than a given amount away from each of your mapmarkers. Though this is sort of the wrong way around, and uses scripting time when it's not necessary - I still think you'd be better off with the trigger boxes as they don't use up resources until needed, and trigger exactly when entered, not up to a second off (or whatever your polling time is). Even if there's hundreds of them, there's no additional game overhead.

Btw, I think the trigger box you'd want to use is... defaultEnableDisableLinkedRef

This mod would include many vanilla radiant quests--with locations that would be all over the map. Not knowing which location will be chosen would mean setting up triggerboxes for hundreds of locations. Ain't nobody got time for dat. You're told about the Shrine, it appears on your map. Or a quest mod mentions a location--it appears on the map. I just want to be able to pre-empt that.

The polling method is what I'm working on now. I know it's very inelegant, but I'll do it the ugly way before getting to another option (skse ?).

What I've done is create an alias 'NearbyMapMarker' / Find matching reference in loaded area, closest. Allow disabled. Optional. I've set conditions getdisabled=1, getdistance (from player to object) < 2500 and HasRefType MapMarkerRefType = 1. I'm not sure about that last one. I don't think the alias is getting filled because I'm not getting anything out of my code attached to the alias:

  Event OnInit()
	    RegisterForUpdate(10.0)
 EndEvent


Event OnUpdate()
	If (NearbyMarker.getReference() as ObjectReference)

		ObjectReference FoundAMarker = NearbyMarker.getReference()
		debug.notification("this thing just happened--------------------------------------------------->")
		FoundAMarker.enable()
             GoToState("Active")
	else
		GoToState("Disabled")
	Endif
EndEvent

State Active
	;NearbyMarker.Clear()
EndState

State Disabled

EndState

There is probably a lot wrong with this code, given that I've never used onupdate or aliases before !

 

Link to comment
Share on other sites

To get a second go at filling an alias, you need to stop and restart the quest.

When the quest stops, it will unregisterForUpdate.  However, when you restart the quest your OnInit will run again, which will register.

You can probably just add a few lines after gotoState( "Disabled"):

	GoToState("Disabled")
	stop() ; stop() does not wait for the quest to be stopped
	while isStopping() ; start() will fail if you don't wait
		Utility.wait( 1.0)
	endwhile
	start()

You'll also need to do something similar once you are done with state "Active".

 

Edited by xkkmEl
Link to comment
Share on other sites

Okay, I think I'm getting a better idea of the scope of what you're trying to achieve. I'm now thinking you don't care if the undiscovered location appears on the compass or not - just that it doesn't appear on the map when a radiant quest begins (whether or not it is your own radiant quest).

Yes you could certainly do this via your alias method. Or you could just have a trigger box you moveTo() the mapmarker - might get complicated if you have more than one of these quests active at once though, though perhaps that's true of your alias method too.

But what do you want to do with a mapmarker that is currently already discovered before the radiant quest begins? I'm not sure there's a way to query whether its been visited or not yet. Although you could use EnableFastTravel(false) on it to turn off fast travel if it's already been discovered.

 

Link to comment
Share on other sites

9 hours ago, xkkmEl said:

To get a second go at filling an alias, you need to stop and restart the quest.

When the quest stops, it will unregisterForUpdate.  However, when you restart the quest your OnInit will run again, which will register.

You can probably just add a few lines after gotoState( "Disabled"):

	GoToState("Disabled")
	stop() ; stop() does not wait for the quest to be stopped
	while isStopping() ; start() will fail if you don't wait
		Utility.wait( 1.0)
	endwhile
	start()

You'll also need to do something similar once you are done with state "Active".

 

Thanks ! I've adjusted things a little--still have to work out the Active State. I'm not clear about what I'm doing..

 

8 hours ago, dafydd99 said:

Okay, I think I'm getting a better idea of the scope of what you're trying to achieve. I'm now thinking you don't care if the undiscovered location appears on the compass or not - just that it doesn't appear on the map when a radiant quest begins (whether or not it is your own radiant quest).

Yes you could certainly do this via your alias method. Or you could just have a trigger box you moveTo() the mapmarker - might get complicated if you have more than one of these quests active at once though, though perhaps that's true of your alias method too.

But what do you want to do with a mapmarker that is currently already discovered before the radiant quest begins? I'm not sure there's a way to query whether its been visited or not yet. Although you could use EnableFastTravel(false) on it to turn off fast travel if it's already been discovered.

 

Yes, exactly. If a map marker is already discovered by the player, I leave it discovered on the map.

At the startup of my mod (after installation on a game in progress e.g.) it checks to see if a marker is on the map or not--if it is, it leaves it alone without attempting to sleuth and apply the new regime retroactively. So, yeah, ideal on a new game.

I have no idea what I'm doing with aliases and the conditions, so would appreciate any assistance:

Scriptname CheckForDisabledMapMarkers extends ReferenceAlias  

ReferenceAlias property NearbyMarker auto

  Event OnInit()
	    RegisterForUpdate(10.0)
 EndEvent

Event OnUpdate()
	If (Nearbymarker != none)                                                                                                                   ;(NearbyMarker.getReference() as ObjectReference)

		ObjectReference FoundAMarker = NearbyMarker.getReference()
		debug.notification(foundamarker as string)

		debug.messagebox("this thing just happened--------------------------------------------------->")
		FoundAMarker.enable()
              debug.notification(foundamarker)
		GoToState("Active")
	else
		GoToState("Disabled")
		GetOwningQuest().stop() ;                  stop() does not wait for the quest to be stopped
		while GetOwningQuest().isStopping() ; start() will fail if you don't wait
			Utility.wait(1.0)
		endwhile
		GetOwningQuest().start()
	Endif
EndEvent

State Active
	;NearbyMarker.Clear()
EndState

State Disabled

EndState

 

My debugs are probably in the wrong spot, because I get 10s updates but the output is always 'none' even when near disabled mapmarkers.

I've tried several conditions for filling the alias including (getdisabled = 1, HasRefType (mapmarkerRefType) = 1)

But I've had no success. 

 

Link to comment
Share on other sites

Disabled references are not matched by alias fills unless you flag "allow disabled".

Your check "Nearbymarker != none" will always be true.  You definitely mean:

Nearbymarker.getReference() != none

If you have multiple aliases on this quest, you will need to make some changes, as the different referenceAlias scripts will be competing to stop and restart the quest.

When I wrote about the OnInit being run when the quest starts, and unregisterForUpdate happening when the quest stop, I was thinking of the quest script.  I have not tested thoroughly how the referenceAlias script behaves under these conditions.  I suggest you move your code to the quest script for now to reduce the number of unknowns.  In any case, you should stick to a single alias for the same reason until you make progress.

Don't forget to fill your properties!  Use "sqv myquest" in game to double check!

 

Link to comment
Share on other sites

16 hours ago, xkkmEl said:

Disabled references are not matched by alias fills unless you flag "allow disabled".

Your check "Nearbymarker != none" will always be true.  You definitely mean:

Nearbymarker.getReference() != none

If you have multiple aliases on this quest, you will need to make some changes, as the different referenceAlias scripts will be competing to stop and restart the quest.

When I wrote about the OnInit being run when the quest starts, and unregisterForUpdate happening when the quest stop, I was thinking of the quest script.  I have not tested thoroughly how the referenceAlias script behaves under these conditions.  I suggest you move your code to the quest script for now to reduce the number of unknowns.  In any case, you should stick to a single alias for the same reason until you make progress.

Don't forget to fill your properties!  Use "sqv myquest" in game to double check!

 

Thanks a lot. Yeah, I knew something was wrong when the != none was being satisfied but then the debug was printing out 'none' !

My problem now is that no objects (map markers) are satisfying the conditions I have on the alias: getdisabled = 1 and HasRefType (location ref type = mapmarkerRefType) = 1

I expect that standing near a disabled map marker will fill the alias but it isn't happening.

One alias makes sense for my purpose. Once a mapmarker fills the alias and then is enabled, the alias should be emptied and await the next one satisfying the conditions.

Is there an obvious way to set up an alias + conditions to nab map markers ?

 

Link to comment
Share on other sites

Do make sure you keep the quest start/stop loop going.  Aliases are only filled in the quest start process.  Either the alias fills, or not.  It's up to you to stop the quest and restart it if you want to try filling the alias again.  The last bit of code you shared had the loop going only while the alias fill was successful.

You may want to read Attaching Scripts to Objects.  Its goal is somewhat different from yours, but it shows how to setup a looping stop/start quest, if that's still an issue.

With or without the start/stop loop, you may want to start the quest manually from the console (startquest myquest / stopquest myquest).  It will trace most of your alias fill conditions, show you which ones pass and fail.

You may also want to note the refID of a map marker you are testing with, and check it out in xEdit, to confirm what base object it is using, what keywords are attached and whatever else.

LocationRefTypes are somewhat poorly named; it doubt the condition does what you intend (they access a type of key/value store associated with location objects). Unfortunately, I have not used map markers and don't know off hand how they are encoded.  The ones I can easily find in xEdit (out of 434 in skyrim.esm) have no markings except for the common base form (0x000010 MapMarker).  I think the condition you need is "subject.getIsId MapMarker == 1".

 

 

 

Link to comment
Share on other sites

Posted (edited)
On 3/14/2024 at 7:34 AM, xkkmEl said:

Do make sure you keep the quest start/stop loop going.  Aliases are only filled in the quest start process.  Either the alias fills, or not.  It's up to you to stop the quest and restart it if you want to try filling the alias again.  The last bit of code you shared had the loop going only while the alias fill was successful.

You may want to read Attaching Scripts to Objects.  Its goal is somewhat different from yours, but it shows how to setup a looping stop/start quest, if that's still an issue.

With or without the start/stop loop, you may want to start the quest manually from the console (startquest myquest / stopquest myquest).  It will trace most of your alias fill conditions, show you which ones pass and fail.

You may also want to note the refID of a map marker you are testing with, and check it out in xEdit, to confirm what base object it is using, what keywords are attached and whatever else.

LocationRefTypes are somewhat poorly named; it doubt the condition does what you intend (they access a type of key/value store associated with location objects). Unfortunately, I have not used map markers and don't know off hand how they are encoded.  The ones I can easily find in xEdit (out of 434 in skyrim.esm) have no markings except for the common base form (0x000010 MapMarker).  I think the condition you need is "subject.getIsId MapMarker == 1".

 

 

 

You made several suggestions that really helped me get to a solution to my problem. Thanks very much.  Here's how I have things set up now:

1) main quest has player alias that has onchangelocation that starts a separate quest, waits 5 seconds then shuts down that quest.

2) that second quest has an alias that looks for a mapmarker with conditions 'getisid mapmarker == 1' and 'getdisabled == 1'. It looks for an object in the loaded area / nearest.

The mapmarker alias has this script:

If Nearbymarker.getReference() != none    ;if the conditions were satisfied and the alias filled by a mapmarker near the player
    ObjectReference Mymarker = NearbyMarker.GetReference() as objectreference
    MyMarker.enable()
    debug.notification("the alias seems to have been filled")
Endif
 

This all works--radiant quests don't add a map marker for the relevant location. But visiting the location does do that.

Now that this works, I guess I have to create something that works more efficiently than this. The problems with what I have include:

1) player can just dip into a location and never notice the area the mapmarker pertains to, but it will be enabled anyway so will show on map when a quest points to it. I think that's not a major issue

2) this check on location change and looking for a mapmarker will occur every single time you cross into a new location. Seems maybe as ugly as just polling every 10s -- but maybe I'm wrong about that.

3) there may be map markers that are disabled in vanilla that I don't even know about that I will inadvertently be altering. I could run a check to see if alias_nearbymarker is in a formlist of mapmarkers - but that compounds the problem of (2)

I actually had an earlier version that skips the start/stop of a second quest and just embeds everything in the player alias onlocationchange--it checks to see if the aknewloc = getcurrentlocation.mapmarker[index]  where mapmarkers I've disabled are stored in a formlist. It worked, but seems like a demanding calculation if the formlist size is potentially in the hundreds.

Edited by csbx
Link to comment
Share on other sites

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...