Script to extract Water & Milk: Compiling failure...plea

Post » Mon Jun 18, 2012 11:07 pm

I've tried to introduce the possibility for the character to activate a bucket and have the option to pickup or fill it with either water (of different types) or milk (cow or goat).

The idea was to have the script check for the surroundings and follow this rationale:
1) The script checks if the activating actor is a NPC or not. NPCs aren't allowed the choice to fill or pickup, but could only pickup.
2) Drinks are prioritized as "cow milk", "goat milk" and "water".
3) The script checks first if any reference with CowRace or GoatRace is around and, if it's so, it'll check which of these in order to give some units of either cow milk or goat milk.
4) The script checks if any viable water source (water activator or water movable static) is around, then will check if the water activator seem to be a source of "putrid water" (puddle, marsh,
etc...) from a FormList or if the Ocean floor statics are at more or less the distance as the water source...which would bring "salt water"...else "fresh water" is extracted.
5) If none of the above will apply, the script will giive a message suggesting the player to find a source of water or a source of milk.

In this script I've tried to use the "State", which seemed to be somewhat like the VBA "labels" and were a concept that I felt familiar...

...however...something has gone horribly wrong with the script, so, please, if anyone knowledgeable could point me out what's I've done wrong it'd be really appreciated... :(
Jashkar

"Scriptname BUABucketFillOrPickup extends ObjectReference
{This script allows to either pickup or fill a bucket with water (near a watersource) or milk (near a goat or cow)}

Message Property msgActivationMenu Auto

Message Property msgFillWaterNotification Auto

Message Property msgFillMilkNotification Auto

Message Property msgFillFailure Auto

Race Property rPrimaryMilkSource Auto

Race Property rSecondaryMilkSource Auto

FormList Property flWaterSources Auto

FormList Property flPutridWaterSources Auto

FormList Property flWaterLandmarks Auto

FormList Property flOceanFloor Auto

Potion[] Property ptWaterFound Auto

Potion[] Property ptMilkFound Auto

Event OnActivate(ObjectReference akActionRef)

bool bPlayerActivated

int iPlayerChoice = 0

int iWaterQuality = 0

float fWaterDistance
float fPutridWaterDistance
float fOceanDistance

if (akActionRef == !(game.GetPlayer()))
GotoState("NPCPickUp")
else
GotoState("SelectionMenu")
EndIf

state SelectionMenu

iPlayerChoice = msgActivationMenu.Show()

if (iPlayerChoice == 0)

ObjectReference.AddToContainer player 1
GotoState("CloseScript")

else
GotoState("CheckForSource")
EndIf

endState

state CheckForSource

ObjectReference orClosestCow = Game.FindClosestReferenceOfTypeFromRef(rPrimaryMilkSource, Game.GetPlayer(), 128.0)
ObjectReference orClosestGoat = Game.FindClosestReferenceOfTypeFromRef(rSecondaryMilkSource, Game.GetPlayer(), 128.0)
ObjectReference orClosestWaterSource = Game.FindClosestReferenceOfAnyTypeInListFromRef(flWaterSources, Game.GetPlayer(), 128.0)
ObjectReference orClosestWaterLandmark = Game.FindClosestReferenceOfAnyTypeInListFromRef(flWaterLandmarks, Game.GetPlayer(), 128.0)
ObjectReference orClosestPutridWaterSource = Game.FindClosestReferenceOfAnyTypeInListFromRef(flPutridWaterSources, Game.GetPlayer(), 128.0)
ObjectReference orClosestOceanFloor= Game.FindClosestReferenceOfAnyTypeInListFromRef(flOceanFloor, Game.GetPlayer(), 2560.0)

if ((orClosestCow != NONE) || (orClosestGoat!= NONE))
GotoState("ExtractMilk")
elseif orClosestWaterSource != NONE || orClosestWaterLandmark != NONE
GotoState("ExtractWater")
else
msgFillFailure.Show()
GotoState("CloseScript")
endif

endState

state ExtractMilk
msgFillMilkNotification.Show()

if orClosestCow != NONE
Player.Additem ptMilkFound[0] 6
else
Player.Additem ptMilkFound[1] 6
endif
GotoState("CloseScript")

endState

state ExtractWater
msgFillWaterNotification.Show()

if orClosestWaterSource == NONE
fWaterDistance = Game.GetPlayer().GetDistance(orClosestWaterLandmark)
else
fWaterDistance = Game.GetPlayer().GetDistance(orClosestWaterSource)
endif

if orClosestPutridWaterSource != NONE
fPutridWaterDistance = Game.GetPlayer().GetDistance(orClosestPutridWaterSource)
if fPutridWaterDistance > fWaterDistance
iWaterQuality += 1
EndIf
elseif orClosestOceanFloor != NONE
fOceanDistance = Game.GetPlayer().GetDistance(orClosestOceanFloor)
if fPutridWaterDistance > fWaterDistance
iWaterQuality += 1
EndIf
EndIf

Player.Additem ptWaterFound[iWaterQuality] 6
iWaterQuality = 0

