From 5d351a14d2225f5c940671f7c8197c566123a79d Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Sat, 4 Sep 2021 03:14:09 +0100 Subject: [PATCH] Add new signal type: no-entry signal This is only passable in one direction, but does not have a signal or show an aspect in the opposite direction Add a setting for whether this is shown in the signal UI. Off by default. --- docs/newgrf-additions-nml.html | 26 ++++++++++++ docs/newgrf-additions.html | 22 ++++++++++ media/baseset/CMakeLists.txt | 1 + media/baseset/extra_signals.grf | Bin 0 -> 1571 bytes media/baseset/extra_signals/extra_signals.nfo | 23 ++++++++++ media/baseset/extra_signals/extra_signals.png | Bin 0 -> 7602 bytes src/console_cmds.cpp | 3 +- src/gfxinit.cpp | 9 ++++ src/lang/english.txt | 4 ++ src/newgrf.cpp | 17 ++++++++ src/newgrf.h | 3 ++ src/newgrf_railtype.cpp | 2 + src/pathfinder/npf/npf.cpp | 5 ++- src/pathfinder/yapf/yapf_costrail.hpp | 36 +++++++++++----- src/pbs.cpp | 1 + src/rail.h | 1 + src/rail_cmd.cpp | 40 +++++++++++++++--- src/rail_gui.cpp | 24 +++++++++-- src/rail_map.h | 9 ++++ src/saveload/extended_ver_sl.cpp | 1 + src/saveload/extended_ver_sl.h | 1 + src/settings_gui.cpp | 1 + src/settings_type.h | 1 + src/signal.cpp | 2 +- src/signal_func.h | 11 ++++- src/signal_type.h | 5 ++- src/table/newgrf_debug_data.h | 5 ++- src/table/settings.ini | 9 ++++ src/table/sprites.h | 9 +++- src/train_cmd.cpp | 12 ++++-- src/widgets/rail_widget.h | 4 ++ 31 files changed, 256 insertions(+), 31 deletions(-) create mode 100644 media/baseset/extra_signals.grf create mode 100644 media/baseset/extra_signals/extra_signals.nfo create mode 100644 media/baseset/extra_signals/extra_signals.png diff --git a/docs/newgrf-additions-nml.html b/docs/newgrf-additions-nml.html index 087cf68b38..e693c344b6 100644 --- a/docs/newgrf-additions-nml.html +++ b/docs/newgrf-additions-nml.html @@ -42,6 +42,13 @@ Programmable pre-signals have a signal type (getbits(extra_callback_info2, 16, 8)) of 6. + enable_no_entry_signals0 or 1 + + Enable no-entry signal graphics in railtype signals.
+ No-entry signals have a signal type (getbits(extra_callback_info2, 16, 8)) of 7.
+ No-entry signals always have a signal state of red. + + enable_restricted_signals0 or 1 Enable restricted signal flag in railtype signals.
@@ -132,6 +139,18 @@ + NO_ENTRY_SIGNAL16 + + No-entry signals +

No-entry signal graphics come in groups of 8. These groups contain sprites in the same order as the red sprites of 1275-1290 in trg1[r].grf and Action 5 type 4 (signals); + red only, for each of: SW-facing, NE-facing, NW-facing, SE-facing, E-facing, W-facing, S-facing, N-facing. + + + + +
GroupContents
0Semaphore no-entry signals
1Lighted no-entry signals
+ +

Signal graphics using switches

@@ -159,6 +178,13 @@ Programmable pre-signals have a signal type (getbits(extra_callback_info2, 16, 8)) of 6. + enable_no_entry_signals0 or 1 + + Enable no-entry signal graphics.
+ No-entry signals have a signal type (getbits(extra_callback_info2, 16, 8)) of 7.
+ No-entry signals always have a signal state of red. + + enable_restricted_signals0 or 1 Enable restricted signal flag.
diff --git a/docs/newgrf-additions.html b/docs/newgrf-additions.html index 8e9887f137..8b98501bba 100644 --- a/docs/newgrf-additions.html +++ b/docs/newgrf-additions.html @@ -223,6 +223,12 @@ The property length is 1 byte. 0 is disabled (default). 1 is enabled.

This is indicated by the feature name: action0_railtype_programmable_signals, version 1

+

Enable custom signal sprites for no-entry signals (mappable property: railtype_enable_no_entry_signals)

+

This enables Action 2/3 - Railtype custom signal sprites for no-entry signals.
+ No-entry signals have the signal type value: 07.
+ The property length is 1 byte. 0 is disabled (default). 1 is enabled. +

+

This is indicated by the feature name: action0_railtype_no_entry_signals, version 1

Enable restricted signal flag for custom signal sprites (mappable property: railtype_enable_restricted_signals)

This applies to Action 2/3 - Railtype custom signal sprites.
When enabled, bit 24 of variable 18 (extra callback info) is set if the signal is restricted (has a routing restriction program attached).
@@ -314,6 +320,12 @@ The Action 0 Id field is not used, the value is ignored.

This is indicated by the feature name: action0_signals_programmable_signals, version 1

+

Enable custom signal sprites for no-entry signals (mappable property: signals_enable_no_entry_signals)

+

This enables Action 2/3 Signals (Feature 0E) custom signal sprites for no-entry signals for this GRF.
+ No-entry signals have the signal type value: 07.
+ The property length is 1 byte. 0 is disabled (default). 1 is enabled. +

+

This is indicated by the feature name: action0_signals_no_entry_signals, version 1

Enable restricted signal flag for custom signal sprites (mappable property: signals_enable_restricted_signals)

This applies to Action 2/3 Signals (Feature 0E) custom signal sprites for this GRF.
When enabled, bit 24 of variable 18 (extra callback info) is set if the signal is restricted (has a routing restriction program attached).
@@ -418,5 +430,15 @@

This is indicated by the feature name: action5_programmable_signals, version 1

+

No-entry signal graphics (mappable type: no_entry_signals)

+

No-entry signal graphics come in groups of 8. These groups contain sprites in the same order as the red sprites of 1275-1290 in trg1[r].grf and Action 5 type 4 (signals); + red only, for each of: SW-facing, NE-facing, NW-facing, SE-facing, E-facing, W-facing, S-facing, N-facing. + + + + +
GroupContents
0Semaphore no-entry signals
1Lighted no-entry signals
+

+

This is indicated by the feature name: action5_no_entry_signals, version 1

