bool IsFlowCorrect(Spell.CompiledRune from, uint toDir) { var to = from.neighs[toDir]; if (!IsFlowInterpretableRune(to.type)) { return(false); } //Logger.Log(from.type + " " + to.type + " " + toDir); //Cross arrow is special if (to != null && to.type == RuneType.ArrowCross) { if (toDir == to.dir) { isArrowCrossDirLeft = false; } else if (toDir == (to.dir + 5) % 6) { isArrowCrossDirLeft = true; } else { return(false); } } //TODO: cant enter "if" rune from two of its directions too... return(true); }
Spell.CompiledRune InterpretArrowSeq(Spell.CompiledRune r, bool onlyOneRune, bool setFlowDir) { do { if (!onlyOneRune) { additionalInterpretedRunes.Add(r); } if (arrowsProcessed.Contains(r.relPos)) { arrowsProcessed.Clear(); return(null); //Cycle detected } arrowsProcessed.Add(r.relPos); uint fromDir = r.dir; uint dirChange; switch (r.type) { case RuneType.Arrow0: dirChange = 0; break; case RuneType.ArrowR60: dirChange = 1; break; case RuneType.ArrowR120: dirChange = 2; break; case RuneType.ArrowL120: dirChange = 4; break; case RuneType.ArrowL60: dirChange = 5; break; case RuneType.ArrowCross: dirChange = isArrowCrossDirLeft ? 5u : 0u; break; default: throw new Tools.AssertException(); } uint toDir = (fromDir + dirChange) % 6; if (!IsFlowCorrect(r, toDir)) { arrowsProcessed.Clear(); return(null); } r = r.neighs[toDir]; if (r == null) { arrowsProcessed.Clear(); return(null); } if (!IsArrowRune(r.type)) { arrowsProcessed.Clear(); //if (setFlowDir) // flowDir = toDir; return(r); } } while (!onlyOneRune); return(r); }
static bool IsArrowFrom(Spell.CompiledRune arrow, uint dir) { switch (arrow.type) { case RuneType.ArrowCross: return(arrow.dir == dir || arrow.dir == (dir + 1) % 6); default: return(arrow.dir == dir); } }
public Avatar(SpellExecuting spell, HexXY pos, uint dir, Spell.CompiledRune startRune, uint id) { this.spell = spell; this.pos = pos; this.dir = dir; this.rune = startRune; this.timeLeft = 0; this.id = id; }
public float OnInterpret(Spell.CompiledRune rune, List <Spell.CompiledRune> additionalRunes) { if (Avatar.IsMovementCommandRune(rune.type)) { return(movTime); } else { return(0); } }
void InterpretFlow() { uint forkCount = 0; Spell.CompiledRune nextRune = null; for (int i = 0; i < 6; i++) { var nrune = rune.neighs[i]; if (nrune == null) { continue; } bool isFlowArrow = IsArrowRune(nrune.type) || nrune.type == RuneType.If; if ((isFlowArrow && !IsArrowFrom(nrune, (uint)i)) || (!isFlowArrow && i != flowDir)) { continue; } if (i == flowDir && !IsFlowCorrect(rune, flowDir)) { continue; } if (forkCount == 0) { nextRune = nrune; } else { if (spell.caster.Mana >= avatarElement.ForkManaCost && avatarElement.CanAvatarFork()) { spell.SpawnAvatar(nrune, this, pos, dir); } else { finishState = FinishedState.CantFork; break; } } ++forkCount; } if (forkCount == 0) { finishState = FinishedState.FlowFinished; } else { rune = nextRune; } }
public float OnInterpret(Spell.CompiledRune rune, List <Spell.CompiledRune> additionalRunes) { foreach (var litRune in litRunes) { litRune.isLit = false; } litRunes.Clear(); var mainLitRune = avatar.spell.compiledSpell.GetRealRune(rune); litRunes.Add(mainLitRune); foreach (var arune in additionalRunes) { litRunes.Add(avatar.spell.compiledSpell.GetRealRune(arune)); } foreach (var litRune in litRunes) { litRune.isLit = true; } float interTime; if (rune.type == RuneType.Wind) { interTime = 2; } else if (Avatar.IsArrowRune(rune.type)) { interTime = 0.25f; } else if (Avatar.IsMovementCommandRune(rune.type)) { interTime = movTime; } else { interTime = 1; } return(interTime);// * 0.1f; }
public void SpawnAvatar(Spell.CompiledRune rune, Avatar forkFrom, HexXY pos, uint dir) { Avatar av = new Avatar(this, pos, dir, rune, avatarLastID++); if (forkFrom != null) { caster.SpendMana(forkFrom.avatarElement.ForkManaCost); forkFrom.avatarElement.ForkTo(av); if (av.avatarElement is Entity) { ((Entity)av.avatarElement).dir = av.dir; } av.avatarElement.OnSpawn(); } avatars.Add(av); if (isLogging) { Logger.Log(av.id + " " + (av.avatarElement == null ? "[no element]" : av.avatarElement.GetType().Name) + " avatar spawned at " + pos); } }
public void Interpret() { if (rune == null) { finishState = FinishedState.FlowFinished; return; } if (SpellExecuting.isLogging) { Logger.Log(id + " " + (avatarElement == null ? "[no element]" : avatarElement.GetType().Name) + "> interpret " + rune.type + " at " + rune.relPos); } //This is written up here and not in the end for correct fork timing if (needsFlow && repeatCounter == 0) { InterpretFlow(); } if (finishState != null) { return; } additionalInterpretedRunes.Clear(); if (IsRepeatableByNumberRune(rune.type)) { //Actually no need to reinterpret numbers, if repeatCounter > 0 //but its needed for proper additionalInterpretedRunes highlight uint repCount = InterpretNearNumber(); if (repeatCounter > 0) { --repeatCounter; } else { if (repCount > 0) { repeatCounter = repCount - 1; } } } var currRune = rune; needsFlow = true; if (IsArrowRune(rune.type)) { rune = InterpretArrowSeq(rune, true, true); needsFlow = false; } else if (IsAvatarElementRune(rune.type)) { InterpretChangeElement(); } else if (IsMovementCommandRune(rune.type)) { InterpretMovementCommand(); } else if (rune.type == RuneType.If) { InterpretIf(); needsFlow = false; } else { finishState = FinishedState.FlowFinished; } if (avatarElement != null) { timeLeft += avatarElement.OnInterpret(currRune, additionalInterpretedRunes); } }
void InterpretIf() { bool isTrue = false; //Checking only separate patterns //TODO: what if pattern is attached like this: (p) (if) (p) where (p)'s are connected elsewhere? //it will be evaluated twice! bool isPredAtZero = false, isPredAtPrev = false; for (int i = 0; i < 6; i++) { var nrune = rune.neighs[i]; if (i != rune.dir && i != (rune.dir + 5) % 6 && nrune != null && IsArrowRune(nrune.type) && IsArrowFrom(nrune, (uint)i)) { //Find following arrows nrune = InterpretArrowSeq(nrune, false, false); if (nrune == null || !IsPredicateRune(nrune.type)) { continue; } isTrue = isTrue || InterpretPredicate(nrune); //using OR isPredAtPrev = false; } else { if (nrune == null || !IsPredicateRune(nrune.type)) { isPredAtPrev = false; continue; } if (isPredAtPrev || (i == 5 && isPredAtZero)) { continue; } isTrue = isTrue || InterpretPredicate(nrune); //using OR if (i == 0) { isPredAtZero = true; } isPredAtPrev = true; } } uint toDir; if (isTrue) { toDir = rune.dir; } else { toDir = (rune.dir + 5) % 6; } //flowDir = toDir; if (!IsFlowCorrect(rune, toDir)) { rune = null; } else { rune = rune.neighs[toDir]; } }
bool InterpretPredicate(Spell.CompiledRune predRune) { //Compute connected component and find avatar ref position Spell.CompiledRune avatarRefRune = null; blobFront.Enqueue(predRune); blobAll.Add(predRune); do { var c = blobFront.Dequeue(); additionalInterpretedRunes.Add(c); if (c.type == RuneType.PredicateAvatarRef) { if (avatarRefRune != null) { //Double avatar ref error finishState = FinishedState.PredicateParseError; return(false); } else { avatarRefRune = c; } } foreach (var n in c.neighs) { if (n == null || !IsPredicateRune(n.type) || blobAll.Contains(n)) { continue; } blobFront.Enqueue(n); blobAll.Add(n); } } while (blobFront.Count > 0); HexXY predRefPos; if (avatarRefRune != null) { predRefPos = avatarRefRune.relPos; } else { if (blobAll.Count > 1) { //No avatar reference in predicate with more than one rune finishState = FinishedState.PredicateParseError; return(false); } else { predRefPos = blobAll.First().relPos; } } //Check predicate bool isMatch = true; foreach (var prune in blobAll) { HexXY checkPos = prune.relPos - predRefPos; for (int i = 0; i < dir; i++) { checkPos = checkPos.RotateRight(new HexXY(0, 0)); } checkPos += this.pos; switch (prune.type) { case RuneType.PredicateTileEmpty: { var blType = Level.S.GetPFBlockedMap(checkPos); if (blType != WorldBlock.PFBlockType.Unblocked && blType != WorldBlock.PFBlockType.DynamicBlocked) { isMatch = false; } break; } case RuneType.PredicateTileWall: if (Level.S.GetPFBlockedMap(checkPos) != WorldBlock.PFBlockType.EdgeBlocked && Level.S.GetPFBlockedMap(checkPos) != WorldBlock.PFBlockType.StaticBlocked && Level.S.GetPFBlockedMap(checkPos) != WorldBlock.PFBlockType.DoorBlocked) { isMatch = false; } break; case RuneType.PredicateTileMonster: if (!Level.S.GetEntities(checkPos).Any(e => e is Mob)) { isMatch = false; } break; } if (!isMatch) { break; } } blobAll.Clear(); if (SpellExecuting.isLogging) { Logger.Log("predicate at " + predRune.relPos + " is " + isMatch); } return(isMatch); }
public float OnInterpret(Spell.CompiledRune rune, List <Spell.CompiledRune> additionalRunes) { return(0); }