GotoState("CloseScript")

endState


state NPCPickUp

ObjectReference.AddToContainer akActionRef 1
GotoState("CloseScript")

endState


state CloseScript


endState


EndEvent
"

Errors

"Starting 1 compile threads for 1 files...
Compiling "BUABucketFillOrPickup"...
e:\giochi\steam\steamapps\common\skyrim\Data\Scripts\Source\temp\BUABucketFillOrPickup.psc(46,0): mismatched input 'state' expecting ENDEVENT
e:\giochi\steam\steamapps\common\skyrim\Data\Scripts\Source\temp\BUABucketFillOrPickup.psc(48,2): no viable alternative at input 'iPlayerChoice'
e:\giochi\steam\steamapps\common\skyrim\Data\Scripts\Source\temp\BUABucketFillOrPickup.psc(48,16): mismatched input '=' expecting LPAREN
e:\giochi\steam\steamapps\common\skyrim\Data\Scripts\Source\temp\BUABucketFillOrPickup.psc(0,0): error while attempting to read script BUABucketFillOrPickup: Reference to an object not set on an instance of object.
[This was liberally translated as this blasted compiler seems to use my own language and English as it "feels like"! :( ]

No output generated for BUABucketFillOrPickup, compilation failed.

Batch compile of 1 files finished. 0 succeeded, 1 failed.
Failed on BUABucketFillOrPickup
"
User avatar
Rachell Katherine
 
Posts: 3380
Joined: Wed Oct 11, 2006 5:21 pm

Post » Mon Jun 18, 2012 7:55 pm

Bump... :(
User avatar
ladyflames
 
Posts: 3355
Joined: Sat Nov 25, 2006 9:45 am

Post » Tue Jun 19, 2012 8:01 am

Firstly to understand your code it is helpful if it contains some formatting. I'm sure yours did when editing it (as I had the same issue with my first post), so once you convert all the tabs to spaces (I use Notepad++) then wrap you code in Spoiler and Code tags, like so:-

Spoiler
"Scriptname BUABucketFillOrPickup extends ObjectReference{This script allows to either pickup or fill a bucket with water (near a watersource) or milk (near a goat or cow)}Message Property msgActivationMenu AutoMessage Property msgFillWaterNotification AutoMessage Property msgFillMilkNotification AutoMessage Property msgFillFailure AutoRace Property rPrimaryMilkSource AutoRace Property rSecondaryMilkSource AutoFormList Property flWaterSources AutoFormList Property flPutridWaterSources AutoFormList Property flWaterLandmarks AutoFormList Property flOceanFloor AutoPotion[] Property ptWaterFound AutoPotion[] Property ptMilkFound AutoEvent OnActivate(ObjectReference akActionRef)	bool bPlayerActivated	int iPlayerChoice = 0	int iWaterQuality = 0	float fWaterDistance	float fPutridWaterDistance	float fOceanDistance	if (akActionRef == !(game.GetPlayer()))		GotoState("NPCPickUp")	else		GotoState("SelectionMenu")	EndIf	state SelectionMenu		iPlayerChoice = msgActivationMenu.Show()		if (iPlayerChoice == 0)			ObjectReference.AddToContainer player 1			GotoState("CloseScript")		else			GotoState("CheckForSource")		EndIf	endState	state CheckForSource		ObjectReference orClosestCow = Game.FindClosestReferenceOfTypeFromRef(rPrimaryMilkSource, Game.GetPlayer(), 128.0)		ObjectReference orClosestGoat = Game.FindClosestReferenceOfTypeFromRef(rSecondaryMilkSource, Game.GetPlayer(), 128.0)		ObjectReference orClosestWaterSource = Game.FindClosestReferenceOfAnyTypeInListFromRef(flWaterSources, Game.GetPlayer(), 128.0)		ObjectReference orClosestWaterLandmark = Game.FindClosestReferenceOfAnyTypeInListFromRef(flWaterLandmarks, Game.GetPlayer(), 128.0)		ObjectReference orClosestPutridWaterSource = Game.FindClosestReferenceOfAnyTypeInListFromRef(flPutridWaterSources, Game.GetPlayer(), 128.0)		ObjectReference orClosestOceanFloor= Game.FindClosestReferenceOfAnyTypeInListFromRef(flOceanFloor, Game.GetPlayer(), 2560.0)		if ((orClosestCow != NONE) || (orClosestGoat!= NONE))			GotoState("ExtractMilk")		elseif orClosestWaterSource != NONE || orClosestWaterLandmark != NONE			GotoState("ExtractWater")		else			msgFillFailure.Show()			GotoState("CloseScript")		endif	endState	state ExtractMilk		msgFillMilkNotification.Show()		if orClosestCow != NONE			Player.Additem ptMilkFound[0] 6		else			Player.Additem ptMilkFound[1] 6		endif		GotoState("CloseScript")	endState	state ExtractWater		msgFillWaterNotification.Show()		if orClosestWaterSource == NONE			fWaterDistance = Game.GetPlayer().GetDistance(orClosestWaterLandmark)		else			fWaterDistance = Game.GetPlayer().GetDistance(orClosestWaterSource)		endif		if orClosestPutridWaterSource != NONE			fPutridWaterDistance = Game.GetPlayer().GetDistance(orClosestPutridWaterSource)			if fPutridWaterDistance > fWaterDistance				iWaterQuality += 1			EndIf		elseif orClosestOceanFloor != NONE			fOceanDistance = Game.GetPlayer().GetDistance(orClosestOceanFloor)			if fPutridWaterDistance > fWaterDistance				iWaterQuality += 1			EndIf		EndIf		Player.Additem ptWaterFound[iWaterQuality] 6		iWaterQuality = 0		GotoState("CloseScript")	endState	state NPCPickUp		ObjectReference.AddToContainer akActionRef 1		GotoState("CloseScript")	endState	state CloseScript	endStateEndEvent

You are more likely to get someone have a quick look and respond ;o)

After, having a quick look! (after re-formatting your code!) , I don't think the states behave like that. See the creationkit on State_Reference for an example (apparently I am not allowed to post a link). Looks like your OnActivate() Event should be within each of the states where you want to decide, rather than those states being inside the Event.

Hope, someone helps you out mate. I have not used states yet and I need to really, but like you I have not quite worked them out yet.

Good Luck, you idea, sounds like a great one.
User avatar
cutiecute
 
Posts: 3432
Joined: Wed Sep 27, 2006 9:51 am

Post » Tue Jun 19, 2012 6:56 am

I don't have almost no experience with programming, so I don't know what you mean by VBA labels. But I do understand the Papyrus scripting language, and one thing you're doing incorrectly is that you seem to be using states when you should be using functions. (Additionally, you can call functions from inside another function/event, but you can't define it there.)

