Oculus Runes
From LSWiki
Revision as of 17:52, 23 May 2021 (edit) Esmene (Talk | contribs) ← Previous diff |
Current revision (14:15, 30 October 2024) (edit) Moxomatosis (Talk | contribs) (Added a web based solver.) |
||
Line 1: | Line 1: | ||
+ | ==Online== | ||
+ | A version of the Python offline solver (see below) is available at https://moxomatosis.github.io/oculus.html. You need to enter the state of the Oculus as a sequence of letters matching the colors. When a color points up, enter the letter in uppercase, otherwise use lowercase. An example would be rOygBiV. The output will be a sequence of flips to perform to get the proper result. Note that the output may be upside down, so you may need to flip the Oculus to complete the puzzle. | ||
+ | |||
+ | ==ZMUD== | ||
The first line directly under the pattern # is the actual trigger pattern. The rest is the execution code. | The first line directly under the pattern # is the actual trigger pattern. The rest is the execution code. | ||
These triggers (put them in a class folder so you can easily disable them later) produce two variables: @oculus, which counts how many times the oculus has been rotated, and @count, which tells the script how many times runes have been flipped. You only get 15 moves, so when the 15th move occurs, it restarts the script. When the oculus has been rotated 5 times, the script attempts to make you enter the portal (assuming success.) If that fails, it moves on to flipping the current first rune until count restarts it. | These triggers (put them in a class folder so you can easily disable them later) produce two variables: @oculus, which counts how many times the oculus has been rotated, and @count, which tells the script how many times runes have been flipped. You only get 15 moves, so when the 15th move occurs, it restarts the script. When the oculus has been rotated 5 times, the script attempts to make you enter the portal (assuming success.) If that fails, it moves on to flipping the current first rune until count restarts it. | ||
Line 7: | Line 11: | ||
To start the script execution, turn off triggers and "flip first rune" until you get a message saying colors flicker across your oculus. Then turn triggers on, and "look at runes on oculus" one time. The rest is automated until success or you get disconnected from the MUD. | To start the script execution, turn off triggers and "flip first rune" until you get a message saying colors flicker across your oculus. Then turn triggers on, and "look at runes on oculus" one time. The rest is automated until success or you get disconnected from the MUD. | ||
+ | |||
+ | Once you've entered the portal, you need to 'place oculus on pedestal.' You could add it to the enter portal trigger if necessary. | ||
+ | |||
+ | 11/28/2022: This script still works to solve the quest via brute force. Changed one pattern to reflect an updated failure message. ("You do not know how to 'enter'." became "You do not see a portal here.") | ||
Pattern 1 | Pattern 1 | ||
Line 48: | Line 56: | ||
Pattern 4 | Pattern 4 | ||
- | You don't know how to 'enter'. | + | You do not see a portal here. |
flip first rune | flip first rune | ||
Line 58: | Line 66: | ||
==Mudlet Port== | ==Mudlet Port== | ||
- | Trigger 1 (perl regex): The first rune is (\w+) and points (\w+). The second rune is (\w+) and points (\w+). The third rune is (\w+) and points (\w+). | + | Before using the triggers, '''Set Usable Columns''' to '''200''' and '''Toggle Columns Override''' to '''Off''' in the '''Terminal Setup Menu'''; when finished go back to default. |
+ | |||
+ | Another thing you could do is to set the in game filter '''OOC -''' and set it on again '''OOC +''' when finished. | ||
+ | |||
+ | Trigger 1 | ||
+ | (perl regex): The first rune is (\w+) and points (\w+). The second rune is (\w+) and points (\w+). The third rune is (\w+) and points (\w+). | ||
runeonedir = matches[3] | runeonedir = matches[3] | ||
Line 68: | Line 81: | ||
elseif runetwodir == "downward" then | elseif runetwodir == "downward" then | ||
send("flip second rune") | send("flip second rune") | ||
- | tempTimer(1.5,<nowiki>[[send("look at runes on oculus")]]</nowiki>) | + | tempTimer(1.5, <nowiki>[[send("look at runes on oculus")]]</nowiki>) |
elseif runethreedir == "downward" then | elseif runethreedir == "downward" then | ||
send("flip third rune") | send("flip third rune") | ||
- | tempTimer(1.5,<nowiki>[[send("look at runes on oculus")]]</nowiki>) | + | tempTimer(1.5, <nowiki>[[send("look at runes on oculus")]]</nowiki>) |
else | else | ||
send("rotate oculus left") | send("rotate oculus left") | ||
+ | oculus = oculus or 0 | ||
oculus = oculus + 1 | oculus = oculus + 1 | ||
- | if oculus==5 then | + | if oculus == 5 then |
oculus = 0 | oculus = 0 | ||
send("enter portal") | send("enter portal") | ||
Line 83: | Line 97: | ||
end | end | ||
- | Trigger 2 (substring) The Illuminatorium Oculus reacts to your proximity | + | Trigger 2 |
+ | (substring): The Illuminatorium Oculus reacts to your proximity | ||
+ | count = count or 0 | ||
count = count + 1 | count = count + 1 | ||
- | Trigger 3 (substring) You see colors flicker across the Illuminatorium Oculus as its runes reorient themselves. | + | Trigger 3 |
+ | (substring): You see colors flicker across the Illuminatorium Oculus as its runes reorient themselves. | ||
count = 0 | count = 0 | ||
send("look at runes on oculus") | send("look at runes on oculus") | ||
- | Trigger 4 (substring) You don't know how to 'enter'. | + | Trigger 4 |
+ | (substring 1): That doesn't make sense. | ||
+ | (substring 2): You do not see a portal here. | ||
function countit() | function countit() | ||
Line 103: | Line 122: | ||
end | end | ||
send("flip first rune") | send("flip first rune") | ||
- | temptimer(1, countit()) | + | tempTimer(1, countit) |
+ | |||
+ | |||
+ | ==Offline Python== | ||
+ | #!/usr/bin/env python3 | ||
+ | |||
+ | from collections import deque | ||
+ | import sys | ||
+ | |||
+ | goal = 'ROYGBIV' | ||
+ | goal_1 = list(goal.lower()) | ||
+ | goal_2 = list(goal.upper()) | ||
+ | |||
+ | def all_shifts(shifts, pattern): | ||
+ | results = {} | ||
+ | for i in range(len(pattern)): | ||
+ | new_arr = list(pattern) | ||
+ | char = pattern[i].lower() if pattern[i].isupper() else pattern[i].upper() | ||
+ | new_pos = ((i + 2) % (len(pattern) - 1)) + 1 | ||
+ | new_arr.pop(i) | ||
+ | new_arr.insert(new_pos, char) | ||
+ | rotate_arr = deque(new_arr) | ||
+ | while rotate_arr[0] not in ['R', 'r']: | ||
+ | rotate_arr.rotate(1) | ||
+ | results[shifts + pattern[i]] = list(rotate_arr) | ||
+ | return results | ||
+ | |||
+ | |||
+ | def main(): | ||
+ | if len(sys.argv) < 2: | ||
+ | print('Usage: %s <starting pattern>' % (sys.argv[0])) | ||
+ | print('Format for the pattern is RoYGBiV where capital is up and lowercase is down, in the order the runes are presently') | ||
+ | sys.exit(1) | ||
+ | else: | ||
+ | pattern = sys.argv[1] | ||
+ | for c in pattern: | ||
+ | if c.upper() not in goal: | ||
+ | print('Invalid color %s' % (c)) | ||
+ | sys.exit(1) | ||
+ | print('origin: ' + str(list(pattern))) | ||
+ | loops = 1 | ||
+ | states = {} | ||
+ | states[0] = all_shifts('', pattern) | ||
+ | while loops < 14: | ||
+ | for shifts, state in iter(states[loops - 1].items()): | ||
+ | new_states = all_shifts(shifts, state) | ||
+ | if goal_1 in new_states.values(): | ||
+ | print(str([ k for k in new_states if new_states[k] == goal_1 ]) + ' => ' + str(goal_1)) | ||
+ | sys.exit(0) | ||
+ | if goal_2 in new_states.values(): | ||
+ | print(str([ k for k in new_states if new_states[k] == goal_2 ]) + ' => ' + str(goal_2)) | ||
+ | sys.exit(0) | ||
+ | if not loops in states: | ||
+ | states[loops] = {} | ||
+ | states[loops].update(new_states) | ||
+ | loops += 1 | ||
+ | print("Couldn't find a solution") | ||
+ | |||
+ | if __name__ == "__main__": | ||
+ | main() | ||
+ | |||
+ | ==Tintin++== | ||
+ | |||
+ | This solution uses only basic functions of Tintin. It's important to make sure that your screen is big enough so none of the trigger elements wrap around and that you have the Oculus identified. It first flips all the runes on the Oculus upwards and will then flip only the first rune until the Oculus resets or the portal appears. | ||
+ | |||
+ | #ALIAS {r} {look at runes on oculus} | ||
+ | #ACTION {The third rune is %1 and points downward} {flip third rune} {1} | ||
+ | #ACTION {The second rune is %1 and points downward} {flip second rune} {2} | ||
+ | #ACTION {The first rune is %1 and points downward} {flip first rune} {3} | ||
+ | #ACTION {The first rune is %1 and points upward. The second rune is %2 and points upward. The third rune is %3 and points upward.} {rotate disc left} | ||
+ | #ACTION {You can see three runes} {#ticker q {flip first rune} 2} | ||
+ | #ACTION {You see colors flicker across the Illuminatorium Oculus as its runes} {#unticker q;#delay 1 r;#delay 2 r;#delay 3 r;#delay 4 | ||
+ | r;#delay 5 r;#delay 6 r;#delay 7 r;#delay 8 r;#delay 9 r;#delay 10 r} | ||
+ | #ACTION {materializes in the air} {#unticker q;enter gold portal;place oculus on pedestal} |
Current revision
Contents |
Online
A version of the Python offline solver (see below) is available at https://moxomatosis.github.io/oculus.html. You need to enter the state of the Oculus as a sequence of letters matching the colors. When a color points up, enter the letter in uppercase, otherwise use lowercase. An example would be rOygBiV. The output will be a sequence of flips to perform to get the proper result. Note that the output may be upside down, so you may need to flip the Oculus to complete the puzzle.
ZMUD
The first line directly under the pattern # is the actual trigger pattern. The rest is the execution code. These triggers (put them in a class folder so you can easily disable them later) produce two variables: @oculus, which counts how many times the oculus has been rotated, and @count, which tells the script how many times runes have been flipped. You only get 15 moves, so when the 15th move occurs, it restarts the script. When the oculus has been rotated 5 times, the script attempts to make you enter the portal (assuming success.) If that fails, it moves on to flipping the current first rune until count restarts it.
It took me about an hour to work out all the kinks and try different iterations of this script, but this is the simplest and most effective version. I had a success after about five minutes of running it.
Special Note: The rest of the Illuminatorium puzzles took me less than 5 minutes a piece to complete. I spent about three HOURS trying to solve the Oculus runes by traditional method (pen and paper) and eventually decided I'd had enough of it.
To start the script execution, turn off triggers and "flip first rune" until you get a message saying colors flicker across your oculus. Then turn triggers on, and "look at runes on oculus" one time. The rest is automated until success or you get disconnected from the MUD.
Once you've entered the portal, you need to 'place oculus on pedestal.' You could add it to the enter portal trigger if necessary.
11/28/2022: This script still works to solve the quest via brute force. Changed one pattern to reflect an updated failure message. ("You do not know how to 'enter'." became "You do not see a portal here.")
Pattern 1
The first rune is %1 and points %2. The second rune is %3 and points %4. The third rune is %5 and points %6.
#IF %2=downward { flip first rune #wait 1000 look at runes on oculus } { #IF %4=downward { flip second rune #wait 1000 look at runes on oculus } { #IF %6=downward { flip third rune #wait 1000 look at runes on oculus } { rotate oculus left #MATH oculus (@oculus+1) #IF @oculus=5 { #MATH oculus (@oculus*0) enter portal } {look at runes on oculus} } } }
Pattern 2
The Illuminatorium Oculus reacts to your proximity
#MATH count (@count+1)
Pattern 3
You see colors flicker across the Illuminatorium Oculus as its runes reorient themselves.
#MATH count (@count*0) look at runes on oculus
Pattern 4
You do not see a portal here.
flip first rune #wait 1000 #IF @count<14 {enter portal} #IF @count=14 {flip first rune}
Mudlet Port
Before using the triggers, Set Usable Columns to 200 and Toggle Columns Override to Off in the Terminal Setup Menu; when finished go back to default.
Another thing you could do is to set the in game filter OOC - and set it on again OOC + when finished.
Trigger 1
(perl regex): The first rune is (\w+) and points (\w+). The second rune is (\w+) and points (\w+). The third rune is (\w+) and points (\w+).
runeonedir = matches[3] runetwodir = matches[5] runethreedir = matches[7] if runeonedir == "downward" then send("flip first rune") tempTimer(1.5, [[send("look at runes on oculus")]]) elseif runetwodir == "downward" then send("flip second rune") tempTimer(1.5, [[send("look at runes on oculus")]]) elseif runethreedir == "downward" then send("flip third rune") tempTimer(1.5, [[send("look at runes on oculus")]]) else send("rotate oculus left") oculus = oculus or 0 oculus = oculus + 1 if oculus == 5 then oculus = 0 send("enter portal") else send("look at runes on oculus") end end
Trigger 2
(substring): The Illuminatorium Oculus reacts to your proximity
count = count or 0 count = count + 1
Trigger 3
(substring): You see colors flicker across the Illuminatorium Oculus as its runes reorient themselves.
count = 0 send("look at runes on oculus")
Trigger 4
(substring 1): That doesn't make sense. (substring 2): You do not see a portal here.
function countit() if count < 14 then send("enter portal") end if count == 14 then send ("flip first rune") end end send("flip first rune") tempTimer(1, countit)
Offline Python
#!/usr/bin/env python3 from collections import deque import sys goal = 'ROYGBIV' goal_1 = list(goal.lower()) goal_2 = list(goal.upper()) def all_shifts(shifts, pattern): results = {} for i in range(len(pattern)): new_arr = list(pattern) char = pattern[i].lower() if pattern[i].isupper() else pattern[i].upper() new_pos = ((i + 2) % (len(pattern) - 1)) + 1 new_arr.pop(i) new_arr.insert(new_pos, char) rotate_arr = deque(new_arr) while rotate_arr[0] not in ['R', 'r']: rotate_arr.rotate(1) results[shifts + pattern[i]] = list(rotate_arr) return results def main(): if len(sys.argv) < 2: print('Usage: %s <starting pattern>' % (sys.argv[0])) print('Format for the pattern is RoYGBiV where capital is up and lowercase is down, in the order the runes are presently') sys.exit(1) else: pattern = sys.argv[1] for c in pattern: if c.upper() not in goal: print('Invalid color %s' % (c)) sys.exit(1) print('origin: ' + str(list(pattern))) loops = 1 states = {} states[0] = all_shifts(, pattern) while loops < 14: for shifts, state in iter(states[loops - 1].items()): new_states = all_shifts(shifts, state) if goal_1 in new_states.values(): print(str([ k for k in new_states if new_states[k] == goal_1 ]) + ' => ' + str(goal_1)) sys.exit(0) if goal_2 in new_states.values(): print(str([ k for k in new_states if new_states[k] == goal_2 ]) + ' => ' + str(goal_2)) sys.exit(0) if not loops in states: states[loops] = {} states[loops].update(new_states) loops += 1 print("Couldn't find a solution") if __name__ == "__main__": main()
Tintin++
This solution uses only basic functions of Tintin. It's important to make sure that your screen is big enough so none of the trigger elements wrap around and that you have the Oculus identified. It first flips all the runes on the Oculus upwards and will then flip only the first rune until the Oculus resets or the portal appears.
#ALIAS {r} {look at runes on oculus} #ACTION {The third rune is %1 and points downward} {flip third rune} {1} #ACTION {The second rune is %1 and points downward} {flip second rune} {2} #ACTION {The first rune is %1 and points downward} {flip first rune} {3} #ACTION {The first rune is %1 and points upward. The second rune is %2 and points upward. The third rune is %3 and points upward.} {rotate disc left} #ACTION {You can see three runes} {#ticker q {flip first rune} 2} #ACTION {You see colors flicker across the Illuminatorium Oculus as its runes} {#unticker q;#delay 1 r;#delay 2 r;#delay 3 r;#delay 4 r;#delay 5 r;#delay 6 r;#delay 7 r;#delay 8 r;#delay 9 r;#delay 10 r} #ACTION {materializes in the air} {#unticker q;enter gold portal;place oculus on pedestal}