AND and OR in scripting, How to simulate them in various IE games |
The Black Wyrm's Lair Terms of Use | Help Search Members Calendar |
AND and OR in scripting, How to simulate them in various IE games |
Jun 29 2005, 04:36 PM
Post
#1
|
|
Mathematical poet Retired team member Posts: 159 Joined: 9-July 04 From: Prague, Czech Republic |
This is rather the compilation of my posts from Black Wyrm Lair, Pocket Plane and Czech modding forums than tutorial. It provides the method how to simulate OR operators and nested ANDs in various Infinity games.
First of all, a small recapitulation of how the script proceeds (for the detailed explaining, see SimDing0's Complete Scripting Guide). The script is parsed from the top. When the triggers of one block are evaluated as true, the actions of the block are performed and the parsing restarts from the top (unless there is the Continue() action in actions of the block - in this case, the parsing continues to the next block). When the trigger of one block is evaluated as false, the parsing skips to the next block. When it reaches the bottom of script (last block), it starts from the top again. Simulating of OR in Baldur's Gate I It is known that there is no OR in BG1. It is also well-known how solve this situation - divide the blocks with n triggers in OR relation into n separate blocks - each with one trigger which would be in OR. CODE IF Race(Player1,ELF) Global("Variable","GLOBAL",1) OR(4) Class(Player1,FIGHTER_ALL) Class(Player1,PALADIN_ALL) Class(Player1,RANGER_ALL) Class(Player1,CLERIC_ALL) THEN RESPONSE #100 Action() END Previous block have to be divided into four blocks in BG1 CODE IF Race(Player1,ELF) Global("Variable","GLOBAL"1) Class(Player1,FIGHTER_ALL) THEN RESPONSE #100 Action() END IF Race(Player1,ELF) Global("Variable","GLOBAL"1) Class(Player1,PALADIN_ALL) THEN RESPONSE #100 Action() END IF Race(Player1,ELF) Global("Variable","GLOBAL"1) Class(Player1,RANGER_ALL) THEN RESPONSE #100 Action() END IF Race(Player1,ELF) Global("Variable","GLOBAL"1) Class(Player1,CLERIC_ALL) THEN RESPONSE #100 Action() END However, there is another way how to accomplish this. The way is based on deMorgan's theorems from Boolean algebra. This way it is possible to simulate OR operator by fixed amount of block - this amount is three blocks regardless of the number of triggers in OR relation. According deMorgan's theorem we can negate OR(n) formula. With Trigger1 OR Trigger2 OR ... OR TriggerN we have: !Trigger1 AND !Trigger2 AND ... AND !TriggerN Ok, but what advantage is hidden in it? We can catch by this negated OR formula the cases when our original OR formula is not evaluated as true. This trick is the core of this method, so some examples how to imagine its logic: Let's compare: "If the enemy is a dwarf or an elf, I'll do something." - "If the enemy is not a dwarf as well as an elf (neither a dwarf, nor an elf), I'll do something else (or maybe nothing)". First block's triggers is true if the enemy is a dwarf or an elf. Second block's triggers is true if the enemy is neither dwarf nor elf - half-elf for example. "If the variable has the value 2 or 4, I'll do something." - "If the variable has not the value 2 and 4, I'll do something else (or maybe nothing)." - the variable could have the value 0, 3, 1000,... - this condition is true in these cases (because of !(var=2 or var=4) ); in case when the variable has the value 2 (or 4), this condition is false. With this logic we can transform following block with OR to the blocks with the same result but without OR. CODE //this is the original OR block (can be coded in BG2, cannot be coded in BG1) IF OR(3) Trigger1 Trigger2 Trigger3 THEN RESPONSE #100 Action() END The block will be transformed to: CODE IF !Trigger1 !Trigger2 !Trigger3 THEN RESPONSE #100 NoAction() END If all triggers are evaluated as true it is the case when my original OR would be evaluated as false, so this block catches this case - the case what is a negation of what we want to do. From the parsing logic of the script we know that when the triggers are evaluated as true, the script restarts from the top. Here, when my original OR would be false, this block is true so the cycling of the script occurs. But when my original OR can be evaluated as true (at least one trigger is true in it), this block would be false (one or more trigger in this AND is not true -> whole AND is not true) and the script continues to the next block which looks like this: CODE IF True() THEN RESPONSE #100 MyAction() //actions which I want to be performed in my original OR block END So it is clear that these two blocks simulate the OR operator. However, it is just a rough form. It can be used just in the case when the script would be made by these two blocks only. Because of one of them is always true, they make the cycle and other block after them would be cut off from the proceeding of the script. For the complete simulation of OR usable anywhere we'll need the third block and one local variable. Following three blocks represent the correct behavior of my original OR block - if the OR block would be performed, the script will restart; if the OR block would not be performed, the script continues to next block... Local variable "OR" - 1: my original OR block would not be performed (it would be false) 0: my original OR block would be performed (it would be true) CODE // "OR" variable must be set to 0 - we don't know whether original OR block would be performed and initially we must expect both cases IF GlobalGT("OR","LOCALS",0) // "OR" is greater than 0 THEN RESPONSE #100 SetGlobal("OR","LOCALS",0) // "OR" is set to 0 Continue() // script continues to the next block !!! END IF !Trigger1 !Trigger2 !Trigger3 THEN RESPONSE #100 SetGlobal("OR","LOCALS",1) // original OR would be false Continue() // script continues to the next block according to the script parsing rules (original OR would not be performed, the script continues to the next block) END IF !GlobalGT("OR","LOCALS",0) // "OR" is not greater than 0, this block is performed. If "OR" is greater than 0, this block is not performed and the script continues to the next block THEN RESPONSE #100 MyAction() // the actions that we want to be performed //no Continue() unless we explicitly want to. The original OR block would be performed, so the script should restart END We can return to the beggining of this article. The block: CODE IF Race(Player1,ELF) Global("Variable","GLOBAL",1) OR(4) Class(Player1,FIGHTER_ALL) Class(Player1,PALADIN_ALL) Class(Player1,RANGER_ALL) Class(Player1,CLERIC_ALL) THEN RESPONSE #100 Action() END will look like this: CODE IF GlobalGT("OR","LOCALS",0) THEN RESPONSE #100 SetGlobal("OR","LOCALS",0) Continue() END IF Race(Player1,ELF) Global("Variable","GLOBAL",1) !Class(Player1,FIGHTER_ALL) !Class(Player1,PALADIN_ALL) !Class(Player1,RANGER_ALL) !Class(Player1,CLERIC_ALL) THEN RESPONSE #100 SetGlobal("OR","LOCALS",1) Continue() END IF Race(Player1,ELF) Global("Variable","GLOBAL",1) !GlobalGT("OR","LOCALS",0) THEN RESPONSE #100 Action() END With possible more triggers in OR, this construction will have always three blocks regardless of the number of triggers in OR. Simulating of AND in IE scripts. (Trigger1 AND Trigger2) OR (Trigger3 AND Trigger4) AND is implicit in triggers and no single AND(n) as OR(n) doesn't exist. But there is a three block solution that can simulate various Sum of Products boolean formulas ( (...AND...AND...AND...) OR (...AND...AND...AND...) OR (...AND...AND...AND...) OR...) I wanted do this two years ago - I tried to simulate AND by !OR() and it didn't work.But it can be accomplished in the following way... The principle - make the negation of: (Trigger1 AND Trigger2) OR (Trigger3 AND Trigger4) - according deMorgan we have: (!Trigger1 OR !Trigger2) AND (!Trigger3 Or !Trigger4). This negation can be coded in IE script block. The action of that block must be the reverse of the original action - or just NoAction() - "I want to do something if condition (Trigger1 AND Trigger2) OR (Trigger3 AND Trigger4) is true and do nothing when it is not true". There is the second block which follow after this. This block has its condition always true and its purpose is to perform the action that we want to perform. Because of the proccesing of scripts the following two possibilites occurs: - the first block condition is true (="Oposition of my original requirements are fulfiled"="My original requirements are not fulfiled") - NoAction (or reverse action) is performed and the script restarts from its beginning. So the second "always true" block is not performed. So I "catch" the undesired cases. - the first block's condition is false (="Oposition of my original requirements are not fulfiled"="My original requirements are fulfiled") - script skips to second block and it is performed then... CODE IF OR(2) !Trigger1 !Trigger2 OR(2) !Trigger3 !Trigger4 THEN RESPONSE #100 NoAction() END IF True() THEN RESPONSE #100 Action() END Well, this solution is rough, however - the rest of the script after the mentioned second block is always cut off from the script procceeding due to second block's always true condition. I can add there Continue() action that ensures the continue of the script proceeding. But by this I'll break a little the standart rules of the script proceeding (when the block is performed, the script restarts). So, I'll add "AND" local variable - its values meaning: - 0: my desired action can be performed - 1: my desired action cannot be performed due to the fact that the opposite conditions are true CODE IF
GlobalGT("AND",LOCALS",0) //if "AND" is greater than 0 THEN RESPONSE #100 SetGlobal("AND","LOCALS",0) // reset to 0 Continue() // I want to continue in the script END IF OR(2) !Trigger1 !Trigger2 OR(2) !Trigger3 !Trigger4 THEN RESPONSE #100 SetGlobal("AND","LOCALS",1) //My desired action cannot be performed (opposite conditions are true), so AND=1 Continue() //!! I want to continue in script because in my imaginary "(Trigger1 AND Trigger2) OR (Trigger3 AND Trigger4)" block I have now the case when its conditions are not true and the script continues to following block in these cases END IF !GlobalGT("AND","LOCALS",0) // "AND" is not greater than 0 THEN RESPONSE #100 Action() //perform desired action //no Continue() - if this block is performed, the script restarts as it is standart. END -------------------- |
|
|
Aug 12 2005, 04:18 PM
Post
#2
|
|
Master of energies Council Member Posts: 3318 Joined: 9-July 04 From: Magyarország |
Shouldn't it be OR(4) instead of OR(3) in the first script block or did something escape my attention?
-------------------- Mental harmony dispels the darkness.
|
|
|
Aug 22 2005, 10:08 AM
Post
#3
|
|
Mathematical poet Retired team member Posts: 159 Joined: 9-July 04 From: Prague, Czech Republic |
QUOTE(Baronius @ Aug 12 2005, 06:18 PM) Shouldn't it be OR(4) instead of OR(3) in the first script block or did something escape my attention? Yep, corrected, thx -------------------- |
|
|
Lo-Fi Version | Time is now: 5th November 2024 - 06:37 PM |