States are what you use when you wish your script to do/ignore something for a while. For example, I could have a script with OnActivate inside different states, "State01" and "State02". When the script is inside "State01", it's as though everything in "State02" does not exist. The script will only run the OnActivate that's inside "State01", and ignore the one inside "State02".

I rewrote your script:

Spoiler
Scriptname BUABucketFillOrPickup extends ObjectReference{This script allows to either pickup or fill a bucket with water (near a watersource) or milk (near a goat or cow)}Message Property msgActivationMenu AutoMessage Property msgFillWaterNotification AutoMessage Property msgFillMilkNotification AutoMessage Property msgFillFailure AutoRace Property rPrimaryMilkSource AutoRace Property rSecondaryMilkSource AutoFormList Property flWaterSources AutoFormList Property flPutridWaterSources AutoFormList Property flWaterLandmarks AutoFormList Property flOceanFloor AutoPotion[] Property ptWaterFound AutoPotion[] Property ptMilkFound AutoActor PlayerObjectReference orClosestCowObjectReference orClosestGoatObjectReference orClosestWaterSourceObjectReference orClosestWaterLandmarkObjectReference orClosestPutridWaterSourceObjectReference orClosestOceanFloorEvent OnInit()	BlockActivation()	;this is so we can control what happens depending on whether or not it's an NPC that activates the bucket	Player = Game.GetPlayer()	;assign to the Player variable so we don't need to keep calling the Game.GetPlayer() functionEndEventEvent OnActivate(ObjectReference akActionRef)	if !(akActionRef == Player)		Activate(akActionRef, True)	;will perform the default activation, ignoring any OnActivate script events, and ignoring blocked activation	else		SelectionMenu()	;calls the SelectionMenu function	endifEndEventFunction SelectionMenu()	int iPlayerChoice = msgActivationMenu.Show()	if (iPlayerChoice == 0)		Activate(Player, True)	;will perform the default activation, ignoring any OnActivate script events, and ignoring blocked activation	else		CheckForSource()	;calls the CheckForSource() function	EndIfEndFunctionFunction CheckForSource()	;you may want to consider increasing the search range (default activation distance is around 150 units)	;also, I'm not sure you can use a Race property as a type	orClosestCow = Game.FindClosestReferenceOfTypeFromRef(rPrimaryMilkSource, Player, 128.0)	orClosestGoat = Game.FindClosestReferenceOfTypeFromRef(rSecondaryMilkSource, Player, 128.0)	orClosestWaterSource = Game.FindClosestReferenceOfAnyTypeInListFromRef(flWaterSources, Player, 128.0)	orClosestWaterLandmark = Game.FindClosestReferenceOfAnyTypeInListFromRef(flWaterLandmarks, Player, 128.0)	orClosestPutridWaterSource = Game.FindClosestReferenceOfAnyTypeInListFromRef(flPutridWaterSources, Player, 128.0)	orClosestOceanFloor = Game.FindClosestReferenceOfAnyTypeInListFromRef(flOceanFloor, Player, 2560.0)	if (orClosestCow || orClosestGoat)		ExtractMilk()	;calls the ExtractMilk() function	elseif (orClosestWaterSource || orClosestWaterLandmark)		ExtractWater()	;calls the ExtractWater() function	else		msgFillFailure.Show()	endifEndFunctionFunction ExtractMilk()	msgFillMilkNotification.Show()	if (orClosestCow)		Player.AddItem(ptMilkFound[0], 6)	else		Player.AddItem(ptMilkFound[1], 6)	endifEndFunctionFunction ExtractWater()	int iWaterQuality = 0	float fWaterDistance	float fPutridWaterDistance	float fOceanDistance	msgFillWaterNotification.Show()	if orClosestWaterSource == NONE		fWaterDistance = Game.GetPlayer().GetDistance(orClosestWaterLandmark)	else		fWaterDistance = Game.GetPlayer().GetDistance(orClosestWaterSource)	endif	if orClosestPutridWaterSource != NONE		fPutridWaterDistance = Game.GetPlayer().GetDistance(orClosestPutridWaterSource)		if fPutridWaterDistance > fWaterDistance			iWaterQuality += 1		EndIf	elseif orClosestOceanFloor != NONE		fOceanDistance = Game.GetPlayer().GetDistance(orClosestOceanFloor)		if fPutridWaterDistance > fWaterDistance			iWaterQuality += 1		EndIf	EndIf	Player.AddItem(ptWaterFound[iWaterQuality], 6)	iWaterQuality = 0EndFunction

