Jump to content

Continue() is very dangerous


King Diamond

Recommended Posts

I think Baldur.bcs gets away with it because the default behavior is to just do nothing (so for the majority of the game, it's really just returning false or silently failing). (At least, this was my assumption; it's one of the things I never really desired to investigate.)

 

It's necessary to use Continue() very carefully
I wonder if the engine would treat the script differently if the Continue() blocks weren't identical. It knows enough to not flush the queue if it hits the same block on the next run, but I don't know how it tracks this. I have seen Continue() work reasonably when the same variable was used between multiple different blocks, but I can't remember exactly what my tests were (and they would have been very brief).
Link to comment

I know Continue() works fine for all five blocks of AR1000.baf in Xan mod:

 

IF
!G("O#XanSpawn",1)
!Dead("O#Xan")
G("O#XanJoined",0)
XPLT(Player1,280001)
THEN
RESPONSE #100
ActionOverride("O#Xan",DestroySelf())
CreateCreature("O#Xan09",[2745.321],4)
SG("O#XanSpawn",1)
Continue()
END

 

etc.

 

I suppose the reason is that each block has different experience requirements, i.e. no two blocks cannot be True at the same time.

Link to comment
Wha?

LOCALS wouldn't work in ANY area script?

Area and info point objects cannot set or get LOCALS variables. Using LOCALS outside an actor script (or SetGlobal() outside ActionOverride() on a valid actor) does nothing (this should be true for any other AI object I forgot).
Link to comment
(or SetGlobal() outside ActionOverride() on a valid actor) does nothing

 

I am not sure I understand:

 

In a mythical AR0100.BAF, set up to EXTEND_BOTTOM ~AR0100.are~

IF
 InParty("imoen") // should work
 Global("Garbage1","AR0100",1) // should work
 Global("Garbage2","MYAREA",1) // should work
 Global("Garbage3","LOCALS",1) // can't work as it is not being run on a specific object
 Global("Garbage4","GLOBAL",1) // works everywhere
THEN RESPONSE #100
 SetGlobal("Garbage1","AR0100",2)//works
 SetGlobal("Garbage1","AR0200",1)// we don't think works
 SetGlobal("Garbage2","MYAREA",2) // should work
 SetGlobal("Garbage3","LOCALS",1) // can't work as it is not run on specific object
 ActionOverride("imoen",SetGlobal("Garbage3","LOCALS",1)) // should work fine to set a LOCALS value on imoen
 SetGlobal("Garbage4","GLOBAL",1) // works everywhere
 Continue() //keep on going
END

IF
 OnCreation()//any actions here would be interfered with if the block above is true the first time the script is run, unless the block contains a Continue(). If more than one block can be true after a Continue(), they are each evaluated true and the cumulative actions taken, until either the end of the script is reached, or a block which reads true but does not have a Continue() loops the script back to the beginning.

 

Is this a correct summary of the conversation so far?

Link to comment

For the first statement, yes, except "MYAREA" will definitely work.

 

The second is the question. I do not believe that is the behavior, but it's not something I ever looked into. Continue() most certainly should NOT be causing triggers to spontaneously return true (IIRC, most BG and ID scripts make heavy use of Continue() with no issues at all). The mystery is exactly when and how the engine executes actions, how long it takes, and how hard it tries to avoid doing something stupid like evaluating Global() in subsequent blocks when already running a SetGlobal() action from previous blocks. Since SetGlobal() should be executed instantly, this shouldn't ever be a problem, but apparently it is.

Link to comment
The mystery is exactly when and how the engine executes actions, how long it takes, and how hard it tries to avoid doing something stupid like evaluating Global() in subsequent blocks when already running a SetGlobal() action from previous blocks. Since SetGlobal() should be executed instantly, this shouldn't ever be a problem, but apparently it is.

 

Then we should ask Avenger about the exact mechanism of how engine handles and executes various actions 'coz I think he's the only person (really?) who studies disassembled code... :)

 

2Avenger

Have you taken a look into that matter already?

Does engine execute all actions instantly, in a single thread, or start separate threads for some actions without waiting for them in a main script running thread(that definitely would take some extra time to complete)?

Link to comment

Nah, i looked only into effect opcodes.

And i have only theoretical assumptions about variable handling.

Theoretically, 'LOCALS' could work exactly like 'MYAREA' in area scripts.

Actually, GemRB works like that.

I'll test if LOCALS truly a dummy scope for area scripts, this would fix an incompatibility with IE (the snippet i supplied was from DLTC and it worked differently under GemRB, because GemRB executed the action block, while IE didn't).

Link to comment
I can't vouch for area scripts because I haven't tested them, but I know the global script, BALDUR.BCS, can do it. It sets variables in at least one area. Sub-areas might be able to read/modify variables in their master area, but again, I haven't tested it yet. Or if I did, it was months/years ago and I've forgotten.

Well, yes, Baldur.BCS contains 2 blocks to keep Nalia from giving her spiel about being orphaned and forced to marry a cretin. But if you notice, they contain checks to make sure the area they set a variable for is the current area.

They could have made it a bit simpler, by using an "OR" for the area, and a "MYAREA" style global check/set.

Link to comment

I did one better by moving all area-checking blocks from BALDUR.BCS to the the target area script and removing the now unnecessary area check. This can be done with a few Nalia blocks, the block that gives XP for finding Montaron's body, the block the sets a variable if the Trademeet Genies are dead or have left the area, and so on. I also moved romance compatibility checks to the pertinant CRE scripts. You can also remove the romance-killing blocks that execute if, for example, an NPC is imprisoned or has been out of the party for more than three game days.

Link to comment

Which leaves multi-area spawns, and talking items.

 

I'd say the talking items could be put in the dplayer scripts, since I don't think they are supposed to talk in cases of NPCs weilding them when not in the party. And then they don't have to check anything but whether the item is equipped and the timer has expired.

Link to comment

Archived

This topic is now archived and is closed to further replies.

×
×
  • Create New...