ArekkusuStorm Posted October 23, 2014 Share Posted October 23, 2014 (edited) 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 October 23, 2014 by ArekkusuStorm Link to comment Share on other sites More sharing options...
DaWrecka Posted October 23, 2014 Share Posted October 23, 2014 (edited) 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 October 23, 2014 by DaWrecka Link to comment Share on other sites More sharing options...
ArekkusuStorm Posted October 23, 2014 Author Share Posted October 23, 2014 (edited) 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 October 23, 2014 by ArekkusuStorm Link to comment Share on other sites More sharing options...
DaWrecka Posted October 23, 2014 Share Posted October 23, 2014 (edited) 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) != FALSEWhich simplifies down toif (TRUE) != FALSEwhich 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 October 23, 2014 by DaWrecka Link to comment Share on other sites More sharing options...
ArekkusuStorm Posted October 23, 2014 Author Share Posted October 23, 2014 (edited) 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 playerYeah, 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 October 23, 2014 by ArekkusuStorm Link to comment Share on other sites More sharing options...
DaWrecka Posted October 23, 2014 Share Posted October 23, 2014 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 ofif player.IsSneaking == 0 ; player isn't sneaking elseif player.IsSneaking == 1 ; player is sneaking endifwhen 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 endifhas 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 endifchanging 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 More sharing options...
ArekkusuStorm Posted October 24, 2014 Author Share Posted October 24, 2014 (edited) 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 ofAh, 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 October 24, 2014 by ArekkusuStorm Link to comment Share on other sites More sharing options...
Recommended Posts