There is no need for any CloseScript function. Papyrus is event driven; the script will not run unless it's told to.

P.S. I wouldn't have taken a look except Minty911 formatted the script. :smile:
User avatar
Multi Multi
 
Posts: 3382
Joined: Mon Sep 18, 2006 4:07 pm

Post » Mon Jun 18, 2012 7:22 pm

P.S. I wouldn't have taken a look except Minty911 formatted the script. :smile:

Thanks RandomNoob, your name does not give you justice! I have seen many of your previous posts helping others, and I have learnt much from your previous scripting examples. Much appreciated.

I was actually, looking for help myself when I found this topic so I would love if you could expand on the states and how they work?

I have a weather modification that adds lightning while the player is in a thunder storm, and this works fine, but I feel the way I have implemented this is just WRONG! and needs states to handle threading?

I have been reading many posts today about how scripts are saved, how they behave after reloaded (once the original script has changed), and how errors thrown by my mod can affect the performance of other mods and even the game! I really don't want to crash anyones game! or especially the save game! Soo...

I would really appreciate you reviewing my code and pointing out any mistakes or suggestions on improvements?

Spoiler
Scriptname MintyQuestScript extends Quest Conditional{Place holder to hook into weather system}import debugimport gameimport weatherimport utility; External propertiesSpell Property MintyForkLightningSpell AutoSpell Property MintySheetLightningSpell AutoSpell Property MintyForkLightningSpellHostile AutoSpell Property MintySheetLightningSpellHostile Auto; Bad [censored] Weathers that justify Lightning Strikes DudeWeather Property SkyrimStormRainTU Auto ; 10a241Weather Property SkyrimStormRainFF Auto ; 10a23cWeather Property SkyrimStormRain Auto ; C8220Weather Property SkyrimOvercastRainVT Auto ; 10A746Weather Property FXMagicStormRain Auto ; D4886; PropsActivator property MintyActivator AutoImageSpaceModifier property MagShockStormImod autoHazard property MintyLightningHazard auto; Script available variablesBool Property isLightningHostile = False Auto hidden ; will a strike kill anyoneint Property chanceToFork = 25 Auto hidden ; Percentage to hit groundint Property distanceMultiplyer = 2 Auto hidden ; how many cells should we coverFloat Property strikeOffset =  100.0 Auto hidden ; movement between sheet targetsint Property maxTargets = 3 Auto hidden ; maximum sheet targetsFloat Property updateFrequency =  5.0 Auto hidden ; game update cycleString Property version = "4.2" Auto hidden ; Current VersionBool Property showDebugMessages = False Auto hidden ; Show debugging messagesBool Property logDebugMessages = False Auto hidden ; Log debugging messages; Variablesbool initalised = falsebool cleanup = trueFloat height = 3584.0Float cellSize = 2048.0Float PosXFloat PosYFloat PosZObjectReference[] TargetRefsFloat minAnimationTime = 3.5Spell spellToCastFork = NoneSpell spellToCastSheet = NoneEvent OnInit()	if !initalised		if Self != None			LogInfo("Minty Lightning Quest (Version:" + version + ") Init...")			RegisterForSingleUpdate(updateFrequency)					initalised = true;		endif	endifEndEventEvent OnUpdate()	if isStormWeather()		LogDebug("Storm Weather Detected - Updating, in " + updateFrequency)		TargetRefs = new ObjectReference[20]			ObjectReference PlaceTarget = None		ObjectReference CasterRef = None		ObjectReference TargetRef = None		int totalTargets = maxTargets - 1 ; as Int		if MintyActivator != None			PlaceTarget = GetPlayer().PlaceAtMe(MintyActivator,1)			Wait(1)		endif		bool fork = (RandomInt(0,100) < chanceToFork)		LogDebug("Chance to Fork = " + chanceToFork + "% : Are we Forking? - " + fork)		if PlaceTarget != None			float strikeArea = (cellSize * distanceMultiplyer)			LogDebug("StrikeArea = " + strikeArea)			PosX = (RandomFloat(-strikeArea, strikeArea))			PosY = (RandomFloat(-strikeArea, strikeArea))			PlaceTarget.MoveTo(GetPlayer(), PosX, PosY, height) ; Position our CasterRef			Wait(1.0)			CasterRef = PlaceTarget.PlaceAtme(MintyActivator,1)						Wait(1.0)			LogDebug("*** Player [ X:" + GetPlayer().X + " Y:" + GetPlayer().Y + " Z:" + GetPlayer().Z + " IS " + GetPlayer() + "]")			LogDebug("+++ Caster [ Distance: " + GetPlayer().GetDistance(CasterRef) + " X:" + CasterRef.X + " Y:" + CasterRef.Y + " Z:" + CasterRef.Z + " IS " + CasterRef + "]")			if fork;				if (GetPlayer().GetPositionZ() < 0)					PosZ = GetPlayer().GetPositionZ() ; Fork so drop targets to ground level;				else;					PosZ = 0 ; Fork so drop targets to ground level;				endif			else				PosZ = CasterRef.Z ; Sheet so place targets in the sky level with caster			endif			LogDebug("--- Total Targets = " + totalTargets)			int count = 0			while count < totalTargets				;Float tPosX = (PosX + (strikeOffset * count))  ; RandomFloat(-strikeOffset, strikeOffset)				;Float tPosY = (PosY + (strikeOffset * count))  ; (PosY + (RandomFloat(-strikeOffset, strikeOffset)))				Float tPosX = (PosX + RandomFloat(-strikeOffset, strikeOffset))				Float tPosY = (PosY + RandomFloat(-strikeOffset, strikeOffset))				PlaceTarget.MoveTo(CasterRef, tPosX, tPosY, PosZ)				Wait(1.0)				TargetRefs[count] = PlaceTarget.PlaceAtme(MintyActivator,1)				Wait(1.0)				LogDebug(" |- Target[" + count + "] X:" + TargetRefs[count].X + " Y:" + TargetRefs[count].Y + " Z:" + TargetRefs[count].Z) + " Distance:" +  CasterRef.GetDistance(TargetRefs[count])				count += 1			endwhile					endif		InitLightning()		if (CasterRef != None && CasterRef.Is3DLoaded() && CasterRef.GetParentCell() != none)			if fork				if (spellToCastFork != None)					TargetRef = TargetRefs[RandomInt(0, totalTargets)]					if (TargetRef != None && TargetRef.Is3DLoaded() && TargetRef.GetParentCell() != none)						Float intensity = getImodIntensity(CasterRef)						LogInfo(getImodDistanceDescription(intensity) + ", FORK Lightning, hostile=" + isLightningHostile)						adjustCastingHeight(CasterRef, TargetRef)						playImodEffect(intensity)						playSkyHazard(CasterRef)						spellToCastFork.Cast(CasterRef, TargetRef)						Wait(RandomFloat(minAnimationTime, (updateFrequency + minAnimationTime)))					endif				endif			else				if (spellToCastSheet != None)					int count = 0					while (count < totalTargets)						TargetRef = TargetRefs[count]						if (TargetRef != None && TargetRef.Is3DLoaded() && TargetRef.GetParentCell() != none)							Float intensity = getImodIntensity(CasterRef)							LogInfo(getImodDistanceDescription(intensity) + ", SHEET Lightning, hostile=" + isLightningHostile)							playImodEffect(intensity)							playSkyHazard(CasterRef)														spellToCastSheet.Cast(CasterRef, TargetRef)							Wait(RandomFloat(minAnimationTime, (updateFrequency + minAnimationTime)))						endif							count += 1					endwhile											endif			endif					endif		if cleanup			int count = 0			while count < totalTargets						if None != TargetRefs[count]					TargetRefs[count].disable()					TargetRefs[count].delete()				endif					count += 1			endwhile			TargetRefs = None			if PlaceTarget != None				PlaceTarget.disable()				PlaceTarget.delete()			endif				if CasterRef != None				CasterRef.disable()				CasterRef.delete()			endif							if TargetRef != None				TargetRef.disable()				TargetRef.delete()			endif			endif	endif	RegisterForSingleUpdate(updateFrequency)		endEventFunction InitLightning()	if isLightningHostile		LogDebug("Going with Hostile Lightning")		spellToCastFork = MintyForkLightningSpellHostile		spellToCastSheet = MintySheetLightningSpellHostile	else		LogDebug("Going with Harmless Lightning")		spellToCastFork = MintyForkLightningSpell		spellToCastSheet = MintySheetLightningSpell	endifEndFunctionFunction adjustCastingHeight(ObjectReference CasterRef, ObjectReference TargetRef)	float castingHeight = CasterRef.Z	float targetHeight = TargetRef.Z	if (castingHeight >= 1024.0)		CasterRef.MoveTo(TargetRef, RandomFloat(-20.0, 20.0), RandomFloat(-20.0, 20.0), 1024.0)		Wait(0.5)	endifEndFunctionFunction playSkyHazard(ObjectReference CasterRef)	if MintyLightningHazard != none		;CasterRef.placeAtMe(MintyLightningHazard)	endif	EndFunctionFunction playImodEffect(Float intensity)	if MagShockStormImod != None		MagShockStormImod.apply(intensity)	endifEndFunctionString Function getImodDistanceDescription(Float distance)	String desc = ("ERROR Getting Imod Distance (getImodDistanceDescription)")	if (distance == 0.10)		desc = "Distant"	elseif (distance == 0.15)		desc = "Medium"	elseif (distance == 0.25)		desc = "Local"	endif	LogDebug("Imod Distance is " + desc + " Distance: " + distance)	return descEndFunctionFloat Function getImodIntensity(ObjectReference CasterRef)	Float distance = GetPlayer().GetDistance(CasterRef)	;if ((distance <= (cellSize * 3)) && (distance >= (cellSize * 2)))	if ((distance <= 6144.0) && (distance >= 4092))		LogDebug("Returning Distant Imod level : " + distance)		return 0.10	;elseif ((distance <= (cellSize * 2)) && (distance >= cellSize))	elseif ((distance <= 4092) && (distance >= 2046))		LogDebug("Returning Medium Imod level : " + distance)		return 0.15	else		LogDebug("Returning Local Imod level : " + distance)		return 0.25	endifEndFunctionbool Function isStormWeather()	bool isBad = false	if IsOutsideWithFullSky()		if !IsWeatherTransitioning()			if IsWeatherRaining()				if isWeatherBadEnoughForLightning()					isBad = true				endif			endif		endif	endif	return isBadendFunctionbool Function isWeatherBadEnoughForLightning()	bool isBad = False	if SkyrimStormRainTU != None && GetCurrentWeather().GetFormID() == SkyrimStormRainTU.GetFormID()		LogDebug("Weather is BadArse, SkyrimStormRainTU = 10a241")		isBad = true	elseif SkyrimStormRainFF != None && GetCurrentWeather().GetFormID() == SkyrimStormRainFF.GetFormID()		LogDebug("Weather is BadArse, SkyrimStormRainFF = 10a23c")		isBad = true	elseif SkyrimStormRain != None && GetCurrentWeather().GetFormID() == SkyrimStormRain.GetFormID()		LogDebug("Weather is BadArse, SkyrimStormRain = C8220")		isBad = true	elseif SkyrimOvercastRainVT != None && GetCurrentWeather().GetFormID() == SkyrimOvercastRainVT.GetFormID()		LogDebug("Weather is BadArse, SkyrimOvercastRainVT = 10A746")		isBad = true	elseif FXMagicStormRain != None && GetCurrentWeather().GetFormID() == FXMagicStormRain.GetFormID()		LogDebug("Weather is BadArse, FXMagicStormRain = D4886")		isBad = true	else		isBad = false	endif	return isBadEndFunctionbool Function LogDebug(String msg)	if (Self.logDebugMessages)		Trace(msg)	endifEndFunctionbool Function LogInfo(String msg)	if (Self.showDebugMessages)		Notification(msg)		Wait(0.5)	endif	LogDebug(msg)EndFunctionbool Function IsOutsideWithFullSky()	return (GetSkyMode() == 3) ; int SKYMODE_FULL = 3EndFunctionbool Function IsWeatherRaining()	return (GetCurrentWeather().GetClassification() == 2) ; int WEATHER_RAINING = 2EndFunctionbool Function IsWeatherTransitioning()	return !(GetCurrentWeatherTransition() == 1.0)EndFunction

