Jump to content

Reference Script


ArekkusuStorm

Recommended Posts

Solved.

 

Hit another obstacle.. Same mod, but this time I have 4 items already placed in the Worldspace each with their own ref id. When activated it will give you an menu with two options 1) Purchase, or 2) Do nothing. (or, you can sneak activate to steal)

 

What I'm stuck on is trying to get the script to link to the reference, ASMagazine1-4 are the Ref Editor IDs that are already placed in the World.

scn ASPurchaseScript

short buttonVar
short awaitingInput

Begin OnActivate
	if player.IsSneaking == 0
		if GetIsReference ASMagazine1 == 1
			ShowMessage ASPurchase
			set awaitingInput to 1
		elseif GetIsReference ASMagazine2 == 1
			ShowMessage ASPurchase
			set awaitingInput to 1
		elseif GetIsReference ASMagazine3 == 1
			ShowMessage ASPurchase
			set awaitingInput to 1
		elseif GetIsReference ASMagazine4 == 1
			ShowMessage ASPurchase
			set awaitingInput to 1
		endif
	endif
end

begin GameMode
	if awaitingInput == 1
		set buttonVar to getbuttonpressed

		if buttonVar > -1
			set awaitingInput to 0

			if buttonVar == 0
				player.AddItem ASNexywoodAid 1
				player.RemoveItem f 25
				Disable
				MarkForDelete
			elseif buttonVar == 1
			endif
		endif
	endif
end

Edited by ArekkusuStorm
Link to comment
Share on other sites

Not to state the obvious here... but you DO have this as the script in the base form for your references, right?

 

 

Actually, better question; are you using activators, or weapons? I'm not sure OnActivate gets called for weapon references.

 

It might help if you specify what SHOULD happen, and what DOES happen.

Edited by DaWrecka
Link to comment
Share on other sites

Yup, it's attached to the base object right now.

 

It's a ingestible so.. I guess an activator (sorry, not familiar with all the terms yet).

 

I pretty much described what should happen above, but:

- I activate the ingestible (Take/Pickup)

- script goes through a check to see if I (the player) am the one activating it

- If I am not sneaking

- If the item being activated is any of the four Ref IDs

- if it is, open a menu (show message), delete this instance of the item, and end.

- If not, end script (So if I'm trying to pick up - not grab - any other instance of this object, the script basically doesn't do anything.)

 

- Menu opens

- I can either purchase the item, add item to inventory, delete this instance of the item and end.

- Or I can do nothing, end.

 

What does happen? Well I can't save the script right now but I can guarantee everything except checking if the item being activated is any of the four Ref IDs works.

 

Basically

if GetIsReference ASMagazine1 == 1

This line right here, something is wrong.

 

OH Son of a gun, it's because I didn't tick off the persistent reference on the Ref item.

Edited by ArekkusuStorm
Link to comment
Share on other sites