diff --git a/media/baseset/CMakeLists.txt b/media/baseset/CMakeLists.txt index dc5ad1ac09..465006d88a 100644 --- a/media/baseset/CMakeLists.txt +++ b/media/baseset/CMakeLists.txt @@ -19,6 +19,7 @@ set(BASESET_OTHER_SOURCE_FILES ${CMAKE_CURRENT_SOURCE_DIR}/orig_extra.grf ${CMAKE_CURRENT_SOURCE_DIR}/innerhighlight.grf ${CMAKE_CURRENT_SOURCE_DIR}/progsignals.grf + ${CMAKE_CURRENT_SOURCE_DIR}/extra_signals.grf ${CMAKE_CURRENT_SOURCE_DIR}/route_step.grf ${CMAKE_CURRENT_SOURCE_DIR}/tracerestrict.grf ) diff --git a/media/baseset/extra_signals.grf b/media/baseset/extra_signals.grf new file mode 100644 index 0000000000000000000000000000000000000000..be14906a817e34af4a9d2483787fc75646824899 GIT binary patch literal 1571 zcmchYziSjh6vt7i>&ppi77=0q)3s%V#@`aNl+LM8!Jhn=bKz*{1FRtv&|Os-uLsq-^Xsx;qxK;I{q+r z8Dqw+{Fk$E5+aCU0j|LvcnFW-8N7g1SciA;9!9V$oAQJ_BhSf;a#7xv59G3Z`h4IZ z%GFQnjw)fU4xLiT+9VKe@A3v*-8tfjM*sNewBz~xNQYeX&yOxSuJ`sz?>`a*mcUa% z3+1L@s@Wn4mtn(VIDP=h=;)zy$brj9e@!q9NPp8M4hU)F1|&Km3OSw<1qHHZIyMOl zQ9@XUkkprX!xC@-;m)bUjKih*?oGPvM}TM}Zqa?rQ$;CEQ5V$He z!FrZld)~qD8?l>bXoN_IL~IdBweIS9(mas4ikoOn8q$D*7sgiaHEHQCXS!Rp_0kjK z_1U*yT!YvwOm<12U8Tz3I_6o^^j)4;K2P<1Uetco(aV2pF@r>4C(qN;_+*k_cmB|Z I{s?q_0Cg8|&j0`b literal 0 HcmV?d00001 diff --git a/media/baseset/extra_signals/extra_signals.nfo b/media/baseset/extra_signals/extra_signals.nfo new file mode 100644 index 0000000000..02c374e1a1 --- /dev/null +++ b/media/baseset/extra_signals/extra_signals.nfo @@ -0,0 +1,23 @@ +// Automatically generated by GRFCODEC. Do not modify! +// (Info version 32) +// Escapes: 2+ 2- 2< 2> 2u< 2u> 2/ 2% 2u/ 2u% 2* 2& 2| 2^ 2sto = 2s 2rst = 2r 2psto 2ror = 2rot 2cmp 2ucmp 2<< 2u>> 2>> +// Escapes: 71 70 7= 7! 7< 7> 7G 7g 7gG 7GG 7gg 7c 7C +// Escapes: D= = DR D+ = DF D- = DC Du* = DM D* = DnF Du<< = DnC D<< = DO D& D| Du/ D/ Du% D% +// Format: spritenum imagefile depth xpos ypos xsize ysize xrel yrel zoom flags + 0 sprites/extra_signals.png 8bpp 40 40 20 30 -9 -28 normal + 1 sprites/extra_signals.png 8bpp 10 40 20 30 -9 -28 normal + 2 sprites/extra_signals.png 8bpp 100 40 20 30 -9 -28 normal + 3 sprites/extra_signals.png 8bpp 70 40 20 30 -9 -28 normal + 4 sprites/extra_signals.png 8bpp 160 40 20 30 -9 -28 normal + 5 sprites/extra_signals.png 8bpp 130 40 20 30 -9 -28 normal + 6 sprites/extra_signals.png 8bpp 220 40 20 30 -9 -28 normal + 7 sprites/extra_signals.png 8bpp 190 40 20 30 -9 -28 normal + + 8 sprites/extra_signals.png 8bpp 20 10 4 22 -1 -20 normal + 9 sprites/extra_signals.png 8bpp 10 10 5 22 -2 -20 normal + 10 sprites/extra_signals.png 8bpp 40 10 5 22 -1 -20 normal + 11 sprites/extra_signals.png 8bpp 30 10 4 22 -1 -20 normal + 12 sprites/extra_signals.png 8bpp 60 10 5 22 -2 -20 normal + 13 sprites/extra_signals.png 8bpp 50 10 5 22 -1 -20 normal + 14 sprites/extra_signals.png 8bpp 80 10 6 22 -3 -20 normal + 15 sprites/extra_signals.png 8bpp 70 10 6 22 -3 -20 normal diff --git a/media/baseset/extra_signals/extra_signals.png b/media/baseset/extra_signals/extra_signals.png new file mode 100644 index 0000000000000000000000000000000000000000..6d195ac0cdf3080b4cef1da40aaecbaa1d32c02e GIT binary patch literal 7602 zcmV;j9ZlkiP) zaB^>EX>4U6ba`-PAZ2)IW&i+q+O3*tawNHOg#Y6dIs*3PH~<1L(+zZdeV$olFVpih zVCAi~4L9cXv{=fAJ}FFs1n-sRGI9kqHs^2j4jUUdI{jOTms`T72Q-1+%i z`1QIgpX)wyDe*JCzqZdC!sL4S@rJK4!us{P>z}{G{&`UNe(>{=G_qdX&y(bOe6NT6 zdC)lTi#mGyd8+I4p#8b=nabxYe^2ZEq2Jvv7aCEr!aym;lS1;(_x{cx=_{nk&+&ZE z+!vlJe0TgvseT?tKz>=?*H7<%4$v<_{(9wpkA4Y%4t|`UJJN5lte+V1;*Wm_<+tnU zd;IwG!0CHN@z+22@s)?a2Kip=_nvokGgl&7KZtsQ9ljpJjf;?{=WUhG##iBWdp-xB z-A}(6%KY|=&mBgHWaYY$gM}GxIM2@=HdD;;#KzAUH;K}*YGu+t7o~2GM zcRY@qLyXwboWeaar=EN1wYT2; z=ySx8;J`BKXrqrY=8SGK(BxT@`zKdcTxsQ1R$XoNHP+m~XXjmZ-EH?h_Oxippb4wi ztlO}8f;%w9$)}up+UaMUdBNIEH{WvWZMWZX=XcgVS^dlBzsOqnWGz0K(tYhaYg~1$ zeLW(GPKt6y#$pa+yeR_!Ix1(rhn%A_r=0l_DT)%AWKnLM1!asB<`ZJM;X8LfGWU=2 z=1TuZd5iy7=A2UZ|B*RI>i(LyKV;3+=k}Aaw+azQ_$jdgNsZefqKkK6sOll%cUjBtzP*5@sGF_*S!T0D^qoKO#_Dv5xC zg~-t1j2ySO!YoR0iJ<0c@eaMZYo{>^f!p=ehaJlvcc*Ucf%iIotYoAeM1^x^X@hX( z>^xHsyNB&>4TbqJ+HPasy2cHHocVKS>tpU}_ZV;lfrR4ZW^)bFGObiqztTI;x~;6c zS2kbvS^1`9b@|!}(~X%5Y($|b9bR+G2G*1X#)!lSJk#N)1(DSPbD7C&a?5V0ZI?FZ z?O96(dgNnsUn2~yM$mslZ(-$`TsXbi_LHEp@KXq8$kxtn_1>NU$I8HC1Uu&wvswi2 zOO);jVcp(ol?bgfAx|6iLRTvD;u8J(@{a>-l!Oxmy-@aEk+tJ*T>FEGycvL3W8&?s2U!RzC|R zgYMWh5~2Pu1p!+HQ1P%it+L42T(^1-l#xS%$)M*uYCiCp+QmaFVOH1eMSTi zaS2_}A9#wDzIOJ^{H7JD^2;zU`i3PYWV7`Aw4}~LrPhGfB0U$)GpMSyE93`8??%;H znFfo1PAGdtVAKt0q$E&c0T>_dR&h~iD;&{mO@6~Dr`Q6OtquU`Lq~`mU`u6W)?t9E zUN7?7EJ^f7R_Qb|0ehHY(gffvp4c-8A_ca(W1ZD%zo&Kv=zz=0xlfJz9WOm*7CX9u zga+Ee?QN3;9+8+D60-iagOP z7Dy)aDU>tTah^z5qP*z}1?c8H;NDTPrzk^vNbhb4%wNCNV2Z&lX-pID>A@k>IjT99 zlj4HQD!mB$Dh6K%g3!3nPMkMomfxVUHrw5SYy>sYw&-z*d{?+*EvIM@2%|^OLJi&- z!(FiLsr85z^K1+|pn%{n)H&1b$Lfs+zDvrxM+oe?n5Zdw70n%%r<^C_QjA0gJ{_~# z!*nay23eD!16k@R-_sR68X(Mcv%63iXY2suLno0!9OY2bfNue- z;ORP0^~wWCv2fU#5{Vs=V+W{;k7F)N@d0)#SLS(G*@BJA^-2lS;0!n{T8XDBPZ=$> znoE^%=SeB218a94e#|cYs##5QQ#S~;F)o#M;WyTL^8s9)aw8OlHUUdFhhE2MC&t@N z*iiEzc7=d0SU!@%eh#R^Z-z?=&;T}8oAC3RD#NVOOpb#v!Fvg(3{4KINQe>IB+w5? zBp!^_!PE3Wy)}|d)M&65sM0JJCWh`c?MZ*_eSy^m6zM`{B#goavou`LfQCp$p<8=P zXCNb}G}Y$P?{d>c0InC)$n@9Bwlheu;izL!uv@`~=S|Uo1PrAjVG9%z& zyyJp_vTHljpdbGIejzl0!NR)X-LDrAUPXp@zLMDbW$|RpsMPna!WFUdL(E}zy{mri z3=2L*7D3YX#rIhcTsFt^M@OKZC&K(ZPf}955_+CuhnRq4;L--2<2lsY5pYu_($1eAGnY^Xzjf(|70?+%-f#DOH5-Sda^|MDjy?Bpd2rvv3~I>upu#p8o}aI>?j~1_e7)y%`GH}uiYjnmj5V+GDhz-bQteAaxf@k zssCCMAavM?4m)mUn&&7X`#Wt+--oS+ChFTL2-@2NEbIxFXcLK&tE`zKML$u}Pl-^2 zhm>(Cw20P6!9vWwqkJFP1c71|h~AMtLJ*jreL$g-=MC9Ihj2>^poA&pa420gR)(Ze z3{)Fku`YCoLPZ}48OK~<3qShPc0=xTA#lagnr!ufA`3bXWlSyY;Yk;jHl{2?8b$n% zBS0vF17u^B*Peh2&w!4Us(6-m@M3ek0#EwWHQbu$ ztzemUN)vW)#)h~s20TlUN$CmStEk`Tm7k&q(QLohSt!7?1Km<$$RPigqK8g(*(j#y zF?s<2LqQ`!qhypAB{WV$c|;r?1`$((oGc#DXL?hz;v}5{oKT+(Q_g!2w-69&?E$KWd&Bua{?CXfR75f9 z9T@HtLqRvHML=vTRkQ%%j|xA!bVe|+Q6Fmkhoz#L;Q-WYgg>x3WZBXX)iNv&Iv5h( z(LoXlkJq>z>^@Z}drPN558y&mrnY{&J5}Hg^D3j z^iPlLKu$hX_-2?zD#K4+@0(z0=H_k3MrdJz;^c);16duP!sUsW;vZQ~uoNkLl;CD6 zX#!`YGaQM5KvN_5v4kf$8yHZ6h{q*+(1(Fz(p+(HSsn<|q_^;_0&o!NhNeMwfh&|B z#9l>UZ9BksA3wMm60bNQhqG|$6XjxJ#g`TV>*hNE-46smspZw1+E@C0SLCAp@04M{ zY806S$wopwcf`cm7@er$>rsUlby6O;Kuj+#JHRI33$Y$iEFbElVym2tOgj`8gLWZan)2Xmw7mS11QMg!5!wtJkM2uJ!aY5m%ii3!XWnt zg**47NvYCEnNm)0sUIRYnVkys@~#u1O9lgJrBkB<-=>irsfBSag~0$8kUF=aV<#*% zD&7+<)RxlUx@#Ya^rx=lJ6v!?6~V(b`|y0IV=myN2#lu+=8 z)cb_upIO=$9L2Cm$vw{ymkJe-hQV+R+f5C^$~coUDzk9V5PD=`#1XXc^rBtc6%i-- zDs_mC3VIp@Hbrs{2-NudUGDeW_;t}5FcGLfUTRl@PO*VItpHZpq5_=c>d9~$7o|T`pxPi?&|dJPxf*j1U5gC`Zz-?@ z*&O(Ad;d|b4=jmX{N#-yfdo#(3i|o*ggL4rGZHZ#h_a{_N1;z-#;!+Yf!TXz*Y++d zt%LcZKWJwKu0q$StZ~`0NKMka(i#d96-k>bKCt=}cb|*W#bzT<`5l_V7~=GhmdQ(X zONCKj?Ya>?U4`POAR+AQ?+ba#9#aaIlH`6T^|4Ys;O1&`pd_Qv@gph6?BNQBerU7^MKRnDMK4FfT?wMP1kN6ii$3o$DEI@q$bG3I6ivG^?Ly-^w2II$0Pr9VbdD zDEafP{Ph+~2oekeef$0I?#B%YOms9V1nDCsf|d;zWq{NZw_;e=-it;wrGMz8(q!7w z19NFP^=EBu8l28334=9wH+_&^0^sO=B#pMz-g?BU7)5!JE)UQ_z78MaGovL3hbkrJ zQ~RPc6w+cSA1L~vEgYk|*yWixa;hF}fEEye){lmy9>^5AfO=RE>_C4;CqwyI_$fg< zM(Say8TkhP0tHCcqaRyFa@0eMfU_~T5M8mtJdrnkQ@%%sM+hX~Ok>|b4yqc6HI*Yb z&W)?1ADs$p6OC89HC|f^nry^DD*L`aO*qG@{l`ldplw1HSsbkQsek`&yZ?Bv`+q?6x2GOyb z3)Vi5&W4#5R1`(6qoZEppp;=WqpZ9{8qRKZc{i!5H87O}?QmDe;95AQXa%nQjRDXsEKCqp{(z*9TgBE7RXqqrY1(Agts=Tw<`V|atI2HcM%#KR>h8KYj==Zn633g z?BHx9Ldg10GHOR#dwES8&sBKAP{U(%hsv`K@fx9K;v(4Q;dOZ1BMW0aXh^i{M8!6V z>h5WM^emn9l2v5aHT$j9St=D;5qXkgqDt3288z( zlF5OUN)N-O!@{((kW?%%g8@ma2PpABjLo6kTHIn0Oy*Gdz}52> zdg5iZm)JP{XCerUhXg2AXY|@9p+f>3xRuCiv zI>-w5zelY)YVvW_slcJ-2MRtEYK`n=3hZWtR23#g-X4c~lslawW87g=V;KLQFji1=&_M!%uajEH8}IUsdy{tZ&?5J#pXjiUd_^XL)oJXORa%GQ5w`$s>W z|Cew0+Xu;1*}!i9FM}C~1Fq&)-|u2P%lqD+t4GP14DboWvrIQE;tk^IO-tvzPaI)INg+Nb9y6#x;zzE_ zF28XuIPB+{5hIYciDr@%1Ul`75E6ZG` z8bkt%Sb_)vGO8${3=1*ZHBwBZ=sfP>A8`C4xny#cz{s(H3RFmrAN&t~&(_ROPPj?o zIMDH8+aE(fXcuVIZ2SAzwi_ov;2F5mTK-BMnE52V*3zO!K<_qiaoy77J>YT&=zr2B zLvo}5l|P>c-p}ZpvOwQ0(7oo)t$B{q2Ov$eO5Okmhrn=wve!M{-Pu03fA2Ks_XBW7 za;60}&QbsX0{~D=R7C&){}2!mARr(xFfc$sKu}OnWMpJ?baaG-gp`z&sHmv8xVXs3 z$k^D}=;-MD{QNXLNJLCrSYU8$bcBSAn4F-ju(-s`(A+RA1VB6tP)rnHTpW0KK$MhZ zu&{*8%&15#1Xw&2XizMCXh@iZT)3ck)V!4R+^|3Z1Xu(Ra1bDfAT*#jOuSTV%xHYv zgpll^Xp|g)s4N^b7%W5}JXkPLXgp|qOn{VJn6PZL%zO|u7$8V2IABOj zbXZ`BYi5-tiYVi+|2O&tTZ&#G&KA)H2h>({E&S7xS;&l z$o%x|NEC2fER1kOsElO9sEFXmu=vop|LD;CJOBV(004jh0H6Q>!~g)`008^|0Q^t@ z{A>XHhyeVg0Q|rJ{M-Qi`~b{|2;`6i{G0&%urU0@Wc=8e2pCulBxn>gd>llKC|smC zc)UoM*kr8WT%0s)ut0psOpxGQ;Pm{+?D(|Y?1a47SeUHz0QB_$_4WYv_W<|!0QmU; z`T79*`vCj=0Q~&`{r&*{{{a6?7zk`E7?4ObuxwP)l79R=0Q^({{Ad9Dd;t8E0Q{@~ z{KNo20093005C8BKtKRcPyqk`03bwgBuI29On59%d@xjiNMw*?gs9l`{9u5jL|}~n z|NqNZOQ8S&00Cl4M??UK1szBL000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2jvL_ z3JWCKPi=bu00J&aL_t(|+U?rgj)E`{2H+;^32%7l(mqMkI8Vt^+YYkUSz|;j{Bu=1 zSmuLCV+7T1HWcWfgTC_Uuc5xRu=zuM_H<7K=wCwrXg`AfQMw8dxBVev89WuUea@=3 z=Mm4T>8PDvx4!t1r|vJad?Wr$JpLFaKnERk&_M?sbkIQueVueNsb->)PL$~#UFk%o zW4h@mePb9=9EGTj?v0K$dq)(%MC5!tfQr13Nqg|xCA?l-B?GxSk_@yw4 z2ZUsz+mUXWZmXsbP3u$pj`ZBT-lT?a*VypNCWx|Q!*^-RBHQI{&W?23C$(Wx8d$W%^{BRy(x1^OIVrsO5A|5@0#A@;q2Gc3Uv(k+3(xJ|N?+)?;hgjrYuFOKu9$~j z#pMKj<8)Psn*-OE1s!zIK?fal&_M?sbkIQu9dyt^2OV_KzlBbXv`l!hOghP!FJ;eC zwvn>boFAW;hAf}BkPYz+-HRoJ7mK6|D zoE2AACy{;<>8H2Q=_nN_-&eUO{84OpF*{TxHT>}{4X+N3SfJeSM`@opG}1ot>1=_% zm&#vJwm{zgrfid; grfs.insert(std::pair(grfid, grf)); } - IConsolePrintF(CC_DEFAULT, " %02u %c%c%c%c, Flags: %c%c%c%c%c%c, Ctrl Flags: %c%c%c, GRF: %08X, %s", + IConsolePrintF(CC_DEFAULT, " %02u %c%c%c%c, Flags: %c%c%c%c%c%c, Ctrl Flags: %c%c%c%c, GRF: %08X, %s", (uint) rt, rti->label >> 24, rti->label >> 16, rti->label >> 8, rti->label, HasBit(rti->flags, RTF_CATENARY) ? 'c' : '-', @@ -2496,6 +2496,7 @@ DEF_CONSOLE_CMD(ConDumpRailTypes) HasBit(rti->ctrl_flags, RTCF_PROGSIG) ? 'p' : '-', HasBit(rti->ctrl_flags, RTCF_RESTRICTEDSIG) ? 'r' : '-', HasBit(rti->ctrl_flags, RTCF_NOREALISTICBRAKING) ? 'b' : '-', + HasBit(rti->ctrl_flags, RTCF_NOENTRYSIG) ? 'n' : '-', BSWAP32(grfid), GetStringPtr(rti->strings.name) ); diff --git a/src/gfxinit.cpp b/src/gfxinit.cpp index 92c3c1051e..4c54ecd1b6 100644 --- a/src/gfxinit.cpp +++ b/src/gfxinit.cpp @@ -177,6 +177,15 @@ static void LoadSpriteTables() DupSprite(SPR_PROGSIGNAL_BASE + i, SPR_DUP_PROGSIGNAL_BASE + i); } + /* Extra signal sprites. */ + SpriteFile &extrasig_file = LoadGrfFile("extra_signals.grf", SPR_EXTRASIGNAL_BASE, false); + extrasig_file.flags |= SFF_PROGSIG; + + /* Fill duplicate extra signal graphics sprite block */ + for (uint i = 0; i < EXTRASIGNAL_SPRITE_COUNT; i++) { + DupSprite(SPR_EXTRASIGNAL_BASE + i, SPR_DUP_EXTRASIGNAL_BASE + i); + } + /* Tracerestrict sprites. */ LoadGrfFile("tracerestrict.grf", SPR_TRACERESTRICT_BASE, false); diff --git a/src/lang/english.txt b/src/lang/english.txt index f733991465..130159894e 100644 --- a/src/lang/english.txt +++ b/src/lang/english.txt @@ -1442,6 +1442,8 @@ STR_CONFIG_SETTING_SHOW_ADV_TRACE_RESTRICT_FEATURES :Show advanced r STR_CONFIG_SETTING_SHOW_ADV_TRACE_RESTRICT_FEATURES_HELPTEXT :Show advanced routing restriction features. When disabled, some advanced features are not shown in the UI, but are still available to all players. STR_CONFIG_SETTING_SHOW_PROGSIG_FEATURES :Show programmable pre-signal feature: {STRING2} STR_CONFIG_SETTING_SHOW_PROGSIG_FEATURES_HELPTEXT :Show programmable pre-signal feature. When disabled, the buttons to build and configure programmable pre-signals are not shown in the UI, but are still available to all players. +STR_CONFIG_SETTING_SHOW_NOENTRYSIG_FEATURES :Show no-entry signal feature: {STRING2} +STR_CONFIG_SETTING_SHOW_NOENTRYSIG_FEATURES_HELPTEXT :Show no-entry signal feature. When disabled, the buttons to build and configure no-entry signals are not shown in the UI, but are still available to all players. STR_CONFIG_SETTING_SHOW_VEH_LIST_CARGO_FILTER :Show cargo type filter in vehicle lists: {STRING2} STR_CONFIG_SETTING_SHOW_VEH_LIST_CARGO_FILTER_HELPTEXT :Show cargo type filter in vehicle lists. When enabled vehicle list windows include an additional filter dropdown. STR_CONFIG_SETTING_SHOW_ADV_LOADING_MODE_FEATURES :Show advanced loading mode features: {STRING2} @@ -2885,6 +2887,7 @@ STR_BUILD_SIGNAL_SEMAPHORE_COMBO_TOOLTIP :{BLACK}Combo Si STR_BUILD_SIGNAL_SEMAPHORE_PROG_TOOLTIP :{BLACK}Programmable Pre-Signal (semaphore){}The programmable pre-signal is a combo-signal which can be programmed to behave in complex ways. STR_BUILD_SIGNAL_SEMAPHORE_PBS_TOOLTIP :{BLACK}Path Signal (semaphore){}A path signal allows more than one train to enter a signal block at the same time, if the train can reserve a path to a safe stopping point. Standard path signals can be passed from the back side STR_BUILD_SIGNAL_SEMAPHORE_PBS_OWAY_TOOLTIP :{BLACK}One-way Path Signal (semaphore){}A path signal allows more than one train to enter a signal block at the same time, if the train can reserve a path to a safe stopping point. One-way path signals can't be passed from the back side +STR_BUILD_SIGNAL_SEMAPHORE_NO_ENTRY_TOOLTIP :{BLACK}No-Entry Signal (semaphore){}A path signal allows more than one train to enter a signal block at the same time, if the train can reserve a path to a safe stopping point. No-entry signals can't be passed from the front side STR_BUILD_SIGNAL_ELECTRIC_NORM_TOOLTIP :{BLACK}Block Signal (electric){}This is the most basic type of signal, allowing only one train to be in the same block at the same time STR_BUILD_SIGNAL_ELECTRIC_ENTRY_TOOLTIP :{BLACK}Entry Signal (electric){}Green as long as there is one or more green exit-signal from the following section of track. Otherwise it shows red STR_BUILD_SIGNAL_ELECTRIC_EXIT_TOOLTIP :{BLACK}Exit Signal (electric){}Behaves in the same way as a block signal but is necessary to trigger the correct colour on entry & combo pre-signals @@ -2892,6 +2895,7 @@ STR_BUILD_SIGNAL_ELECTRIC_COMBO_TOOLTIP :{BLACK}Combo Si STR_BUILD_SIGNAL_ELECTRIC_PROG_TOOLTIP :{BLACK}Programmable Pre-Signal (electric){}The programmable pre-signal is a combo-signal which can be programmed to behave in complex ways. STR_BUILD_SIGNAL_ELECTRIC_PBS_TOOLTIP :{BLACK}Path Signal (electric){}A path signal allows more than one train to enter a signal block at the same time, if the train can reserve a path to a safe stopping point. Standard path signals can be passed from the back side STR_BUILD_SIGNAL_ELECTRIC_PBS_OWAY_TOOLTIP :{BLACK}One-way Path Signal (electric){}A path signal allows more than one train to enter a signal block at the same time, if the train can reserve a path to a safe stopping point. One-way path signals can't be passed from the back side +STR_BUILD_SIGNAL_ELECTRIC_NO_ENTRY_TOOLTIP :{BLACK}No-Entry Signal (electric){}A path signal allows more than one train to enter a signal block at the same time, if the train can reserve a path to a safe stopping point. No-entry signals can't be passed from the front side STR_BUILD_SIGNAL_CONVERT_TOOLTIP :{BLACK}Signal Convert{}When selected, clicking an existing signal will convert it to the selected signal type and variant. Ctrl+Click will toggle the existing variant. Shift+Click shows estimated conversion cost STR_BUILD_SIGNAL_DRAG_SIGNALS_DENSITY_TOOLTIP :{BLACK}Dragging signal distance STR_BUILD_SIGNAL_DRAG_SIGNALS_DENSITY_DECREASE_TOOLTIP :{BLACK}Decrease dragging signal distance diff --git a/src/newgrf.cpp b/src/newgrf.cpp index ce5a55e54f..5454819845 100644 --- a/src/newgrf.cpp +++ b/src/newgrf.cpp @@ -4078,6 +4078,11 @@ static ChangeInfoResult SignalsChangeInfo(uint id, int numinfo, int prop, const SB(_cur.grffile->new_signal_ctrl_flags, NSCF_PROGSIG, 1, (buf->ReadByte() != 0 ? 1 : 0)); break; + case A0RPI_SIGNALS_ENABLE_NO_ENTRY_SIGNALS: + if (MappedPropertyLengthMismatch(buf, 1, mapping_entry)) break; + SB(_cur.grffile->new_signal_ctrl_flags, NSCF_NOENTRYSIG, 1, (buf->ReadByte() != 0 ? 1 : 0)); + break; + case A0RPI_SIGNALS_ENABLE_RESTRICTED_SIGNALS: if (MappedPropertyLengthMismatch(buf, 1, mapping_entry)) break; SB(_cur.grffile->new_signal_ctrl_flags, NSCF_RESTRICTEDSIG, 1, (buf->ReadByte() != 0 ? 1 : 0)); @@ -4416,6 +4421,11 @@ static ChangeInfoResult RailTypeChangeInfo(uint id, int numinfo, int prop, const SB(rti->ctrl_flags, RTCF_PROGSIG, 1, (buf->ReadByte() != 0 ? 1 : 0)); break; + case A0RPI_RAILTYPE_ENABLE_NO_ENTRY_SIGNALS: + if (MappedPropertyLengthMismatch(buf, 1, mapping_entry)) break; + SB(rti->ctrl_flags, RTCF_NOENTRYSIG, 1, (buf->ReadByte() != 0 ? 1 : 0)); + break; + case A0RPI_RAILTYPE_ENABLE_RESTRICTED_SIGNALS: if (MappedPropertyLengthMismatch(buf, 1, mapping_entry)) break; SB(rti->ctrl_flags, RTCF_RESTRICTEDSIG, 1, (buf->ReadByte() != 0 ? 1 : 0)); @@ -4517,6 +4527,7 @@ static ChangeInfoResult RailTypeReserveInfo(uint id, int numinfo, int prop, cons break; case A0RPI_RAILTYPE_ENABLE_PROGRAMMABLE_SIGNALS: + case A0RPI_RAILTYPE_ENABLE_NO_ENTRY_SIGNALS: case A0RPI_RAILTYPE_ENABLE_RESTRICTED_SIGNALS: case A0RPI_RAILTYPE_DISABLE_REALISTIC_BRAKING: case A0RPI_RAILTYPE_ENABLE_SIGNAL_RECOLOUR: @@ -8487,7 +8498,9 @@ static const GRFFeatureInfo _grf_feature_list[] = { GRFFeatureInfo("action0_bridge_pillar_flags", 1), GRFFeatureInfo("action0_bridge_availability_flags", 1), GRFFeatureInfo("action5_programmable_signals", 1), + GRFFeatureInfo("action5_no_entry_signals", 1), GRFFeatureInfo("action0_railtype_programmable_signals", 1), + GRFFeatureInfo("action0_railtype_no_entry_signals", 1), GRFFeatureInfo("action0_railtype_restricted_signals", 1), GRFFeatureInfo("action0_railtype_disable_realistic_braking", 1), GRFFeatureInfo("action0_railtype_recolour", 1), @@ -8495,6 +8508,7 @@ static const GRFFeatureInfo _grf_feature_list[] = { GRFFeatureInfo("action0_roadtype_extra_flags", 1), GRFFeatureInfo("action0_global_extra_station_names", 1), GRFFeatureInfo("action0_signals_programmable_signals", 1), + GRFFeatureInfo("action0_signals_no_entry_signals", 1), GRFFeatureInfo("action0_signals_restricted_signals", 1), GRFFeatureInfo("action0_signals_recolour", 1), GRFFeatureInfo("action0_signals_extra_aspects", 1), @@ -8616,6 +8630,7 @@ static const GRFPropertyMapDefinition _grf_action0_remappable_properties[] = { GRFPropertyMapDefinition(GSF_BRIDGES, A0RPI_BRIDGE_PILLAR_FLAGS, "bridge_pillar_flags"), GRFPropertyMapDefinition(GSF_BRIDGES, A0RPI_BRIDGE_AVAILABILITY_FLAGS, "bridge_availability_flags"), GRFPropertyMapDefinition(GSF_RAILTYPES, A0RPI_RAILTYPE_ENABLE_PROGRAMMABLE_SIGNALS, "railtype_enable_programmable_signals"), + GRFPropertyMapDefinition(GSF_RAILTYPES, A0RPI_RAILTYPE_ENABLE_NO_ENTRY_SIGNALS, "railtype_enable_no_entry_signals"), GRFPropertyMapDefinition(GSF_RAILTYPES, A0RPI_RAILTYPE_ENABLE_RESTRICTED_SIGNALS, "railtype_enable_restricted_signals"), GRFPropertyMapDefinition(GSF_RAILTYPES, A0RPI_RAILTYPE_DISABLE_REALISTIC_BRAKING, "railtype_disable_realistic_braking"), GRFPropertyMapDefinition(GSF_RAILTYPES, A0RPI_RAILTYPE_ENABLE_SIGNAL_RECOLOUR, "railtype_enable_signal_recolour"), @@ -8624,6 +8639,7 @@ static const GRFPropertyMapDefinition _grf_action0_remappable_properties[] = { GRFPropertyMapDefinition(GSF_TRAMTYPES, A0RPI_ROADTYPE_EXTRA_FLAGS, "roadtype_extra_flags"), GRFPropertyMapDefinition(GSF_GLOBALVAR, A0RPI_GLOBALVAR_EXTRA_STATION_NAMES, "global_extra_station_names"), GRFPropertyMapDefinition(GSF_SIGNALS, A0RPI_SIGNALS_ENABLE_PROGRAMMABLE_SIGNALS, "signals_enable_programmable_signals"), + GRFPropertyMapDefinition(GSF_SIGNALS, A0RPI_SIGNALS_ENABLE_NO_ENTRY_SIGNALS, "signals_enable_no_entry_signals"), GRFPropertyMapDefinition(GSF_SIGNALS, A0RPI_SIGNALS_ENABLE_RESTRICTED_SIGNALS, "signals_enable_restricted_signals"), GRFPropertyMapDefinition(GSF_SIGNALS, A0RPI_SIGNALS_ENABLE_SIGNAL_RECOLOUR, "signals_enable_signal_recolour"), GRFPropertyMapDefinition(GSF_SIGNALS, A0RPI_SIGNALS_EXTRA_ASPECTS, "signals_extra_aspects"), @@ -8633,6 +8649,7 @@ static const GRFPropertyMapDefinition _grf_action0_remappable_properties[] = { /** Action14 Action5 remappable type list */ static const Action5TypeRemapDefinition _grf_action5_remappable_types[] = { Action5TypeRemapDefinition("programmable_signals", A5BLOCK_ALLOW_OFFSET, SPR_PROGSIGNAL_BASE, 1, 32, "Programmable pre-signal graphics"), + Action5TypeRemapDefinition("no_entry_signals", A5BLOCK_ALLOW_OFFSET, SPR_EXTRASIGNAL_BASE, 1, 16, "No-entry signal graphics"), Action5TypeRemapDefinition(), }; diff --git a/src/newgrf.h b/src/newgrf.h index 1c1f26b6b9..f20f77f53f 100644 --- a/src/newgrf.h +++ b/src/newgrf.h @@ -116,6 +116,7 @@ enum Action0RemapPropertyIds { A0RPI_BRIDGE_PILLAR_FLAGS, A0RPI_BRIDGE_AVAILABILITY_FLAGS, A0RPI_RAILTYPE_ENABLE_PROGRAMMABLE_SIGNALS, + A0RPI_RAILTYPE_ENABLE_NO_ENTRY_SIGNALS, A0RPI_RAILTYPE_ENABLE_RESTRICTED_SIGNALS, A0RPI_RAILTYPE_DISABLE_REALISTIC_BRAKING, A0RPI_RAILTYPE_ENABLE_SIGNAL_RECOLOUR, @@ -123,6 +124,7 @@ enum Action0RemapPropertyIds { A0RPI_ROADTYPE_EXTRA_FLAGS, A0RPI_GLOBALVAR_EXTRA_STATION_NAMES, A0RPI_SIGNALS_ENABLE_PROGRAMMABLE_SIGNALS, + A0RPI_SIGNALS_ENABLE_NO_ENTRY_SIGNALS, A0RPI_SIGNALS_ENABLE_RESTRICTED_SIGNALS, A0RPI_SIGNALS_ENABLE_SIGNAL_RECOLOUR, A0RPI_SIGNALS_EXTRA_ASPECTS, @@ -227,6 +229,7 @@ enum NewSignalCtrlFlags { NSCF_PROGSIG = 1, ///< Custom signal sprites enabled for programmable pre-signals. NSCF_RESTRICTEDSIG = 2, ///< Custom signal sprite flag enabled for restricted signals. NSCF_RECOLOUR_ENABLED = 3, ///< Recolour sprites enabled + NSCF_NOENTRYSIG = 4, ///< Custom signal sprites enabled for no-entry signals. }; enum { diff --git a/src/newgrf_railtype.cpp b/src/newgrf_railtype.cpp index 88edd18dce..7ea1db3278 100644 --- a/src/newgrf_railtype.cpp +++ b/src/newgrf_railtype.cpp @@ -127,6 +127,7 @@ static PalSpriteID GetRailTypeCustomSignalSprite(const RailtypeInfo *rti, TileIn { if (rti->group[RTSG_SIGNALS] == nullptr) return { 0, PAL_NONE }; if (type == SIGTYPE_PROG && !HasBit(rti->ctrl_flags, RTCF_PROGSIG)) return { 0, PAL_NONE }; + if (type == SIGTYPE_NO_ENTRY && !HasBit(rti->ctrl_flags, RTCF_NOENTRYSIG)) return { 0, PAL_NONE }; uint32 param1 = gui ? 0x10 : 0x00; uint32 param2 = (type << 16) | (var << 8) | RemapAspect(aspect, rti->signal_extra_aspects); @@ -157,6 +158,7 @@ CustomSignalSpriteResult GetCustomSignalSprite(const RailtypeInfo *rti, TileInde for (const GRFFile *grf : _new_signals_grfs) { if (type == SIGTYPE_PROG && !HasBit(grf->new_signal_ctrl_flags, NSCF_PROGSIG)) continue; + if (type == SIGTYPE_NO_ENTRY && !HasBit(grf->new_signal_ctrl_flags, NSCF_NOENTRYSIG)) continue; uint32 param1 = gui ? 0x10 : 0x00; uint32 param2 = (type << 16) | (var << 8) | RemapAspect(aspect, grf->new_signal_extra_aspects); diff --git a/src/pathfinder/npf/npf.cpp b/src/pathfinder/npf/npf.cpp index dcd6469c6b..ec1636d28f 100644 --- a/src/pathfinder/npf/npf.cpp +++ b/src/pathfinder/npf/npf.cpp @@ -495,7 +495,7 @@ static int32 NPFRailPathCost(AyStar *as, AyStarNode *current, OpenListNode *pare NPFSetFlag(current, NPF_FLAG_LAST_SIGNAL_BLOCK, !IsPbsSignal(sigtype)); } - if (HasPbsSignalOnTrackdir(tile, ReverseTrackdir(trackdir)) && !NPFGetFlag(current, NPF_FLAG_3RD_SIGNAL)) { + if (HasPbsSignalOnTrackdir(tile, ReverseTrackdir(trackdir)) && !NPFGetFlag(current, NPF_FLAG_3RD_SIGNAL) && !IsNoEntrySignal(tile, TrackdirToTrack(trackdir))) { cost += _settings_game.pf.npf.npf_rail_pbs_signal_back_penalty; } } @@ -965,6 +965,9 @@ static void NPFFollowTrack(AyStar *aystar, OpenListNode *current) /* If there's a one-way signal not pointing towards us, stop going in this direction. */ break; } + if (HasSignalOnTrackdir(dst_tile, dst_trackdir) && IsNoEntrySignal(dst_tile, TrackdirToTrack(dst_trackdir))) { + break; + } } if (IsTileType(dst_tile, MP_TUNNELBRIDGE) && IsTunnelBridgeSignalSimulationExitOnly(dst_tile) && DiagDirToDiagTrackdir(GetTunnelBridgeDirection(dst_tile)) == dst_trackdir) { /* Entering a signalled bridge/tunnel from the wrong side, equivalent to encountering a one-way signal from the wrong side */ diff --git a/src/pathfinder/yapf/yapf_costrail.hpp b/src/pathfinder/yapf/yapf_costrail.hpp index 0b65006f48..581fa15159 100644 --- a/src/pathfinder/yapf/yapf_costrail.hpp +++ b/src/pathfinder/yapf/yapf_costrail.hpp @@ -328,6 +328,11 @@ public: SignalState sig_state = GetSignalStateByTrackdir(tile, trackdir); SignalType sig_type = GetSignalType(tile, TrackdirToTrack(trackdir)); + if (IsNoEntrySignal(sig_type)) { + n.m_segment->m_end_segment_reason |= ESRB_DEAD_END; + return cost; + } + n.m_last_signal_type = sig_type; /* cache the look-ahead polynomial constant only if we didn't pass more signals than the look-ahead limit is */ @@ -393,18 +398,21 @@ public: n.m_segment->m_last_signal_td = trackdir; } - if (has_signal_against && IsPbsSignal(GetSignalType(tile, TrackdirToTrack(trackdir)))) { - bool no_add_cost = false; + if (has_signal_against) { + SignalType sig_type = GetSignalType(tile, TrackdirToTrack(trackdir)); + if (IsPbsSignal(sig_type) && !IsNoEntrySignal(sig_type)) { + bool no_add_cost = false; - if (ShouldCheckTraceRestrict(n, tile)) { - TraceRestrictProgramResult out; - if (ExecuteTraceRestrict(n, tile, trackdir, cost, out, nullptr, &no_add_cost)) { - return -1; + if (ShouldCheckTraceRestrict(n, tile)) { + TraceRestrictProgramResult out; + if (ExecuteTraceRestrict(n, tile, trackdir, cost, out, nullptr, &no_add_cost)) { + return -1; + } } - } - if (!no_add_cost) { - cost += n.m_num_signals_passed < Yapf().PfGetSettings().rail_look_ahead_max_signals ? Yapf().PfGetSettings().rail_pbs_signal_back_penalty : 0; + if (!no_add_cost) { + cost += n.m_num_signals_passed < Yapf().PfGetSettings().rail_look_ahead_max_signals ? Yapf().PfGetSettings().rail_pbs_signal_back_penalty : 0; + } } } } @@ -702,7 +710,15 @@ no_entry_cost: // jump here at the beginning if the node has no parent (it is th if (TrackFollower::DoTrackMasking() && IsTileType(next.tile, MP_RAILWAY)) { if (HasSignalOnTrackdir(next.tile, next.td) && IsPbsSignal(GetSignalType(next.tile, TrackdirToTrack(next.td)))) { /* Possible safe tile. */ - end_segment_reason |= ESRB_SAFE_TILE; + if (IsNoEntrySignal(next.tile, TrackdirToTrack(next.td))) { + if (likely(_settings_game.pf.back_of_one_way_pbs_waiting_point)) { + /* Possible safe tile, but not so good as it's the back of a signal... */ + end_segment_reason |= ESRB_SAFE_TILE | ESRB_DEAD_END; + extra_cost += Yapf().PfGetSettings().rail_lastred_exit_penalty; + } + } else { + end_segment_reason |= ESRB_SAFE_TILE; + } } else if (likely(_settings_game.pf.back_of_one_way_pbs_waiting_point) && HasSignalOnTrackdir(next.tile, ReverseTrackdir(next.td)) && GetSignalType(next.tile, TrackdirToTrack(next.td)) == SIGTYPE_PBS_ONEWAY) { /* Possible safe tile, but not so good as it's the back of a signal... */ diff --git a/src/pbs.cpp b/src/pbs.cpp index 5c5cf70f61..39af9f5051 100644 --- a/src/pbs.cpp +++ b/src/pbs.cpp @@ -1162,6 +1162,7 @@ bool IsSafeWaitingPosition(const Train *v, TileIndex tile, Trackdir trackdir, bo Trackdir td = FindFirstTrackdir(ft.m_new_td_bits); /* PBS signal on next trackdir? Conditionally safe position. */ if (HasPbsSignalOnTrackdir(ft.m_new_tile, td)) { + if (GetSignalType(ft.m_new_tile, TrackdirToTrack(td)) == SIGTYPE_NO_ENTRY) return include_line_end; if (IsRestrictedSignal(ft.m_new_tile)) { const TraceRestrictProgram *prog = GetExistingTraceRestrictProgram(ft.m_new_tile, TrackdirToTrack(td)); if (prog && prog->actions_used_flags & TRPAUF_RESERVE_THROUGH) { diff --git a/src/rail.h b/src/rail.h index 57b5e33d04..d46b77c28d 100644 --- a/src/rail.h +++ b/src/rail.h @@ -47,6 +47,7 @@ enum RailTypeCtrlFlags { RTCF_RESTRICTEDSIG = 1, ///< Custom signal sprite flag enabled for restricted signals. RTCF_NOREALISTICBRAKING = 2, ///< Realistic braking disabled for this track type RTCF_RECOLOUR_ENABLED = 3, ///< Recolour sprites enabled + RTCF_NOENTRYSIG = 4, ///< Custom signal sprites enabled for no-entry signals. }; struct SpriteGroup; diff --git a/src/rail_cmd.cpp b/src/rail_cmd.cpp index 84b91ff4ae..ab56d5243a 100644 --- a/src/rail_cmd.cpp +++ b/src/rail_cmd.cpp @@ -104,22 +104,26 @@ void ResolveRailTypeGUISprites(RailtypeInfo *rti) const SpriteID _signal_lookup[2][SIGTYPE_END] = { {SPR_IMG_SIGNAL_ELECTRIC_NORM, SPR_IMG_SIGNAL_ELECTRIC_ENTRY, SPR_IMG_SIGNAL_ELECTRIC_EXIT, SPR_IMG_SIGNAL_ELECTRIC_COMBO, SPR_IMG_SIGNAL_ELECTRIC_PBS, SPR_IMG_SIGNAL_ELECTRIC_PBS_OWAY, - SPR_IMG_SIGNAL_ELECTRIC_PROG}, + SPR_IMG_SIGNAL_ELECTRIC_PROG, SPR_IMG_SIGNAL_ELECTRIC_NO_ENTRY}, {SPR_IMG_SIGNAL_SEMAPHORE_NORM, SPR_IMG_SIGNAL_SEMAPHORE_ENTRY, SPR_IMG_SIGNAL_SEMAPHORE_EXIT, SPR_IMG_SIGNAL_SEMAPHORE_COMBO, SPR_IMG_SIGNAL_SEMAPHORE_PBS, SPR_IMG_SIGNAL_SEMAPHORE_PBS_OWAY, - SPR_IMG_SIGNAL_SEMAPHORE_PROG}, + SPR_IMG_SIGNAL_SEMAPHORE_PROG, SPR_IMG_SIGNAL_SEMAPHORE_NO_ENTRY}, }; for (SignalType type = SIGTYPE_NORMAL; type < SIGTYPE_END; type = (SignalType)(type + 1)) { for (SignalVariant var = SIG_ELECTRIC; var <= SIG_SEMAPHORE; var = (SignalVariant)(var + 1)) { PalSpriteID red = GetCustomSignalSprite(rti, INVALID_TILE, type, var, 0, true).sprite; - PalSpriteID green = GetCustomSignalSprite(rti, INVALID_TILE, type, var, 255, true).sprite; if (red.sprite != 0) { rti->gui_sprites.signals[type][var][0] = { red.sprite + SIGNAL_TO_SOUTH, red.pal }; } else { rti->gui_sprites.signals[type][var][0] = { _signal_lookup[var][type], PAL_NONE }; } + if (type == SIGTYPE_NO_ENTRY) { + rti->gui_sprites.signals[type][var][1] = rti->gui_sprites.signals[type][var][0]; + continue; + } + PalSpriteID green = GetCustomSignalSprite(rti, INVALID_TILE, type, var, 255, true).sprite; if (green.sprite != 0) { rti->gui_sprites.signals[type][var][1] = { green.sprite + SIGNAL_TO_SOUTH, green.pal }; } else { @@ -1689,6 +1693,8 @@ CommandCost CmdBuildSingleSignal(TileIndex tile, DoCommandFlag flags, uint32 p1, /* Query current signal type so the check for PBS signals below works. */ sigtype = GetSignalType(tile, track); } else { + if (GetSignalType(tile, track) == SIGTYPE_NO_ENTRY) CycleSignalSide(tile, track); + /* convert the present signal to the chosen type and variant */ if (IsPresignalProgrammable(tile, track)) { FreeSignalProgram(SignalReference(tile, track)); @@ -1698,13 +1704,18 @@ CommandCost CmdBuildSingleSignal(TileIndex tile, DoCommandFlag flags, uint32 p1, if (IsPbsSignal(sigtype) && (GetPresentSignals(tile) & SignalOnTrack(track)) == SignalOnTrack(track)) { SetPresentSignals(tile, (GetPresentSignals(tile) & ~SignalOnTrack(track)) | KillFirstBit(SignalOnTrack(track))); } + + if (sigtype == SIGTYPE_NO_ENTRY) CycleSignalSide(tile, track); } } else if (ctrl_pressed) { /* cycle through signal types */ sigtype = (SignalType)(GetSignalType(tile, track)); - if(IsProgrammableSignal(sigtype)) + if (IsProgrammableSignal(sigtype)) { FreeSignalProgram(SignalReference(tile, track)); + } + + if (sigtype == SIGTYPE_NO_ENTRY) CycleSignalSide(tile, track); do { sigtype = NextSignalType(sigtype, which_signals); @@ -1714,6 +1725,8 @@ CommandCost CmdBuildSingleSignal(TileIndex tile, DoCommandFlag flags, uint32 p1, if (IsPbsSignal(sigtype) && (GetPresentSignals(tile) & SignalOnTrack(track)) == SignalOnTrack(track)) { SetPresentSignals(tile, (GetPresentSignals(tile) & ~SignalOnTrack(track)) | KillFirstBit(SignalOnTrack(track))); } + + if (sigtype == SIGTYPE_NO_ENTRY) CycleSignalSide(tile, track); } else { /* programmable pre-signal dependencies are invalidated when the signal direction is changed */ CheckRemoveSignal(tile, track); @@ -2680,6 +2693,8 @@ static void GetSignalXY(TileIndex tile, uint pos, uint &x, uint &y) void DrawSingleSignal(TileIndex tile, const RailtypeInfo *rti, Track track, SignalState condition, SignalOffsets image, uint pos, SignalType type, SignalVariant variant, bool show_restricted, bool exit_signal = false) { + if (type == SIGTYPE_NO_ENTRY) pos ^= 1; + uint x, y; GetSignalXY(tile, pos, x, y); @@ -2711,6 +2726,15 @@ void DrawSingleSignal(TileIndex tile, const RailtypeInfo *rti, Track track, Sign sprite = SPR_PROGSIGNAL_BASE + 16 + image * 2 + condition; } + SpriteFile *file = GetOriginFile(sprite); + is_custom_sprite = !(file != nullptr && file->flags & SFF_PROGSIG); + } else if (type == SIGTYPE_NO_ENTRY) { + if (variant == SIG_SEMAPHORE) { + sprite = SPR_EXTRASIGNAL_BASE + image; + } else { + sprite = SPR_EXTRASIGNAL_BASE + 8 + image; + } + SpriteFile *file = GetOriginFile(sprite); is_custom_sprite = !(file != nullptr && file->flags & SFF_PROGSIG); } else { @@ -2730,6 +2754,12 @@ void DrawSingleSignal(TileIndex tile, const RailtypeInfo *rti, Track track, Sign } else { sprite = SPR_DUP_PROGSIGNAL_BASE + 16 + image * 2 + condition; } + } else if (type == SIGTYPE_NO_ENTRY) { + if (variant == SIG_SEMAPHORE) { + sprite = SPR_DUP_EXTRASIGNAL_BASE + image; + } else { + sprite = SPR_DUP_EXTRASIGNAL_BASE + 8 + image; + } } else { sprite = (type == SIGTYPE_NORMAL && variant == SIG_ELECTRIC) ? SPR_DUP_ORIGINAL_SIGNALS_BASE : SPR_DUP_SIGNALS_BASE - 16; sprite += type * 16 + variant * 64 + image * 2 + condition + (IsSignalSpritePBS(type) ? 64 : 0); @@ -2746,7 +2776,7 @@ void DrawSingleSignal(TileIndex tile, const RailtypeInfo *rti, Track track, Sign AddSortableSpriteToDraw(sprite, SPR_TRACERESTRICT_BASE, x, y, 1, 1, BB_HEIGHT_UNDER_BRIDGE, GetSaveSlopeZ(x, y, track), false, 0, 0, 0, &lower_part); AddSortableSpriteToDraw(sprite, PAL_NONE, x, y, 1, 1, BB_HEIGHT_UNDER_BRIDGE, GetSaveSlopeZ(x, y, track), false, 0, 0, 0, &upper_part); } else { - AddSortableSpriteToDraw(sprite, SPR_TRACERESTRICT_BASE + 1, x, y, 1, 1, BB_HEIGHT_UNDER_BRIDGE, GetSaveSlopeZ(x, y, track)); + AddSortableSpriteToDraw(sprite, SPR_TRACERESTRICT_BASE + (type == SIGTYPE_NO_ENTRY ? 0 : 1), x, y, 1, 1, BB_HEIGHT_UNDER_BRIDGE, GetSaveSlopeZ(x, y, track)); } } else { AddSortableSpriteToDraw(sprite, pal, x, y, 1, 1, BB_HEIGHT_UNDER_BRIDGE, GetSaveSlopeZ(x, y, track)); diff --git a/src/rail_gui.cpp b/src/rail_gui.cpp index ec9b9512af..ad65a43e86 100644 --- a/src/rail_gui.cpp +++ b/src/rail_gui.cpp @@ -278,6 +278,7 @@ static void GenericPlaceSignals(TileIndex tile) SB(p1, 5, 3, _cur_signal_type); SB(p1, 8, 1, _convert_signal_button); SB(p1, 9, 6, _settings_client.gui.cycle_signal_types); + if (_cur_signal_type == SIGTYPE_NO_ENTRY) SB(p1, 15, 2, 1); // reverse default signal direction } else { SB(p1, 3, 1, _ctrl_pressed); SB(p1, 4, 1, (_cur_year < _settings_client.gui.semaphore_build_before ? SIG_SEMAPHORE : SIG_ELECTRIC)); @@ -1786,6 +1787,7 @@ private: int sig_sprite_bottom_offset; ///< Maximum extent of signal GUI sprite from reference point towards bottom. bool progsig_ui_shown; ///< Whether programmable pre-signal UI is shown bool presig_ui_shown; ///< Whether pre-signal UI is shown + bool noentry_ui_shown; ///< Whether no-entry signal UI is shown /** * Draw dynamic a signal-sprite in a button in the signal GUI @@ -1812,6 +1814,7 @@ private: void SetSignalUIMode() { this->progsig_ui_shown = _settings_client.gui.show_progsig_ui; this->presig_ui_shown = _settings_game.vehicle.train_braking_model != TBM_REALISTIC; + this->noentry_ui_shown = _settings_client.gui.show_noentrysig_ui; bool show_progsig = this->progsig_ui_shown && this->presig_ui_shown; this->GetWidget(WID_BS_SEMAPHORE_ENTRY_SEL)->SetDisplayedPlane(this->presig_ui_shown ? 0 : SZSP_NONE); this->GetWidget(WID_BS_ELECTRIC_ENTRY_SEL)->SetDisplayedPlane(this->presig_ui_shown ? 0 : SZSP_NONE); @@ -1821,6 +1824,8 @@ private: this->GetWidget(WID_BS_ELECTRIC_COMBO_SEL)->SetDisplayedPlane(this->presig_ui_shown ? 0 : SZSP_NONE); this->GetWidget(WID_BS_SEMAPHORE_PROG_SEL)->SetDisplayedPlane(show_progsig ? 0 : SZSP_NONE); this->GetWidget(WID_BS_ELECTRIC_PROG_SEL)->SetDisplayedPlane(show_progsig ? 0 : SZSP_NONE); + this->GetWidget(WID_BS_SEMAPHORE_NOEN_SEL)->SetDisplayedPlane(this->noentry_ui_shown ? 0 : SZSP_NONE); + this->GetWidget(WID_BS_ELECTRIC_NOEN_SEL)->SetDisplayedPlane(this->noentry_ui_shown ? 0 : SZSP_NONE); this->GetWidget(WID_BS_PROGRAM_SEL)->SetDisplayedPlane(show_progsig ? 0 : 1); this->SetWidgetDisabledState(WID_BS_PROGRAM, !show_progsig); this->SetWidgetsDisabledState(!show_progsig, WID_BS_SEMAPHORE_PROG, WID_BS_ELECTRIC_PROG, WIDGET_LIST_END); @@ -1894,7 +1899,7 @@ public: void DrawWidget(const Rect &r, int widget) const override { - if (IsInsideMM(widget, WID_BS_SEMAPHORE_NORM, WID_BS_ELECTRIC_PBS_OWAY + 1)) { + if (IsInsideMM(widget, WID_BS_SEMAPHORE_NORM, WID_BS_ELECTRIC_NO_ENTRY + 1)) { /* Extract signal from widget number. */ SignalType type = TypeForClick((widget - WID_BS_SEMAPHORE_NORM) % SIGTYPE_END); int var = SIG_SEMAPHORE - (widget - WID_BS_SEMAPHORE_NORM) / SIGTYPE_END; // SignalVariant order is reversed compared to the widgets. @@ -1914,6 +1919,7 @@ public: case 4: return SIGTYPE_PROG; case 5: return SIGTYPE_PBS; case 6: return SIGTYPE_PBS_ONEWAY; + case 7: return SIGTYPE_NO_ENTRY; default: assert(!"Bad signal type button ID"); return SIGTYPE_NORMAL; @@ -1930,6 +1936,7 @@ public: case WID_BS_SEMAPHORE_PROG: case WID_BS_SEMAPHORE_PBS: case WID_BS_SEMAPHORE_PBS_OWAY: + case WID_BS_SEMAPHORE_NO_ENTRY: case WID_BS_ELECTRIC_NORM: case WID_BS_ELECTRIC_ENTRY: case WID_BS_ELECTRIC_EXIT: @@ -1937,6 +1944,7 @@ public: case WID_BS_ELECTRIC_PROG: case WID_BS_ELECTRIC_PBS: case WID_BS_ELECTRIC_PBS_OWAY: + case WID_BS_ELECTRIC_NO_ENTRY: this->RaiseWidget((_cur_signal_variant == SIG_ELECTRIC ? WID_BS_ELECTRIC_NORM : WID_BS_SEMAPHORE_NORM) + _cur_signal_button); _cur_signal_button = (uint)((widget - WID_BS_SEMAPHORE_NORM) % (SIGTYPE_END)); @@ -2009,7 +2017,8 @@ public: this->SetWidgetDisabledState(WID_BS_DRAG_SIGNALS_DENSITY_DECREASE, _settings_client.gui.drag_signals_density == 1); this->SetWidgetDisabledState(WID_BS_DRAG_SIGNALS_DENSITY_INCREASE, _settings_client.gui.drag_signals_density == 20); - if (this->progsig_ui_shown != _settings_client.gui.show_progsig_ui || this->presig_ui_shown != (_settings_game.vehicle.train_braking_model != TBM_REALISTIC)) { + if (this->progsig_ui_shown != _settings_client.gui.show_progsig_ui || this->presig_ui_shown != (_settings_game.vehicle.train_braking_model != TBM_REALISTIC) || + this->noentry_ui_shown != _settings_client.gui.show_noentrysig_ui) { this->SetSignalUIMode(); this->ReInit(); } @@ -2029,6 +2038,7 @@ static Hotkey signaltoolbar_hotkeys[] = { Hotkey((uint16)0, "semaphore_prog", WID_BS_SEMAPHORE_PROG), Hotkey((uint16)0, "semaphore_pbs", WID_BS_SEMAPHORE_PBS), Hotkey((uint16)0, "semaphore_pbs_oneway", WID_BS_SEMAPHORE_PBS_OWAY), + Hotkey((uint16)0, "semaphore_no_entry", WID_BS_SEMAPHORE_NO_ENTRY), Hotkey('G', "signal_normal", WID_BS_ELECTRIC_NORM), Hotkey((uint16)0, "signal_entry", WID_BS_ELECTRIC_ENTRY), Hotkey((uint16)0, "signal_exit", WID_BS_ELECTRIC_EXIT), @@ -2036,6 +2046,7 @@ static Hotkey signaltoolbar_hotkeys[] = { Hotkey((uint16)0, "signal_prog", WID_BS_ELECTRIC_PROG), Hotkey('H', "signal_pbs", WID_BS_ELECTRIC_PBS), Hotkey('J', "signal_pbs_oneway", WID_BS_ELECTRIC_PBS_OWAY), + Hotkey((uint16)0, "signal_no_entry", WID_BS_ELECTRIC_NO_ENTRY), HOTKEY_LIST_END }; HotkeyList BuildSignalWindow::hotkeys("signaltoolbar", signaltoolbar_hotkeys); @@ -2063,6 +2074,9 @@ static const NWidgetPart _nested_signal_builder_widgets[] = { EndContainer(), NWidget(WWT_PANEL, COLOUR_DARK_GREEN, WID_BS_SEMAPHORE_PBS), SetDataTip(STR_NULL, STR_BUILD_SIGNAL_SEMAPHORE_PBS_TOOLTIP), EndContainer(), SetFill(1, 1), NWidget(WWT_PANEL, COLOUR_DARK_GREEN, WID_BS_SEMAPHORE_PBS_OWAY), SetDataTip(STR_NULL, STR_BUILD_SIGNAL_SEMAPHORE_PBS_OWAY_TOOLTIP), EndContainer(), SetFill(1, 1), + NWidget(NWID_SELECTION, INVALID_COLOUR, WID_BS_SEMAPHORE_NOEN_SEL), + NWidget(WWT_PANEL, COLOUR_DARK_GREEN, WID_BS_SEMAPHORE_NO_ENTRY), SetDataTip(STR_NULL, STR_BUILD_SIGNAL_SEMAPHORE_NO_ENTRY_TOOLTIP), EndContainer(), SetFill(1, 1), + EndContainer(), NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_BS_CONVERT), SetDataTip(SPR_IMG_SIGNAL_CONVERT, STR_BUILD_SIGNAL_CONVERT_TOOLTIP), SetFill(1, 1), NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_BS_TRACE_RESTRICT), SetDataTip(SPR_IMG_SETTINGS, STR_TRACE_RESTRICT_SIGNAL_GUI_TOOLTIP), SetFill(1, 1), EndContainer(), @@ -2082,6 +2096,9 @@ static const NWidgetPart _nested_signal_builder_widgets[] = { EndContainer(), NWidget(WWT_PANEL, COLOUR_DARK_GREEN, WID_BS_ELECTRIC_PBS), SetDataTip(STR_NULL, STR_BUILD_SIGNAL_ELECTRIC_PBS_TOOLTIP), EndContainer(), SetFill(1, 1), NWidget(WWT_PANEL, COLOUR_DARK_GREEN, WID_BS_ELECTRIC_PBS_OWAY), SetDataTip(STR_NULL, STR_BUILD_SIGNAL_ELECTRIC_PBS_OWAY_TOOLTIP), EndContainer(), SetFill(1, 1), + NWidget(NWID_SELECTION, INVALID_COLOUR, WID_BS_ELECTRIC_NOEN_SEL), + NWidget(WWT_PANEL, COLOUR_DARK_GREEN, WID_BS_ELECTRIC_NO_ENTRY), SetDataTip(STR_NULL, STR_BUILD_SIGNAL_ELECTRIC_NO_ENTRY_TOOLTIP), EndContainer(), SetFill(1, 1), + EndContainer(), NWidget(WWT_PANEL, COLOUR_DARK_GREEN), SetDataTip(STR_NULL, STR_BUILD_SIGNAL_DRAG_SIGNALS_DENSITY_TOOLTIP), SetFill(1, 1), NWidget(WWT_LABEL, COLOUR_DARK_GREEN, WID_BS_DRAG_SIGNALS_DENSITY_LABEL), SetDataTip(STR_ORANGE_INT, STR_BUILD_SIGNAL_DRAG_SIGNALS_DENSITY_TOOLTIP), SetFill(1, 1), NWidget(NWID_HORIZONTAL), SetPIP(2, 0, 2), @@ -2407,7 +2424,8 @@ void InitializeRailGUI() _cur_signal_button = _cur_signal_type == SIGTYPE_PROG ? 4 : _cur_signal_type == SIGTYPE_PBS ? 5 : - _cur_signal_type == SIGTYPE_PBS_ONEWAY ? 6 : _cur_signal_type; + _cur_signal_type == SIGTYPE_PBS_ONEWAY ? 6 : + _cur_signal_type == SIGTYPE_NO_ENTRY ? 7 : _cur_signal_type; ResetSignalVariant(); } diff --git a/src/rail_map.h b/src/rail_map.h index fd96e8d961..4535774237 100644 --- a/src/rail_map.h +++ b/src/rail_map.h @@ -349,6 +349,11 @@ static inline bool IsPresignalProgrammable(TileIndex t, Track track) return IsProgrammableSignal(GetSignalType(t, track)); } +static inline bool IsNoEntrySignal(TileIndex t, Track track) +{ + return IsNoEntrySignal(GetSignalType(t, track)); +} + /** One-way signals can't be passed the 'wrong' way. */ static inline bool IsOnewaySignal(TileIndex t, Track track) { @@ -526,6 +531,10 @@ static inline bool HasOnewaySignalBlockingTrackdir(TileIndex tile, Trackdir td) !HasSignalOnTrackdir(tile, td) && IsOnewaySignal(tile, TrackdirToTrack(td))) { return true; } + if (IsTileType(tile, MP_RAILWAY) && HasSignalOnTrackdir(tile, td) && + IsNoEntrySignal(tile, TrackdirToTrack(td))) { + return true; + } if (IsTileType(tile, MP_TUNNELBRIDGE) && IsTunnelBridgeSignalSimulationExitOnly(tile) && TrackdirEntersTunnelBridge(tile, td)) { return true; diff --git a/src/saveload/extended_ver_sl.cpp b/src/saveload/extended_ver_sl.cpp index 40c83824a1..9892b347bf 100644 --- a/src/saveload/extended_ver_sl.cpp +++ b/src/saveload/extended_ver_sl.cpp @@ -155,6 +155,7 @@ const SlxiSubChunkInfo _sl_xv_sub_chunk_infos[] = { { XSLFI_TRAIN_SPEED_ADAPTATION, XSCF_NULL, 1, 1, "train_speed_adaptation", nullptr, nullptr, "TSAS" }, { XSLFI_EXTRA_STATION_NAMES, XSCF_NULL, 1, 1, "extra_station_names", nullptr, nullptr, nullptr }, { XSLFI_DEPOT_ORDER_EXTRA_FLAGS,XSCF_IGNORABLE_UNKNOWN, 1, 1, "depot_order_extra_flags", nullptr, nullptr, nullptr }, + { XSLFI_EXTRA_SIGNAL_TYPES, XSCF_NULL, 1, 1, "extra_signal_types", nullptr, nullptr, nullptr }, { XSLFI_NULL, XSCF_NULL, 0, 0, nullptr, nullptr, nullptr, nullptr },// This is the end marker }; diff --git a/src/saveload/extended_ver_sl.h b/src/saveload/extended_ver_sl.h index 55455248d1..d42986dcce 100644 --- a/src/saveload/extended_ver_sl.h +++ b/src/saveload/extended_ver_sl.h @@ -109,6 +109,7 @@ enum SlXvFeatureIndex { XSLFI_TRAIN_SPEED_ADAPTATION, ///< Train speed adaptation XSLFI_EXTRA_STATION_NAMES, ///< Extra station names XSLFI_DEPOT_ORDER_EXTRA_FLAGS, ///< Depot order extra flags + XSLFI_EXTRA_SIGNAL_TYPES, ///< Extra signal types XSLFI_RIFF_HEADER_60_BIT, ///< Size field in RIFF chunk header is 60 bit XSLFI_HEIGHT_8_BIT, ///< Map tile height is 8 bit instead of 4 bit, but savegame version may be before this became true in trunk diff --git a/src/settings_gui.cpp b/src/settings_gui.cpp index 6a98b06080..e809d08127 100644 --- a/src/settings_gui.cpp +++ b/src/settings_gui.cpp @@ -1816,6 +1816,7 @@ static SettingsContainer &GetSettingsTree() SettingsPage *advsig = interface->Add(new SettingsPage(STR_CONFIG_SETTING_INTERFACE_ADV_SIGNALS)); { advsig->Add(new SettingEntry("gui.show_progsig_ui")); + advsig->Add(new SettingEntry("gui.show_noentrysig_ui")); advsig->Add(new SettingEntry("gui.show_adv_tracerestrict_features")); } diff --git a/src/settings_type.h b/src/settings_type.h index de2c002c39..5cb9cfd3f7 100644 --- a/src/settings_type.h +++ b/src/settings_type.h @@ -202,6 +202,7 @@ struct GUISettings : public TimeSettings { bool show_restricted_signal_default; ///< Show restricted electric signals using the default sprite bool show_adv_tracerestrict_features; ///< Show advanced trace restrict features in UI bool show_progsig_ui; ///< Show programmable pre-signals feature in UI + bool show_noentrysig_ui; ///< Show no-entry signals feature in UI bool show_veh_list_cargo_filter; ///< Show cargo list filter in UI uint8 osk_activation; ///< Mouse gesture to trigger the OSK. byte starting_colour; ///< default color scheme for the company to start a new game with diff --git a/src/signal.cpp b/src/signal.cpp index 1ca9e587a6..e1efee9043 100644 --- a/src/signal.cpp +++ b/src/signal.cpp @@ -774,7 +774,7 @@ static void UpdateSignalsAroundSegment(SigInfo info) } /* determine whether the new state is red */ - if (info.flags & SF_TRAIN) { + if (info.flags & SF_TRAIN || sig == SIGTYPE_NO_ENTRY) { /* train in the segment */ newstate = SIGNAL_STATE_RED; } else if (sig == SIGTYPE_PROG && diff --git a/src/signal_func.h b/src/signal_func.h index ec9d1fb98e..33311c488e 100644 --- a/src/signal_func.h +++ b/src/signal_func.h @@ -73,7 +73,7 @@ static inline bool IsComboSignal(SignalType type) /// Is a given signal type a PBS signal? static inline bool IsPbsSignal(SignalType type) { - return _settings_game.vehicle.train_braking_model == TBM_REALISTIC || type == SIGTYPE_PBS || type == SIGTYPE_PBS_ONEWAY; + return _settings_game.vehicle.train_braking_model == TBM_REALISTIC || type == SIGTYPE_PBS || type == SIGTYPE_PBS_ONEWAY || type == SIGTYPE_NO_ENTRY; } /// Is a given signal type a PBS signal? @@ -88,10 +88,16 @@ static inline bool IsProgrammableSignal(SignalType type) return type == SIGTYPE_PROG; } +/// Is this a programmable pre-signal? +static inline bool IsNoEntrySignal(SignalType type) +{ + return type == SIGTYPE_NO_ENTRY; +} + /** One-way signals can't be passed the 'wrong' way. */ static inline bool IsOnewaySignal(SignalType type) { - return type != SIGTYPE_PBS; + return type != SIGTYPE_PBS && type != SIGTYPE_NO_ENTRY; } /// Is this signal type unsuitable for realistic braking? @@ -119,6 +125,7 @@ static inline SignalType NextSignalType(SignalType cur, uint which_signals) case SIGTYPE_PROG: return pbs ? SIGTYPE_PBS : SIGTYPE_NORMAL; case SIGTYPE_PBS: return pbs ? SIGTYPE_PBS_ONEWAY : SIGTYPE_NORMAL; case SIGTYPE_PBS_ONEWAY: return block ? SIGTYPE_NORMAL : SIGTYPE_PBS; + case SIGTYPE_NO_ENTRY: return pbs ? SIGTYPE_PBS : SIGTYPE_NORMAL; default: DEBUG(map, 0, "Attempt to cycle from signal type %d", cur); return SIGTYPE_NORMAL; // Fortunately mostly harmless diff --git a/src/signal_type.h b/src/signal_type.h index fb7ccae4f5..042f0b9fea 100644 --- a/src/signal_type.h +++ b/src/signal_type.h @@ -29,11 +29,12 @@ enum SignalType { SIGTYPE_EXIT = 2, ///< presignal block exit SIGTYPE_COMBO = 3, ///< presignal inter-block SIGTYPE_PBS = 4, ///< normal pbs signal - SIGTYPE_PBS_ONEWAY = 5, ///< no-entry signal + SIGTYPE_PBS_ONEWAY = 5, ///< one-way PBS signal SIGTYPE_PROG = 6, ///< programmable presignal + SIGTYPE_NO_ENTRY = 7, ///< no-entry signal SIGTYPE_END, - SIGTYPE_LAST = SIGTYPE_PROG, + SIGTYPE_LAST = SIGTYPE_NO_ENTRY, SIGTYPE_FIRST_PBS_SPRITE = SIGTYPE_PBS, }; /** Helper information for extract tool. */ diff --git a/src/table/newgrf_debug_data.h b/src/table/newgrf_debug_data.h index fc7744ba7c..b45ffafd63 100644 --- a/src/table/newgrf_debug_data.h +++ b/src/table/newgrf_debug_data.h @@ -890,10 +890,11 @@ class NIHRailType : public NIHelper { HasBit(info->flags, RTF_ALLOW_90DEG) ? 'a' : '-', HasBit(info->flags, RTF_DISALLOW_90DEG) ? 'd' : '-'); print(buffer); - seprintf(buffer, lastof(buffer), " Ctrl flags: %c%c%c", + seprintf(buffer, lastof(buffer), " Ctrl flags: %c%c%c%c", HasBit(info->ctrl_flags, RTCF_PROGSIG) ? 'p' : '-', HasBit(info->ctrl_flags, RTCF_RESTRICTEDSIG) ? 'r' : '-', - HasBit(info->ctrl_flags, RTCF_NOREALISTICBRAKING) ? 'b' : '-'); + HasBit(info->ctrl_flags, RTCF_NOREALISTICBRAKING) ? 'b' : '-', + HasBit(info->ctrl_flags, RTCF_NOENTRYSIG) ? 'n' : '-'); print(buffer); seprintf(buffer, lastof(buffer), " Powered: 0x" OTTD_PRINTFHEX64, info->powered_railtypes); print(buffer); diff --git a/src/table/settings.ini b/src/table/settings.ini index 638b0d06c6..ce0c1a9a70 100644 --- a/src/table/settings.ini +++ b/src/table/settings.ini @@ -5412,6 +5412,15 @@ strhelp = STR_CONFIG_SETTING_SHOW_PROGSIG_FEATURES_HELPTEXT proc = ProgrammableSignalsShownChanged cat = SC_ADVANCED +[SDTC_BOOL] +var = gui.show_noentrysig_ui +flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC +def = false +str = STR_CONFIG_SETTING_SHOW_NOENTRYSIG_FEATURES +strhelp = STR_CONFIG_SETTING_SHOW_NOENTRYSIG_FEATURES_HELPTEXT +proc = ProgrammableSignalsShownChanged +cat = SC_ADVANCED + [SDTC_BOOL] var = gui.show_veh_list_cargo_filter flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC diff --git a/src/table/sprites.h b/src/table/sprites.h index 1fdf7ac142..1543225abe 100644 --- a/src/table/sprites.h +++ b/src/table/sprites.h @@ -314,8 +314,13 @@ static const SpriteID SPR_PROGSIGNAL_BASE = SPR_PALETTE_BASE + PALETTE_SPRITE_CO static const uint16 PROGSIGNAL_SPRITE_COUNT = 32; static const SpriteID SPR_DUP_PROGSIGNAL_BASE = SPR_PROGSIGNAL_BASE + PROGSIGNAL_SPRITE_COUNT; +/* Extra signal sprites */ +static const SpriteID SPR_EXTRASIGNAL_BASE = SPR_DUP_PROGSIGNAL_BASE + PALETTE_SPRITE_COUNT; +static const uint16 EXTRASIGNAL_SPRITE_COUNT = 16; +static const SpriteID SPR_DUP_EXTRASIGNAL_BASE = SPR_EXTRASIGNAL_BASE + EXTRASIGNAL_SPRITE_COUNT; + /* Zoning sprites */ -static const SpriteID SPR_ZONING_INNER_HIGHLIGHT_BASE = SPR_DUP_PROGSIGNAL_BASE + PROGSIGNAL_SPRITE_COUNT; +static const SpriteID SPR_ZONING_INNER_HIGHLIGHT_BASE = SPR_DUP_EXTRASIGNAL_BASE + EXTRASIGNAL_SPRITE_COUNT; static const uint16 ZONING_INNER_HIGHLIGHT_SPRITE_COUNT = 32; static const SpriteID SPR_ZONING_INNER_HIGHLIGHT_RED = SPR_ZONING_INNER_HIGHLIGHT_BASE + 19; static const SpriteID SPR_ZONING_INNER_HIGHLIGHT_GREEN = SPR_ZONING_INNER_HIGHLIGHT_BASE + 20; @@ -1372,6 +1377,7 @@ static const SpriteID SPR_IMG_SIGNAL_ELECTRIC_COMBO = SPR_SIGNALS_BASE + 44; static const SpriteID SPR_IMG_SIGNAL_ELECTRIC_PBS = SPR_SIGNALS_BASE + 124; static const SpriteID SPR_IMG_SIGNAL_ELECTRIC_PBS_OWAY = SPR_SIGNALS_BASE + 140; static const SpriteID SPR_IMG_SIGNAL_ELECTRIC_PROG = SPR_PROGSIGNAL_BASE + 28; +static const SpriteID SPR_IMG_SIGNAL_ELECTRIC_NO_ENTRY = SPR_EXTRASIGNAL_BASE + 14; static const SpriteID SPR_IMG_SIGNAL_SEMAPHORE_NORM = SPR_SIGNALS_BASE + 60; static const SpriteID SPR_IMG_SIGNAL_SEMAPHORE_ENTRY = SPR_SIGNALS_BASE + 76; static const SpriteID SPR_IMG_SIGNAL_SEMAPHORE_EXIT = SPR_SIGNALS_BASE + 92; @@ -1379,6 +1385,7 @@ static const SpriteID SPR_IMG_SIGNAL_SEMAPHORE_COMBO = SPR_SIGNALS_BASE + 108; static const SpriteID SPR_IMG_SIGNAL_SEMAPHORE_PBS = SPR_SIGNALS_BASE + 188; static const SpriteID SPR_IMG_SIGNAL_SEMAPHORE_PBS_OWAY= SPR_SIGNALS_BASE + 204; static const SpriteID SPR_IMG_SIGNAL_SEMAPHORE_PROG = SPR_PROGSIGNAL_BASE + 12; +static const SpriteID SPR_IMG_SIGNAL_SEMAPHORE_NO_ENTRY= SPR_EXTRASIGNAL_BASE + 6; static const SpriteID SPR_IMG_SIGNAL_CONVERT = SPR_OPENTTD_BASE + 135; static const SpriteID SPR_IMG_TUNNEL_RAIL = 2430; diff --git a/src/train_cmd.cpp b/src/train_cmd.cpp index e2e9e120a8..5ea0a9e315 100644 --- a/src/train_cmd.cpp +++ b/src/train_cmd.cpp @@ -3172,7 +3172,8 @@ static void CheckNextTrainTile(Train *v) if (!HasReservedTracks(ft.m_new_tile, TrackdirBitsToTrackBits(ft.m_new_td_bits))) { /* Next tile is not reserved. */ if (KillFirstBit(ft.m_new_td_bits) == TRACKDIR_BIT_NONE) { - if (HasPbsSignalOnTrackdir(ft.m_new_tile, FindFirstTrackdir(ft.m_new_td_bits))) { + Trackdir td = FindFirstTrackdir(ft.m_new_td_bits); + if (HasPbsSignalOnTrackdir(ft.m_new_tile, td) && !IsNoEntrySignal(ft.m_new_tile, TrackdirToTrack(td))) { /* If the next tile is a PBS signal, try to make a reservation. */ TrackBits tracks = TrackdirBitsToTrackBits(ft.m_new_td_bits); if (ft.m_tiles_skipped == 0 && Rail90DegTurnDisallowedTilesFromTrackdir(ft.m_old_tile, ft.m_new_tile, ft.m_old_td)) { @@ -3575,7 +3576,7 @@ void FreeTrainTrackReservation(Train *v, TileIndex origin, Trackdir orig_td) break; } if (HasPbsSignalOnTrackdir(tile, td)) { - if (GetSignalStateByTrackdir(tile, td) == SIGNAL_STATE_RED) { + if (GetSignalStateByTrackdir(tile, td) == SIGNAL_STATE_RED || IsNoEntrySignal(tile, TrackdirToTrack(td))) { /* Red PBS signal? Can't be our reservation, would be green then. */ break; } else { @@ -3972,6 +3973,7 @@ static bool LookaheadWithinCurrentTunnelBridge(const Train *t) static bool HasLongReservePbsSignalOnTrackdir(Train* v, TileIndex tile, Trackdir trackdir, bool default_value) { if (HasPbsSignalOnTrackdir(tile, trackdir)) { + if (IsNoEntrySignal(tile, TrackdirToTrack(trackdir))) return false; if (IsRestrictedSignal(tile)) { const TraceRestrictProgram *prog = GetExistingTraceRestrictProgram(tile, TrackdirToTrack(trackdir)); if (prog && prog->actions_used_flags & TRPAUF_LONG_RESERVE) { @@ -4122,7 +4124,7 @@ static Track ChooseTrainTrack(Train *v, TileIndex tile, DiagDirection enterdir, if (KillFirstBit(tracks) == TRACK_BIT_NONE) { Track track = FindFirstTrack(tracks); /* We need to check for signals only here, as a junction tile can't have signals. */ - if (track != INVALID_TRACK && HasPbsSignalOnTrackdir(tile, TrackEnterdirToTrackdir(track, enterdir))) { + if (track != INVALID_TRACK && HasPbsSignalOnTrackdir(tile, TrackEnterdirToTrackdir(track, enterdir)) && !IsNoEntrySignal(tile, track)) { if (IsRestrictedSignal(tile) && v->force_proceed != TFP_SIGNAL) { const TraceRestrictProgram *prog = GetExistingTraceRestrictProgram(tile, track); if (prog && prog->actions_used_flags & (TRPAUF_WAIT_AT_PBS | TRPAUF_SLOT_ACQUIRE | TRPAUF_SLOT_ACQUIRE_ON_RES | TRPAUF_TRAIN_NOT_STUCK)) { @@ -5279,6 +5281,10 @@ bool TrainController(Train *v, Vehicle *nomove, bool reverse) /* Don't handle stuck trains here. */ if (HasBit(v->flags, VRF_TRAIN_STUCK)) return false; + if (IsNoEntrySignal(gp.new_tile, TrackdirToTrack(i)) && HasSignalOnTrackdir(gp.new_tile, i)) { + goto reverse_train_direction; + } + if (!HasSignalOnTrackdir(gp.new_tile, ReverseTrackdir(i))) { v->cur_speed = 0; v->subspeed = 0; diff --git a/src/widgets/rail_widget.h b/src/widgets/rail_widget.h index 0fafb5ca70..9ec9afc8a6 100644 --- a/src/widgets/rail_widget.h +++ b/src/widgets/rail_widget.h @@ -86,6 +86,7 @@ enum BuildSignalWidgets { WID_BS_SEMAPHORE_PROG, ///< Build a semahore programmable pre-signal WID_BS_SEMAPHORE_PBS, ///< Build a semaphore path signal. WID_BS_SEMAPHORE_PBS_OWAY, ///< Build a semaphore one way path signal. + WID_BS_SEMAPHORE_NO_ENTRY, ///< Build a semaphore no-entry signal. WID_BS_ELECTRIC_NORM, ///< Build an electric normal block signal WID_BS_ELECTRIC_ENTRY, ///< Build an electric entry block signal WID_BS_ELECTRIC_EXIT, ///< Build an electric exit block signal @@ -93,6 +94,7 @@ enum BuildSignalWidgets { WID_BS_ELECTRIC_PROG, ///< Build an electric programmable pre-signal WID_BS_ELECTRIC_PBS, ///< Build an electric path signal. WID_BS_ELECTRIC_PBS_OWAY, ///< Build an electric one way path signal. + WID_BS_ELECTRIC_NO_ENTRY, ///< Build an electric no-entry signal. WID_BS_CONVERT, ///< Convert the signal. WID_BS_TRACE_RESTRICT, ///< Open trace restrict window. WID_BS_PROGRAM, ///< Enter program to prog signal @@ -107,6 +109,8 @@ enum BuildSignalWidgets { WID_BS_ELECTRIC_COMBO_SEL, ///< NWID_SELECTION for WID_BS_ELECTRIC_COMBO WID_BS_SEMAPHORE_PROG_SEL, ///< NWID_SELECTION for WID_BS_SEMAPHORE_PROG WID_BS_ELECTRIC_PROG_SEL, ///< NWID_SELECTION for WID_BS_ELECTRIC_PROG + WID_BS_SEMAPHORE_NOEN_SEL, ///< NWID_SELECTION for WID_BS_SEMAPHORE_NO_ENTRY + WID_BS_ELECTRIC_NOEN_SEL, ///< NWID_SELECTION for WID_BS_ELECTRIC_NO_ENTRY WID_BS_PROGRAM_SEL, ///< NWID_SELECTION for WID_BS_PROGRAM };