I have a 2nd script for configuration, but again I am not sure it has been implemented correctly? and if two separate scripts should communicate this way? It is a pretty horribly long method but I don't know how to separate that into thread safe objects.


Spoiler
Scriptname MintyLightningConfigScript extends activemagiceffectimport Gameimport debugimport utilityimport weatherMintyQuestScript Property MintyLightningQuest AutoBook Property MintyLightningConfigBook Auto; Config MenusMessage Property MintyMsgMainMenu AutoMessage Property MintyMsgDamageMenu AutoMessage Property MintyMsgTypeMenu AutoMessage Property MintyMsgDistanceMenu AutoMessage Property MintyMsgFrequencyMenu Auto; Debug MenusMessage Property MintyMsgDebugMenu AutoMessage Property MintyMsgStrikeOffsetMenu AutoMessage Property MintyMsgNumTargetsMenu AutoMessage Property MintyMsgDbgForceWeatherMenu AutoMessage Property MintyMsgDbgFeedBackMenu AutoEvent OnEffectStart(Actor Target, Actor Caster)	DisablePlayerControls(abMenu = True) ; Momentarily disable other menus	EnablePlayerControls(abMenu = True) ; Undo DisablePlayerControls	ShowMainMenu()EndEventFunction ShowMainMenu(Bool abMenu = True, Int aiButton = 0)	Wait(0.5)	While abMenu		If (aiButton != -1) ; Wait for input			aiButton = MintyMsgMainMenu.Show() ; Main Menu			If (aiButton == 0) ; DAMAGE MENU				aiButton = MintyMsgDamageMenu.Show()				If (aiButton == 0) ; Gives Damage					Notification("Lightning is now hostile!")					MintyLightningQuest.isLightningHostile = true				ElseIf (aiButton == 1) ; No Damage					Notification("Lightning is now harmless.")					MintyLightningQuest.isLightningHostile = false				EndIf			ElseIf (aiButton == 1) ; FORK/SHEET				aiButton = MintyMsgTypeMenu.Show()				If (aiButton == 0) ; 0%					Notification("Only Sheet Lightning.")					MintyLightningQuest.chanceToFork = 0				ElseIf (aiButton == 1) ; 10%					Notification("10% Chance of Fork Lightning.")					MintyLightningQuest.chanceToFork = 10				ElseIf (aiButton == 2) ; 25%					Notification("25% Chance of Fork Lightning.")					MintyLightningQuest.chanceToFork = 25 ; DEFAULT				ElseIf (aiButton == 3) ; 50%					Notification("50% Chance of Fork Lightning.")					MintyLightningQuest.chanceToFork = 50				ElseIf (aiButton == 4) ; 75%					Notification("75% Chance of Fork Lightning.")					MintyLightningQuest.chanceToFork = 75				ElseIf (aiButton == 5) ; 100%					Notification("Only Fork Lightning.")					MintyLightningQuest.chanceToFork = 100				EndIf			ElseIf (aiButton == 2) ; DISTANCE				aiButton = MintyMsgDistanceMenu.Show()				If (aiButton == 0) ; Local					Notification("Local Strikes Only.")					MintyLightningQuest.distanceMultiplyer = 1				ElseIf (aiButton == 1) ; Medium					Notification("Medium Range Strikes.")					MintyLightningQuest.distanceMultiplyer = 2				ElseIf (aiButton == 2) ; Long range (Default)					Notification("Long Range Strikes.")					MintyLightningQuest.distanceMultiplyer = 3				EndIf			ElseIf (aiButton == 3)	 ; FREQUENCY				aiButton = MintyMsgFrequencyMenu.Show()				If (aiButton == 0) ; Low					Notification("Low Strike Potential.")					MintyLightningQuest.updateFrequency = 10.0				ElseIf (aiButton == 1) ; Medium (Default)					Notification("Medium Strike Potential.")					MintyLightningQuest.updateFrequency = 5.0				ElseIf (aiButton == 2) ; High					Notification("High Strike Potential.")					MintyLightningQuest.updateFrequency = 2.0				EndIf			ElseIf (aiButton == 4)	 ; DEBUG MENU				While abMenu					aiButton = MintyMsgDebugMenu.Show()					If (aiButton == 0)						aiButton = MintyMsgStrikeOffsetMenu.Show() ; STRIKE OFFSET						If (aiButton == 0)							MintyLightningQuest.strikeOffset = 10.0						ElseIf (aiButton == 1)							MintyLightningQuest.strikeOffset = 50.0						ElseIf (aiButton == 2)							MintyLightningQuest.strikeOffset = 100.0 ; DEFAULT						ElseIf (aiButton == 3)							MintyLightningQuest.strikeOffset = 200.0						ElseIf (aiButton == 4)							MintyLightningQuest.strikeOffset = 500.0						EndIf					ElseIf (aiButton == 1)						aiButton = MintyMsgNumTargetsMenu.Show() ; TARGETS						If (aiButton == 0)							MintyLightningQuest.maxTargets = 1						ElseIf (aiButton == 1)							MintyLightningQuest.maxTargets = 3 ;DEFAULT						ElseIf (aiButton == 2)							MintyLightningQuest.maxTargets = 5						ElseIf (aiButton == 3)							MintyLightningQuest.maxTargets = 10						ElseIf (aiButton == 4)							MintyLightningQuest.maxTargets = 20						EndIf					ElseIf (aiButton == 2)						aiButton = MintyMsgDbgForceWeatherMenu.Show() ; Force Weather						If (aiButton == 0)							; RANDOM selection							int random = RandomInt(1,5)							if (random == 1)								Notification("'fw 10a241' = SkyrimStormRainTU")								MintyLightningQuest.SkyrimStormRainTU.ForceActive()							elseif (random == 2)								Notification("'fw 10a23c' = SkyrimStormRainFF")								MintyLightningQuest.SkyrimStormRainFF.ForceActive()							elseif (random == 3)								Notification("'fw C8220' = SkyrimStormRain")								MintyLightningQuest.SkyrimStormRain.ForceActive()							elseif (random == 4)								Notification("'fw 10A746' = SkyrimOvercastRainVT")								MintyLightningQuest.SkyrimOvercastRainVT.ForceActive()							elseif (random == 5)								Notification("'fw D4886' = FXMagicStormRain")								MintyLightningQuest.FXMagicStormRain.ForceActive()							endif						ElseIf (aiButton == 1) ; SkyrimStormRainTU 10a241							Notification("'fw 10a241' = SkyrimStormRainTU")							MintyLightningQuest.SkyrimStormRainTU.ForceActive()						ElseIf (aiButton == 2) ; SkyrimStormRainFF 10a23c							Notification("'fw 10a23c' = SkyrimStormRainFF")							MintyLightningQuest.SkyrimStormRainFF.ForceActive()						ElseIf (aiButton == 3) ; SkyrimStormRain C8220							Notification("'fw C8220' = SkyrimStormRain")							MintyLightningQuest.SkyrimStormRain.ForceActive()						ElseIf (aiButton == 4) ; SkyrimOvercastRainVT 10A746							Notification("'fw 10A746' = SkyrimOvercastRainVT")							MintyLightningQuest.SkyrimOvercastRainVT.ForceActive()						ElseIf (aiButton == 5) ; FXMagicStormRain D4886							Notification("'fw D4886' = FXMagicStormRain")							MintyLightningQuest.FXMagicStormRain.ForceActive()						EndIf					ElseIf (aiButton == 3) ; SHOW STATUS						TraceAndBox("Minty Lightning Mod (Version: " + MintyLightningQuest.version + ")" \						+ "\n\t Max Targets: " + MintyLightningQuest.maxTargets \						+ "\n\t Strike Offset: " + MintyLightningQuest.strikeOffset \						+ "\n\t Frequncy: " + MintyLightningQuest.updateFrequency \						+ "\n\t Distance: " + MintyLightningQuest.distanceMultiplyer \						+ "\n\t Fork Chance: " + MintyLightningQuest.chanceToFork \						+ "\n\t Hostile: " + MintyLightningQuest.isLightningHostile \						+ "\n\t Logging: " + MintyLightningQuest.logDebugMessages \						+ "\n\t Notifications: " + MintyLightningQuest.showDebugMessages \						+ "\n\t Weather: " + GetCurrentWeather())					ElseIf (aiButton == 4) ; SHOW FEEDBACK						aiButton = MintyMsgDbgFeedBackMenu.Show() ; Show Logging						If (aiButton == 0) ; Off							MintyLightningQuest.showDebugMessages = False							MintyLightningQuest.logDebugMessages = False						elseIf (aiButton == 1) ; Info							MintyLightningQuest.showDebugMessages = True							MintyLightningQuest.logDebugMessages = True						elseIf (aiButton == 2) ; Debug							MintyLightningQuest.showDebugMessages = False							MintyLightningQuest.logDebugMessages = True						else							abMenu = False ; End the log level function						endif					Else						abMenu = False ; End the debug menu function					EndIf				EndWhile			Else				abMenu = False ; End the main message function			EndIf		EndIf	EndWhileEndFunction