A few tips then.

  • Activators are special actors whose sole purpose is to, well, be activated. This includes triggers, volumes which act when the player (or something else) enters them, and objects which wait to be activated, then take action. An activator can have any mesh or texture, so you can make it look like anything - or you can have an invisible trigger which the player can't see at all. You COULD use activators with the same mesh and texture as your ingestibles, but equally-valid would be to use the ingestible form, and then put an invisible activator around it, so that the player can't activate the ingestible itself. You'd need to remember to disable the ingestible reference too, but you could possibly achieve that by setting its Activate Parent in GECK to the activator itself.
  • Whenever using OnActivate, never forget to call Activate. Calling the Activate function from script ensures that any animations the target has take effect. For example, you're coding a button whose model has an on state and an off state. Unless you call Activate from your script, the switch's sounds won't play and it won't ever switch between states. To bring it back home, if the player were to activate one of your ingestible actors using this script, nothing would happen - because the script would catch that they were sneaking, and then do nothing.
  • Keep in mind that the player isn't the only entity in the world capable of activating something. If a Raider were to come in and take a liking to one of the ingestibles, he'd run over to it and activate - and then the script would react as if the player just activated it, meaning that either nothing would happen because the player was sneaking, or the player would suddenly have a buy/nothing interface in their face even though they weren't trying to take anything.
  • Using OnActivate in non-Activators might work, but it's not a good idea. As an example, suppose the player were to buy/steal one of your ingestibles here, then later drop one. When they tried to pick it up again, the OnActivate block would fire again, only this time it's not running on one of your pre-set references - meaning they'll never be able to pick it up again, unless they use the console. An activator doesn't travel with the player (unless it happens to be attached to a moveable static that they grab, at least) and thus they could drop and pick the ingestible back up as much as they liked.
  • It's pointless to test for "== 1" or even "== 0" on the result of a boolean function. GetIsReference always returns either a 0 or a 1. In if statements, the engine evaluates any non-zero value as TRUE, and a value of zero as FALSE. To put it another way, here's the process the engine has to go through when the player activates one of your triggers:
    if (1 == 1) != FALSE
    Which simplifies down to
    if (TRUE) != FALSE
    which adds an unnecessary extra step. Not all functions return booleans, this is true, but GetIsReference does; Thus "if GetIsReference ASMagazine1 == 1" has the same logic as "if GetIsReference ASMagazine1". Omitting the unnecessary comparison step makes your code cleaner and saves a couple of cycles - perhaps making little difference here, but a good habit to start.
  • Equally, you can simplify code a little bit using this logic. For the sake of this example, let's suppose you have a trigger volume; a death zone, if you like. If the death zone is supposed to ka-splode robots that enter it, but do nothing otherwise, then you could use the following code:
    begin OnTriggerEnter
    	ref MyActionRef
    
    	set MyActionRef to GetActionRef ; GetActionRef returns the reference that just activated the activator.
    	
    	if MyActionRef && MyActionRef.IsActor
    	; The above is a sanity check. It just makes sure we're not trying to run potentially crash-inducing functions on something that can't run them.
    	; Remember when I said any non-zero value is treated as TRUE by an if statement? We're using that here. If MyActionRef is a valid reference, GetActionRef
    	; will be evaluated as that reference's refID, which is non-zero, therefore that part of the function evaluates to TRUE.
    	; IsActor is a function that returns a boolean; again, if it's non-zero, then it evaluates to TRUE by the if statement.
    		if MyActionRef.GetDead
    			; MyActionRef is already dead. This can happen if the push force from the killing shot sent it flying.
    			; Either way, we've got nothing to do.
    			Return
    		endif
    		
    		; Creature type 6 is robots, so if GetIsCreatureType 6 returns TRUE, the action ref is a robot.
    		if MyActionRef.GetIsCreatureType 6
    			; Here's where you make robots go 'squish'. Or 'ka-BEWM!', as you prefer.
    		endif
    	endif
    end
    
    But suppose you wanted it to do the opposite - you wanted robots to be ignored, and meatbags of all kinds to go 'squish'. You COULD achieve this as follows:
    		if MyActionRef.GetIsCreatureType 6 == 0
    			; Here's where you make non-robots go 'squish'. Or 'ka-BEWM!', as you prefer.
    
    and that works, but in my opinion it's a little cleaner if you instead change the code as follows:
    		if MyActionRef.GetIsCreatureType 6
    		else
    			; Now this is where we make meatbags go 'squish'.
    
    I'm not completely certain how much impact this makes on execution time, but I do feel it makes the code easier to read, so I use it whenever it's appropriate.
EDIT: I'll get this right sooner or later. Edited by DaWrecka
Link to comment
Share on other sites

Ah, thanks for the tips. Stuff like the whole == 1 can be written as just sagsdg 1 thing is useful, something I didn't know.

 

 


  • Keep in mind that the player isn't the only entity in the world capable of activating something. If a Raider were to come in and take a liking to one of the ingestibles, he'd run over to it and activate - and then the script would react as if the player just activated it, meaning that either nothing would happen because the player was sneaking, or the player would suddenly have a buy/nothing interface in their face even though they weren't trying to take anything.
    if IsActionRef player

Yeah, I saw that mistake later on and put this line of code in.

 

 


  • Whenever using OnActivate, never forget to call Activate. Calling the Activate function from script ensures that any animations the target has take effect. For example, you're coding a button whose model has an on state and an off state. Unless you call Activate from your script, the switch's sounds won't play and it won't ever switch between states. To bring it back home, if the player were to activate one of your ingestible actors using this script, nothing would happen - because the script would catch that they were sneaking, and then do nothing.

 


  • Using OnActivate in non-Activators might work, but it's not a good idea. As an example, suppose the player were to buy/steal one of your ingestibles here, then later drop one. When they tried to pick it up again, the OnActivate block would fire again, only this time it's not running on one of your pre-set references - meaning they'll never be able to pick it up again, unless they use the console. An activator doesn't travel with the player (unless it happens to be attached to a moveable static that they grab, at least) and thus they could drop and pick the ingestible back up as much as they liked.

Which is why I ended up with this thing.

scn ASPurchaseScript

short buttonVar
short awaitingInput

