private static Thing BestWaterInInventory(Pawn holder, WaterPreferability minWaterPref = WaterPreferability.SeaWater, WaterPreferability maxWaterPref = WaterPreferability.ClearWater, float minStackWaterAmount = 0.0f, bool allowDrug = false) { // 所持品から探すのに所持品オブジェクトなし if (holder?.inventory == null) { return(null); } foreach (var thing in holder.inventory.innerContainer) { // 所持品をひとつずつチェック var waterAmount = thing.GetWaterAmount(); var waterPreferability = thing.GetWaterPreferability(); if (thing.CanGetWater() && // 飲み物として飲めるもの thing.CanDrinkWaterNow() && // 現在飲める状態にある !thing.def.IsIngestible && // 食べ物ではない waterPreferability >= minWaterPref && waterPreferability <= maxWaterPref && // 品質が指定範囲内 (allowDrug || !thing.def.IsDrug) && // ドラッグ許可か、そもそもドラッグでない waterAmount * thing.stackCount >= minStackWaterAmount) { // 水の量の最低値指定を満たしている return(thing); } } // 条件に合うものが1個も見つからなかった return(null); }
public static ThingDef GetWaterThingDefFromWaterPreferability(WaterPreferability waterPreferability) { // 水の種類→水アイテム switch (waterPreferability) { case WaterPreferability.ClearWater: return(MizuDef.Thing_ClearWater); case WaterPreferability.NormalWater: return(MizuDef.Thing_NormalWater); case WaterPreferability.RawWater: return(MizuDef.Thing_RawWater); case WaterPreferability.MudWater: return(MizuDef.Thing_MudWater); case WaterPreferability.SeaWater: return(MizuDef.Thing_SeaWater); default: return(null); } }
private static Thing BestWaterSourceOnMap(Pawn getter, Pawn eater, bool priorQuality, WaterPreferability maxPref = WaterPreferability.ClearWater, bool allowDrug = false, bool allowForbidden = false, bool allowSociallyImproper = false) { if (!getter.CanManipulate() && getter != eater) { // 取得者は操作不可、取得者と摂取者が違う // →マップから取得して持ち運ぶことができない // →エラー Log.Error(string.Concat(getter, " tried to find food to bring to ", eater, " but ", getter, " is incapable of Manipulation.")); return(null); } bool waterValidator(Thing t) { // 禁止されている&禁止を無視して取得してはいけない if (!allowForbidden && t.IsForbidden(getter)) { return(false); } // ドラッグ禁止&対象はドラッグ if (!allowDrug && t.def.IsDrug) { return(false); } // 取得者が予約できない if (!getter.CanReserve(t)) { return(false); } var comp = t.TryGetComp <CompWaterSource>(); // 水源として使用できない if (comp == null || !comp.IsWaterSource) { return(false); } // 食べられるものは飲み物としては選ばれない if (t.def.IsIngestible) { return(false); } // 操作が必要なのに操作できない if (comp.NeedManipulate && !getter.CanManipulate()) { return(false); } var waterTypeDef = MizuDef.Dic_WaterTypeDef[comp.WaterType]; if (comp.SourceType == CompProperties_WaterSource.SourceType.Item) { // 水分がない if (!t.CanGetWater()) { return(false); } // 水分を持っている=水アイテムである var waterPreferability = t.GetWaterPreferability(); // 水の品質が範囲外 if (waterPreferability < WaterPreferability.SeaWater || waterPreferability > maxPref) { return(false); } // 現在飲める状態には無い if (!t.CanDrinkWaterNow()) { return(false); } // 入植者は囚人部屋のアイテムを扱えないことがあるが、そのことに関するチェックでダメならfalse if (!IsWaterSourceOnMapSociallyProper(t, getter, eater, allowSociallyImproper)) { return(false); } // 取得者がそれに気づいていない if (!getter.AnimalAwareOf(t)) { return(false); } return(true); } if (comp.SourceType != CompProperties_WaterSource.SourceType.Building) { return(false); } // 取得者と摂取者が異なる(自分で飲みに行く必要がある) if (getter != eater) { return(false); } // 水汲みに使えない if (!(t is IBuilding_DrinkWater drinkWaterBuilding)) { return(false); } // 水を飲む人が飲めない(能力が無い、水の量がない) if (!drinkWaterBuilding.CanDrinkFor(eater)) { return(false); } // 最大水質を超えていたらダメ if (waterTypeDef.waterPreferability > maxPref) { return(false); } // 野生人?(派閥所属なし?)はダメ if (eater.IsWildMan()) { return(false); } // 自陣営or自陣営のホストの設備でなければダメ // 動物でない場合は、という条件を追加 if (!eater.RaceProps.Animal && t.Faction != eater.Faction && t.Faction != eater.HostFaction) { return(false); } // 使えない状態はダメ if (!drinkWaterBuilding.IsActivated) { return(false); } // 入植者は囚人部屋のアイテムを扱えないことがあるが、そのことに関するチェックでダメならfalse if (!IsWaterSourceOnMapSociallyProper(t, getter, eater, allowSociallyImproper)) { return(false); } if (t.def.hasInteractionCell) { // 使用場所がある if (!t.InteractionCell.Standable(t.Map) || !eater.Map.reachability.CanReachNonLocal(getter.Position, new TargetInfo(t.InteractionCell, t.Map), PathEndMode.OnCell, TraverseParms.For(getter, Danger.Some))) { // 使用場所に立てない or 使用場所まで行けない return(false); } } else { // 使用場所が無い if (!getter.Map.reachability.CanReachNonLocal(getter.Position, new TargetInfo(t.Position, t.Map), PathEndMode.ClosestTouch, TraverseParms.For(getter, Danger.Some))) { // その設備にタッチできない return(false); } } return(true); // それ以外 } if (getter.RaceProps.Humanlike) { // 取得者はHumanlikeである // →条件を満たすものの中から最適な物を探す return(SpawnedWaterSearchInnerScan( eater, getter.Position, getter.Map.listerThings.ThingsInGroup(ThingRequestGroup.Everything).FindAll( t => { if (t.CanDrinkWaterNow()) { return true; } if (t is IBuilding_DrinkWater building && building.CanDrinkFor(eater)) { return true; } return false; }), PathEndMode.ClosestTouch, TraverseParms.For(getter), priorQuality, 9999f, waterValidator)); } // 取得者はHumanlikeではない // プレイヤー派閥に所属しているかどうかでリージョン?数を変える var searchRegionsMax = 30; if (getter.Faction == Faction.OfPlayer) { searchRegionsMax = 100; } var filtered = new HashSet <Thing>(); foreach (var current in GenRadial.RadialDistinctThingsAround(getter.Position, getter.Map, 2f, true)) { // 自分を中心に半径2以内の物をチェック if (current is Pawn pawn && pawn != getter && pawn.RaceProps.Animal && pawn.CurJob != null && pawn.CurJob.def == MizuDef.Job_DrinkWater && pawn.CurJob.GetTarget(TargetIndex.A).HasThing) { // 自分ではない動物が現在水アイテムを摂取している // →今まさに摂取している物は探索対象から除外 filtered.Add(pawn.CurJob.GetTarget(TargetIndex.A).Thing); } } var ignoreEntirelyForbiddenRegions = !allowForbidden && // 禁止物のアクセスは許可されていない ForbidUtility.CaresAboutForbidden(getter, true) && getter.playerSettings?.EffectiveAreaRestrictionInPawnCurrentMap != null; // 有効な制限エリアなし bool predicate(Thing t) { // アイテムが条件を満たしていない if (!waterValidator(t)) { return(false); } // すぐ近くで他の動物が飲んでいる水のリストに入っていない if (filtered.Contains(t)) { return(false); } // 水の品質が最低値未満 if (t.GetWaterPreferability() < WaterPreferability.SeaWater) { return(false); } return(true); } // 指定の条件下でアクセスできるものを探す // 水アイテムから var thing = GenClosest.ClosestThingReachable(getter.Position, getter.Map, ThingRequest.ForGroup(ThingRequestGroup.HaulableEver), PathEndMode.ClosestTouch, TraverseParms.For(getter), 9999f, predicate, null, 0, searchRegionsMax, false, RegionType.Set_Passable, ignoreEntirelyForbiddenRegions); if (thing != null) { return(thing); } // 水汲み設備 thing = GenClosest.ClosestThingReachable(getter.Position, getter.Map, ThingRequest.ForGroup(ThingRequestGroup.BuildingArtificial), PathEndMode.ClosestTouch, TraverseParms.For(getter), 9999f, predicate, null, 0, searchRegionsMax, false, RegionType.Set_Passable, ignoreEntirelyForbiddenRegions); if (thing != null) { return(thing); } // 条件を変えて再探索 // 水アイテム thing = GenClosest.ClosestThingReachable( getter.Position, getter.Map, ThingRequest.ForGroup(ThingRequestGroup.HaulableEver), PathEndMode.ClosestTouch, TraverseParms.For(getter), 9999f, waterValidator, // ここが変わった null, 0, searchRegionsMax, false, RegionType.Set_Passable, ignoreEntirelyForbiddenRegions); if (thing != null) { return(thing); } // 水汲み設備 thing = GenClosest.ClosestThingReachable( getter.Position, getter.Map, ThingRequest.ForGroup(ThingRequestGroup.BuildingArtificial), PathEndMode.ClosestTouch, TraverseParms.For(getter), 9999f, waterValidator, // ここが変わった null, 0, searchRegionsMax, false, RegionType.Set_Passable, ignoreEntirelyForbiddenRegions); return(thing); }