I will keep reading and trying to understand, And I do appreciate any feedback, good or bad, especially the bad if you can explain why it is bad ;o)
User avatar
marie breen
 
Posts: 3388
Joined: Thu Aug 03, 2006 4:50 am

Post » Tue Jun 19, 2012 11:33 am

For your first script, I don't see anything wrong with it, or any reason why it would need states. There are some thing that I think could be changed.
  • I think that the values for properties are baked into the saved games, so your version property might not update properly.
  • You may want to insert a note saying that maxtargets should be a maximum of 20.
  • There's a Wait() in your LogInfo() function. Is that really necessary?
  • Why do you use GetFormID() in your isWeatherBadEnoughForLightning() function?
  • You have a lot of different checks that basically come down to whether or not you assigned a value to your MintyActivator property.
  • Why do you even need a PlaceTarget? Why not just use your CasterRef?
  • If you ever do anything with your PlaySkyHazard() function, remember that you're going to need to delete the spawned hazard too.
For your config menu, I see you followed JustinOther's guide on the wiki. Personally, I like to separate each menu into its own function, but either way it works.
User avatar
phil walsh
 
Posts: 3317
Joined: Wed May 16, 2007 8:46 pm

Post » Mon Jun 18, 2012 9:07 pm

@RandomNoob; Thanks for taking the time to review my code and give me feedback. Much appreciated.

I thought I might need states because the log files seem to show that some properties are None even after seeing them used quite happily earlier in the log! I suspect that I have a rouge thread that is also running but for whatever reason is not initialised. I was thinking that maybe states could control this. I will keep looking ;o)

The Wait() after the Notification() call was an attempt to try and sync the message to the actual strike as they seemed to get out of sync. It didn't work anyway so I will remove that.

The GetFormID's was from when I was trying to monitor the weather within keeping the weather properties (i.e String compare rather than object), I will fix that now.

Thanks again.
I will make the changes you suggest.
User avatar
NAkeshIa BENNETT
 
Posts: 3519
Joined: Fri Jun 16, 2006 12:23 pm


Return to V - Skyrim