void Start() { moduleId = moduleIdCounter++; // Show the runes the first time the module is selected Activator.OnInteract += delegate { if (moduleStarted) { return(false); } StartCoroutine(CrashDownSetup()); moduleStarted = true; Activator.gameObject.SetActive(false); // This doesn't appear to work on the latest version of KTaNE //GamepadSupport(); Module.Children = RuneOrder.ToArray(); UpdateChildren(); return(false); }; // Set the runes to invisible until they appear for (int i = 0; i < Runes.Length; i++) { Runes[i].gameObject.SetActive(false); Runes[i].OnInteract += RunePressed(i); } // Assign RuneLetters with the different positions RuneLetters = new[] { RuneLetters_1, RuneLetters_2, RuneLetters_3 }; // Assign RuneTransforms with their childs RuneTransforms = Runes.Select(rune => rune.transform.parent).ToArray(); RuneParentPos = Runes.Select(rune => rune.transform.parent.localPosition).ToArray(); // Shuffle positions var randPos = Enumerable.Range(0, RuneTransforms.Length).ToList(); var runeOrder = new KMSelectable[selectableLocations.Length]; for (int i = 0; i < RuneTransforms.Length; i++) { int index = Random.Range(0, randPos.Count); RuneTransforms[i].localPosition = RuneParentPos[randPos[index]]; DustSystemRunes[i].transform.localPosition = RuneParentPos[randPos[index]]; Vector3 DustPos = DustSystemRunes[i].transform.localPosition; DustPos.y = 0.01f; DustSystemRunes[i].transform.localPosition = DustPos; runeOrder[Array.IndexOf(selectableLocations, randPos[index])] = Runes[i]; randPos.RemoveAt(index); } RuneOrder = runeOrder.ToArray(); // Generate a random 3-letter word for (int i = 0; i < RuneLetters.Length; i++) { pickedRuneLetters[i] = Random.Range(0, RuneLetters[i].Length); pickedRuneNames[i] = ElderFuthark[pickedRuneLetters[i]]; Debug.LogFormat(@"[Elder Futhark #{0}] The {1} rune is {2}", moduleId, i == 0 ? "first" : i == 1 ? "second" : "third", pickedRuneNames[i]); } // Rule-seeded rules var rnd = RuleSeedable.GetRNG(); Debug.LogFormat(@"[Elder Futhark #{0}] Using rule seed: {1}.", moduleId, rnd.Seed); var cycleLeft = rnd.Seed == 1 ? false : rnd.Next(0, 2) != 0; var order = rnd.Seed == 1 ? new[] { 0, 1, 2 } : rnd.ShuffleFisherYates(Enumerable.Range(0, 3).ToArray()); var edgeworkConditions = newArray ( // the sum of the digits in the serial number Bomb.GetSerialNumberNumbers().Sum(), // the sum of the first three characters in the serial number (use alphabetic positions for letters) Bomb.GetSerialNumber().Take(3).Select(ch => ch >= 'A' && ch <= 'Z' ? ch - 'A' + 1 : ch - '0').Sum(), // the sum of the last three characters in the serial number (use alphabetic positions for letters) Bomb.GetSerialNumber().Skip(3).Select(ch => ch >= 'A' && ch <= 'Z' ? ch - 'A' + 1 : ch - '0').Sum(), // the number of ports Bomb.GetPortCount(), // the number of indicators Bomb.GetIndicators().Count(), // the number of batteries Bomb.GetBatteryCount(), // the number of ports plus indicators Bomb.GetPortCount() + Bomb.GetIndicators().Count(), // the number of ports plus batteries Bomb.GetPortCount() + Bomb.GetBatteryCount(), // the number of indicators plus batteries Bomb.GetIndicators().Count() + Bomb.GetBatteryCount() ); var edgeworkCondition = rnd.Seed == 1 ? 0 : rnd.Next(0, edgeworkConditions.Length); var modulo = rnd.Seed == 1 ? 6 : rnd.Next(4, 9); var rowShuffle = rnd.ShuffleFisherYates(Enumerable.Range(0, 23).ToArray()); var columnShuffle = rnd.ShuffleFisherYates(Enumerable.Range(0, 23).ToArray()); // Find the encryption key var name1 = pickedRuneNames[order[0]].ToLowerInvariant(); var name2 = pickedRuneNames[order[1]].ToLowerInvariant(); var name3 = pickedRuneNames[order[2]].ToLowerInvariant(); var maxLength = Math.Max(name1.Length, Math.Max(name2.Length, name3.Length)); var interweaved = Enumerable.Range(0, maxLength).Select(ix => name1[ix % name1.Length].ToString() + name2[ix % name2.Length].ToString() + name3[ix % name3.Length].ToString()).Join(""); var cycleAmount = edgeworkConditions[edgeworkCondition] % modulo; if (cycleLeft) { cycleAmount = interweaved.Length - cycleAmount; } var encryptionKey = (interweaved.Substring(interweaved.Length - cycleAmount) + interweaved.Substring(0, interweaved.Length - cycleAmount)).Substring(0, pickedRuneNames[0].Length + pickedRuneNames[1].Length + pickedRuneNames[2].Length); Debug.LogFormat(@"[Elder Futhark #{0}] The encryption key is {1}.", moduleId, encryptionKey); // Encrypt the name of both runes together var transliteratedRunes = (pickedRuneNames[0] + pickedRuneNames[1] + pickedRuneNames[2]).ToLowerInvariant().Select(ch => ElderFutharkTranslated.IndexOf(tr => tr.Contains(ch))).ToArray(); Debug.LogFormat(@"[Elder Futhark #{0}] transliteratedRunes = {1}", moduleId, transliteratedRunes.Select(ix => ElderFuthark[ix]).Join(", ")); var transliteratedKey = encryptionKey.Select(ch => ElderFutharkTranslated.IndexOf(tr => tr.Contains(ch))).ToArray(); Debug.LogFormat(@"[Elder Futhark #{0}] transliteratedKey = {1}", moduleId, transliteratedKey.Select(ix => ElderFuthark[ix]).Join(", ")); var ciphered = transliteratedRunes.Select((ch, ix) => (columnShuffle[ch] + rowShuffle[transliteratedKey[ix]]) % 23).ToArray(); pickedRuneNamesCipher = newArray( ciphered.Take(pickedRuneNames[0].Length).ToArray(), ciphered.Skip(pickedRuneNames[0].Length).Take(pickedRuneNames[1].Length).ToArray(), ciphered.Skip(pickedRuneNames[0].Length + pickedRuneNames[1].Length).ToArray() ); Debug.LogFormat(@"[Elder Futhark #{0}] The encrypted first rune is: {1}.", moduleId, pickedRuneNamesCipher[0].Select(ix => ElderFuthark[ix]).Join(", ")); Debug.LogFormat(@"[Elder Futhark #{0}] The encrypted second rune is: {1}.", moduleId, pickedRuneNamesCipher[1].Select(ix => ElderFuthark[ix]).Join(", ")); Debug.LogFormat(@"[Elder Futhark #{0}] The encrypted third rune is: {1}.", moduleId, pickedRuneNamesCipher[2].Select(ix => ElderFuthark[ix]).Join(", ")); }