+
+ true
+ true
+
+
+
diff --git a/1.5/Languages/ChineseSimplified-by-Juijote.txt b/1.5/Languages/ChineseSimplified-by-Juijote.txt
new file mode 100644
index 0000000..e69de29
diff --git a/1.5/Languages/ChineseSimplified/Keyed/ProjectHeron_Keys.xml b/1.5/Languages/ChineseSimplified/Keyed/ProjectHeron_Keys.xml
new file mode 100644
index 0000000..339a65e
--- /dev/null
+++ b/1.5/Languages/ChineseSimplified/Keyed/ProjectHeron_Keys.xml
@@ -0,0 +1,25 @@
+
+
+
+ 断开按钮或控制杆
+ 断开所有连接的按钮或控制杆。
+ {0}需要远程打开电源。
+ 使用按钮或控制杆
+ 切换殖民者是否应该去激活或停用按钮或控制杆。
+ 连接电源进行远程安全防护。
+ 连接按钮或控制杆进行远程安全防护。
+ 连接到按钮或控制杆
+ 立即将遥控门连接到按钮
+ 在 {0} 处成功设置新按钮或控制杆
+ {0}无法设置新按钮
+ 在 {0} 取消链接先前连接的按钮或控制杆
+ 取消链接先前连接的按钮或控制杆
+ 必须连接到遥控门
+ 必须接通电源
+ 远程安全防护
+ 启用此设置后,只能通过对应按钮远程开关此门,此门关闭时,将处于锁定状态,无法出入。 当此设置关闭时,任何人都可以像使用普通门一样自由开关此门。
+
+
+ 必须安装在墙上。
+
+
diff --git a/1.5/Languages/English/Keyed/ProjectHeron_Keys.xml b/1.5/Languages/English/Keyed/ProjectHeron_Keys.xml
new file mode 100644
index 0000000..48539a1
--- /dev/null
+++ b/1.5/Languages/English/Keyed/ProjectHeron_Keys.xml
@@ -0,0 +1,29 @@
+
+
+
+ Doors Expanded
+ Log level (for debugging)
+ Normal
+ Debug
+ Stack Trace
+
+ Can be opened and closed from a distance with a button or lever.
+ Disconnect button or lever
+ Disconnects any connected button or lever.
+ {0} requires power to be opened remotely.
+ Use {0}
+ Toggles whether or not a colonist should make their way over to activate or deactivate {0}.
+ Connect a power source to secure remotely.
+ Connect a button or lever to secure remotely.
+ Connect to a button or lever
+ Instantly links the remote door to a button or lever
+ Failed to set new button or lever from {0}
+ Must be connected to a remote door
+ Must be connected to power
+ Secured remotely
+ With this setting on, the door may only be opened remotely by using the corresponding button or lever. The door will act like it is in a locked state, no entry or exit, while closed. When this setting is off, characters may freely open and close the door like normal doors.
+
+
+ Must be placed on a wall.
+
+
diff --git a/1.5/Languages/French-by-qux.txt b/1.5/Languages/French-by-qux.txt
new file mode 100644
index 0000000..e69de29
diff --git a/1.5/Languages/French/DefInjected/JobDef/PH_Jobs.xml b/1.5/Languages/French/DefInjected/JobDef/PH_Jobs.xml
new file mode 100644
index 0000000..1405b2a
--- /dev/null
+++ b/1.5/Languages/French/DefInjected/JobDef/PH_Jobs.xml
@@ -0,0 +1,6 @@
+
+
+
+ Utilise TargetA.
+
+
\ No newline at end of file
diff --git a/1.5/Languages/French/DefInjected/ResearchProjectDef/Heron_ResearchProjects.xml b/1.5/Languages/French/DefInjected/ResearchProjectDef/Heron_ResearchProjects.xml
new file mode 100644
index 0000000..ac05d32
--- /dev/null
+++ b/1.5/Languages/French/DefInjected/ResearchProjectDef/Heron_ResearchProjects.xml
@@ -0,0 +1,19 @@
+
+
+
+ Rideaux
+ Déverrouille des techniques de construction simples pour fabriquer des anneaux, des crochets simples et des tringles pour fabriquer des rideaux qui s'ouvrent beaucoup plus rapidement que les portes standard, mais libèrent lentement les températures entre les pièces.
+
+ Portes de prison
+ Fournit des portes de prison simples pour protéger les détenus.
+
+ Portes automatique
+ Déverrouille les portes automatique ainsi que les télécommandes pour les contrôler.
+
+ Portails
+ Les charnières et les techniques de fixation permettent de construire des portes battantes.
+
+ Portes anti-souffle
+ Permet la fabrication de portes résistantes aux explosions.
+
+
\ No newline at end of file
diff --git a/1.5/Languages/French/DefInjected/ResearchTabDef/Heron_ResearchTab.xml b/1.5/Languages/French/DefInjected/ResearchTabDef/Heron_ResearchTab.xml
new file mode 100644
index 0000000..fa53eca
--- /dev/null
+++ b/1.5/Languages/French/DefInjected/ResearchTabDef/Heron_ResearchTab.xml
@@ -0,0 +1,6 @@
+
+
+
+ Recherche de portes
+
+
\ No newline at end of file
diff --git a/1.5/Languages/French/DefInjected/ThingDef/Heron_Doors.xml b/1.5/Languages/French/DefInjected/ThingDef/Heron_Doors.xml
new file mode 100644
index 0000000..2157e15
--- /dev/null
+++ b/1.5/Languages/French/DefInjected/ThingDef/Heron_Doors.xml
@@ -0,0 +1,58 @@
+
+
+
+
+
+
+
+
+
+ Porte de prison
+ Une porte de prison avec de solides barreaux.
+
+
+
+ Rideaux
+ Sépare les chambres. Les rideaux s'ouvrent beaucoup plus rapidement que les portes conventionnelles, mais ils sont hautement inflammables et laissent lentement l'air passer entre les pièces.
+
+
+
+
+
+
+ Portail
+
+
+
+ Porte anti-souffle
+ Une porte lourde qui est beaucoup plus résistante aux dommages que les portes classiques.
+
+ Porte anti-souffle
+ Une paire de portes lourdes qui sont beaucoup plus résistantes aux dommages que les portes classique.
+
+
+
+
diff --git a/1.5/Languages/French/DefInjected/ThingDef/Heron_RemoteDoorsAndButtons.xml b/1.5/Languages/French/DefInjected/ThingDef/Heron_RemoteDoorsAndButtons.xml
new file mode 100644
index 0000000..01d5f36
--- /dev/null
+++ b/1.5/Languages/French/DefInjected/ThingDef/Heron_RemoteDoorsAndButtons.xml
@@ -0,0 +1,15 @@
+
+
+
+ Poignée de porte
+ Une poignée qui se connecte aux portes (fonctionne comme un levier).
+
+ Levier de porte
+ Un levier qui se connecte aux portes (fonctionne comme un bouton).
+
+ Porte automatique
+ Porte métallique coulissante verticale. Utilise moins d'énergie qu'une porte automatique mais s'ouvre plus lentement
+
+
+
+
diff --git a/1.5/Languages/French/DefInjected/WorkGiverDef/PH_WorkGivers.xml b/1.5/Languages/French/DefInjected/WorkGiverDef/PH_WorkGivers.xml
new file mode 100644
index 0000000..a408c8a
--- /dev/null
+++ b/1.5/Languages/French/DefInjected/WorkGiverDef/PH_WorkGivers.xml
@@ -0,0 +1,9 @@
+
+
+
+ Utilise TargetA
+ Utiliser
+ Utilise
+
+
+
\ No newline at end of file
diff --git a/1.5/Languages/French/Keyed/ProjectHeron_Keys.xml b/1.5/Languages/French/Keyed/ProjectHeron_Keys.xml
new file mode 100644
index 0000000..2802c93
--- /dev/null
+++ b/1.5/Languages/French/Keyed/ProjectHeron_Keys.xml
@@ -0,0 +1,23 @@
+
+
+
+ Peut être ouvert et fermé à distance avec un bouton ou un levier.
+ Bouton ou levier de déconnexion
+ Déconnecte tous les boutons ou leviers attachés.
+ {0}Une alimentation électrique doit être établie pour ouvrir la porte.
+ Utilise {0}.
+ Indique si un colon doit passer pour activer ou désactiver {0}.
+ Connectez une source d'alimentation pour assurer le contrôle à distance.
+ Connectez un bouton ou un levier pour la télécommande.
+ Connectez-vous avec un bouton ou un levier
+ Connecte instantanément la porte avec un bouton
+ Le nouveau bouton n'a pas pu être défini{0}
+ Doit être connecté à une porte télécommandée
+ Doit être connecté à l'alimentation
+ Télécommandé
+ Lorsque ce paramètre est activé, la porte ne peut être ouverte qu'à distance en appuyant sur le bouton approprié. La porte se comporte comme si elle était verrouillée, sans entrée ni sortie tant qu'elle est fermée. Lorsque ce paramètre est désactivé, les personnes peuvent ouvrir et fermer librement la porte comme des portes normales.
+
+
+ Doit être placé sur un mur.
+
+
diff --git a/1.5/Languages/German/DefInjected/JobDef/PH_Jobs.xml b/1.5/Languages/German/DefInjected/JobDef/PH_Jobs.xml
new file mode 100644
index 0000000..f371a6b
--- /dev/null
+++ b/1.5/Languages/German/DefInjected/JobDef/PH_Jobs.xml
@@ -0,0 +1,7 @@
+
+
+
+ Benutze TargetA.
+
+
+
\ No newline at end of file
diff --git a/1.5/Languages/German/DefInjected/ResearchProjectDef/Heron_ResearchProjects.xml b/1.5/Languages/German/DefInjected/ResearchProjectDef/Heron_ResearchProjects.xml
new file mode 100644
index 0000000..c40a870
--- /dev/null
+++ b/1.5/Languages/German/DefInjected/ResearchProjectDef/Heron_ResearchProjects.xml
@@ -0,0 +1,20 @@
+
+
+
+ Einfache Vorhänge
+ Schaltet einfache Konstruktionstechniken zur Herstellung von Ringen, einfachen Haken und Stangen für die Herstellung von Vorhängen frei, die sich weitaus schneller öffnen als Standardtüren, jedoch die Temperaturen zwischen den Räumen langsam ablassen.
+
+ Häftlingskontrolle
+ Bietet einfache Gefängnistüren, um die Insassen größtenteils zu schützen.
+
+ Fernbediente Türen
+ Schalte Fernbedienbare Türen für die ferngesteuerte Kontrolle sowie Knöpfe und Hebel frei, um sie zu kontrollieren.
+
+ Scharniere und Tore
+ Scharniere und Befestigungstechniken ermöglichen den Bau von Pendeltüren, z. B. großen Toren.
+
+ Explosionsschutztüren
+ Ermöglicht die Herstellung von druckstoßabsorbierenden Türen.
+
+
+
\ No newline at end of file
diff --git a/1.5/Languages/German/DefInjected/ResearchTabDef/Heron_ResearchTab.xml b/1.5/Languages/German/DefInjected/ResearchTabDef/Heron_ResearchTab.xml
new file mode 100644
index 0000000..bc429c8
--- /dev/null
+++ b/1.5/Languages/German/DefInjected/ResearchTabDef/Heron_ResearchTab.xml
@@ -0,0 +1,7 @@
+
+
+
+ Türforschung
+
+
+
\ No newline at end of file
diff --git a/1.5/Languages/German/DefInjected/ThingDef/Heron_Doors.xml b/1.5/Languages/German/DefInjected/ThingDef/Heron_Doors.xml
new file mode 100644
index 0000000..8cd0213
--- /dev/null
+++ b/1.5/Languages/German/DefInjected/ThingDef/Heron_Doors.xml
@@ -0,0 +1,58 @@
+
+
+
+
+
+
+
+
+
+ Gefängnistür
+ Schiebegefängniszellentür mit starken Metallstangen.
+
+
+
+ Vorhang (Stamm)
+ Teilt Räume. Vorhänge lassen sich viel schneller öffnen als Standardtüren, sind jedoch entflammbar und lüften langsam die Temperaturen zwischen den Räumen.
+
+
+
+
+
+
+ Tor
+
+
+
+ Explosionsschutztür
+ Eine schwere Tür, die viel widerstandsfähiger gegen Beschädigungen ist.
+
+ Explosionsschutztür
+ Ein schweres Türenpaar, das viel widerstandsfähiger gegen Beschädigungen ist.
+
+
+
+
diff --git a/1.5/Languages/German/DefInjected/ThingDef/Heron_RemoteDoorsAndButtons.xml b/1.5/Languages/German/DefInjected/ThingDef/Heron_RemoteDoorsAndButtons.xml
new file mode 100644
index 0000000..c3bd6bf
--- /dev/null
+++ b/1.5/Languages/German/DefInjected/ThingDef/Heron_RemoteDoorsAndButtons.xml
@@ -0,0 +1,15 @@
+
+
+
+ Türknopf
+ Eine Taste, die mit Türen verbunden wird (funktioniert wie ein Hebel).
+
+ Türhebel
+ Ein Hebel, der mit Türen verbunden wird (funktioniert wie ein Knopf).
+
+ Fernbedienbare Tür
+ Vertikale Metallschiebetür. Teilt Räume.
+
+
+
+
diff --git a/1.5/Languages/German/DefInjected/WorkGiverDef/PH_WorkGivers.xml b/1.5/Languages/German/DefInjected/WorkGiverDef/PH_WorkGivers.xml
new file mode 100644
index 0000000..691c76d
--- /dev/null
+++ b/1.5/Languages/German/DefInjected/WorkGiverDef/PH_WorkGivers.xml
@@ -0,0 +1,9 @@
+
+
+
+ Benutze TargetA
+ Benutze
+ Benutzt
+
+
+
\ No newline at end of file
diff --git a/1.5/Languages/German/Keyed/ProjectHeron_Keys.xml b/1.5/Languages/German/Keyed/ProjectHeron_Keys.xml
new file mode 100644
index 0000000..6862325
--- /dev/null
+++ b/1.5/Languages/German/Keyed/ProjectHeron_Keys.xml
@@ -0,0 +1,23 @@
+
+
+
+ Kann mit einem Knopf aus der Ferne geöffnet und geschlossen werden.
+ Knopf oder Hebel trennen
+ Trennt alle angeschlossenen Knöpfe oder Hebel.
+ {0} Zum Öffnen der Tür muss eine Stromversorgung hergestllt werden.
+ Benutzen Sie {0}.
+ Schaltet ein oder aus, ob ein Kolonist vorbeikommen soll, um {0} zu aktivieren oder zu deaktivieren.
+ Schließen Sie eine Stromquelle an, um die Fernbedienbarkeit zu gewährleisten.
+ Schließen Sie einen Knopf oder Hebel an, um eine Fernbedienbarkeit zu gewährleisten.
+ Mit einem Knopf oder Hebel verbinden
+ Verbindet die Tür sofort mit einem Knopf
+ Neuer Knopf konnte nicht festgelegt werden {0}
+ Muss an eine Fernbedienbare Tür angeschlossen werden
+ Muss an die Stromversorgung angeschlossen sein
+ Ferngesteuert
+ Wenn diese Einstellung aktiviert ist, kann die Tür nur durch Drücken der entsprechenden Taste aus der Ferne geöffnet werden. Die Tür verhält sich so, als wäre sie verriegelt, kein Ein- oder Ausgang, solange sie geschlossen ist. Wenn diese Einstellung deaktiviert ist, können Menschen die Tür wie normale Türen frei öffnen und schließen..
+
+
+ Muss an eine Wand gestellt werden.
+
+
diff --git a/1.5/Languages/Japanese/DefInjected/JobDef/PH_Jobs.xml b/1.5/Languages/Japanese/DefInjected/JobDef/PH_Jobs.xml
new file mode 100644
index 0000000..552ea86
--- /dev/null
+++ b/1.5/Languages/Japanese/DefInjected/JobDef/PH_Jobs.xml
@@ -0,0 +1,6 @@
+
+
+
+ TargetAを使用中
+
+
\ No newline at end of file
diff --git a/1.5/Languages/Japanese/DefInjected/ResearchProjectDef/Heron_ResearchProjects.xml b/1.5/Languages/Japanese/DefInjected/ResearchProjectDef/Heron_ResearchProjects.xml
new file mode 100644
index 0000000..b710983
--- /dev/null
+++ b/1.5/Languages/Japanese/DefInjected/ResearchProjectDef/Heron_ResearchProjects.xml
@@ -0,0 +1,16 @@
+
+
+
+ 簡素なカーテン
+ 標準的なドアよりも素早く開く事ができるカーテンの製造するのに、リングと簡単なフック、ポールを取り付けるための簡単な建築技術のロックを解除します。ただしカーテンで仕切られている部屋同士や屋外の熱がゆっくりと入ってきます。
+
+ 囚人の隔離
+ 基本的な隔離技術です。
+
+ ちょうつがいとゲート
+ ちょうつがいと留め金具の技術は、大きなゲートのような開き戸の建設を可能にします。
+
+ ブラストドア
+ 爆発の圧力を吸収して内部の人や物を守る防爆扉の建設を可能にします。
+
+
\ No newline at end of file
diff --git a/1.5/Languages/Japanese/DefInjected/ResearchTabDef/Heron_ResearchTab.xml b/1.5/Languages/Japanese/DefInjected/ResearchTabDef/Heron_ResearchTab.xml
new file mode 100644
index 0000000..c592e09
--- /dev/null
+++ b/1.5/Languages/Japanese/DefInjected/ResearchTabDef/Heron_ResearchTab.xml
@@ -0,0 +1,6 @@
+
+
+
+ Doors
+
+
\ No newline at end of file
diff --git a/1.5/Languages/Japanese/DefInjected/ThingDef/Heron_Doors.xml b/1.5/Languages/Japanese/DefInjected/ThingDef/Heron_Doors.xml
new file mode 100644
index 0000000..d37eac0
--- /dev/null
+++ b/1.5/Languages/Japanese/DefInjected/ThingDef/Heron_Doors.xml
@@ -0,0 +1,59 @@
+
+
+
+
+
+
+
+
+
+ 囚人用ドア
+ 強力な鉄格子を持ちスライドさせて開閉する刑務所用の囚人部屋のドアです.
+
+
+
+ カーテン (部族)
+ 部屋を隔てる手動扉です.カーテンは標準的なドアよりも素早く開く事ができますが,可燃性なのと換気口のように仕切られた空間同士の温度が通り抜けます.
+
+
+
+
+
+
+ ゲート
+
+
+
+ ブラストドア
+ 損傷に対してはるかに弾力性のある重いドア。
+
+ ブラストドア
+ 損傷に対してはるかに弾力性のある重いドアのペア。
+
+
+
+
diff --git a/1.5/Languages/Japanese/DefInjected/ThingDef/Heron_RemoteDoorsAndButtons.xml b/1.5/Languages/Japanese/DefInjected/ThingDef/Heron_RemoteDoorsAndButtons.xml
new file mode 100644
index 0000000..025d4ca
--- /dev/null
+++ b/1.5/Languages/Japanese/DefInjected/ThingDef/Heron_RemoteDoorsAndButtons.xml
@@ -0,0 +1,15 @@
+
+
+
+ ドアボタン
+ ドアを操作するボタン(レバーと同じ機能)です.
+
+ ドアレバー
+ ドアを操作するレバー(ボタンと同じ機能)です.
+
+ 遠隔ドア
+ 垂直にスライドする金属製のドアです.部屋を分割します.
+
+
+
+
diff --git a/1.5/Languages/Japanese/DefInjected/WorkGiverDef/PH_WorkGivers.xml b/1.5/Languages/Japanese/DefInjected/WorkGiverDef/PH_WorkGivers.xml
new file mode 100644
index 0000000..e036e7d
--- /dev/null
+++ b/1.5/Languages/Japanese/DefInjected/WorkGiverDef/PH_WorkGivers.xml
@@ -0,0 +1,8 @@
+
+
+
+ TargetAを使用
+ 使用
+ 使用
+
+
\ No newline at end of file
diff --git a/1.5/Languages/Japanese/Keyed/ProjectHeron_Keys.xml b/1.5/Languages/Japanese/Keyed/ProjectHeron_Keys.xml
new file mode 100644
index 0000000..38318b1
--- /dev/null
+++ b/1.5/Languages/Japanese/Keyed/ProjectHeron_Keys.xml
@@ -0,0 +1,23 @@
+
+
+
+ ボタンで遠くから開閉できます。
+ ボタンやレバーを解除
+ 接続されているボタンまたはレバーを解除します。
+ {0}を遠隔操作で開く必要があります。
+ {0}を使用
+ 入植者が{0}の操作をできるのか、できないかを切り替えます。
+ 遠隔操作で安全を確保するために電源に接続してください。
+ ボタンやレバーを接続して遠隔操作で安全を確保します。
+ ボタンに接続
+ 離れていても操作できるように遠隔ドアをドアボタンやドアレバーに接続します。
+ 新しい操作ボタン(座標:{0})に設定できませんでした
+ 遠隔操作するドアに接続する必要があります
+ 電源に接続する必要があります
+ 遠隔ドアを施錠
+ この設定がオンの場合、ドアは対応するボタンを押すことによってのみ遠隔操作で開くことができます。閉じられている間、ドアはロックされた状態、つまり出入り口とはならない状態になります。この設定がオフの場合、ポーン(人間や動物)は通常のドアのようにドアを自由に開閉できます。
+
+
+ 壁に置く必要があります。
+
+
diff --git a/1.5/Languages/Korean-by-MarinHigh.txt b/1.5/Languages/Korean-by-MarinHigh.txt
new file mode 100644
index 0000000..e69de29
diff --git a/1.5/Languages/Korean/DefInjected/ThingDef/Heron_Doors.xml b/1.5/Languages/Korean/DefInjected/ThingDef/Heron_Doors.xml
new file mode 100644
index 0000000..6700408
--- /dev/null
+++ b/1.5/Languages/Korean/DefInjected/ThingDef/Heron_Doors.xml
@@ -0,0 +1,59 @@
+
+
+
+
+
+
+
+
+
+ 감옥 문
+ 튼튼한 창살이 있는 미닫이식 감방 문입니다.
+
+
+
+ 커튼 (부족민)
+ 방을 나눕니다. 커튼은 평범한 문보다 훨씬 빨리 열리지만, 불탈 수 있고 서서히 방 사이의 온도를 전달합니다.
+
+
+
+
+
+
+ 관문
+
+
+
+ 방폭 문
+ 손상에 훨씬 더 탄력적인 무거운 문.
+
+ 방폭 문
+ 손상에 훨씬 더 탄력적인 무거운 한 쌍의 문.
+
+
+
+
diff --git a/1.5/Languages/Polish-by-sma342.txt b/1.5/Languages/Polish-by-sma342.txt
new file mode 100644
index 0000000..e69de29
diff --git a/1.5/Languages/Polish/DefInjected/ThingDef/Heron_Doors.xml b/1.5/Languages/Polish/DefInjected/ThingDef/Heron_Doors.xml
new file mode 100644
index 0000000..3be8d0a
--- /dev/null
+++ b/1.5/Languages/Polish/DefInjected/ThingDef/Heron_Doors.xml
@@ -0,0 +1,59 @@
+
+
+
+
+
+
+
+
+
+ więzienne drzwi
+ Przesuwane więzienne drzwi z mocnymi kratami.
+
+
+
+ kurtyna (plemienna)
+ Rozdziela pomieszczenia. Kurtyny otwierają się szybciej niż zwykłe drzwi, ale są łatwopalne i powoli przepuszczają temperatury z innych pomieszczeń.
+
+
+
+
+
+
+ brama
+
+
+
+ drzwi pancerne
+ Ciężkie drzwi, które są znacznie bardziej odporne na uszkodzenia.
+
+ drzwi pancerne
+ Ciężka para drzwi, które są znacznie bardziej odporne na uszkodzenia.
+
+
+
+
diff --git a/1.5/Languages/Portuguese/DefInjected/ThingDef/Heron_Doors.xml b/1.5/Languages/Portuguese/DefInjected/ThingDef/Heron_Doors.xml
new file mode 100644
index 0000000..79c55e9
--- /dev/null
+++ b/1.5/Languages/Portuguese/DefInjected/ThingDef/Heron_Doors.xml
@@ -0,0 +1,59 @@
+
+
+
+
+
+
+
+
+
+ porta de cela
+ Uma porta de cadeia deslisante com barras bem fortes.
+
+
+
+ cortina (tribal)
+ Divide as salas. As cortinas são bem mais rápidas para abrir do que as portas normais, porém são bem inflamáveis e tenta equilibrar a temperatura entre salas.
+
+
+
+
+
+
+ portão
+
+
+
+ portão blindado/anti-explosão
+ Uma porta pesada que é muito mais resistente a danos.
+
+ portão blindado/anti-explosão
+ Um par de portas pesadas que são muito mais resistentes a danos.
+
+
+
+
diff --git a/1.5/Languages/PortugueseBrazilian-by-Freewayz.txt b/1.5/Languages/PortugueseBrazilian-by-Freewayz.txt
new file mode 100644
index 0000000..e69de29
diff --git a/1.5/Languages/PortugueseBrazilian/DefInjected/ThingDef/Heron_Doors.xml b/1.5/Languages/PortugueseBrazilian/DefInjected/ThingDef/Heron_Doors.xml
new file mode 100644
index 0000000..79c55e9
--- /dev/null
+++ b/1.5/Languages/PortugueseBrazilian/DefInjected/ThingDef/Heron_Doors.xml
@@ -0,0 +1,59 @@
+
+
+
+
+
+
+
+
+
+ porta de cela
+ Uma porta de cadeia deslisante com barras bem fortes.
+
+
+
+ cortina (tribal)
+ Divide as salas. As cortinas são bem mais rápidas para abrir do que as portas normais, porém são bem inflamáveis e tenta equilibrar a temperatura entre salas.
+
+
+
+
+
+
+ portão
+
+
+
+ portão blindado/anti-explosão
+ Uma porta pesada que é muito mais resistente a danos.
+
+ portão blindado/anti-explosão
+ Um par de portas pesadas que são muito mais resistentes a danos.
+
+
+
+
diff --git a/1.5/Languages/Russian-by-kr33man.txt b/1.5/Languages/Russian-by-kr33man.txt
new file mode 100644
index 0000000..e69de29
diff --git a/1.5/Languages/Russian/DefInjected/ResearchProjectDef/Heron_ResearchProjects.xml b/1.5/Languages/Russian/DefInjected/ResearchProjectDef/Heron_ResearchProjects.xml
new file mode 100644
index 0000000..84e6ae8
--- /dev/null
+++ b/1.5/Languages/Russian/DefInjected/ResearchProjectDef/Heron_ResearchProjects.xml
@@ -0,0 +1,17 @@
+
+
+
+ простые шторы
+ Открывает простые строительные технологии для изготовления колец, простых крючков и шестов для производства штор, которые открываются намного быстрее, чем стандартные двери, но медленно пропускают воздух между комнатами.
+
+ содержание заключенных
+ Базовое
+
+ петли и ворота
+ Петли и способ скрепления позволяют создавать раздвижные двери, такие как большие ворота.
+
+ взрывозащищенные двери
+ Позволяет производить герметичные взрывозащищенные двери.
+
+
+
\ No newline at end of file
diff --git a/1.5/Languages/Russian/DefInjected/ResearchTabDef/Heron_ResearchTab.xml b/1.5/Languages/Russian/DefInjected/ResearchTabDef/Heron_ResearchTab.xml
new file mode 100644
index 0000000..80b6f5a
--- /dev/null
+++ b/1.5/Languages/Russian/DefInjected/ResearchTabDef/Heron_ResearchTab.xml
@@ -0,0 +1,7 @@
+
+
+
+ исследование дверей
+
+
+
\ No newline at end of file
diff --git a/1.5/Languages/Russian/DefInjected/ThingDef/Heron_Doors.xml b/1.5/Languages/Russian/DefInjected/ThingDef/Heron_Doors.xml
new file mode 100644
index 0000000..323a36d
--- /dev/null
+++ b/1.5/Languages/Russian/DefInjected/ThingDef/Heron_Doors.xml
@@ -0,0 +1,59 @@
+
+
+
+
+
+
+
+
+
+ тюремная дверь
+ Раздвижная дверь тюремной камеры с прочной решеткой.
+
+
+
+ занавес (племя)
+ Разделяет комнаты. Занавесы открываются гораздо быстрее обычных дверей, но легко воспламеняются и медленно пропускают воздух между комнатами.
+
+
+
+
+
+
+ ворота
+
+
+
+ взрывозащищенная дверь
+ Тяжелая дверь, более устойчивая к повреждениям.
+
+ взрывозащищенная дверь
+ Тяжелая пара дверей, которые гораздо более устойчивы к повреждениям.
+
+
+
+
diff --git a/1.5/Languages/Spanish-by-Crusader.txt b/1.5/Languages/Spanish-by-Crusader.txt
new file mode 100644
index 0000000..e69de29
diff --git a/1.5/Languages/Spanish/DefInjected/JobDef/PH_Jobs.xml b/1.5/Languages/Spanish/DefInjected/JobDef/PH_Jobs.xml
new file mode 100644
index 0000000..b7f2240
--- /dev/null
+++ b/1.5/Languages/Spanish/DefInjected/JobDef/PH_Jobs.xml
@@ -0,0 +1,6 @@
+
+
+
+ usando TargetA.
+
+
\ No newline at end of file
diff --git a/1.5/Languages/Spanish/DefInjected/ResearchProjectDef/Heron_ResearchProjects.xml b/1.5/Languages/Spanish/DefInjected/ResearchProjectDef/Heron_ResearchProjects.xml
new file mode 100644
index 0000000..1081590
--- /dev/null
+++ b/1.5/Languages/Spanish/DefInjected/ResearchProjectDef/Heron_ResearchProjects.xml
@@ -0,0 +1,19 @@
+
+
+
+ Cortinas simples
+ Desbloquea técnicas de construcción simples para hacer anillos, ganchos simples y postes para la producción de cortinas, que se abren mucho más rápido que las puertas estándar, pero que ventilan lentamente las temperaturas entre las habitaciones.
+
+ Contención de prisioneros
+ Proporciona puertas de prisión simples para mantener a los internos seguros, bueno, en su mayoría.
+
+ Puertas remotas
+ Desbloquea puertas remotas para contención remota, así como botones y palancas para manipularlas.
+
+ Bisagras y puertas
+ Las bisagras y las técnicas de fijación permiten la construcción de puertas batientes, como puertas grandes.
+
+ Puertas batientes
+ Permite la producción de puertas de explosión presurizadas que absorben explosiones.
+
+
\ No newline at end of file
diff --git a/1.5/Languages/Spanish/DefInjected/ResearchTabDef/Heron_ResearchTab.xml b/1.5/Languages/Spanish/DefInjected/ResearchTabDef/Heron_ResearchTab.xml
new file mode 100644
index 0000000..bb401c3
--- /dev/null
+++ b/1.5/Languages/Spanish/DefInjected/ResearchTabDef/Heron_ResearchTab.xml
@@ -0,0 +1,6 @@
+
+
+
+ Investigación de puertas
+
+
\ No newline at end of file
diff --git a/1.5/Languages/Spanish/DefInjected/ThingDef/Heron_Doors.xml b/1.5/Languages/Spanish/DefInjected/ThingDef/Heron_Doors.xml
new file mode 100644
index 0000000..54f35a1
--- /dev/null
+++ b/1.5/Languages/Spanish/DefInjected/ThingDef/Heron_Doors.xml
@@ -0,0 +1,58 @@
+
+
+
+
+
+
+
+
+
+ Puerta de prisión
+ Puerta corredera de celda con fuertes rejas.
+
+
+
+ Cortina (tribal)
+ Divide habitaciones. Las cortinas son mucho más rápidas de abrir que las puertas estándar, pero son inflamables y ventilan lentamente las temperaturas entre las habitaciones.
+
+
+
+
+
+
+ Portón
+
+
+
+ Puerta blindada
+ Una puerta pesada que es mucho más resistente al daño.
+
+ Puerta blindada
+ Un par de puertas pesadas que es mucho más resistente al daño.
+
+
+
+
diff --git a/1.5/Languages/Spanish/DefInjected/ThingDef/Heron_RemoteDoorsAndButtons.xml b/1.5/Languages/Spanish/DefInjected/ThingDef/Heron_RemoteDoorsAndButtons.xml
new file mode 100644
index 0000000..aaf4e69
--- /dev/null
+++ b/1.5/Languages/Spanish/DefInjected/ThingDef/Heron_RemoteDoorsAndButtons.xml
@@ -0,0 +1,15 @@
+
+
+
+ Botón de puerta
+ Un botón que se conecta a las puertas (funciona igual que una palanca).
+
+ Palanca de puerta
+ Una palanca que se conecta a las puertas (funciona igual que un botón).
+
+ Puerta remota
+ Puerta corredera vertical de metal. Divide habitaciones. Se puede abrir y cerrar a distancia con un botón.
+
+
+
+
diff --git a/1.5/Languages/Spanish/DefInjected/WorkGiverDef/PH_WorkGivers.xml b/1.5/Languages/Spanish/DefInjected/WorkGiverDef/PH_WorkGivers.xml
new file mode 100644
index 0000000..2c4c380
--- /dev/null
+++ b/1.5/Languages/Spanish/DefInjected/WorkGiverDef/PH_WorkGivers.xml
@@ -0,0 +1,8 @@
+
+
+
+ usa TargetA
+ usa
+ usando
+
+
\ No newline at end of file
diff --git a/1.5/Languages/Spanish/Keyed/ProjectHeron_Keys.xml b/1.5/Languages/Spanish/Keyed/ProjectHeron_Keys.xml
new file mode 100644
index 0000000..81b63e1
--- /dev/null
+++ b/1.5/Languages/Spanish/Keyed/ProjectHeron_Keys.xml
@@ -0,0 +1,23 @@
+
+
+
+ Se puede abrir y cerrar a distancia con un botón o palanca.
+ Botón o palanca de desconexión
+ Desconecta cualquier botón o palanca conectada.
+ {0} requiere que la energía se abra de forma remota.
+ Usa {0}
+ Alterna si un colono debe o no hacer su camino para activar o desactivar {0}.
+ Conecte una fuente de alimentación para proteger de forma remota.
+ Conecte un botón o palanca para asegurar de forma remota.
+ Conectarse a un botón o palanca
+ Vincula instantáneamente la puerta remota a un botón
+ No se pudo establecer el nuevo botón desde {0}
+ Debe estar conectado a una puerta remota
+ Debe estar conectado a la alimentación
+ Protegido de forma remota
+ Con esta configuración, la puerta solo se puede abrir de forma remota presionando el botón correspondiente. La puerta actuará como si estuviera en un estado cerrado, sin entrada ni salida, mientras está cerrada. Cuando esta configuración está desactivada, los personajes pueden abrir y cerrar libremente la puerta como las puertas normales.
+
+
+ Debe ser colocado en la pared.
+
+
diff --git a/1.5/Patches/VanillaDoors.xml b/1.5/Patches/VanillaDoors.xml
new file mode 100644
index 0000000..02a8174
--- /dev/null
+++ b/1.5/Patches/VanillaDoors.xml
@@ -0,0 +1,54 @@
+
+
+
+
+
+
- 1.4.1.1 (10-21-2022)
+ 1.5.0.0 (04-20-2024)
Adds new types and sizes of doors to RimWorld and an extensible framework for other mods to add such doors.
@@ -38,11 +39,15 @@ Commissioned by CMDR Toss Antilles.
Thank you to my Patrons for supporting me in my efforts. Without you, none of this would be possible.
These are the most excellent rim dwellers who support me:
-Michael Fisher, Storm D Bain, Luke Salinas, WonkyWoo WeebHoo, Daniel Schott, RainerWingel , Lea Stannard, David Silberstein, Matt Harris, Kiya Nicoll, Paul Fenwick, Elodie , Genaeve , David Turner, Populous25 , Matthew Isom, Charlie Garnham, TinyATuin, Michael Cailler, Jimes Tooper, Landon Cash, Sharp Spook, Don Homer, roxxploxx , Alex Mederer, Justin Andres, Dan Jones, Kaz, Michael Whitehead, iknowdude00, Alexander , Ken Birdwell, Michael Fisher, Storm D Bain, Luke Salinas, WonkyWoo WeebHoo, Daniel Schott, RainerWingel , Lea Stannard, David Silberstein, Matt Harris, Kiya Nicoll, Paul Fenwick, Elodie , Genaeve , David Turner, Populous25 , Matthew Isom, Charlie Garnham, TinyATuin, Michael Cailler, Jimes Tooper, Landon Cash, Sharp Spook, Don Homer, roxxploxx , Alex Mederer, Justin Andres, Dan Jones, Kaz, Michael Whitehead, iknowdude00, Alexander , Ken Birdwell
+
========================
Changelog
========================
+1.5.0.0 (04-20-2024)
+========================
+Updated for RimWorld 1.5 to use the new MultiTileDoor class instead of invisible doors. Saves from 1.4 to 1.5 will need to rebuild their doors in the new 1.5 version.
+
1.4.1.1 (10-21-2022)
========================
Initial update for RimWorld 1.4 for Doors Expanded
diff --git a/About/Changelog.txt b/About/Changelog.txt
index d545600..95bb1bd 100644
--- a/About/Changelog.txt
+++ b/About/Changelog.txt
@@ -1,3 +1,7 @@
+1.5.0.0 (04-20-2024)
+========================
+Updated for RimWorld 1.5 to use the new MultiTileDoor class instead of invisible doors. Saves from 1.4 to 1.5 will need to rebuild their doors in the new 1.5 version.
+
1.4.1.1 (10-21-2022)
========================
Initial update for RimWorld 1.4 for Doors Expanded
diff --git a/About/Manifest.xml b/About/Manifest.xml
index 08a4f6d..c520cbb 100644
--- a/About/Manifest.xml
+++ b/About/Manifest.xml
@@ -1,7 +1,7 @@
DoorsExpanded
- 1.4.1.1
+ 1.5.0.0https://raw.githubusercontent.com/jecrell/DoorsExpanded/master/About/Manifest.xml
diff --git a/About/Version.txt b/About/Version.txt
index 3d5fc67..5d7661f 100644
--- a/About/Version.txt
+++ b/About/Version.txt
@@ -1 +1 @@
-1.4.1.1
+1.5.0.0
diff --git a/LoadFolders.xml b/LoadFolders.xml
index 46b13fb..59cf667 100644
--- a/LoadFolders.xml
+++ b/LoadFolders.xml
@@ -22,4 +22,8 @@
/
1.4
+
+
/
+
1.5
+
diff --git a/Source/Building_DoorExpanded.cs b/Source/Building_DoorExpanded.cs
index 01e556e..ed9d250 100644
--- a/Source/Building_DoorExpanded.cs
+++ b/Source/Building_DoorExpanded.cs
@@ -8,6 +8,7 @@
using Verse.AI;
using Verse.AI.Group;
using Verse.Sound;
+using static HarmonyLib.Code;
namespace DoorsExpanded
{
@@ -15,268 +16,27 @@ namespace DoorsExpanded
///
/// Building_DoorExpanded
///
- /// What: A class for multi-celled, larger and more complicated doors.
- ///
- /// HowWhy: This class is a copy of the Building_Door class without inheriting it.
- /// This prevents it from being passed into region checks that cause region
- /// link errors. It also spawns in Building_DoorRegionHandler classed Things
- /// to act as invisible doors between the spaces of the larger door. This
- /// prevents portal errors.
+ /// What: Originally, a class for multi-celled, larger and more complicated doors.
+ /// RimWorld 1.5 officially implemented a Building_MultiTileDoor class. This class is
+ /// somewhat obsolete and exists as an extension of MultiTileDoor. Previous versions of
+ /// RimWorld required a complete new class.
+ ///
+ /// There is still value in the Expanded class, as it allows for swinging doors, stretching doors,
+ /// and is also extended into remote controlled doors.
///
///
- // TODO: Since we're spending so much effort copying and patching things such that a door that's not a
- // Building_Door acts like Building_Door with extra features just to avoid RimWorld limitations regarding doors,
- // at this point, shouldn't we consider attacking those limitations directly rather than all these workarounds?
- public class Building_DoorExpanded : Building
+ public class Building_DoorExpanded : Building_MultiTileDoor
{
- // All of these constants are currently the same as those in Building_Door.
- private const float OpenTicks = 45f;
- private const int CloseDelayTicks = 110;
- private const int WillCloseSoonThreshold = 111;
- private const int ApproachCloseDelayTicks = 300;
- private const int MaxTicksSinceFriendlyTouchToAutoClose = 120;
- private const float PowerOffDoorOpenSpeedFactor = 0.25f;
- private const float VisualDoorOffsetStart = 0f;
- internal const float VisualDoorOffsetEnd = 0.45f;
- private const float NotifyFogGridDoorOpenPct = 0.4f;
- private List invisDoors = new();
private CompProperties_DoorExpanded props;
- private CompPowerTrader powerComp;
private CompForbiddable forbiddenComp;
- private bool openInt;
- private bool holdOpenInt;
- private int lastFriendlyTouchTick = -9999;
- protected int ticksUntilClose;
- protected int ticksSinceOpen;
- private bool freePassageWhenClearedReachabilityCache;
- private Pawn approachingPawn;
- private bool lastForbiddenState;
- private bool preventDoorOpenRecursion;
- private bool preventDoorTryCloseRecursion;
-
- [Obsolete("Use Props instead")]
- public DoorExpandedDef Def => def as DoorExpandedDef;
-
- public CompProperties_DoorExpanded Props =>
- props ??= def.GetDoorExpandedProps() ?? throw new Exception("Missing " + typeof(CompProperties_DoorExpanded));
-
- public List InvisDoors => invisDoors;
-
- public bool Open => props.doorType is DoorType.FreePassage || openInt;
-
- protected virtual bool OpenInt
- {
- get => openInt;
- set
- {
- if (openInt == value)
- return;
- openInt = value;
- foreach (var invisDoor in invisDoors)
- {
- invisDoor.Open = value;
- }
- }
- }
-
- public virtual bool HoldOpen => holdOpenInt;
-
- public int TicksUntilClose => ticksUntilClose;
-
- public int TicksSinceOpen => ticksSinceOpen;
-
- public bool FreePassage => Open && (HoldOpen || !WillCloseSoon);
-
- public int TicksTillFullyOpened
- {
- get
- {
- var ticksTillFullyOpened = TicksToOpenNow - ticksSinceOpen;
- if (ticksTillFullyOpened < 0)
- {
- ticksTillFullyOpened = 0;
- }
- return ticksTillFullyOpened;
- }
- }
-
- public bool WillCloseSoon
- {
- get
- {
- if (!Spawned)
- {
- return true;
- }
- if (!Open)
- {
- return true;
- }
- if (HoldOpen)
- {
- return false;
- }
- if (ticksUntilClose > 0 && ticksUntilClose <= WillCloseSoonThreshold && !BlockedOpenMomentary)
- {
- return true;
- }
- if (CanTryCloseAutomatically && !BlockedOpenMomentary)
- {
- return true;
- }
- var searchRect = this.OccupiedRect().ExpandedBy(1);
- foreach (var c in searchRect)
- {
- if (!searchRect.IsCorner(c) && c.InBounds(Map))
- {
- var thingList = c.GetThingList(Map);
- for (var j = 0; j < thingList.Count; j++)
- {
- if (thingList[j] is Pawn pawn && !pawn.HostileTo(this) && !pawn.Downed &&
- (pawn.Position == Position || (pawn.pather.Moving && pawn.pather.nextCell == Position)))
- {
- return true;
- }
- }
- }
- }
- return true;
- }
- }
-
- public bool BlockedOpenMomentary
- {
- get
- {
- foreach (var c in this.OccupiedRect())
- {
- var thingList = c.GetThingList(Map);
- for (var i = 0; i < thingList.Count; i++)
- {
- var thing = thingList[i];
- if (thing.def.category is ThingCategory.Item or ThingCategory.Pawn)
- {
- return true;
- }
- }
- }
- return false;
- }
- }
-
- public bool DoorPowerOn => powerComp is { PowerOn: true };
-
- public bool DoorPowerOff => powerComp is { PowerOn: false };
-
- public bool SlowsPawns => /*!DoorPowerOn ||*/ TicksToOpenNow > 20;
-
- public int TicksToOpenNow => DoorOpenTicks(StatRequest.For(this), DoorPowerOn);
-
- internal bool CanTryCloseAutomatically => FriendlyTouchedRecently && !HoldOpen;
-
- internal protected virtual bool FriendlyTouchedRecently =>
- Find.TickManager.TicksGame < lastFriendlyTouchTick + MaxTicksSinceFriendlyTouchToAutoClose;
-
- public override bool FireBulwark => !Open && base.FireBulwark;
-
+ private const float VisualDoorOffsetStart = 0f;
+ internal const float VisualDoorOffsetEnd = 0.45f;
public virtual bool Forbidden => forbiddenComp?.Forbidden ?? false;
- private float OpenPct
- {
- get
- {
- // If TicksToOpenNow == 0 (instantaneous open), have to use different logic to avoid NRE.
- var ticksToOpenNow = TicksToOpenNow;
- if (ticksToOpenNow == 0)
- {
- return Open ? 1f : 0f;
- }
- else
- {
- return Mathf.Clamp01((float)ticksSinceOpen / ticksToOpenNow);
- }
- }
- }
-
- // This method works for both Building_Door and Building_DoorExpanded.
- private static int DoorOpenTicks(StatRequest statRequest, bool doorPowerOn, bool applyPostProcess = true)
- {
- if (statRequest.Def.GetDoorExpandedProps() is { doorType: DoorType.FreePassage })
- {
- return 0;
- }
- var ticksToOpenNow = OpenTicks / StatDefOf.DoorOpenSpeed.Worker.GetValue(statRequest, applyPostProcess);
- if (doorPowerOn)
- {
- ticksToOpenNow *= PowerOffDoorOpenSpeedFactor;
- }
- return Mathf.RoundToInt(ticksToOpenNow);
- }
-
- public static float DoorOpenTime(StatRequest statRequest, bool doorPowerOn, bool applyPostProcess)
- {
- return GenTicks.TicksToSeconds(DoorOpenTicks(statRequest, doorPowerOn, applyPostProcess));
- }
-
- // This method works for both Building_Door and Building_DoorExpanded.
- public static string DoorOpenTimeExplanation(StatRequest statRequest, bool doorPowerOn, StatDef stat)
- {
- var explanation = new StringBuilder();
-
- // Treat powered door open speed as the "normal" speed.
- // This is done partly due to the lack of a vanilla "has power" translation key.
- var defaultSpeed = OpenTicks * PowerOffDoorOpenSpeedFactor;
- explanation.AppendLine("StatsReport_BaseValue".Translate() + ": " + stat.ValueToString(defaultSpeed / GenTicks.TicksPerRealSecond));
-
- if (statRequest.Def.GetDoorExpandedProps() is { doorType: DoorType.FreePassage })
- {
- explanation.AppendLine($"{DoorType.FreePassage}: x0");
- return explanation.ToString();
- }
-
- var doorOpenSpeedStat = StatDefOf.DoorOpenSpeed;
- var doorOpenSpeed = doorOpenSpeedStat.Worker.GetValue(statRequest);
- explanation.AppendLine($"{doorOpenSpeedStat.LabelCap}:");
- var doorOpenSpeedExplanation = doorOpenSpeedStat.Worker.GetExplanationFull(statRequest, doorOpenSpeedStat.toStringNumberSense, doorOpenSpeed);
- explanation.AppendLine(" " + string.Join("\n ",
- doorOpenSpeedExplanation.Split(new[] { '\n' }, System.StringSplitOptions.RemoveEmptyEntries)));
- explanation.AppendLine($" 1/x => x{(1f / doorOpenSpeed).ToStringPercent()}");
-
- if (!doorPowerOn)
- {
- explanation.AppendLine($"{"NoPower".Translate()}: x{(1f / PowerOffDoorOpenSpeedFactor).ToStringPercent()}");
- }
-
- return explanation.ToString();
- }
-
- // This method works for both Building_Door and Building_DoorExpanded.
- public static bool DoorNeedsPower(ThingDef def) => def.HasComp(typeof(CompPowerTrader));
-
- // This method works for both Building_Door and Building_DoorExpanded.
- public static bool? DoorIsPoweredOn(Thing thing)
- {
- if (thing is Building_Door door)
- return door.DoorPowerOn;
- else if (thing is Building_DoorExpanded doorEx)
- return doorEx.DoorPowerOn;
- return null;
- }
-
- public override void PostMake()
- {
- base.PostMake();
- _ = Props; // ensures props is initialized
- powerComp = GetComp();
- forbiddenComp = GetComp();
- }
+ public CompProperties_DoorExpanded Props =>
+ props ??= def.GetDoorExpandedProps() ?? throw new Exception("Missing " + typeof(CompProperties_DoorExpanded));
- public override void PostMapInit()
- {
- if (Spawned)
- SpawnInvisDoorsAsNeeded(Map, this.OccupiedRect());
- }
public override void SpawnSetup(Map map, bool respawningAfterLoad)
{
@@ -286,25 +46,14 @@ public override void SpawnSetup(Map map, bool respawningAfterLoad)
// Fortunately once rotated, no further non-1x1 rotations will change the footprint further.
// Restricted rotation logic in both patched Designator_Place and Blueprint shouldn't allow invalid rotations by
// this point, but better safe than sorry, especially if this is spawned without Designator_Place or Blueprint.
- Rotation = DoorRotationAt(def, props, Position, Rotation, map);
+ Rotation = DoorRotationAt(def, Props, Position, Rotation, map);
- // Note: We only want invisDoors to register in the edificeGrid (during its SpawnSetup).
- // A harmony patch to EdificeGrid.Register, which is called in Building.SpawnSetup,
- // prevents this Building_DoorExpanded from being registered in the edificeGrid.
base.SpawnSetup(map, respawningAfterLoad);
- // During game loading/initialization, we can't tell whether another door (including invis door) is actually spawned
- // (and thus listed in GridsUtility.GetThingList()), since things are initially set to unspawned state and then spawned
- // as the game is being initialized, so another door may have SpawnSetup called later than this.
- // Therefore, we delay spawning (and the involved sanity checks) of invis doors until game is initialized.
- if (!respawningAfterLoad)
- {
- SpawnInvisDoorsAsNeeded(map, this.OccupiedRect());
- }
powerComp = GetComp();
forbiddenComp = GetComp();
- SetForbidden(Forbidden);
+ ForbidUtility.SetForbidden(this,Forbidden);
ClearReachabilityCache(map);
if (BlockedOpenMomentary)
{
@@ -312,550 +61,47 @@ public override void SpawnSetup(Map map, bool respawningAfterLoad)
}
}
- // Note: This method is also filled with sanity checks for invis doors that manifest as warnings.
- private void SpawnInvisDoorsAsNeeded(Map map, CellRect occupiedRect)
- {
- if (TLog.Enabled)
- TLog.Log(this, $"{this} (#invisDoors={invisDoors.Count}/{occupiedRect.Area})");
- var invisDoorsToRespawn = new List();
- var invisDoorsToReposition = new List();
- var spawnedInvisDoors = new List();
- var errors = new List();
-
- if (invisDoors.Count > 0)
- {
- var invisDoorCells = new HashSet(); // only for detecting multiple existing invis doors at same cell
- for (var i = invisDoors.Count - 1; i >= 0; i--)
- {
- var invisDoor = invisDoors[i];
- var removeInvisDoor = false;
- if (invisDoor is null)
- {
- errors.Add($"{this}.invisDoors[{i}] is unexpectedly null - removing it");
- removeInvisDoor = true;
- }
- else if (invisDoor.Destroyed)
- {
- errors.Add($"{invisDoor} is unexpectedly destroyed - removing it");
- removeInvisDoor = true;
- }
- else
- {
- if (!invisDoor.Spawned)
- {
- // Error msg is added later in this case.
- removeInvisDoor = true;
- invisDoorsToRespawn.Add(invisDoor);
- }
- else
- {
- var cell = invisDoor.Position;
- if (!occupiedRect.Contains(cell))
- {
- errors.Add($"{invisDoor} has position {cell} outside of {occupiedRect} - destroying it");
- removeInvisDoor = true;
- invisDoor.Destroy();
- }
- else if (!invisDoorCells.Add(cell))
- {
- var existingInvisDoors = cell.GetThingList(map).OfType();
- errors.Add($"{invisDoor} has position {cell} taken by multiple invis doors " +
- $"({existingInvisDoors.ToStringSafeEnumerable()}) - destroying it");
- removeInvisDoor = true;
- invisDoor.Destroy();
- }
- }
- }
-
- if (removeInvisDoor)
- {
- invisDoors.RemoveAt(i);
- }
- else
- {
- if (invisDoor.ParentDoor is null)
- {
- errors.Add($"{invisDoor} has no parent - reparenting it to {this}");
- invisDoor.ParentDoor = this;
- }
- else if (invisDoor.ParentDoor != this)
- {
- errors.Add($"{invisDoor} has different parent - removing it from {this}");
- // Don't destroy this invis door here - let the invis door's parent handle it.
- invisDoors.RemoveAt(i);
- }
-
- if (invisDoor.Faction != Faction)
- {
- errors.Add($"{invisDoor} has different faction ({invisDoor.Faction}) - setting it to {Faction}");
- invisDoor.SetFactionDirect(Faction);
- }
- }
- }
- }
-
- foreach (var cell in occupiedRect)
- {
- var thingList = cell.GetThingList(map);
- // Another spawned overlapping doorEx shouldn't ever by possible due to GenSpawn.SpawningWipes checks, but just in case...
- foreach (var existingThing in thingList)
- {
- if (existingThing != this && existingThing is Building_DoorExpanded existingDoorEx)
- {
- var existingOccupiedRect = existingDoorEx.OccupiedRect();
- if (occupiedRect.Overlaps(existingOccupiedRect))
- {
- errors.Add($"Unexpected {existingDoorEx} (occupying {existingOccupiedRect}) overlaps {this} " +
- $"(occupying {occupiedRect}) - refunding it");
- // This should also destroy all the invis doors associated with the refunded doorEx.
- GenSpawn.Refund(existingDoorEx, map, occupiedRect);
- }
- }
- }
-
- Building_DoorRegionHandler invisDoor = null;
- var existingInvisDoors = thingList.OfType();
- foreach (var existingInvisDoor in existingInvisDoors)
- {
- if (existingInvisDoor.ParentDoor != this)
- {
- errors.Add($"Unexpected {invisDoor} already spawned at {cell} - destroying it");
- // By this point, it's impossible for another spawned doorEx to overlap this doorEx,
- // so if existing invis door's parent is another doorEx, assume it's either unspawned or in another location,
- // so don't destroy that doorEx. Just destroy
- invisDoor.Destroy();
- }
- else if (invisDoor is not null)
- {
- // This isn't redundant with the earlier multiple invis doors check, since it's technically possible for
- // some existing invis doors at the cell to not all be within invisDoors, thus warranting this sanity check.
- errors.Add($"{invisDoor} has position {cell} taken by multiple invis doors " +
- $"({existingInvisDoors.ToStringSafeEnumerable()}) - destroying it");
- invisDoor.Destroy();
- }
- else
- {
- invisDoor = existingInvisDoor;
- }
- }
-
- if (invisDoor is null)
- {
- if (invisDoorsToRespawn.Count > 0)
- {
- invisDoor = invisDoorsToRespawn.Pop();
- errors.Add($"{invisDoor} is unexpectedly unspawned - respawning it at {cell}");
- }
- else
- {
- invisDoor = (Building_DoorRegionHandler)ThingMaker.MakeThing(HeronDefOf.HeronInvisibleDoor);
- invisDoor.ParentDoor = this;
- invisDoor.SetFactionDirect(Faction);
- }
- GenSpawn.Spawn(invisDoor, cell, map);
- spawnedInvisDoors.Add(invisDoor);
- }
-
- // Open is the only field that needs to be manually synced with the parent door;
- // all other fields in the invis door are unused.
- invisDoor.Open = Open;
- }
-
- foreach (var invisDoor in invisDoorsToRespawn)
- {
- errors.Add($"{invisDoor} is unexpectedly unspawned and is extraneous - destroying it");
- invisDoor.Destroy();
- }
-
- invisDoors.AddRange(spawnedInvisDoors);
-
- if (errors.Count > 0)
- {
- var errorMsg = $"[Doors Expanded] Encountered errors when spawning invis doors for {this}:\n" + errors.ToLineList("\t");
- if (spawnedInvisDoors.Count > 0)
- errorMsg += "\nSpawned invis doors:\n" + spawnedInvisDoors.Select(invisDoor => invisDoor.ToString()).ToLineList("\t");
- Log.Error(errorMsg);
- }
- }
-
- public override void DeSpawn(DestroyMode mode = DestroyMode.Vanish)
- {
- TLog.Log(this);
- var spawnedInvisDoors = invisDoors.FindAll(invisDoor => invisDoor.Spawned);
- foreach (var invisDoor in spawnedInvisDoors)
- {
- // If this parent door is respawned later, it will always recreate the invis doors,
- // so destroy (rather than just despawn) existing invis doors.
- // And invis doors are always despawned/destroyed in the default Vanish mode.
- invisDoor.Destroy();
- }
- invisDoors.Clear();
- var map = Map;
- // Note: To be safe, this room notifying is done after all invis doors are despawned.
- // See also HarmonyPatches.InvisDoorRoomNotifyContainedThingSpawnedOrDespawnedPrefix.
- foreach (var invisDoor in spawnedInvisDoors)
- {
- // Following partially copied from Thing.DeSpawn.
- map.regionGrid.GetValidRegionAt_NoRebuild(Position)?.Room?.Notify_ContainedThingSpawnedOrDespawned(invisDoor);
- }
- // Following conditions copied from Building.DeSpawn.
- if (mode is not DestroyMode.WillReplace && def.MakeFog)
- {
- // FogGrid.Notify_FogBlockerRemoved needs to be called on all invis door positions (same as OccupiedRect()),
- // or else there can be some cases where despawning a large door doesn't properly defog rooms.
- // Building.DeSpawn only calls this on the single Position location.
- // See also HarmonyPatches.InvisDoorMakeFogTranspiler.
- // Following is kinda inefficient, but this isn't perfomance critical code, so it shouldn't matter.
- foreach (var c in this.OccupiedRect())
- {
- map.fogGrid.Notify_FogBlockerRemoved(c);
- }
- }
- base.DeSpawn(mode);
- ClearReachabilityCache(map);
- }
-
- public override void Destroy(DestroyMode mode = DestroyMode.Vanish)
- {
- TLog.Log(this);
- base.Destroy(mode);
- }
-
- public override void ExposeData()
- {
- base.ExposeData();
- Scribe_Collections.Look(ref invisDoors, nameof(invisDoors), LookMode.Reference);
- invisDoors ??= new List(); // in case a save file somehow has missing or null invisDoors
- Scribe_Values.Look(ref openInt, "open", false);
- Scribe_Values.Look(ref holdOpenInt, "holdOpen", false);
- Scribe_Values.Look(ref lastFriendlyTouchTick, nameof(lastFriendlyTouchTick), 0);
- Scribe_References.Look(ref approachingPawn, nameof(approachingPawn));
- if (Scribe.mode is LoadSaveMode.LoadingVars)
- {
- // Ensure props is available for Open usage since PostMake hasn't been called yet.
- // base.ExposeData() ensures that def is available, which is required for props initialization.
- _ = Props;
- if (Open)
- {
- ticksSinceOpen = TicksToOpenNow;
- }
- }
- }
-
- // Simulated to be "virtual" via Harmony patch on Thing.SetFactionDirect.
- public new void SetFactionDirect(Faction newFaction)
- {
- if (Faction == newFaction)
- return;
- base.SetFactionDirect(newFaction);
- foreach (var invisDoor in invisDoors)
- {
- invisDoor.SetFactionDirect(newFaction);
- }
- }
-
- public override void SetFaction(Faction newFaction, Pawn recruiter = null)
- {
- // This check prevents redundant calls from all the invis doors' SetFaction.
- if (Faction == newFaction)
- return;
- base.SetFaction(newFaction, recruiter);
- foreach (var invisDoor in invisDoors)
- {
- invisDoor.SetFaction(newFaction, recruiter);
- }
- if (Spawned)
- {
- ClearReachabilityCache(Map);
- }
- }
-
- public override void Tick()
- {
- // Workaround for MinifyEverything issue where reinstalling doors sometimes causes a transient and harmless NRE
- // in GridsUtility.GetThingList. This also effects vanilla doors, which are fixed in a harmony patch
- // (see HarmonyPatches.BuildingDoorTickPrefix).
- if (!Spawned)
- return;
-
- base.Tick();
-
- var occupiedRect = this.OccupiedRect();
- var map = Map;
-
- // Periodic sanity checks.
- if (invisDoors.Count(invisDoor => invisDoor is { Spawned: true }) != occupiedRect.Area ||
- this.IsHashIntervalTick(GenTicks.TickLongInterval))
- {
- SpawnInvisDoorsAsNeeded(map, occupiedRect);
- }
-
- if (FreePassage != freePassageWhenClearedReachabilityCache)
- {
- ClearReachabilityCache(map);
- }
- if (!Open)
- {
- if (ticksSinceOpen > 0)
- {
- ticksSinceOpen--;
- }
- if ((Find.TickManager.TicksGame + thingIDNumber.HashOffset()) % TemperatureTuning.Door_TempEqualizeIntervalClosed == 0)
- {
- GenTemperature.EqualizeTemperaturesThroughBuilding(this, props.tempEqualizeRate, twoWay: false);
- }
- }
- else
- {
- if (ticksSinceOpen < TicksToOpenNow)
- {
- ticksSinceOpen++;
- }
- var isPawnPresent = false;
- foreach (var c in occupiedRect)
- {
- var thingList = c.GetThingList(map);
- for (var i = 0; i < thingList.Count; i++)
- {
- if (thingList[i] is Pawn pawn)
- {
- CheckFriendlyTouched(pawn);
- isPawnPresent = true;
- }
- }
- }
- if (ticksUntilClose > 0)
- {
- if (isPawnPresent)
- {
- ticksUntilClose = CloseDelayTicks;
- }
- ticksUntilClose--;
- if (ticksUntilClose <= 0 && !HoldOpen && !DoorTryClose())
- {
- ticksUntilClose = 1;
- }
- }
- else if (CanTryCloseAutomatically)
- {
- ticksUntilClose = CloseDelayTicks;
- }
- if ((Find.TickManager.TicksGame + thingIDNumber.HashOffset()) % TemperatureTuning.Door_TempEqualizeIntervalOpen == 0)
- {
- GenTemperature.EqualizeTemperaturesThroughBuilding(this, TemperatureTuning.Door_TempEqualizeRate, twoWay: false);
- }
- if (OpenPct >= NotifyFogGridDoorOpenPct && approachingPawn is not null)
- {
- // Following is kinda inefficient, but this isn't perfomance critical code, so it shouldn't matter.
- foreach (var invisDoor in invisDoors)
- {
- map.fogGrid.Notify_PawnEnteringDoor(invisDoor, approachingPawn);
- }
- approachingPawn = null;
- }
- }
- }
-
- public void CheckFriendlyTouched(Pawn p)
- {
- if (!p.HostileTo(this) && PawnCanOpen(p))
- {
- lastFriendlyTouchTick = Find.TickManager.TicksGame;
- }
- }
-
- public void Notify_PawnApproaching(Pawn p, int moveCost)
- {
- CheckFriendlyTouched(p);
- var pawnCanOpen = PawnCanOpen(p);
- if (pawnCanOpen || Open)
- {
- approachingPawn = p;
- }
- if (pawnCanOpen && !SlowsPawns)
- {
- var ticksToClose = Mathf.Max(ApproachCloseDelayTicks, moveCost + 1);
- DoorOpen(ticksToClose);
- }
- }
-
- public void Notify_ForbiddenInputChanged()
- {
- var forbidden = Forbidden;
- if (forbidden != lastForbiddenState)
- {
- SetForbidden(forbidden);
- }
- }
-
- private void SetForbidden(bool forbidden)
- {
- lastForbiddenState = forbidden;
- foreach (var invisDoor in invisDoors)
- {
- invisDoor.SetForbidden(forbidden);
- }
- }
-
- public bool CanPhysicallyPass(Pawn p)
- {
- return FreePassage || PawnCanOpen(p) || (Open && p.HostileTo(this));
- }
-
- public virtual bool PawnCanOpen(Pawn p)
- {
- if (Map is { } map && map.Parent.doorsAlwaysOpenForPlayerPawns && p.Faction == Faction.OfPlayer)
- {
- return true;
- }
- if (p.GetLord() is { LordJob: { } lordJob } && lordJob.CanOpenAnyDoor(p))
- {
- return true;
- }
- if (WildManUtility.WildManShouldReachOutsideNow(p))
- {
- return true;
- }
- if (p.RaceProps.FenceBlocked && !def.building.roamerCanOpen && (!p.roping.IsRopedByPawn || !PawnCanOpen(p.roping.RopedByPawn)))
- {
- return false;
- }
- if (Faction is null)
- {
- return true;
- }
- if (p.guest is { Released: true })
- {
- return true;
- }
- return GenAI.MachinesLike(Faction, p);
- }
-
- public override bool BlocksPawn(Pawn p) => !Open && !PawnCanOpen(p);
-
- protected internal void DoorOpen(int ticksToClose = CloseDelayTicks)
- {
- // For compatibility with other mods that patch Building_Door.DoorOpen,
- // which is only internally called within Building_Door, need to call DoorOpen on each invis door.
- // However doing so would end up calling this DoorOpen recursively.
- // preventDoorOpenRecursion is used to prevent this unwanted recursion.
- if (preventDoorOpenRecursion)
- return;
- preventDoorOpenRecursion = true;
- try
- {
- foreach (var invisDoor in invisDoors)
- invisDoor.DoorOpen(ticksToClose);
- }
- finally
- {
- preventDoorOpenRecursion = false;
- }
-
- if (Open)
- {
- ticksUntilClose = ticksToClose;
- }
- else
- {
- ticksUntilClose = TicksToOpenNow + ticksToClose;
- OpenInt = true;
- CheckClearReachabilityCacheBecauseOpenedOrClosed();
- if (DoorPowerOn)
- {
- def.building.soundDoorOpenPowered?.PlayOneShot(new TargetInfo(Position, Map));
- }
- else
- {
- def.building.soundDoorOpenManual?.PlayOneShot(new TargetInfo(Position, Map));
- }
- }
- }
-
- protected internal bool DoorTryClose()
+ public static Rot4 DoorRotationAt(ThingDef def, CompProperties_DoorExpanded props, IntVec3 loc, Rot4 rot, Map map)
{
- // For compatibility with other mods that patch Building_Door.DoorTryClose,
- // which is only internally called within Building_Door, need to call DoorTryClose on each invis door.
- // However doing so would end up calling this DoorTryClose recursively.
- // preventDoorTryCloseRecursion is used to prevent this unwanted recursion.
- if (preventDoorTryCloseRecursion)
- return false;
- preventDoorTryCloseRecursion = true;
- try
- {
- foreach (var invisDoor in invisDoors)
- invisDoor.DoorTryClose();
- }
- finally
- {
- preventDoorTryCloseRecursion = false;
- }
-
- if (HoldOpen || BlockedOpenMomentary)
- {
- return false;
- }
- OpenInt = false;
- CheckClearReachabilityCacheBecauseOpenedOrClosed();
- if (DoorPowerOn)
- {
- def.building.soundDoorClosePowered?.PlayOneShot(new TargetInfo(Position, Map));
- }
- else
+ if (!def.rotatable)
{
- def.building.soundDoorCloseManual?.PlayOneShot(new TargetInfo(Position, Map));
+ var size = def.Size;
+ if ((size.x == 1 && size.z == 1) || props.doorType is DoorType.StretchVertical or DoorType.Stretch)
+ rot = DoorUtility.DoorRotationAt(loc, map, false);
}
- return true;
- }
-
- public void StartManualOpenBy(Pawn opener)
- {
- DoorOpen();
- }
-
- public void StartManualCloseBy(Pawn closer)
- {
- ticksUntilClose = CloseDelayTicks;
- }
-
- // This exists to expose draw vectors for debugging purposes.
- internal class DebugDrawVectors
- {
- public float openPct;
- public Vector3 offsetVector, scaleVector, graphicVector;
+ if (!props.rotatesSouth && rot == Rot4.South)
+ rot = Rot4.North;
+ return rot;
}
- internal DebugDrawVectors debugDrawVectors = new();
-
- public override void Draw()
+ protected override void DrawAt(Vector3 drawLoc, bool flip = false)
{
- var drawPos = DrawPos;
- drawPos.y = AltitudeLayer.DoorMoveable.AltitudeFor();
- var rotation = DoorRotationAt(def, props, Position, Rotation, Map);
+ drawLoc.y = AltitudeLayer.DoorMoveable.AltitudeFor();
+ var rotation = DoorRotationAt(def, Props, Position, Rotation, Map);
Rotation = rotation;
var openPct = OpenPct;
for (var i = 0; i < 2; i++)
{
var flipped = i != 0;
- var graphic = (!flipped && props.doorAsync is { } doorAsyncGraphic)
+ var graphic = (!flipped && Props.doorAsync is { } doorAsyncGraphic)
? doorAsyncGraphic.GraphicColoredFor(this)
: Graphic;
- Draw(def, props, graphic, drawPos, rotation, openPct, flipped,
- i == 0 && DebugViewSettingsMoreWrite.writeDoors ? debugDrawVectors : null);
- graphic.ShadowGraphic?.DrawWorker(drawPos, rotation, def, this, 0f);
+ Draw(def, Props, graphic, drawLoc, rotation, openPct, flipped, null);
+ //i == 0 && DebugViewSettingsMoreWrite.writeDoors ? debugDrawVectors : null);
+ graphic.ShadowGraphic?.DrawWorker(drawLoc, rotation, def, this, 0f);
if (props.singleDoor)
break;
}
if (props.doorFrame is not null)
{
- DrawFrameParams(def, props, drawPos, rotation, false, out var fMesh, out var fMatrix);
+ DrawFrameParams(def, Props, drawLoc, rotation, false, out var fMesh, out var fMatrix);
Graphics.DrawMesh(fMesh, fMatrix, props.doorFrame.GraphicColoredFor(this).MatAt(rotation), 0);
if (props.doorFrameSplit is not null)
{
- DrawFrameParams(def, props, drawPos, rotation, true, out fMesh, out fMatrix);
+ DrawFrameParams(def, Props, drawLoc, rotation, true, out fMesh, out fMatrix);
Graphics.DrawMesh(fMesh, fMatrix, props.doorFrameSplit.GraphicColoredFor(this).MatAt(rotation), 0);
}
}
@@ -964,7 +210,7 @@ private static void DrawDoubleSwingParams(ThingDef def, CompProperties_DoorExpan
rotQuat = rotation.AsQuat;
offsetVector = rotQuat * offsetVector;
- var offsetMod = (VisualDoorOffsetStart + props.doorOpenMultiplier * openPct) * def.Size.x;
+ var offsetMod = ((VisualDoorOffsetStart + props.doorOpenMultiplier * openPct) * def.Size.x);
offsetVector *= offsetMod;
if (verticalRotation)
@@ -1008,6 +254,7 @@ private static void DrawStandardParams(ThingDef def, CompProperties_DoorExpanded
scaleVector = new Vector3(drawSize.x * persMod, 1f, drawSize.y * persMod);
}
+
private static void DrawFrameParams(ThingDef def, CompProperties_DoorExpanded props,
Vector3 drawPos, Rot4 rotation, bool split,
out Mesh mesh, out Matrix4x4 matrix)
@@ -1072,63 +319,19 @@ private static void DrawFrameParams(ThingDef def, CompProperties_DoorExpanded pr
matrix = Matrix4x4.TRS(graphicVector, rotQuat, scaleVector);
}
- public static Rot4 DoorRotationAt(ThingDef def, CompProperties_DoorExpanded props, IntVec3 loc, Rot4 rot, Map map)
- {
- if (!def.rotatable)
- {
- var size = def.Size;
- if ((size.x == 1 && size.z == 1) || props.doorType is DoorType.StretchVertical or DoorType.Stretch)
- rot = Building_Door.DoorRotationAt(loc, map);
- }
- if (!props.rotatesSouth && rot == Rot4.South)
- rot = Rot4.North;
- return rot;
- }
-
- public override IEnumerable GetGizmos()
- {
- foreach (var gizmo in base.GetGizmos())
- {
- yield return gizmo;
- }
- if (Faction == Faction.OfPlayer)
- {
- yield return new Command_Toggle
- {
- defaultLabel = "CommandToggleDoorHoldOpen".Translate(),
- defaultDesc = "CommandToggleDoorHoldOpenDesc".Translate(),
- hotKey = KeyBindingDefOf.Misc3,
- icon = TexCommand.HoldOpen,
- isActive = () => holdOpenInt,
- toggleAction = () => holdOpenInt = !holdOpenInt,
- };
- if (DebugSettings.godMode)
- {
- yield return new Command_Toggle
- {
- defaultLabel = "DEV: Open",
- defaultDesc = "debug".Translate(),
- hotKey = KeyBindingDefOf.Misc3,
- icon = TexCommand.HoldOpen,
- isActive = () => OpenInt,
- toggleAction = () => OpenInt = !OpenInt,
- };
- }
- }
- }
-
private void ClearReachabilityCache(Map map)
{
map.reachability.ClearCache();
- freePassageWhenClearedReachabilityCache = FreePassage;
+ //freePassageWhenClearedReachabilityCache = FreePassage;
}
- private void CheckClearReachabilityCacheBecauseOpenedOrClosed()
+ // This exists to expose draw vectors for debugging purposes.
+ internal class DebugDrawVectors
{
- if (Spawned)
- {
- Map.reachability.ClearCacheForHostile(this);
- }
+ public float openPct;
+ public Vector3 offsetVector, scaleVector, graphicVector;
}
+
+ internal DebugDrawVectors debugDrawVectors = new();
}
}
diff --git a/Source/Building_DoorRegionHandler.cs b/Source/Building_DoorRegionHandler.cs
index aa94917..21df54b 100644
--- a/Source/Building_DoorRegionHandler.cs
+++ b/Source/Building_DoorRegionHandler.cs
@@ -12,181 +12,24 @@ namespace DoorsExpanded
///
/// Door Region Handler
///
- /// What: These are children doors spawned inside a larger door.
- ///
- /// Why: This class is used instead of rewriting the base RimWorld code for
- /// handling regions. Regions do not handle large doors well. So this class
- /// will add smaller, invisible doors, inside a bigger door.
+ /// Now deprecated code. This will exist only to destroy previously existing invisible doors.
+ /// Previously this was used in RimWorld as a way to have a door spread across as many tiles as needed.
+ /// A 3x5 door would simply be filled with invisible doors that acted all at once.
+ ///
+ /// As this is no longer necessary, previously saved DoorRegionHandlers will now simply delete after
+ /// their first tick.
///
///
+ [Obsolete("No longer in use. RimWorld 1.5 introduced the MultiTileDoor and Invisible Doors inside " +
+ "larger frames are no longer needed.")]
public class Building_DoorRegionHandler : Building_Door
{
- private Building_DoorExpanded parentDoor;
-
- public Building_DoorExpanded ParentDoor
- {
- get => parentDoor;
- set => parentDoor = value;
- }
-
- // A harmony patch ensures that null or empty mouseover labels are not displayed.
- public override string LabelMouseover => null;
-
- public override string Label => parentDoor.Label;
-
- public override string LabelShort => parentDoor.LabelShort;
-
- // Following Building_Door fields are going to be synced with Building_DoorExpanded (handled in that class):
- // private bool openInt - since bool Open property is inlined and thus cannot be harmony patched
-
- // Other fields are ignored.
-
- // Following Building_Door non-virtual properties/methods are harmony patched to delegate to ParentDoor:
- // public bool FreePassage
- // public int TicksTillFullyOpened
- // public bool WillCloseSoon
- // - Note: Although only used by Building_Door.FreePassage, it could be used outside of vanilla code.
- // public bool BlockedOpenMomentary
- // public bool SlowsPawns
- // public int TicksToOpenNow
- // public void CheckFriendlyTouched(Pawn p)
- // public void Notify_PawnApproaching(Pawn p, int moveCost)
- // public bool CanPhysicallyPass(Pawn p)
- // protected void DoorOpen(int ticksToClose) - in case another subclass calls this
- // protected bool DoorTryClose() - in case another subclass calls this
- // public void StartManualOpenBy(Pawn opener)
- // public void StartManualCloseBy(Pawn closer)
- // - Note: This is inlined, so can only patch its caller Pawn_PathFollower.TryEnterNextPathCell
-
- // Following Building_Door methods are left as-is (they might have some extraneous yet non-harmful behavior, which is fine):
- // public override void PostMake()
- // public override void DeSpawn(DestroyMode mode = DestroyMode.Vanish)
-
- // Other methods are overriden here.
-
- public new bool Open
- {
- get => Building_Door_openInt(this);
- set => Building_Door_openInt(this) = value;
- }
-
- private static readonly AccessTools.FieldRef Building_Door_openInt =
- AccessTools.FieldRefAccess("openInt");
-
- private static readonly AccessTools.FieldRef Building_Door_holdOpenInt =
- AccessTools.FieldRefAccess("holdOpenInt");
-
- private static readonly AccessTools.FieldRef Thing_positionInt =
- AccessTools.FieldRefAccess("positionInt");
-
- public override bool FireBulwark => ParentDoor.FireBulwark;
-
- public override void SpawnSetup(Map map, bool respawningAfterLoad)
- {
- TLog.Log(this);
- // See HarmonyPatches.InvisDoorSpawnSetupTranspiler.
- base.SpawnSetup(map, respawningAfterLoad);
- }
-
- public override void DeSpawn(DestroyMode mode = DestroyMode.Vanish)
- {
- TLog.Log(this);
- // This check is necessary to prevent errors during operations that despawn all things in the same cell,
- // since despawning/destroying parent doors also destroys their invis doors.
- if (Spawned)
- base.DeSpawn(mode);
- }
-
- public override void Destroy(DestroyMode mode = DestroyMode.Vanish)
- {
- TLog.Log(this);
- // This check is necessary to prevent errors during operations that destroy all things in the same cell,
- // since despawning/destroying parent doors also destroys their invis doors.
- if (!Destroyed)
- base.Destroy(mode);
- }
-
- public override void ExposeData()
- {
- base.ExposeData();
- // This roundabout way of setting parentDoor is to handle the case where parentDoor is no longer a Building_DoorExpanded
- // (potentially due to XML def/patch changes), in which case, we invalidate the position to prevent spawning this invis door.
- var tempParentDoor = (ILoadReferenceable)parentDoor;
- Scribe_References.Look(ref tempParentDoor, nameof(parentDoor));
- parentDoor = tempParentDoor as Building_DoorExpanded;
- if (tempParentDoor is not null && parentDoor is null)
- {
- if (TLog.Enabled)
- TLog.Log(this, $"{this} has invalid parentDoor type {tempParentDoor.GetType()} - invalidating position to avoid spawning");
- Thing_positionInt(this) = IntVec3.Invalid;
- }
- }
-
- public override void SetFaction(Faction newFaction, Pawn recruiter = null)
- {
- // This check is necessary to prevent infinite loop between this method and Building_DoorExpanded.SetFaction.
- if (newFaction == Faction)
- return;
- base.SetFaction(newFaction, recruiter);
- ParentDoor.SetFaction(newFaction, recruiter);
- }
-
public override void Tick()
{
- // Sanity checks. These are inexpensive and thus done every tick.
- var parentDoor = ParentDoor;
- if (parentDoor is not { Spawned: true })
- {
- var stateStr = parentDoor is null ? "null" : parentDoor.Destroyed ? "destroyed" : "unspawned";
- Log.Error($"{this}.ParentDoor is unexpectedly {stateStr} - destroying this");
- Destroy();
- return;
- }
- if (Faction != parentDoor.Faction)
- SetFaction(parentDoor.Faction);
-
- // Some mods (such as OpenedDoorsDontBlockLight) directly read ticksSinceOpen or ticksUntilClose fields,
- // since no public accessor exists for those fields, so for compatibility with such mods, copy them from parent door here.
- ticksSinceOpen = parentDoor.TicksSinceOpen;
- ticksUntilClose = parentDoor.TicksUntilClose;
-
- // See HarmonyPatches.InvisDoorTickTranspiler.
- base.Tick();
- }
-
- public override void PostApplyDamage(DamageInfo dinfo, float totalDamageDealt)
- {
- // Note: The invis door def has useHitPoints=true, so invis doors never take damage.
- // A harmony patch allows PathFinder.IsDestroyable to still return true for invis doors.
- ParentDoor.TakeDamage(dinfo);
- }
-
- public override bool PawnCanOpen(Pawn p) => ParentDoor.PawnCanOpen(p);
-
- public override bool BlocksPawn(Pawn p) => ParentDoor.BlocksPawn(p);
-
- // Only for exposing public access to Building_Door.DoorOpen.
- public new void DoorOpen(int ticksToClose) => base.DoorOpen(ticksToClose);
-
- // Only for exposing public access to Building_Door.DoorTryClose.
- public new void DoorTryClose() => base.DoorTryClose();
-
- public override void Draw()
- {
- // Do nothing, not even call base.Draw(), since this is an invisible door.
- }
-
- public override IEnumerable GetGizmos()
- {
- // This invis door shouldn't be selectable to get gizmos, but just in case, return empty.
- return Enumerable.Empty();
- }
-
- public override string ToString()
- {
- if (parentDoor is null)
- return base.ToString() + " (NO PARENT)";
- return base.ToString() + $" ({parentDoor}.invisDoors[{parentDoor.InvisDoors.IndexOf(this)}])";
+ Log.Warning($"{this} remains from RimWorld v1.4 - destroying this to remain in-line with new" +
+ "RW 1.5 MultiTileDoor code for DoorsExpanded");
+ Destroy();
+ return;
}
}
}
diff --git a/Source/Building_DoorRemote.cs b/Source/Building_DoorRemote.cs
index 739d746..0f0288b 100644
--- a/Source/Building_DoorRemote.cs
+++ b/Source/Building_DoorRemote.cs
@@ -33,34 +33,38 @@ public bool SecuredRemotely
{
securedRemotely = value;
// Reactive update due to Forbidden depending on SecuredRemotely (via ForcedClosed).
- Notify_ForbiddenInputChanged();
+ ForbidUtility.SetForbidden(this, value);
}
}
- protected override bool OpenInt
+ protected bool OpenInt
{
set
{
- base.OpenInt = value;
+ base.openInt = value;
// Reactive update due to Forbidden depending on OpenInt (via Open via ForcedClosed).
- Notify_ForbiddenInputChanged();
+ ForbidUtility.SetForbidden(this, value);
+ }
+ }
+
+ protected bool HoldOpenInt
+ {
+ set
+ {
+ base.holdOpenInt = value;
}
}
// When secured remotely, only care about whether its held open remotely;
// else can be held open either remotely or by gizmo.
- public override bool HoldOpen => securedRemotely ? HoldOpenRemotely : HoldOpenRemotely || base.HoldOpen;
+ public bool HoldOpen => securedRemotely ? HoldOpenRemotely : HoldOpenRemotely || base.HoldOpen;
public bool HoldOpenRemotely => Button is { ButtonOn: true };
public bool ForcedClosed => SecuredRemotely && !Open;
- public override bool Forbidden => ForcedClosed || base.Forbidden;
+ public bool Forbidden => ForcedClosed || ForbidUtility.IsForbidden(this, this.Faction);
- // For purposes of determining whether a door can be closed automatically,
- // treat a powered door that's linked to an enabled button (NeedsPower is false) as always being "friendly touched".
- internal protected override bool FriendlyTouchedRecently =>
- button is { NeedsPower: false } && DoorPowerOn || base.FriendlyTouchedRecently;
public override void ExposeData()
{
@@ -75,12 +79,11 @@ public override void ExposeData()
private static readonly float LockDrawY =
AltitudeLayer.MetaOverlays.AltitudeFor() + Altitudes.AltInc * 6; // from OverlayDrawer.RenderQuestionMarkOverlay
- public override void Draw()
+ protected override void DrawAt(Vector3 drawLoc, bool flip = false)
{
if (ForcedClosed)
{
// This is based off OverlayDrawer.RenderQuestionMarkOverlay/RenderPulsingOverlayInternal, with customized parameters.
- var drawLoc = DrawPos;
drawLoc.y = LockDrawY;
var sineInput = (Time.realtimeSinceStartup + 397f * (thingIDNumber % 571)) * LockPulseFrequency;
var alpha = (Mathf.Sin(sineInput) + 1f) * 0.5f;
@@ -90,7 +93,7 @@ public override void Draw()
drawBatch.DrawMesh(MeshPool.plane05, Matrix4x4.TRS(drawLoc, Quaternion.identity, Vector3.one), material,
layer: 0, renderInstanced: true);
}
- base.Draw();
+ base.DrawAt(drawLoc, flip);
}
private static readonly AccessTools.FieldRef OverlayDrawer_drawBatch =
@@ -161,7 +164,7 @@ public override IEnumerable GetGizmos()
public void Notify_ButtonPushed()
{
- if (DoorPowerOff)
+ if (powerComp is CompPowerTrader power && !power.PowerOn)
{
Messages.Message("PH_CannotOpenRemotelyWithoutPower".Translate(Label), this, MessageTypeDefOf.RejectInput);
return;
diff --git a/Source/CompProperties_DoorExpanded.cs b/Source/CompProperties_DoorExpanded.cs
index e08a316..45065b5 100644
--- a/Source/CompProperties_DoorExpanded.cs
+++ b/Source/CompProperties_DoorExpanded.cs
@@ -71,7 +71,11 @@ public override void ResolveReferences(ThingDef parentDef)
if (typeof(Building_DoorRemote).IsAssignableFrom(parentDef.thingClass))
{
var remoteDoorDescription = "PH_RemoteDoor".Translate();
- if (!parentDef.description.Contains(remoteDoorDescription))
+ if(parentDef.description is null)
+ {
+ parentDef.description = remoteDoorDescription;
+ }
+ else if(!parentDef.description.Contains(remoteDoorDescription))
{
parentDef.description += " " + remoteDoorDescription;
}
@@ -106,6 +110,7 @@ public override void ResolveReferences(ThingDef parentDef)
.FindAll(def => typeof(Building_DoorRemoteButton).IsAssignableFrom(def.thingClass));
buildingProps.relatedBuildCommands = cachedDoorRemoteDefs;
}
+
}
[ThreadStatic]
diff --git a/Source/DebugInspectorPatches.cs b/Source/DebugInspectorPatches.cs
deleted file mode 100644
index 099dcc1..0000000
--- a/Source/DebugInspectorPatches.cs
+++ /dev/null
@@ -1,455 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Diagnostics;
-using System.Linq;
-using System.Reflection;
-using System.Reflection.Emit;
-using System.Text;
-using HarmonyLib;
-using RimWorld;
-using UnityEngine;
-using Verse;
-using Verse.AI;
-
-namespace DoorsExpanded
-{
- public static class DebugViewSettingsMoreDraw
- {
- public static bool drawDoorTempEqualization;
- }
-
- public static class DebugViewSettingsMoreWrite
- {
- public static bool writeTemperature;
- public static bool writeEdificeGrid;
- public static bool writeDoors;
- public static bool writePatchCallRegistry;
- }
-
- public static class DebugInspectorPatches
- {
- public static void PatchDebugInspector()
- {
- //var harmony = HarmonyPatches.harmony;
- //var type = typeof(DebugInspectorPatches);
- //harmony.Patch(original: AccessTools.Constructor(typeof(Dialog_DebugSettingsMenu)),
- // transpiler: new HarmonyMethod(type, nameof(AddMoreDebugViewSettingsTranspiler)));
- //harmony.Patch(original: AccessTools.Method(typeof(Dialog_DebugSettingsMenu), "DoListingItems"),
- // transpiler: new HarmonyMethod(type, nameof(AddMoreDebugViewSettingsTranspiler)),
- // postfix: new HarmonyMethod(type, nameof(AddMoreDebugViewSettingsPostfix)));
- //harmony.Patch(original: AccessTools.Method(typeof(EditWindow_DebugInspector), "CurrentDebugString"),
- // transpiler: new HarmonyMethod(type, nameof(EditWindowDebugInspectorTranspiler)));
- //harmony.Patch(original: AccessTools.Method(typeof(District), "DebugString"),
- // postfix: new HarmonyMethod(type, nameof(DistrictMoreDebugString)));
- //harmony.Patch(original: AccessTools.Method(typeof(Room), nameof(Room.DebugString)),
- // postfix: new HarmonyMethod(type, nameof(RoomMoreDebugString)));
- //harmony.Patch(original: AccessTools.Method(typeof(DoorsDebugDrawer), nameof(DoorsDebugDrawer.DrawDebug)),
- // postfix: new HarmonyMethod(type, nameof(AddMoreDoorsDebugDrawer)));
- }
-
- private static Dictionary patchCallRegistry;
-
- // Note: Callers of RegisterPatch and RegisterPatchCalled need to have #define PATCH_CALL_REGISTRY in their file,
- // since its callers of Conditional-attributed methods that are ellided rather than the method itself.
- [Conditional("PATCH_CALL_REGISTRY")]
- public static void RegisterPatch(string name)
- {
- if (name is not null)
- {
- patchCallRegistry ??= new Dictionary();
- patchCallRegistry[name] = false;
- }
- }
-
- [Conditional("PATCH_CALL_REGISTRY")]
- public static void RegisterPatchCalled(string name) => patchCallRegistry[name] = true;
-
- // Dialog_DebugSettingsMenu constructor (for RW 1.2)
- // Dialog_DebugSettingsMenu.DoListingItems
- public static IEnumerable AddMoreDebugViewSettingsTranspiler(
- IEnumerable instructions)
- {
- // This transforms the following code:
- // typeof(DebugViewSettings).GetFields()
- // into:
- // AddMoreDebugViewSettings(typeof(DebugViewSettings).GetFields())
-
- var instructionList = instructions.AsList();
- var debugViewSettingsIndex = instructionList.FindIndex(instr => instr.OperandIs(typeof(DebugViewSettings)));
- if (debugViewSettingsIndex >= 0)
- {
- var getFieldsIndex = instructionList.FindIndex(debugViewSettingsIndex + 1, instr => instr.Calls(methodof_Type_GetFields));
- instructionList.SafeInsertRange(getFieldsIndex + 1, new[]
- {
- new CodeInstruction(OpCodes.Call, AccessTools.Method(typeof(DebugInspectorPatches), nameof(AddMoreDebugViewSettings))),
- });
- }
- return instructionList;
- }
-
- private static FieldInfo[] AddMoreDebugViewSettings(FieldInfo[] fields)
- {
- var fieldList = fields.ToList();
- var fieldsToInsert = typeof(DebugViewSettingsMoreWrite).GetFields().AsEnumerable();
- if (patchCallRegistry is null)
- fieldsToInsert = fieldsToInsert.Where(field => field != fieldof_MoreDebugViewSettings_writePatchCallRegistry);
- fieldList.InsertRange(fieldList.IndexOf(fieldof_DebugViewSettings_writePathCosts) + 1, fieldsToInsert);
- fieldList.InsertRange(fieldList.IndexOf(fieldof_DebugViewSettings_drawDoorsDebug) + 1,
- typeof(DebugViewSettingsMoreDraw).GetFields());
- return fieldList.ToArray();
- }
-
- private static readonly MethodInfo methodof_Type_GetFields = AccessTools.Method(typeof(Type), nameof(Type.GetFields));
- private static readonly FieldInfo fieldof_DebugViewSettings_drawDoorsDebug =
- AccessTools.Field(typeof(DebugViewSettings), nameof(DebugViewSettings.drawDoorsDebug));
- private static readonly FieldInfo fieldof_DebugViewSettings_writePathCosts =
- AccessTools.Field(typeof(DebugViewSettings), nameof(DebugViewSettings.writePathCosts));
- private static readonly FieldInfo fieldof_MoreDebugViewSettings_writePatchCallRegistry =
- AccessTools.Field(typeof(DebugViewSettingsMoreWrite), nameof(DebugViewSettingsMoreWrite.writePatchCallRegistry));
-
- public static void AddMoreDebugViewSettingsPostfix()
- {
- // We do dynamic patching here to try to avoid the performance overhead in the patched methods when toggled off.
- if (temperatureEqualizationMethodsPatched != DebugViewSettingsMoreDraw.drawDoorTempEqualization)
- {
- foreach (var pair in temperatureEqualizationMethods)
- {
- var origMethod = pair.Key;
- var patchMethod = pair.Value;
- if (temperatureEqualizationMethodsPatched)
- HarmonyPatches.harmony.Unpatch(origMethod, patchMethod);
- else
- HarmonyPatches.harmony.Patch(origMethod, transpiler: new HarmonyMethod(patchMethod));
- }
- temperatureEqualizationMethodsPatched = DebugViewSettingsMoreDraw.drawDoorTempEqualization;
- }
- }
-
- private static bool temperatureEqualizationMethodsPatched = false;
- private static readonly Dictionary temperatureEqualizationMethods = new()
- {
- [AccessTools.Method(typeof(RoomTempTracker), nameof(RoomTempTracker.EqualizeTemperature))] =
- AccessTools.Method(typeof(DebugInspectorPatches), nameof(RoomTempTracker_EqualizeTemperature_Transpiler)),
- [AccessTools.Method(typeof(GenTemperature), nameof(GenTemperature.EqualizeTemperaturesThroughBuilding))] =
- AccessTools.Method(typeof(DebugInspectorPatches), nameof(GenTemperature_EqualizeTemperaturesThroughBuilding_Transpiler)),
- };
-
- public static IEnumerable RoomTempTracker_EqualizeTemperature_Transpiler(IEnumerable instructions)
- {
- // This transforms the following code:
- // this.room.Temperature += WallEqualizationTempChangePerInterval()
- // into:
- // RoomTempTracker_EqualizeTemperature_SetRoomTemperature(this.room,
- // this.room.Temperature + WallEqualizationTempChangePerInterval())
-
- return Transpilers.MethodReplacer(instructions,
- AccessTools.PropertySetter(typeof(Room), nameof(Room.Temperature)),
- AccessTools.Method(typeof(DebugInspectorPatches),
- nameof(RoomTempTracker_EqualizeTemperature_SetRoomTemperature)));
- }
-
- private static void RoomTempTracker_EqualizeTemperature_SetRoomTemperature(Room room, float temperature)
- {
- SetRoomTemperatureAndDrawDelta(room, temperature, Color.red);
- }
-
- public static IEnumerable GenTemperature_EqualizeTemperaturesThroughBuilding_Transpiler(
- IEnumerable instructions)
- {
- // This transforms the following code:
- // room.Temperature += tempDelta
- // into:
- // SetRoomTemperatureAndDrawDelta(room, room.Temperature + tempDelta)
-
- return Transpilers.MethodReplacer(instructions,
- AccessTools.PropertySetter(typeof(Room), nameof(Room.Temperature)),
- AccessTools.Method(typeof(DebugInspectorPatches),
- nameof(GenTemperature_EqualizeTemperaturesThroughBuilding_SetRoomTemperature)));
- }
-
- private static void GenTemperature_EqualizeTemperaturesThroughBuilding_SetRoomTemperature(Room room, float temperature)
- {
- SetRoomTemperatureAndDrawDelta(room, temperature, Color.white);
- }
-
- private static void SetRoomTemperatureAndDrawDelta(Room room, float temperature, Color color)
- {
- if (room.IsDoorway)
- {
- var tempDelta = temperature - room.Temperature;
- var door = room.FirstRegion.door;
- if (door is Building_DoorRegionHandler)
- Log.Message($"[{color}] temperature of {door}: {room.Temperature} => {temperature}");
- if (tempDelta != 0f)
- MoteMaker.ThrowText(room.ExtentsClose.CenterVector3, room.Map, $"{tempDelta:+0.##;-0.##}", color);
- }
- room.Temperature = temperature;
- }
-
- // EditWindow_DebugInspector.CurrentDebugString
- public static IEnumerable EditWindowDebugInspectorTranspiler(IEnumerable instructions,
- MethodBase method, ILGenerator ilGen)
- {
- var methodof_UI_MouseCell = AccessTools.Method(typeof(UI), nameof(UI.MouseCell));
- var methodof_object_ToString = AccessTools.Method(typeof(object), nameof(ToString));
- var instructionList = instructions.AsList();
- var locals = new Locals(method, ilGen);
-
- // Assume first found StringBuilder var (currently the only StringBuilder var) is the one we want.
- var stringBuilderVar = locals.FromStloc(instructionList.Find(instr =>
- locals.IsStloc(instr, out var local) && local.LocalType == typeof(StringBuilder)));
-
- var mouseCellIndex = instructionList.FindIndex(instr => instr.Calls(methodof_UI_MouseCell));
- var mouseCellVar = locals.FromStloc(instructionList[mouseCellIndex + 1]);
-
- var mouseCellToStringIndex = instructionList.FindSequenceIndex(
- instr => locals.IsLdloca(instr, mouseCellVar),
- instr => instr.Is(OpCodes.Constrained, typeof(IntVec3)),
- instr => instr.Calls(methodof_object_ToString));
- instructionList.SafeReplaceRange(mouseCellToStringIndex, 3, new[]
- {
- new CodeInstruction(OpCodes.Call,
- AccessTools.Method(typeof(DebugInspectorPatches), nameof(MousePositionToString))),
- });
-
- var writePathCostsFlagIndex = instructionList.FindIndex(
- instr => instr.LoadsField(fieldof_DebugViewSettings_writePathCosts));
- var nextFlagIndex = instructionList.FindIndex(writePathCostsFlagIndex + 1, IsDebugViewSettingFlagAccess);
- // Note: Not using SafeInsertRange, since labels need to be transferred to a new instruction in the middle.
- instructionList.InsertRange(nextFlagIndex - 1, new[]
- {
- stringBuilderVar.ToLdloc(),
- mouseCellVar.ToLdloc(),
- new CodeInstruction(OpCodes.Call,
- AccessTools.Method(typeof(DebugInspectorPatches), nameof(WriteMorePathCostsDebugOutput))),
- stringBuilderVar.ToLdloc().TransferLabelsAndBlocksFrom(instructionList[nextFlagIndex]),
- mouseCellVar.ToLdloc(),
- new CodeInstruction(OpCodes.Call,
- AccessTools.Method(typeof(DebugInspectorPatches), nameof(WriteMoreDebugOutput))),
- });
-
- return instructionList;
- }
-
- private static string MousePositionToString()
- {
- var mousePos = UI.MouseMapPosition();
- return $"({mousePos.x:000.00}, {mousePos.z:000.00})";
- }
-
- private static bool IsDebugViewSettingFlagAccess(CodeInstruction instruction) =>
- instruction.opcode == OpCodes.Ldsfld && ((FieldInfo)instruction.operand).DeclaringType == typeof(DebugViewSettings);
-
- private static void WriteMorePathCostsDebugOutput(StringBuilder debugString, IntVec3 mouseCell)
- {
- if (Find.Selector.SingleSelectedObject is Pawn pawn)
- {
- debugString.AppendLine($"CalculatedCostAt({mouseCell}, false, {pawn.Position}): " +
- pawn.Map.pathing.For(pawn).pathGrid.CalculatedCostAt(mouseCell, perceivedStatic: false, pawn.Position));
- debugString.AppendLine($"CostToMoveIntoCell({pawn}, {mouseCell}): " + CostToMoveIntoCell(pawn, mouseCell));
- using var pawnPath = pawn.Map.pathFinder.FindPath(pawn.Position, mouseCell, pawn);
- debugString.AppendLine($"FindPath({pawn.Position}, {mouseCell}, {pawn}).TotalCost: " + pawnPath.TotalCost);
- }
- }
-
- private static readonly Func CostToMoveIntoCell =
- (Func)Delegate.CreateDelegate(typeof(Func),
- AccessTools.Method(typeof(Pawn_PathFollower), "CostToMoveIntoCell", new[] { typeof(Pawn), typeof(IntVec3) }));
-
- private static void WriteMoreDebugOutput(StringBuilder debugString, IntVec3 mouseCell)
- {
- var map = Find.CurrentMap;
-
- if (DebugViewSettingsMoreWrite.writeTemperature)
- {
- debugString.AppendLine("---");
- debugString.AppendLine("Temperature: " +
- (GenTemperature.TryGetTemperatureForCell(mouseCell, map, out var temperature) ? $"{temperature:f1}" : ""));
- }
-
- if (DebugViewSettingsMoreWrite.writeEdificeGrid)
- {
- debugString.AppendLine("---");
- debugString.AppendLine("Building at edifice grid: " + map.edificeGrid[mouseCell]);
- }
-
- if (DebugViewSettingsMoreWrite.writeDoors)
- {
- debugString.AppendLine("---");
- var pawn = Find.Selector.SingleSelectedObject as Pawn;
- if (pawn is not null)
- {
- debugString.AppendLine("From selected pawn " + pawn + " to door");
- debugString.AppendLine("- CaresAboutForbidden(p, false): " + ForbidUtility.CaresAboutForbidden(pawn, false));
- //debugString.AppendLine("- mindState.maxDistToSquadFlag: " + pawn.mindState.maxDistToSquadFlag);
- }
-
- foreach (var thing in map.thingGrid.ThingsAt(mouseCell))
- {
- if (thing is Building_Door door)
- {
- debugString.AppendLine("Door: " + door);
- debugString.AppendLine("- Open: " + door.Open);
- debugString.AppendLine("- HoldOpen: " + door.HoldOpen);
- debugString.AppendLine("- FreePassage: " + door.FreePassage);
- debugString.AppendLine("- WillCloseSoon: " + door.WillCloseSoon);
- debugString.AppendLine("- BlockedOpenMomentary: " + door.BlockedOpenMomentary);
- debugString.AppendLine("- SlowsPawns: " + door.SlowsPawns);
- debugString.AppendLine("- TicksToOpenNow: " + door.TicksToOpenNow);
- debugString.AppendLine("- FriendlyTouchedRecently: " +
- methodof_Building_Door_FriendlyTouchedRecently.Invoke(door, Array.Empty