Begin OnActivate
	if IsActionRef player
		if player.IsSneaking == 0
			if GetIsReference ASMagazine1 == 1
				ShowMessage ASPurchase
				set awaitingInput to 1
				SendAssaultAlarm
			elseif GetIsReference ASMagazine2 == 1
				ShowMessage ASPurchase
				set awaitingInput to 1
			elseif GetIsReference ASMagazine3 == 1
				ShowMessage ASPurchase
				set awaitingInput to 1
			elseif GetIsReference ASMagazine4 == 1
				ShowMessage ASPurchase
				set awaitingInput to 1
			else
				player.AddItem ASNexywoodAid 1
				Disable
				MarkForDelete
			endif
		elseif player.IsSneaking == 1
			if TrudyRef.GetDetected player == 1
				if GetIsReference ASMagazine1 == 1
					SetPCEnemyOfFaction GoodspringsFaction 1
					player.AddItem ASNexywoodAid 1
					Disable
					MarkForDelete
				elseif GetIsReference ASMagazine2 == 1
					SetPCEnemyOfFaction GoodspringsFaction 1
					player.AddItem ASNexywoodAid 1
					Disable
					MarkForDelete
				elseif GetIsReference ASMagazine3 == 1
					SetPCEnemyOfFaction GoodspringsFaction 1
					player.AddItem ASNexywoodAid 1
					Disable
					MarkForDelete
				elseif GetIsReference ASMagazine4 == 1
					SetPCEnemyOfFaction GoodspringsFaction 1
					player.AddItem ASNexywoodAid 1
					Disable
					MarkForDelete
				else
					player.AddItem ASNexywoodAid 1
					Disable
					MarkForDelete
				endif
			else
				if GetIsReference ASMagazine1 == 1
					player.AddItem ASNexywoodAid 1
					Disable
					MarkForDelete
				elseif GetIsReference ASMagazine2 == 1
					player.AddItem ASNexywoodAid 1
					Disable
					MarkForDelete
				elseif GetIsReference ASMagazine3 == 1
					player.AddItem ASNexywoodAid 1
					Disable
					MarkForDelete
				elseif GetIsReference ASMagazine4 == 1
					player.AddItem ASNexywoodAid 1
					Disable
					MarkForDelete
				else
					player.AddItem ASNexywoodAid 1
					Disable
					MarkForDelete
				endif
			endif
		endif
	endif
end

begin GameMode
	if awaitingInput == 1
		set buttonVar to getbuttonpressed

		if buttonVar > -1
			set awaitingInput to 0

			if buttonVar == 0
				player.RemoveItem f 25
				player.AddItem ASNexywoodAid 1
				Disable
				MarkForDelete
			elseif buttonVar == 1
			endif
		endif
	endif
end

I ran through quite a few tests and it seems to do what I want for the most part, it's really not efficient/hacky, I know.

 

I'll do some more research on the activators, but the way you described what it can do sound like what I'm after instead of doing all the scripting to work around the problems.

Edited by ArekkusuStorm
Link to comment
Share on other sites

GetDetected and IsSneaking are boolean functions, so like GetIsReference you don't need "== 1" in those conditions. "if TrudyRef.GetDetected Player" has exactly the same effect as "if TrudyRef.GetDetected Player == 1", but executes slightly-faster. Additionally, you've got code to the effect of
if player.IsSneaking == 0
; player isn't sneaking
elseif player.IsSneaking == 1
; player is sneaking
endif
when IsSneaking can't return any value but 0 or 1 - meaning that you're testing the same condition twice and making the same function call twice when you only need to test it once.
if player.IsSneaking == 0
; player isn't sneaking
else
; player is sneaking
endif
has exactly the same effect. You only need to use elseif when you need to test for more than two possible outcomes - and even then, you can usually just use else for the last of those. Also, and this might be my own personal preference, I really don't like how this looks. I prefer to test for the positive, and then operate on the negative in an else block. Like this:
if player.IsSneaking
; player *is* sneaking, run that code
else
; player isn't sneaking, run that code
endif
changing the way the code reads from "if 'player is sneaking' is false then do {} else do {}" to "if player is sneaking then do {} else do {}".
Link to comment
Share on other sites

GetDetected and IsSneaking are boolean functions, so like GetIsReference you don't need "== 1" in those conditions. "if TrudyRef.GetDetected Player" has exactly the same effect as "if TrudyRef.GetDetected Player == 1", but executes slightly-faster. Additionally, you've got code to the effect of

Ah, alright, I'll go fix that.

 

 

 

when IsSneaking can't return any value but 0 or 1 - meaning that you're testing the same condition twice and making the same function call twice when you only need to test it once.

Will fix.

 

 

 

has exactly the same effect. You only need to use elseif when you need to test for more than two possible outcomes - and even then, you can usually just use else for the last of those. Also, and this might be my own personal preference, I really don't like how this looks. I prefer to test for the positive, and then operate on the negative in an else block. Like this:

Fair enough. Usually I would do that, but I was just adding on to the code when I wrote that and wasn't really reorganizing anything.

 

Thanks for taking the time to go through my code and pointing out ways to make it better.

Edited by ArekkusuStorm
Link to comment
Share on other sites

  • Recently Browsing   0 members

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