[Resource] GetCurrentHold() function script

Post » Thu Oct 22, 2015 4:49 pm

The other day I posted in the QQQA thread asking for the current best practice for discerning which hold the player is currently in. I was suggested to check for a keyword on the current cell's Location. The problem with that is most of the unnamed "Wilderness" cells don't have a Location set. So I eventually figured it out by using a resource Chesko posted in here a while ago for a IsPointInPoligon() function.

First thing I had to do was find out some coordinates for vertices along the hold borders, so I made this:

https://www.dropbox.com/s/2sia3qrcb1eu1d4/SkyrimHoldRegions.png?dl=0%E2%80%8B

Then using those coordinates, I put together this script:

Spoiler

Scriptname TEST_HoldCheckerScript extends Quest;---------------------------------------------------------------PROPERTIESActor property playerREF  auto;----------------------------------------------------------------VARIABLESfloat[] fWhiterunXfloat[] fWhiterunYfloat[] fSolitudeXfloat[] fSolitudeYfloat[] fWindhelmXfloat[] fWindhelmYfloat[] fMarkarthXfloat[] fMarkarthYfloat[] fRiftenXfloat[] fRiftenYfloat[] fFalkreathXfloat[] fFalkreathYfloat[] fWinterholdXfloat[] fWinterholdYfloat[] fMorthalXfloat[] fMorthalYfloat[] fDawnstarXfloat[] fDawnstarY;-------------------------------------------------------------------EVENTSevent OnInit()	Setup()endEvent;----------------------------------------------------------------FUNCTIONSfunction Setup()	fWhiterunX = new float[16]	fWhiterunY = new float[16]	fWhiterunX[00] = -28.00	fWhiterunX[01] = -23.00	fWhiterunX[02] = -11.00	fWhiterunX[03] = 0.00	fWhiterunX[04] = 8.00	fWhiterunX[05] = 16.00	fWhiterunX[06] = 19.00	fWhiterunX[07] = 18.00	fWhiterunX[08] = 16.00	fWhiterunX[09] = 12.00	fWhiterunX[10] = 0.00	fWhiterunX[11] = -4.00	fWhiterunX[12] = -13.00	fWhiterunX[13] = -9.00	fWhiterunX[14] = -24.00	fWhiterunX[15] = -28.00	fWhiterunY[00] = 8.00	fWhiterunY[01] = 6.00	fWhiterunY[02] = 5.00	fWhiterunY[03] = 5.00	fWhiterunY[04] = 3.00	fWhiterunY[05] = 2.00	fWhiterunY[06] = -1.00	fWhiterunY[07] = -5.00	fWhiterunY[08] = -12.00	fWhiterunY[09] = -16.00	fWhiterunY[10] = -13.00	fWhiterunY[11] = -14.00	fWhiterunY[12] = -9.00	fWhiterunY[13] = -6.00	fWhiterunY[14] = -2.00	fWhiterunY[15] = 4.00	fSolitudeX = new float[11]	fSolitudeY = new float[11]	fSolitudeX[00] = -44.00	fSolitudeX[01] = -42.00	fSolitudeX[02] = -36.00	fSolitudeX[03] = -18.00	fSolitudeX[04] = -12.00	fSolitudeX[05] = -11.00	fSolitudeX[06] = -20.00	fSolitudeX[07] = -24.00	fSolitudeX[08] = -27.00	fSolitudeX[09] = -31.00	fSolitudeX[10] = -37.00	fSolitudeY[00] = 8.00	fSolitudeY[01] = 24.00	fSolitudeY[02] = 31.00	fSolitudeY[03] = 36.00	fSolitudeY[04] = 34.00	fSolitudeY[05] = 28.00	fSolitudeY[06] = 21.00	fSolitudeY[07] = 21.00	fSolitudeY[08] = 18.00	fSolitudeY[09] = 20.00	fSolitudeY[10] = 19.00	fWindhelmX = new float[12]	fWindhelmY = new float[12]	fWindhelmX[00] = 16.00	fWindhelmX[01] = 18.00	fWindhelmX[02] = 19.00	fWindhelmX[03] = 24.00	fWindhelmX[04] = 29.00	fWindhelmX[05] = 32.00	fWindhelmX[06] = 44.00	fWindhelmX[07] = 48.00	fWindhelmX[08] = 42.00	fWindhelmX[09] = 46.00	fWindhelmX[10] = 40.00	fWindhelmX[11] = 28.00	fWindhelmY[00] = -12.00	fWindhelmY[01] = -5.00	fWindhelmY[02] = -1.00	fWindhelmY[03] = 4.00	fWindhelmY[04] = 8.00	fWindhelmY[05] = 12.00	fWindhelmY[06] = 20.00	fWindhelmY[07] = 0.00	fWindhelmY[08] = -16.00	fWindhelmY[09] = -13.00	fWindhelmY[10] = -12.00	fWindhelmY[11] = -12.00	fRiftenX = new float[11]	fRiftenY = new float[11]	fRiftenX[00] = 16.00	fRiftenX[01] = 17.00	fRiftenX[02] = 12.00	fRiftenX[03] = 16.00	fRiftenX[04] = 28.00	fRiftenX[05] = 40.00	fRiftenX[06] = 46.00	fRiftenX[07] = 52.00	fRiftenX[08] = 52.00	fRiftenX[09] = 40.00	fRiftenX[10] = 28.00	fRiftenY[00] = -28.00	fRiftenY[01] = -20.00	fRiftenY[02] = -16.00	fRiftenY[03] = -12.00	fRiftenY[04] = -12.00	fRiftenY[05] = -12.00	fRiftenY[06] = -13.00	fRiftenY[07] = -16.00	fRiftenY[08] = -32.00	fRiftenY[09] = -36.00	fRiftenY[10] = -32.00	fFalkreathX = new float[11]	fFalkreathY = new float[11]	fFalkreathX[00] = -24.00	fFalkreathX[01] = -16.00	fFalkreathX[02] = -13.00	fFalkreathX[03] = -4.00	fFalkreathX[04] = 0.00	fFalkreathX[05] = 12.00	fFalkreathX[06] = 17.00	fFalkreathX[07] = 16.00	fFalkreathX[08] = 8.00	fFalkreathX[09] = -8.00	fFalkreathX[10] = -16.00	fFalkreathY[00] = -13.00	fFalkreathY[01] = -12.00	fFalkreathY[02] = -9.00	fFalkreathY[03] = -14.00	fFalkreathY[04] = -13.00	fFalkreathY[05] = -16.00	fFalkreathY[06] = -20.00	fFalkreathY[07] = -28.00	fFalkreathY[08] = 32.00	fFalkreathY[09] = -32.00	fFalkreathY[10] = -28.00	fMarkarthX = new float[17]	fMarkarthY = new float[17]	fMarkarthX[00] = -48.00	fMarkarthX[01] = -48.00	fMarkarthX[02] = -44.00	fMarkarthX[03] = -37.00	fMarkarthX[04] = -31.00	fMarkarthX[05] = -27.00	fMarkarthX[06] = -25.00	fMarkarthX[07] = -25.00	fMarkarthX[08] = -23.00	fMarkarthX[09] = -28.00	fMarkarthX[10] = -28.00	fMarkarthX[11] = -24.00	fMarkarthX[12] = -19.00	fMarkarthX[13] = -13.00	fMarkarthX[14] = -16.00	fMarkarthX[15] = -24.00	fMarkarthX[16] = -40.00	fMarkarthY[00] = -8.00	fMarkarthY[01] = 8.00	fMarkarthY[02] = 16.00	fMarkarthY[03] = 19.00	fMarkarthY[04] = 20.00	fMarkarthY[05] = 18.00	fMarkarthY[06] = 16.00	fMarkarthY[07] = 12.00	fMarkarthY[08] = 6.00	fMarkarthY[09] = 8.00	fMarkarthY[10] = 4.00	fMarkarthY[11] = -2.00	fMarkarthY[12] = -6.00	fMarkarthY[13] = -9.00	fMarkarthY[14] = -12.00	fMarkarthY[15] = -13.00	fMarkarthY[16] = -8.00	fWinterholdX = new float[13]	fWinterholdY = new float[13]	fWinterholdX[00] = 8.00	fWinterholdX[01] = 8.00	fWinterholdX[02] = 12.00	fWinterholdX[03] = 13.00	fWinterholdX[04] = 12.00	fWinterholdX[05] = 28.00	fWinterholdX[06] = 44.00	fWinterholdX[07] = 44.00	fWinterholdX[08] = 32.00	fWinterholdX[09] = 29.00	fWinterholdX[10] = 24.00	fWinterholdX[11] = 20.00	fWinterholdX[12] = 12.00	fWinterholdY[00] = 16.00	fWinterholdY[01] = 22.00	fWinterholdY[02] = 23.00	fWinterholdY[03] = 25.00	fWinterholdY[04] = 32.00	fWinterholdY[05] = 32.00	fWinterholdY[06] = 28.00	fWinterholdY[07] = 20.00	fWinterholdY[08] = 12.00	fWinterholdY[09] = 8.00	fWinterholdY[10] = 9.00	fWinterholdY[11] = 12.00	fWinterholdY[12] = 14.00	fMorthalX = new float[13]	fMorthalY = new float[13]	fMorthalX[00] = -23.00	fMorthalX[01] = -25.00	fMorthalX[02] = -25.00	fMorthalX[03] = -27.00	fMorthalX[04] = -24.00	fMorthalX[05] = -20.00	fMorthalX[06] = -12.00	fMorthalX[07] = -7.00	fMorthalX[08] = -4.00	fMorthalX[09] = -2.00	fMorthalX[10] = 2.00	fMorthalX[11] = 0.00	fMorthalX[12] = -11.00	fMorthalY[00] = 6.00	fMorthalY[01] = 12.00	fMorthalY[02] = 16.00	fMorthalY[03] = 18.00	fMorthalY[04] = 21.00	fMorthalY[05] = 21.00	fMorthalY[06] = 25.00	fMorthalY[07] = 26.00	fMorthalY[08] = 22.00	fMorthalY[09] = 20.00	fMorthalY[10] = 16.00	fMorthalY[11] = 5.00	fMorthalY[12] = 5.00	fDawnstarX = new float[19]	fDawnstarY = new float[19]	fDawnstarX[00] = 0.00	fDawnstarX[01] = 2.00	fDawnstarX[02] = -2.00	fDawnstarX[03] = -4.00	fDawnstarX[04] = -7.00	fDawnstarX[05] = -6.00	fDawnstarX[06] = 9.00	fDawnstarX[07] = 13.00	fDawnstarX[08] = 12.00	fDawnstarX[09] = 8.00	fDawnstarX[10] = 8.00	fDawnstarX[11] = 12.00	fDawnstarX[12] = 20.00	fDawnstarX[13] = 24.00	fDawnstarX[14] = 29.00	fDawnstarX[15] = 24.00	fDawnstarX[16] = 19.00	fDawnstarX[17] = 16.00	fDawnstarX[18] = 8.00	fDawnstarY[00] = 5.00	fDawnstarY[01] = 16.00	fDawnstarY[02] = 20.00	fDawnstarY[03] = 22.00	fDawnstarY[04] = 26.00	fDawnstarY[05] = 30.00	fDawnstarY[06] = 29.00	fDawnstarY[07] = 25.00	fDawnstarY[08] = 23.00	fDawnstarY[09] = 22.00	fDawnstarY[10] = 16.00	fDawnstarY[11] = 14.00	fDawnstarY[12] = 12.00	fDawnstarY[13] = 9.00	fDawnstarY[14] = 8.00	fDawnstarY[15] = 4.00	fDawnstarY[16] = -1.00	fDawnstarY[17] = 2.00	fDawnstarY[18] = 3.00	;Debug.Notification("Init complete")endFunctionbool function IsPointInPolygon(float[] polyX, float[] polyY, float x, float y)	;-----------\	;Description \	;----------------------------------------------------------------	;Attempts to determine if a given point (x, y) lies inside the bounds of a polygon described as a series	;of ordered pairs described in the polyX[] and polyY[] arrays.	;If (x, y) lies exactly on one of the line segments, this functiom may return True or False.	;From http://alienryderflex.com/polygon/, converted to Papyrus by Chesko		;-------------\	;Return Values \	;----------------------------------------------------------------	;		True				=		 	Point is inside polygon	;		False				=			Point lies outside polygon OR polygon arrays are of different lengths	;float[] polyX = array that describes the polygon's x coordinates	;float[] polyY = array that describes the polygon's y coordinates	;float x	   = the x coordinate under test	;float y	   = the y coordinate under test		;Polygon arrays must be the same length	if polyX.Length != polyY.Length		return false	endif		int polySides = polyX.Length	int i = 0	int j = polySides - 1	bool oddNodes = false	while i < polySides		if (((polyY[i] < y && polyY[j] >= y) || (polyY[j] < y && polyY[i] >= y)) && (polyX[i] <= x || polyX[j] <= x))			if (polyX[i] + (y- polyY[i]) / (polyY[j] - polyY[i]) * (polyX[j] - polyX[i])) < x				oddNodes = !oddNodes			endif		endif		j = i		i += 1	endWhile		return oddNodesendFunctionint function GetCurrentHold()	float fX = (playerREF as ObjectReference).GetPositionX() / 4096	float fY = (playerREF as ObjectReference).GetPositionY() / 4096	Debug.Notification("Player position = " + fX + "," + fY)	if IsPointInPolygon(fWhiterunX, fWhiterunY, fX, fY) == true		return 01	elseIf IsPointInPolygon(fSolitudeX, fSolitudeY, fX, fY) == true		return 02	elseIf IsPointInPolygon(fWindhelmX, fWindhelmY, fX, fY) == true		return 03	elseIf IsPointInPolygon(fMarkarthX, fMarkarthY, fX, fY) == true		return 04	elseIf IsPointInPolygon(fRiftenX, fRiftenY, fX, fY) == true		return 05	elseIf IsPointInPolygon(fFalkreathX, fFalkreathY, fX, fY) == true		return 06	elseIf IsPointInPolygon(fWinterholdX, fWinterholdY, fX, fY) == true		return 07	elseIf IsPointInPolygon(fMorthalX, fMorthalY, fX, fY) == true		return 08	elseIf IsPointInPolygon(fDawnstarX, fDawnstarY, fX, fY) == true		return 09	else		return 00	endIfendFunction


All you have to do is make a Quest, attach that script to it (maybe change the name) and fill the PlayerREF property. Then call the GetCurrentHold() function from your script. I would recommend you do an if-check first to make sure the player is in the "Tamriel" worldspace, because anywhere else will give false results. Here are the return values:

0 = ERROR
1 = Whiterun
2 = Solitude
3 = Windhelm
4 = Markarth
5 = Riften
6 = Falkreath
7 = Winterhold
8 = Morthal
9 = Dawnstar


Finally, I quickly put together a mod to test the script. It adds a spell that diplays the current hold as well as the players coordinates. I would appreciate if a few people would test it and let me know how relable the script is, the only character I have has not unlocked many points on the map so I am a bit limited in my testing

http://www.nexusmods.com/skyrim/mods/70768/?

Hope it helps,

- Hypno
User avatar
Sista Sila
 
Posts: 3381
Joined: Fri Mar 30, 2007 12:25 pm

Return to V - Skyrim