public static void PrePostIngested(Pawn ingester, Thing t, int num) { Need_Water need_water = ingester.needs.water(); if (need_water == null) { return; } var comp = t.TryGetComp <CompWaterSource>(); if (comp == null) { return; } // 食事のついでの水分摂取の場合、帰ってくる水分量は常に1個分 float gotWaterAmount = MizuUtility.GetWater(ingester, t, need_water.WaterWanted, true); // 後で個数を掛け算する gotWaterAmount *= num; if (!ingester.Dead) { need_water.CurLevel += gotWaterAmount; } ingester.records.AddTo(MizuDef.Record_WaterDrank, gotWaterAmount); }
public static bool CanDrinkFromTerrain(this Pawn pawn) { // 心情無し = 地面から水をすすることに抵抗なし if (pawn.needs == null || pawn.needs.mood == null) { return(true); } Need_Water need_water = pawn.needs.water(); // 水分要求なし = そもそも水を必要としていない if (need_water == null) { return(false); } // 心情有り、水分要求あり、状態が脱水症状 = (心情悪化するけど)地形から水を摂取する if (need_water.CurCategory == ThirstCategory.Dehydration) { return(true); } // 心情あり、水分要求あり、状態はまだ大丈夫 = 地形から水を摂取しない return(false); }
protected override Job TryGiveJob(Pawn pawn) { Need_Water need_water = pawn.needs.water(); if (need_water == null) { return(null); } if (need_water.lastSearchWaterTick + SearchWaterIntervalTick > Find.TickManager.TicksGame) { return(null); } // Only trink if we're really thirsty. if (need_water.CurLevelPercentage > need_water.PercentageThreshThirsty) { return(null); } need_water.lastSearchWaterTick = Find.TickManager.TicksGame; Thing thing = MizuUtility.TryFindBestWaterSourceFor(pawn, pawn, false, true); if (thing != null) { if (thing.CanDrinkWater()) { return(new Job(MizuDef.Job_DrinkWater, thing) { count = MizuUtility.WillGetStackCountOf(pawn, thing) }); } else if (thing is IBuilding_DrinkWater) { return(new Job(MizuDef.Job_DrinkWaterFromBuilding, thing)); } } // 何も見つからなかった場合は隠し水飲み場を探す // 人間、家畜、野生の動物全て IntVec3 hiddenWaterSpot; if (MizuUtility.TryFindHiddenWaterSpot(pawn, out hiddenWaterSpot)) { return(new Job(MizuDef.Job_DrinkWater, hiddenWaterSpot) { count = 1 }); } // 水を発見できず return(null); }
protected override Job TryGiveJob(Pawn pawn) { Need_Water need_water = pawn.needs.water(); if (need_water == null) { return(null); } // 最後に水を探してから少し経つまで次の探索はしない if (need_water.lastSearchWaterTick + SearchWaterIntervalTick > Find.TickManager.TicksGame) { return(null); } need_water.lastSearchWaterTick = Find.TickManager.TicksGame; // 水の供給源を探す Thing thing = MizuUtility.TryFindBestWaterSourceFor(pawn, pawn, false, true); if (thing != null) { if (thing.CanDrinkWater()) { // 水アイテムが見つかった return(new Job(MizuDef.Job_DrinkWater, thing) { count = MizuUtility.WillGetStackCountOf(pawn, thing) }); } else if (thing is IBuilding_DrinkWater) { // 水を汲める設備が見つかった return(new Job(MizuDef.Job_DrinkWaterFromBuilding, thing)); } } // 何も見つからなかった場合は隠し水飲み場を探す // 人間、家畜、野生の動物全て IntVec3 hiddenWaterSpot; if (MizuUtility.TryFindHiddenWaterSpot(pawn, out hiddenWaterSpot)) { return(new Job(MizuDef.Job_DrinkWater, hiddenWaterSpot) { count = 1 }); } // 水を発見できず return(null); }
public static Toil FinishDrinkTerrain(TargetIndex terrainVecIndex) { Toil toil = new Toil(); toil.initAction = delegate { Pawn actor = toil.actor; Need_Water need_water = actor.needs.water(); float numWater = need_water.MaxLevel - need_water.CurLevel; TerrainDef terrain = actor.Map.terrainGrid.TerrainAt(actor.CurJob.GetTarget(terrainVecIndex).Cell); WaterTerrainType drankTerrainType = terrain.GetWaterTerrainType(); if (actor.needs.mood != null) { // 直接飲んだ if (actor.CanManipulate()) { actor.needs.mood.thoughts.memories.TryGainMemory(MizuDef.Thought_DrankScoopedWater); } else { actor.needs.mood.thoughts.memories.TryGainMemory(MizuDef.Thought_SippedWaterLikeBeast); } ThoughtDef thoughtDef = MizuUtility.GetThoughtDefFromTerrainType(drankTerrainType); if (thoughtDef != null) { // 水の種類による心情 actor.needs.mood.thoughts.memories.TryGainMemory(thoughtDef); } } if (drankTerrainType == WaterTerrainType.SeaWater) { // 海水の場合の健康状態悪化 actor.health.AddHediff(HediffMaker.MakeHediff(MizuDef.Hediff_DrankSeaWater, actor)); } if (!actor.Dead) { actor.needs.water().CurLevel += numWater; } actor.records.AddTo(MizuDef.Record_WaterDrank, numWater); }; toil.defaultCompleteMode = ToilCompleteMode.Instant; return(toil); }
static void Postfix(Caravan ___caravan) { // キャラバンのポーンの水分要求の処理 foreach (Pawn pawn in ___caravan.pawns) { if (pawn.needs == null) { continue; } Need_Water need_water = pawn.needs.water(); if (need_water == null) { continue; } // 喉が渇いてない場合は飲まない if (need_water.CurCategory <= ThirstCategory.Healthy) { continue; } // タイルが0以上(?)、死んでない、ローカルではなく惑星マップ上にいる(キャラバンしてる)、そのポーンが地形から水を飲める(心情がある/ない、脱水症状まで進んでいる/いない、など) if (pawn.Tile >= 0 && !pawn.Dead && pawn.IsWorldPawn() && pawn.CanDrinkFromTerrain()) { WaterTerrainType drankTerrainType = ___caravan.GetWaterTerrainType(); // 水を飲めない場所 if (drankTerrainType == WaterTerrainType.NoWater) { continue; } // 地形から水を飲む need_water.CurLevel = 1.0f; if (drankTerrainType == WaterTerrainType.SeaWater) { // 海水の場合の健康状態悪化 pawn.health.AddHediff(HediffMaker.MakeHediff(MizuDef.Hediff_DrankSeaWater, pawn)); } // 心情要求がなければここで終了 if (pawn.needs.mood == null) { continue; } // 直接水を飲んだ心情付加 if (pawn.CanManipulate()) { pawn.needs.mood.thoughts.memories.TryGainMemory(MizuDef.Thought_DrankScoopedWater); } else { pawn.needs.mood.thoughts.memories.TryGainMemory(MizuDef.Thought_SippedWaterLikeBeast); } // キャラバンのいる地形に応じた心情を付加 ThoughtDef thoughtDef = MizuUtility.GetThoughtDefFromTerrainType(drankTerrainType); if (thoughtDef != null) { // 水の種類による心情 pawn.needs.mood.thoughts.memories.TryGainMemory(thoughtDef); } continue; } // 水アイテムを探す Thing waterThing; Pawn inventoryPawn; // アイテムが見つからない if (!MizuCaravanUtility.TryGetBestWater(___caravan, pawn, out waterThing, out inventoryPawn)) { continue; } // アイテムに応じた水分を摂取&心情変化&健康変化 float numWater = MizuUtility.GetWater(pawn, waterThing, need_water.WaterWanted, false); need_water.CurLevel += numWater; pawn.records.AddTo(MizuDef.Record_WaterDrank, numWater); // 水アイテムが消滅していない場合(スタックの一部だけ消費した場合等)はここで終了 if (!waterThing.Destroyed) { continue; } if (inventoryPawn != null) { // 誰かの所持品にあった水スタックを飲みきったのであれば、所持品欄から除去 inventoryPawn.inventory.innerContainer.Remove(waterThing); // 移動不可状態を一旦リセット(して再計算させる?) ___caravan.RecacheImmobilizedNow(); // 水の残量再計算フラグON MizuCaravanUtility.daysWorthOfWaterDirty = true; } if (!MizuCaravanUtility.TryGetBestWater(___caravan, pawn, out waterThing, out inventoryPawn)) { // 飲んだことにより水がなくなったら警告を出す Messages.Message(string.Format(MizuStrings.MessageCaravanRunOutOfWater.Translate(), ___caravan.LabelCap, pawn.Label), ___caravan, MessageTypeDefOf.ThreatBig); } } }
private static bool WaterAvailableInRoomTo(Pawn prisoner) { // 囚人が何か物を運んでいる&その物から得られる水分量は正の値 if (prisoner.carryTracker.CarriedThing != null && WorkGiver_Warden_DeliverWater.WaterAmountAvailableForFrom(prisoner, prisoner.carryTracker.CarriedThing) > 0f) { return(true); } float allPawnWantedWater = 0.0f; float allThingWaterAmount = 0f; Room room = prisoner.GetRoom(RegionType.Set_Passable); if (room == null) { return(false); } foreach (var region in room.Regions) { // 囚人の部屋の中の全水アイテムの水分量を計算 foreach (var thing in region.ListerThings.ThingsInGroup(ThingRequestGroup.HaulableEver)) { if (!thing.IsIngestibleFor(prisoner) && (!thing.CanDrinkWater() || thing.GetWaterPreferability() > WaterPreferability.NeverDrink)) { allThingWaterAmount += WorkGiver_Warden_DeliverWater.WaterAmountAvailableForFrom(prisoner, thing); } } // 囚人の部屋のポーンの要求水分量の合計を計算 foreach (var thing in region.ListerThings.ThingsInGroup(ThingRequestGroup.Pawn)) { Pawn pawn = thing as Pawn; Need_Water need_water = pawn.needs.water(); // 水要求なし if (need_water == null) { continue; } // コロニーの囚人ではない if (!pawn.IsPrisonerOfColony) { continue; } // 喉が渇いていない if (need_water.CurLevelPercentage >= need_water.PercentageThreshThirsty + 0.02f) { continue; } // 物を運んでいる if (pawn.carryTracker.CarriedThing != null) { continue; } allPawnWantedWater += need_water.WaterWanted; } } // その部屋に十分な水の量があればtrue return(allThingWaterAmount + 0.5f >= allPawnWantedWater); }
public override Job JobOnThing(Pawn pawn, Thing t, bool forced = false) { Pawn warden = pawn; Pawn prisoner = t as Pawn; // 世話が必要でない if (!base.ShouldTakeCareOfPrisoner(warden, prisoner)) { return(null); } // 囚人が食事を持って来てもらえる扱いではない if (!prisoner.guest.CanBeBroughtFood) { return(null); } // 囚人は牢屋にいない if (!prisoner.Position.IsInPrisonCell(prisoner.Map)) { return(null); } Need_Water need_water = prisoner.needs.water(); // 水分要求がない if (need_water == null) { return(null); } // 喉が渇いていない if (need_water.CurLevelPercentage >= need_water.PercentageThreshThirsty + 0.02f) { return(null); } // (囚人が病人だから)食事を与えられるべき状態である(部屋に運ばれたものを自分で食べることができない) if (WardenFeedUtility.ShouldBeFed(prisoner)) { return(null); } // 水が見つからない Thing thing = MizuUtility.TryFindBestWaterSourceFor(warden, prisoner, false, false); if (thing == null) { return(null); } // 見つかった水アイテムは既に囚人がいる部屋の中にある if (thing.GetRoom(RegionType.Set_Passable) == prisoner.GetRoom(RegionType.Set_Passable)) { return(null); } // 部屋の中に十分な量の水がある if (WorkGiver_Warden_DeliverWater.WaterAvailableInRoomTo(prisoner)) { return(null); } // 水を運んでくるジョブを発行 return(new Job(MizuDef.Job_DeliverWater, thing, prisoner) { count = MizuUtility.WillGetStackCountOf(prisoner, thing), targetC = RCellFinder.SpotToChewStandingNear(prisoner, thing) }); }
private static float ApproxDaysWorthOfWater(List <Pawn> pawns, List <ThingCount> extraWater, IgnorePawnsInventoryMode ignoreInventory) { if (!DaysWorthOfWaterCalculator.AnyNonTerrainDrinkingPawn(pawns)) { return(1000f); } List <ThingCount> tmpWater = new List <ThingCount>(); tmpWater.Clear(); if (extraWater != null) { for (int i = 0; i < extraWater.Count; i++) { bool canGetWater = false; for (int j = 0; j < extraWater[i].ThingDef.comps.Count; j++) { var compprop = extraWater[i].ThingDef.comps[j] as CompProperties_WaterSource; if (compprop != null && compprop.sourceType == CompProperties_WaterSource.SourceType.Item && compprop.waterAmount > 0.0f) { canGetWater = true; break; } } if (canGetWater && extraWater[i].Count > 0) { tmpWater.Add(extraWater[i]); } } } for (int j = 0; j < pawns.Count; j++) { if (!InventoryCalculatorsUtility.ShouldIgnoreInventoryOf(pawns[j], ignoreInventory)) { ThingOwner <Thing> innerContainer = pawns[j].inventory.innerContainer; for (int k = 0; k < innerContainer.Count; k++) { if (innerContainer[k].CanGetWater()) { tmpWater.Add(new ThingCount(innerContainer[k].def, innerContainer[k].stackCount)); } } } } if (!tmpWater.Any <ThingCount>()) { return(0f); } List <float> tmpDaysWorthOfFoodPerPawn = new List <float>(); List <bool> tmpAnyFoodLeftIngestibleByPawn = new List <bool>(); tmpDaysWorthOfFoodPerPawn.Clear(); tmpAnyFoodLeftIngestibleByPawn.Clear(); for (int l = 0; l < pawns.Count; l++) { tmpDaysWorthOfFoodPerPawn.Add(0f); tmpAnyFoodLeftIngestibleByPawn.Add(true); } float num = 0f; bool flag; do { flag = false; for (int m = 0; m < pawns.Count; m++) { Pawn pawn = pawns[m]; if (tmpAnyFoodLeftIngestibleByPawn[m]) { do { int num2 = DaysWorthOfWaterCalculator.BestEverGetWaterIndexFor(pawns[m], tmpWater); if (num2 < 0) { tmpAnyFoodLeftIngestibleByPawn[m] = false; break; } CompProperties_WaterSource compprop = null; for (int x = 0; x < tmpWater[num2].ThingDef.comps.Count; x++) { compprop = tmpWater[num2].ThingDef.comps[x] as CompProperties_WaterSource; if (compprop != null && compprop.sourceType == CompProperties_WaterSource.SourceType.Item) { break; } } if (compprop == null) { tmpAnyFoodLeftIngestibleByPawn[m] = false; break; } Need_Water need_water = pawn.needs.water(); if (need_water == null) { tmpAnyFoodLeftIngestibleByPawn[m] = false; break; } float num3 = Mathf.Min(compprop.waterAmount, need_water.WaterAmountBetweenThirstyAndHealthy); float num4 = num3 / need_water.WaterAmountBetweenThirstyAndHealthy * (float)need_water.TicksUntilThirstyWhenHealthy / 60000f; tmpDaysWorthOfFoodPerPawn[m] = tmpDaysWorthOfFoodPerPawn[m] + num4; tmpWater[num2] = tmpWater[num2].WithCount(tmpWater[num2].Count - 1); flag = true; }while (tmpDaysWorthOfFoodPerPawn[m] < num); num = Mathf.Max(num, tmpDaysWorthOfFoodPerPawn[m]); } } }while (flag); float num6 = 1000f; for (int n = 0; n < pawns.Count; n++) { num6 = Mathf.Min(num6, tmpDaysWorthOfFoodPerPawn[n]); } return(num6); }
protected override Job TryGiveJob(Pawn pawn) { drawerList.Clear(); Need_Water need_water = pawn.needs.water(); if (need_water == null) { return(null); } // 最後に水汲み設備を探してから少し経つまで次の探索はしない if (need_water.lastSearchWaterTick + SearchDrawerIntervalTick > Find.TickManager.TicksGame) { return(null); } need_water.lastSearchWaterTick = Find.TickManager.TicksGame; // 手が使えなければ水汲みはできない if (!pawn.CanManipulate()) { return(null); } // 部屋を取得 var myRoom = pawn.Position.GetRoom(pawn.Map); if (myRoom == null) { return(null); } // 部屋の中にある水汲み設備を探す foreach (var t in pawn.Map.listerThings.AllThings) { bool isDrawer = false; // 同じ部屋になければダメ if (t.Position.GetRoom(t.Map) != myRoom) { continue; } // レシピを持っていないものはダメ if (t.def.recipes == null) { continue; } // 水汲みレシピを持っているかチェック foreach (var recipe in t.def.recipes) { var ext = recipe.GetModExtension <DefExtension_WaterRecipe>(); if (ext == null) { continue; } if (ext.recipeType == DefExtension_WaterRecipe.RecipeType.DrawFromTerrain || ext.recipeType == DefExtension_WaterRecipe.RecipeType.DrawFromWaterNet || ext.recipeType == DefExtension_WaterRecipe.RecipeType.DrawFromWaterPool) { isDrawer = true; break; } } if (isDrawer) { drawerList.Add(t); } } Thing bestDrawer = null; WaterType bestWaterType = WaterType.SeaWater; // 部屋の中の水汲み設備の中で最良の条件の物を探す foreach (var drawer in drawerList) { // 水汲みが出来るものは水を飲むことも出来る var drinkWaterBuilding = drawer as IBuilding_DrinkWater; if (drinkWaterBuilding == null) { continue; } // 作業場所をもっているならそこ、そうでないなら隣接セル var peMode = drawer.def.hasInteractionCell ? PathEndMode.InteractionCell : PathEndMode.Touch; // 予約と到達が出来ないものはダメ if (!pawn.CanReserveAndReach(drawer, peMode, Danger.Deadly)) { continue; } // 動作していないものはダメ if (!drinkWaterBuilding.IsActivated) { continue; } // 汲むことが出来ないものはダメ if (!drinkWaterBuilding.CanDrawFor(pawn)) { continue; } // 水の種類が飲めないタイプの物はダメ if (drinkWaterBuilding.WaterType == WaterType.Undefined || drinkWaterBuilding.WaterType == WaterType.NoWater) { continue; } if (bestWaterType <= drinkWaterBuilding.WaterType) { // 水質が悪くなければ、更新 bestDrawer = drawer; bestWaterType = drinkWaterBuilding.WaterType; } } // 水汲み設備が見つからなかった if (bestDrawer == null) { return(null); } return(new Job(MizuDef.Job_DrawWaterByPrisoner, bestDrawer)); }
protected override Job TryGiveJob(Pawn pawn) { // 所持品インスタンスがない if (pawn.inventory == null) { return(null); } // 水分要求がない Need_Water need_water = pawn.needs.water(); if (need_water == null) { return(null); } Predicate <Thing> validator = (t) => { // 食べられるものは携帯飲料としては選ばれない if (t.def.IsIngestible) { return(false); } var comp = t.TryGetComp <CompWaterSource>(); if (comp == null) { return(false); // 水源でないもの× } if (!comp.IsWaterSource) { return(false); // 水源でないもの× } if (comp.SourceType != CompProperties_WaterSource.SourceType.Item) { return(false); // 水アイテムではないもの× } if (comp.WaterAmount * comp.MaxNumToGetAtOnce < Need_Water.MinWaterAmountPerOneDrink) { return(false); // 最低水分量を満たしていないもの× } if (MizuDef.Dic_WaterTypeDef[comp.WaterType].waterPreferability < MinWaterPreferability) { return(false); // 最低の水質を満たしていないもの× } return(true); }; // 既に条件を満たしたアイテムを持っているか? foreach (var thing in pawn.inventory.innerContainer) { if (!validator(thing)) { continue; } return(null); } // マップ中の水アイテムの合計水分量が、最低限必要とされる水の量(×入植者の人数)以下しかなければ、 // 個人の所持品には入れない if (pawn.Map.resourceCounter.TotalWater() < (float)pawn.Map.mapPawns.ColonistsSpawnedCount * MinWaterPerColonistToDo) { return(null); } var waterThing = GenClosest.ClosestThing_Regionwise_ReachablePrioritized( pawn.Position, pawn.Map, ThingRequest.ForGroup(ThingRequestGroup.HaulableEver), PathEndMode.ClosestTouch, TraverseParms.For(pawn), 20f, (t) => { if (!validator(t)) { return(false); // 所持品チェック時と同じ条件を満たしていない× } if (t.IsForbidden(pawn)) { return(false); // 禁止されている× } if (!pawn.CanReserve(t)) { return(false); // 予約不可能× } if (!t.IsSociallyProper(pawn)) { return(false); // 囚人部屋の物× } return(true); }, (x) => MizuUtility.GetWaterItemScore(pawn, x, 0f, true) // スコアの高いものが優先? ); if (waterThing == null) { return(null); } return(new Job(JobDefOf.TakeInventory, waterThing) { count = Mathf.Min(MizuUtility.StackCountForWater(waterThing, NeedTotalWaterAmount), waterThing.stackCount) }); }