public override bool ActivateOn(Lord lord, TriggerSignal signal) { if (signal.type == TriggerSignalType.Tick && Find.TickManager.TicksGame% GenTicks.TickRareInterval == 0) { var tradeCenters = Find.ListerBuildings.AllBuildingsColonistOfClass<TradeCenter>() .Where(building => building.trader == null); var trader = TraderCaravanUtility.FindTrader(lord); var carrier = lord.ownedPawns.FirstOrDefault(pawn => pawn.GetCaravanRole() == TraderCaravanRole.Carrier); if (tradeCenters.Any() && trader != null && carrier != null) { if (trader.CanReach(tradeCenters.FirstOrDefault(), PathEndMode.InteractionCell, trader.NormalMaxDanger()) && carrier.CanReach(tradeCenters.FirstOrDefault(), PathEndMode.InteractionCell, trader.NormalMaxDanger())) return true; } } return false; }
public void AddObserver(IObserver obs) { Signal += new TriggerSignal(obs.Trigger); }
private async Task ProcessMultiKeySelectionResult( IList <Timestamped <PointAndKeyValue> > pointsAndKeyValues, TriggerSignal startSelectionTriggerSignal) { Log.DebugFormat("Multi-key selection captured a set of '{0}' PointAndKeyValues.", pointsAndKeyValues.Count); RequestSuspend(); //Pause everything (i.e. processing new points) while we perform the (CPU bound) word matching try { if (pointsAndKeyValues.Any()) { var timeSpan = pointsAndKeyValues.Last().Timestamp.Subtract(pointsAndKeyValues.First().Timestamp); var sequenceThreshold = (int)Math.Round( ((double)pointsAndKeyValues.Count / (double)timeSpan.TotalMilliseconds) * Settings.Default.MultiKeySelectionFixationMinDwellTime.TotalMilliseconds); Log.DebugFormat( "Multi-key selection capture lasted {0}ms. Minimum dwell time is {1}ms, or {2} points.", timeSpan.TotalMilliseconds, Settings.Default.MultiKeySelectionFixationMinDwellTime.TotalMilliseconds, sequenceThreshold); //Always assume the start trigger is reliable if it occurs on a letter string reliableFirstLetter = startMultiKeySelectionTriggerSignal != null && startMultiKeySelectionTriggerSignal.Value.PointAndKeyValue != null && startMultiKeySelectionTriggerSignal.Value.PointAndKeyValue.Value.StringIsLetter ? startMultiKeySelectionTriggerSignal.Value.PointAndKeyValue.Value.String : null; Log.DebugFormat( "First letter ('{0}') of multi-key selection capture {1} reliable.", reliableFirstLetter, reliableFirstLetter != null ? "IS" : "IS NOT"); //If we are using a fixation trigger and the stop trigger has occurred on a letter then it is reliable - use it string reliableLastLetter = selectionTriggerSource is IFixationTriggerSource && stopMultiKeySelectionTriggerSignal != null && stopMultiKeySelectionTriggerSignal.Value.PointAndKeyValue != null && stopMultiKeySelectionTriggerSignal.Value.PointAndKeyValue.Value.StringIsLetter ? stopMultiKeySelectionTriggerSignal.Value.PointAndKeyValue.Value.String : null; Log.DebugFormat( "Last letter ('{0}') of multi-key selection capture {1} reliable.", reliableLastLetter, reliableLastLetter != null ? "IS" : "IS NOT"); if (reliableLastLetter != null) { Log.Debug("Publishing selection event on last letter of multi-key selection capture."); PublishSelection(stopMultiKeySelectionTriggerSignal.Value.PointAndKeyValue.Value); } //Why am I wrapping this call in a Task.Run? Internally the MapCaptureToEntries method uses PLINQ which also blocks the UI thread - this frees it up. //This cannot be done inside the MapCaptureToEntries method as the method takes a ref param, which cannot be used inside an anonymous delegate or lambda. //The method cannot be made awaitable as async/await also does not support ref params. Tuple <List <Point>, FunctionKeys?, string, List <string> > result = null; await Task.Run(() => { result = dictionaryService.MapCaptureToEntries( pointsAndKeyValues.ToList(), sequenceThreshold, reliableFirstLetter, reliableLastLetter, ref mapToDictionaryMatchesCancellationTokenSource, exception => PublishError(this, exception)); }); if (result != null) { if (result.Item2 == null && result.Item3 == null && (result.Item4 == null || !result.Item4.Any())) { //Nothing useful in the result - play error message. Publish anyway as the points can be rendered in debugging mode. audioService.PlaySound(Settings.Default.ErrorSoundFile, Settings.Default.ErrorSoundVolume); } PublishSelectionResult(result); } } } finally { RequestResume(); } }
private void ProcessSelectionTrigger(TriggerSignal triggerSignal) { if (triggerSignal.Signal >= 1 && !CapturingMultiKeySelection) { //We are not currently capturing a multikey selection and have received a high (start) trigger signal if (triggerSignal.PointAndKeyValue != null) { Log.Debug("Selection trigger signal (with relevent PointAndKeyValue) detected."); if (SelectionMode == SelectionModes.Key) { if (triggerSignal.PointAndKeyValue.Value.KeyValue != null && (keyStateService.KeyEnabledStates == null || keyStateService.KeyEnabledStates[triggerSignal.PointAndKeyValue.Value.KeyValue.Value])) { Log.Debug("Selection mode is KEY and the key on which the trigger occurred is enabled."); if (MultiKeySelectionSupported && keyStateService.KeyDownStates[KeyValues.MultiKeySelectionIsOnKey].Value.IsDownOrLockedDown() && triggerSignal.PointAndKeyValue.Value.KeyValue != null && KeyValues.MultiKeySelectionKeys.Contains(triggerSignal.PointAndKeyValue.Value.KeyValue.Value) && !KeyValues.CombiningKeys.Any(key => keyStateService.KeyDownStates[key].Value.IsDownOrLockedDown())) //Do not start if any combining ("dead") keys are down { Log.Debug("Multi-key selection is currently enabled and the key on which the trigger occurred is a letter. Publishing the selection and beginning a new multi-key selection capture."); //Multi-key selection is allowed and the trigger occurred on a letter - start a capture startMultiKeySelectionTriggerSignal = triggerSignal; stopMultiKeySelectionTriggerSignal = null; CapturingMultiKeySelection = true; PublishSelection(triggerSignal.PointAndKeyValue.Value); multiKeySelectionSubscription = CreateMultiKeySelectionSubscription() .ObserveOnDispatcher() .Subscribe( async pointsAndKeyValues => await ProcessMultiKeySelectionResult(pointsAndKeyValues, triggerSignal), (exception => { PublishError(this, exception); stopMultiKeySelectionTriggerSignal = null; CapturingMultiKeySelection = false; }), () => { Log.Debug("Multi-key selection capture has completed."); stopMultiKeySelectionTriggerSignal = null; CapturingMultiKeySelection = false; }); } else { PublishSelection(triggerSignal.PointAndKeyValue.Value); PublishSelectionResult(new Tuple <List <Point>, FunctionKeys?, string, List <string> >( new List <Point> { triggerSignal.PointAndKeyValue.Value.Point }, triggerSignal.PointAndKeyValue.Value.KeyValue.Value.FunctionKey, triggerSignal.PointAndKeyValue.Value.KeyValue.Value.String, null)); } } else { Log.Debug("Selection mode is KEY, but the trigger occurred away from a key or over a disabled key."); } } else if (SelectionMode == SelectionModes.Point) { PublishSelection(triggerSignal.PointAndKeyValue.Value); PublishSelectionResult(new Tuple <List <Point>, FunctionKeys?, string, List <string> >( new List <Point> { triggerSignal.PointAndKeyValue.Value.Point }, null, null, null)); } } else { Log.Error("TriggerSignal.Signal==1, but TriggerSignal.PointAndKeyValue is null. " + "Discarding trigger as point source is down, or producing stale points. " + "Publishing error instead."); PublishError(this, new ApplicationException(Resources.TRIGGER_WITHOUT_POSITION_ERROR)); } } else if (CapturingMultiKeySelection) { //We are capturing and may have received the stop capturing signal if ((triggerSignal.Signal >= 1 && Settings.Default.MultiKeySelectionTriggerStopSignal == TriggerStopSignals.NextHigh) || (triggerSignal.Signal <= -1 && Settings.Default.MultiKeySelectionTriggerStopSignal == TriggerStopSignals.NextLow)) { //If we are using a fixation trigger source then the stop signal must occur on a letter if (!(selectionTriggerSource is IFixationTriggerSource) || (triggerSignal.PointAndKeyValue != null && triggerSignal.PointAndKeyValue.Value.StringIsLetter)) { Log.Debug("Trigger signal to stop the current multi-key selection capture detected."); stopMultiKeySelectionTriggerSignal = triggerSignal; } } } }
static bool Prefix(ref Trigger_ChanceOnTickInteval __instance, ref bool __result, ref Lord lord, ref TriggerSignal signal) { __result = signal.type == TriggerSignalType.Tick && Find.TickManager.TicksGame % __instance.interval < RefcellRespeedConfig.currentTimeMultiplier && (double)Rand.Value < (double)__instance.chancePerInterval; return(false); }
static bool Prefix(ref Trigger_WoundedGuestPresent __instance, ref bool __result, ref Lord lord, ref TriggerSignal signal) { if (signal.type == TriggerSignalType.Tick && Find.TickManager.TicksGame % 800 < RefcellRespeedConfig.currentTimeMultiplier) { TriggerData_PawnCycleInd data = __instance.Data; ++data.pawnCycleInd; if (data.pawnCycleInd >= lord.ownedPawns.Count) { data.pawnCycleInd = 0; } if (lord.ownedPawns.Any <Pawn>()) { Pawn ownedPawn = lord.ownedPawns[data.pawnCycleInd]; if (ownedPawn.Spawned && !ownedPawn.Downed && (!ownedPawn.InMentalState && KidnapAIUtility.ReachableWoundedGuest(ownedPawn) != null)) { __result = true; return(false); } } } __result = false; return(false); }
static bool Prefix(ref Trigger_KidnapVictimPresent __instance, ref bool __result, ref Lord lord, ref TriggerSignal signal) { if (signal.type == TriggerSignalType.Tick && Find.TickManager.TicksGame % 120 < RefcellRespeedConfig.currentTimeMultiplier) { if (__instance.data == null || !(__instance.data is TriggerData_PawnCycleInd)) { BackCompatibility.TriggerDataPawnCycleIndNull(__instance); } if (Find.TickManager.TicksGame - lord.lastPawnHarmTick > 300) { TriggerData_PawnCycleInd data = __instance.Data; ++data.pawnCycleInd; if (data.pawnCycleInd >= lord.ownedPawns.Count) { data.pawnCycleInd = 0; } if (lord.ownedPawns.Any <Pawn>()) { Pawn ownedPawn = lord.ownedPawns[data.pawnCycleInd]; if (ownedPawn.Spawned && !ownedPawn.Downed && (ownedPawn.MentalStateDef == null && KidnapAIUtility.TryFindGoodKidnapVictim(ownedPawn, 8f, out Pawn _)) && !GenAI.InDangerousCombat(ownedPawn)) { __result = true; return(false); } } } } __result = false; return(false); }
static bool Prefix(ref Trigger_TicksPassedAfterConditionMet __instance, ref bool __result, ref Lord lord, ref TriggerSignal signal) { if (!__instance.Data.conditionMet && signal.type == TriggerSignalType.Tick && Find.TickManager.TicksGame % __instance.checkEveryTicks == 0) { __instance.Data.conditionMet = __instance.condition(); } __result = __instance.Data.conditionMet && ActivateOn(__instance, lord, signal); return(false); }
static bool ActivateOn(Trigger_TicksPassedAfterConditionMet __instance, Lord lord, TriggerSignal signal) { return(false); }
static bool Prefix(ref Trigger_HighValueThingsAround __instance, ref bool __result, ref Lord lord, ref TriggerSignal signal) { __result = signal.type == TriggerSignalType.Tick && Find.TickManager.TicksGame % 120 < RefcellRespeedConfig.currentTimeMultiplier && (!TutorSystem.TutorialMode && Find.TickManager.TicksGame - lord.lastPawnHarmTick > 300) && (double)StealAIUtility.TotalMarketValueAround(lord.ownedPawns) > (double)StealAIUtility.StartStealingMarketValueThreshold(lord); return(false); }
static bool Prefix(ref Trigger_TickCondition __instance, ref bool __result, ref Lord lord, ref TriggerSignal signal) { __result = signal.type == TriggerSignalType.Tick && Find.TickManager.TicksGame % __instance.checkEveryTicks < RefcellRespeedConfig.currentTimeMultiplier && __instance.condition(); return(false); }
static bool Prefix(ref Trigger_PawnExperiencingDangerousTemperatures __instance, ref bool __result, ref Lord lord, ref TriggerSignal signal) { if (signal.type == TriggerSignalType.Tick && Find.TickManager.TicksGame % 197 < RefcellRespeedConfig.currentTimeMultiplier) { for (int index = 0; index < lord.ownedPawns.Count; ++index) { Pawn ownedPawn = lord.ownedPawns[index]; if (ownedPawn.Spawned && !ownedPawn.Dead && !ownedPawn.Downed) { Hediff firstHediffOfDef1 = ownedPawn.health.hediffSet.GetFirstHediffOfDef(HediffDefOf.Heatstroke); if (firstHediffOfDef1 != null && (double)firstHediffOfDef1.Severity > (double)__instance.temperatureHediffThreshold) { __result = true; return(false); } Hediff firstHediffOfDef2 = ownedPawn.health.hediffSet.GetFirstHediffOfDef(HediffDefOf.Hypothermia); if (firstHediffOfDef2 != null && (double)firstHediffOfDef2.Severity > (double)__instance.temperatureHediffThreshold) { __result = true; return(false); } } } } __result = false; return(false); }
static bool Prefix(ref Trigger_PawnCanReachMapEdge __instance, ref bool __result, ref Lord lord, ref TriggerSignal signal) { if (signal.type != TriggerSignalType.Tick || Find.TickManager.TicksGame % 193 > RefcellRespeedConfig.currentTimeMultiplier - 1) { __result = false; return(false); } for (int index = 0; index < lord.ownedPawns.Count; ++index) { Pawn ownedPawn = lord.ownedPawns[index]; if (ownedPawn.Spawned && !ownedPawn.Dead && (!ownedPawn.Downed && !ownedPawn.CanReachMapEdge())) { __result = false; return(false); } } __result = true; return(false); }