From 4bb4c7027728bfe933b5b17f54b9782ddbf82b12 Mon Sep 17 00:00:00 2001
From: SapphicOverload <93578146+SapphicOverload@users.noreply.github.com>
Date: Thu, 2 Oct 2025 07:14:54 -0400
Subject: [PATCH 1/3] Language Menu + Language Scrambling Rework + Splits
Kalixcian Into Multiple Languages (#4988)
Replaces the language quirks with a proper language menu, where you can
select which languages your character knows and how well.
This also splits Kalixcian Common into two different languages, Gezenan
and Zohilan, originating from the Pan-Gezena Federation and Zohil
Explorat respectively as well as being widely spoken in their current
and former colonies. Both have a very high (90%) mutual understanding of
each other.
The way not understanding a language scrambles text has also been
reworked so that instead of being randomized for every message, it now
uses a hash function to always scramble the same original words to the
same scrambled text within a given round, making it possible to infer
the meaning of certain words based on context.
Images:
Zohilan to a native Gezenan speaker. For fun, try to figure out the
meaning of some of the words in this paragraph.

Helm console on a PGFN vessel.

Language selection!

Zohilan language icon by Aquidu:
"
dat += "Preferred AI Core Display: [preferred_ai_core_display]
"
+ dat += "
| [get_language_point_balance()] points left. | |
| Native Language: [initial(native_language.name)] | |
| [initial(lang_type.name)]: | " + dat += "[learned_languages[lang_type]] |
| Reset Languages |
hi~9S~o-A0m(0PY>)AN)j z8&ql^77;i6Kuo-f=_T9Jedkq&6=TYzNl;yOp_&h*=0y}3mTDQ2g3BCMthQPS*MHkWWK~uzXrcc0V35!jiIv2+)K F4fJ~EUA=JJxtF8qXcGD&FASN2 RQ3hVbt0vO>hac6Q$RcQH%EuxfvNd*oaq z^x}BlB}`7&cmj}PZRqw3U6++Nre9eS7+9vKtE$31yG)C(^T~oiahz*v&Z=U)`p-%= zo{~K*8medVI+X78iDr03xwcu^q9x809?l6Wi7D!e=?^ss8LBaJMY0J?sj)T+G8&6s zB9_2f8Fy)%aUWFZp_O`LESQqP>%i_DGD3?T9uQlgSN2Zua7r(desr@&0?A2QMpMR< zJpugX+OAX`QA^{t__^yNhN`swPB`BbO-xVONSb;F=Z+3nV-4hCl+cw7TX_CXh1DEm zvZ2$hm=hATfE%W=4fpchV8IzSZ2gsjcqho!%zrHz=emE_U39vR2Sj8`4vo7yiya)8 zAXo0%U?g^$MkCegSZJYLvWzddHkKLVV$MC1NQ@`0P8D#~(kW+>e}ZA>pEqyMAK{0o z6*DyxijNDkV`@GUI@#Bgg?)UjrfTxqlu1II$(h>q(n%oHOQ(p$t?b!8!Gt&B1QQdp zT0vj_(S1JheRBibYo7feDu_eAhYs%lU$&y4NF6T?gM#|bpRtn=XC#e&3X?(wz|72? z>$0|oD_CAq$upp?&x8hKNWY0}i~R>z4}x50ME|bJV*Z z24@>8RS8;~W(tRI&WISlG^Hkuc6H_;`Z#u)Cr?yu?d)0y22}W8&GG7ry?F7r>^nnH z=txH$wS{|IUTrI#FW0}Z)nv6#hRf)gK^U5W03A?u;z%8mY*&sRqPj`;wTS5lERsR| zrfjKL_NwR*S6u~iA^e;%h9I{eL4`fYVK7C(*pMS>71iU3Cy5B^dj7Mykbc;Av-{a* z^Y$L;SheI+!pq+M`=fNeCTYr1s(0T6tiG-32>l6Ge&o2lU9%A^v{gv}3-PO%W<)`9 zlLGLjpeYMFLlayoN(Ccn#m>k|5iZrKYq@3y6Bs=SQ1qd$zMhmy1TP>UV+V1>baux7 z|J(fhd=0iP0-x3S7H-RBtTO#)*T~0bZDqWc7CXS3y^$lPCQnGmcCQ#n8 _?&EkJgL20}&B(_&MH~xn z+kG9heLq=D97>s%H=Piwg%fd%1KCb#`tt*l0}6brgmQb*{VmRjG{pszPU;Qr8|2&E zuHk-a&YqF``(SX-C4O$%5&P IVn2_M=v#Jbl);UUQPne$HjX62v?fis9RCn+Qz~EKf6=^i9rH36$-h# z`--Z}jWP1JDCuSd!zG+`UyU;0Z-tTP6b9!{Qo2G+@<@o{5ly|NuA_4}>^%Di&il-` zOjGDW%K^O=b^>D)?_ww91cij=yOONwu3%89x49pP>1`TKk%!+!Yy-TGDifGrnx0Sz z3co0DjiwA;A8Re-jCBcZTYxq+2+BY7H3PuivSr=1>{Bj6W*a `}< z;aO@a`cn5b!b@b!88Uct!Tcpbw)yL#MpkyFVgRCRVVWq>?2v$n#DkuP{Bi2atfe=t zOEvMMO@sxjYK6YuL6^3k-bdUw#>VNd%*Ls%*7AUYKzojRVf%2!O=5W?vc43u7H?GB zLA*xWBTPW GaSX_@g zsRSYIBKey@2R~7b$X2{t;`^^j7N$4<&{FSteT4EiSAP>*=R76ty@Acz-m8g89%KBf ze8&3{nx7+<*%PD#1AhHGmP6gQ<7SH`gf*3bbwmD`0szYCrwdzZ`g1NF^gb7Piev3& zdk)`hglra{*SGosyf!Ad1%*5xFZPwaS`lgVwqRz$m6pUV&*Uquq(8 Yu;+T0j*#92O4F(19CFBCKaTeRr;+Kxl1sN9cZTwNZrA9I0&i@uE!h2wiCi zjJSDQyx?Z!5tW~Uh+yjU>}(v7vVo!DQ?XA|M1U8M^h*+f%c}0!D`ZQWKdud;x_#a9 z4`b!KuQ9`&oHDDMmLcqIs(tHX5*^4yDITJ?M%o^L%yCZVNnR;X)IpflOst+}lv-F^ z3u_XHq9uK~5aiLzX-)OM`HGl9T!6q5t&jJxQ}{5-i9cf?mCMXHa440FH$!8TC0ztf z##ss5iw~bHHFD)gbtuTkdy7a!q5)ByY Q3{JzknPrcGn! zPl+`qH8XHb8=V$tWt&{FL3mp@0ed*?!r&VKk29m~#Pp|!)$nIh&eXCNj=$R+O2b&O zn9sCVYg8@n{qZBwY-4b6Pq@-&;jAGuy(YRnBpgR}Rn;CWRPLgjm%AQ*Z0kqi_~-je z2nt}V+TUm~SSQTG4|%x-h8v(d5hsB4_1Wey^oy#K2@=LJ&S->FQ%8+DtC0NAa!CTV zhwPRma@26DKSFXbBND;X+fcLEY-H3S=t5QH@Ujo469y)w M!8w^(wwsQdag>ThAk>%d4SgwjjQ|$i*{L zZ)y4jntOUUO>tL(7+I2ROHIe;u;x0u7cXwfrT}+8&_(>>Cr=*q;1A9&^>^Li=F9KC zD54eU=FzH?dpl}W$9+D_llrVl_1>E3l%V!OooD@$EpOicgMP&{!ml}rj2eSy@c=v{ zHp(_?+q)?z(0p%sy*_s_y=YzsAA}GAP2YYbzp?8o&9WpY#?&&c!u0aH(lJN2XB1-) zSIR7&8&`@#W9m|^ug*6x^zBsf*SebTu`)aB-u03f6?*w!b~jzY(E;QOx2?1IYvUFt zQWNkV6yCC%EJ6GtENO3#Rtz#bDRn7F)(YCzzp`MIuvz%VN$x(6kX<51=^DerK=9~4 zzcLlL->f<~^4nM9=uL9w{)9;1!?A*D+irf~5>maj>3dt_y*+}@Q+;IN{3KGf81s0C z?e=MCU}Ky)Uz594&r$Mi56#&Ks*2J#LE5FeEw{Sh2oZf +`_G?WO`9PV z1ZKw8E`h8i?=L(DAd?dl>6_yifSS5`Qg(KvR<^i*O6vFvJ=(h>I-%)bA~&j%Qxz6@ zmWSwf*dd3nu7-=|aDH`#$I`=Xbg{x`XKX3q!#X3D14HffAfU{I|9pDMS%Y&7cqA^W zh{oYSaB%7xe0yNk3kbk67xw`GL5UDTZS6n6(vqaizLKKiYq|Z3vMv9*3u>t13P@#r zHH ~X{`6=aVSnl$3L`E z1D7Fk3W{%*wyOn-m;lHV8dp!&=6@+Ci?Ctb+oQ**@v-6%g-`i{EcvE~6}U-i^~Vfp zV7ltI*dO#)*C*{vOh97+Yi*TE16N-d)8m|yvkeftXQ+Kyzm*?gIhgA~llh!Ld(un5 zV|#mbx-(T9UaG;t3cq<2&-=y!{M!%`ri@jx0*3K(BcFelaXwl3GA`wYh)ZNU&lQIU zT*&C?kU0FxjAWEY2TrQAn1v`J+1RS`$BrEJo&VBqM4Xhk`~`UBU#ah7yqxLnphija zscYi&{-KVVI#;vh *K71{> !<{MgrY*xGop+ zOsk5nxTy)g?7FyDv5TCaoyzL#la-fqB;|T2xVdo!USHMRAQ50wRBdgclPK!~Oz?8w zE++W1A&=TXdwW(&x5%5X7q<=r%SQ2J#lKAr5$65cHZEvz<3^SIeRnW%1_mikuUw+) z>jl8_9GjaO{<(9eHK)YB*F 6Tn>GF~)_VYv{0Slr@DP=I9t4nvK{qu=L7Bo$nRm z>WYX`a{u-Q-4}rS1h8fKO#W3%Ei&C6${P>o*!(SmlqsE- RYfg@Dmm-7{{iZm#`6FG delta 4678 zcmV-M61nY>DBC2EBmvQpB_My CR=lc7LS?kO?YH*MY~gU4U^>q3A1u(+UBWGdQUCxE zMM*?KRCt{2oOyH=Ri4K`g$aa3NC<=-5^Rvoh73bH4#In=5QGN7qe$XWlhX~&I=oS^ znFzRqj%g9*At39S1UY{usC`BjL6+|3JrEU{n1p@nyvINmvL}QPvvB8+%B|F^ye%}? z@i^ae>Qvpesy^@cyT5yH3KW~o#{cW?)e2zcEwj*PF4!{5CGD&H=d1vCaMsV>s>rji za!(yki;5BeyAB>y^w+)~$ZT%BpUq}djA?&gY~8wbF3-Ji;X;4E+crl5%i7zTK+?-s zxn9$vqJ#vt`&Yl>neV ?ex^(G6QNw+q5okg}g7638#OU$by$_@v_E=weY9Cs~ zW$jfL(YvSK`rLn&OHGT45=;8`XH|B#2F{&UWoP^4%2J+y8r@mKGlFxcgoK19mS|2j z30sU^fkt@MQ)&p>+Zt$usILdmYFT@mlK=4l4Guu}7cXlayDRskW2L1Uykn)Mtjf;T zj$@^z04(X>UmG9Y$!s dTF3XtcgDAt4&PZ%a$rb?~4fk8ev$HHhB8 zxy$$1$RKy{Bs625%RN#}BCt;wL3>*>^wGgue%%AX+V#*!2NSfnHGzG?FsGWdXKH1< zp+A=9OA>#cK2Jh)Ctr}HCCaq^T3VkG3N!_!m$X82s!0UxZLPWJ*%Rma+ZiVS0rjf2 z{q2mCvnS32sw)TWZLLAPXF=rgE?u z8`;m#Mq-p>HE<~%|N2c-}&9$Oly4h z* }+BC*EMe%f&mg#G(G)7tp&)xWFl+n`kVBNXz zx^;i+gvDa<)} oE&A0IC29tg&6Z=9l-OeSGW2h^AGm#?z4JfABOqncCS zIHdvqmUG_Z&Po?9T&P&B*2Y=Ev}tbJ?%K7>rH#JqFJEOTm`pD3rHAKIPp5kpM2ym} zfo0m?w#F5SKW+3tjB`A9b==7vFkj_9S0aDLw7Zqb&soa7-VaO}H% lRr-l3@)MO(4_ec*cW!yNS2c=Kz>lqc%u|(8nyes-f zPRC?2iA(m)^o^WOZFL0^9ZQ7CFiv?=Mv_J7&&`psjkiAT89;YXj1YaPHsf8 GM#pQWpH>D_X6VxBWZdj$dJc=G#j~>6oZa+zn9>0Hd$@k+q zG}m +DpQ`k(_SA!TM}GHlocE?h{b z|5x8};X*pYhD{(dGZSwRjZlA5#*Gu+f`w6S0)C)ffI>*SRy^EYp{PpDh3;JsyPG z+IqS~!_IfkxP>5HSF=8;bNi95?9L4>mS8fHEFyBLRU!SP=B^T^WlIdCpCodrRmn)Q z2#ck0o6BVy6CWQhh7Fs*mT`|UbmcP6E?cRcXCL{7GiMIr%Z)uj^W}fW8*(2JL!> z2MBG*D+aFV>Ri8APKPUR z=+r6D8v_?mMv%VdfS-STbc(uSGld
*F_}h@mzT$5i$^kO&`2Iz44pa! z(yd!J?Dms*k|%!)a|hBJL pQX10QJG|E3frc2kNH zx1+1eSO{qFWF2?+wFkYW*n{3uVmGBI+C;j+qO+W3#BNGaWF37w4d8|itCZu%_j!G} z s)CCb~fia(j64tH`>T4(|%%!%r)^|s`dEi}X x_3{1gD&A0P4gL#E7$6|tLA z6nSpWyBOEQ!^4BMXm8X#+fX%bUwNzNF5k9PQOtjdM+A53;LdHR`vLC!0JW8__56VM z_bPI!RUyeD 9h)BV7ovQAv=AWmHD(Ch%%q5;Om#fiAMxF7Xn&gMdF zG6r6Le~kzXsB_5+x4ho$ai>kr$D(`BF!FN?_@UQ}&1!Fpj#j^pGNjFEX@2*Ul9J*A zA~t_E)@$2GAFfnRT >KBaDbGJa*w7I;E~!62W_ku;Lq{;>`6v8_=yW>8+O=!7^xCy+ zaXOv%J(x@}g(_j)`w`Z?pJs)=f=Yh?K;_MH&R#l8{hd4XerO=Mjw_Uwm(sCAN3Q4P z&>J*(r_P_^MnO%JjwHOn!-jDF%sJY$X~X9C|BETlKLNntVM74eyK$Z{&Hd1$J35_C z5fKpqsNeu(+Tn1B@bK{aI+n^{BGU!=SK;AMkM&ytnAdGkzWtx;oVjp@!v}wMbNa$* zE@xlH_Kl5#ynMd@KAnQRd~))0+;(E$I8VGVD@KC^&@Q;U%NbONFU*SZXo-4w?i3Lb z;nNb|eADyr;;l@|I2Oh}Kf KPOAd#FMT-^zsw?{gS8BD%#A^nKt4$`q+so<8UVE|Fe+(v#388 h4`}I6wx)9RdI|k{cLtze@6KGkUcx6^8~4^u>_6Z&py=TN zELyY(hr{9RQ2}`S?YFfbcD2dma=5GGOH)jtim$n#Uz-Vs=loWCS)=t`-Lp(Q@~ ;Hi6<@6c=1;`gz;^*p0DooF~G2b*A6cmCDsU%Y-wh1aFb|r=TAd;Lk}~5IK7E zs2DqTtYW OS!z(%M& #0}@ni)*y>u#aCQX=)-% z_rz0FA4Sg|YGA4 C>&lqUn_Rdv1L>i`={tit3~Me7*ZGmof0Q z*Iw0L>{iunh7BFUh!K%&-n_XaEUas1Stemhd4jj+4RsU1{CaD5#jN}ARjr@YS7wS| zKN!@c&KEbUS@G>@Zhbk6@)3WeQ|9k!|MXU_Ts*4)v Qb h*MQ2)OH8L6ctJa J?BR- ?=T1F^h3Xc*EN__ZxP>U)RPU}5Ui4c3;Kgj; zsXXiallb>lN432FTr!rR@aI~T^+AIRpFVZUB{=lz*^}DZTFS~w$ g4PM TUwLWODKxut) z9F*x>Rkt;Ga(Q?3=ux3>15K?^%CsU}gC-BDv`>?K0+CkNQmqdROF6xTd6Ks}`ZYSP zH%s#eo>b~9GljRv+ae~?Ql8w>-#XF~qh~C2yCiE4xSxvt4@W%|7=(l|4FCWD07*qo IM6N<$f}}l2mjD0& diff --git a/shiptest.dme b/shiptest.dme index 03f4b126a71..f35c34b5e57 100644 --- a/shiptest.dme +++ b/shiptest.dme @@ -918,6 +918,7 @@ #include "code\datums\traits\negative\frail.dm" #include "code\datums\traits\negative\heavy_sleeper.dm" #include "code\datums\traits\negative\light_drinker.dm" +#include "code\datums\traits\negative\monolingual.dm" #include "code\datums\traits\negative\mute.dm" #include "code\datums\traits\negative\nearsighted.dm" #include "code\datums\traits\negative\paraplegic.dm" @@ -928,7 +929,6 @@ #include "code\datums\traits\neutral\bald.dm" #include "code\datums\traits\neutral\deviant_tastes.dm" #include "code\datums\traits\neutral\gunslinger.dm" -#include "code\datums\traits\neutral\languages.dm" #include "code\datums\traits\neutral\monochromatic.dm" #include "code\datums\traits\neutral\musician.dm" #include "code\datums\traits\neutral\photographer.dm" @@ -941,6 +941,7 @@ #include "code\datums\traits\positive\friendly.dm" #include "code\datums\traits\positive\light_step.dm" #include "code\datums\traits\positive\self_aware.dm" +#include "code\datums\traits\positive\trilingual.dm" #include "code\datums\votes\_vote_datum.dm" #include "code\datums\votes\custom_vote.dm" #include "code\datums\votes\restart_vote.dm" @@ -2542,11 +2543,10 @@ #include "code\modules\keybindings\focus.dm" #include "code\modules\keybindings\setup.dm" #include "code\modules\language\aphasia.dm" -#include "code\modules\language\buzzwords.dm" #include "code\modules\language\codespeak.dm" #include "code\modules\language\common.dm" -#include "code\modules\language\draconic.dm" #include "code\modules\language\drone.dm" +#include "code\modules\language\gezenan.dm" #include "code\modules\language\language.dm" #include "code\modules\language\language_holder.dm" #include "code\modules\language\language_menu.dm" @@ -2563,6 +2563,7 @@ #include "code\modules\language\teceti_unified.dm" #include "code\modules\language\vox_pidgin.dm" #include "code\modules\language\xenocommon.dm" +#include "code\modules\language\zohilan.dm" #include "code\modules\library\lib_items.dm" #include "code\modules\library\lib_machines.dm" #include "code\modules\library\random_books.dm" diff --git a/tgui/packages/tgui/interfaces/LanguageMenu.tsx b/tgui/packages/tgui/interfaces/LanguageMenu.tsx index ad58fd2163c..03577e0402a 100644 --- a/tgui/packages/tgui/interfaces/LanguageMenu.tsx +++ b/tgui/packages/tgui/interfaces/LanguageMenu.tsx @@ -70,6 +70,7 @@ const LangUnderstandIcon = (props: LanguageProps) => { borderBottom: '2px dotted rgba(255, 255, 255, 0.8)', }} > + {language.partial_understanding}% From c45643910cc550e4d9151c22ef05b657b0f34855 Mon Sep 17 00:00:00 2001 From: "Ossa88 (SYNAPSE)" Date: Thu, 30 Jul 2026 06:42:15 -0700 Subject: [PATCH 2/3] Language system hardening --- code/modules/client/preferences.dm | 34 +++++++++++++++++++ code/modules/client/preferences_savefile.dm | 9 +++++ .../code/modules/language/language_holder.dm | 32 ----------------- 3 files changed, 43 insertions(+), 32 deletions(-) diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm index adeb1b9c571..9bf04fad3bf 100644 --- a/code/modules/client/preferences.dm +++ b/code/modules/client/preferences.dm @@ -1614,6 +1614,18 @@ GLOBAL_LIST_EMPTY(preferences_datums) if(balance + value < 0) to_chat(user, span_warning("Refunding this would cause you to go below your balance!")) return + // PENTEST ADDITION - START - Check if removing Trilingual or adding Monolingual would cause negative language points + if(quirk == "Trilingual" || quirk == "Monolingual") + var/temp_quirks = all_quirks.Copy() + temp_quirks -= quirk + var/old_all_quirks = all_quirks + all_quirks = temp_quirks + var/lang_balance = get_language_point_balance() + all_quirks = old_all_quirks + if(lang_balance < 0) + to_chat(user, span_warning("You cannot remove this quirk as it would leave you with insufficient language points! Reset your languages first.")) + return + // PENTEST ADDITION - END all_quirks -= quirk else var/is_positive_quirk = SSquirks.quirk_points[quirk] > 0 @@ -1623,6 +1635,18 @@ GLOBAL_LIST_EMPTY(preferences_datums) if(balance - value < 0) to_chat(user, span_warning("You don't have enough balance to gain this quirk!")) return + // PENTEST ADDITION - START - Check if adding Monolingual or removing Trilingual would cause negative language points + if(quirk == "Trilingual" || quirk == "Monolingual") + var/temp_quirks = all_quirks.Copy() + temp_quirks += quirk + var/old_all_quirks = all_quirks + all_quirks = temp_quirks + var/lang_balance = get_language_point_balance() + all_quirks = old_all_quirks + if(lang_balance < 0) + to_chat(user, span_warning("You cannot select this quirk as it would leave you with insufficient language points! Reset your languages first.")) + return + // PENTEST ADDITION - END all_quirks += quirk SetQuirks(user) if("reset") @@ -2634,7 +2658,17 @@ GLOBAL_LIST_EMPTY(preferences_datums) character.dna.update_body_size() if(!character_setup && get_language_point_balance() < 0) + // PENTEST ADDITON - START - This is a check to prevent exploits where players can gain more languages than they should be able to. If this happens, it will reset their languages and log it to admins. + log_admin("WARNING: [parent?.ckey] spawned with negative language points. Resetting languages.") + message_admins("WARNING: [key_name_admin(parent)] spawned with negative language points. Languages have been reset.") + // PENTEST ADDITION - END init_learned_languages() // no exploits allowed + else if(get_language_point_balance() < 0) + // Pentest ADDITION - START - Additional check during character setup + log_admin("WARNING: [parent?.ckey] in character setup with negative language points. Resetting languages.") + message_admins("WARNING: [key_name_admin(parent)] in character setup with negative language points. Languages have been reset.") + init_learned_languages() + // PENTEST ADDITION - END character.grant_language(native_language) character.get_language_holder().selected_language = native_language for(var/datum/language/lang_type as anything in learned_languages) diff --git a/code/modules/client/preferences_savefile.dm b/code/modules/client/preferences_savefile.dm index e89d7230b5a..17bd8fd7046 100644 --- a/code/modules/client/preferences_savefile.dm +++ b/code/modules/client/preferences_savefile.dm @@ -610,6 +610,15 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car /datum/preferences/proc/save_character() if(!path) return FALSE + + // PENTEST ADDITION - START - Validate language points before saving + var/lang_balance = get_language_point_balance() + if(lang_balance < 0) + log_admin("WARNING: [parent?.ckey] attempted to save character with negative language points ([lang_balance]). Resetting languages.") + message_admins("WARNING: [key_name_admin(parent)] attempted to save character with negative language points ([lang_balance]). Languages have been reset.") + init_learned_languages() + // PENTEST ADDITION - END + var/savefile/S = new /savefile(path) if(!S) return FALSE diff --git a/modular_pentest/master_files/code/modules/language/language_holder.dm b/modular_pentest/master_files/code/modules/language/language_holder.dm index b8d38baf1f8..cdfaef69360 100644 --- a/modular_pentest/master_files/code/modules/language/language_holder.dm +++ b/modular_pentest/master_files/code/modules/language/language_holder.dm @@ -6,35 +6,3 @@ understood_languages = list(/datum/language/swarmer = list(LANGUAGE_ATOM)) spoken_languages = list(/datum/language/swarmer = list(LANGUAGE_ATOM)) blocked_languages = list(/datum/language/galactic_common = list(LANGUAGE_ATOM)) - -/* -/datum/language_holder/human - understood_languages = list(/datum/language/galactic_common = list(LANGUAGE_ATOM), - /datum/language/solarian_international = list(LANGUAGE_ATOM)) - spoken_languages = list(/datum/language/galactic_common = list(LANGUAGE_ATOM), - /datum/language/solarian_international = list(LANGUAGE_ATOM)) -*/ - -/datum/language_holder/lizard - understood_languages = list(/datum/language/galactic_common = list(LANGUAGE_ATOM), - /datum/language/kalixcian_common = list(LANGUAGE_ATOM)) - spoken_languages = list(/datum/language/galactic_common = list(LANGUAGE_ATOM), - /datum/language/kalixcian_common = list(LANGUAGE_ATOM)) - -/datum/language_holder/moth - understood_languages = list(/datum/language/galactic_common = list(LANGUAGE_ATOM), - /datum/language/moffic = list(LANGUAGE_ATOM)) - spoken_languages = list(/datum/language/galactic_common = list(LANGUAGE_ATOM), - /datum/language/moffic = list(LANGUAGE_ATOM)) - -/datum/language_holder/ethereal - understood_languages = list(/datum/language/galactic_common = list(LANGUAGE_ATOM), - /datum/language/kalixcian_common = list(LANGUAGE_ATOM)) - spoken_languages = list(/datum/language/galactic_common = list(LANGUAGE_ATOM), - /datum/language/kalixcian_common = list(LANGUAGE_ATOM)) - -/datum/language_holder/kepori - understood_languages = list(/datum/language/galactic_common = list(LANGUAGE_ATOM), - /datum/language/teceti_unified = list(LANGUAGE_ATOM)) - spoken_languages = list(/datum/language/galactic_common = list(LANGUAGE_ATOM), - /datum/language/teceti_unified = list(LANGUAGE_ATOM)) From 5daa416e96447f13b130e046cc1bac8c9d393d40 Mon Sep 17 00:00:00 2001 From: generalthrax <139387950+generalthrax@users.noreply.github.com> Date: Sat, 4 Oct 2025 22:19:22 -0700 Subject: [PATCH 3/3] Static Sectors (#5326) ## About The Pull Request Adds an additional sector that the outpost spawns in, along with a normal overmap that the usual shiptest stuff is in - [x] Create systems for every outpost - [x] Colours rough draft - [x] Remove the 20 minute no-jump cooldown at roundstart - [x] Make outpost and wild sector generate - [x] Make outpost sector select from list - [x] Make outpost sector actually spawn the matching outpost - [x] Make outpost sector star static - [x] Make outpost sector spawn no planets - [x] Colours final Unique sectors for each of the outposts - High-Pier system (Orange Dwarf, Chana) (Arrowsong Refueling Platform, CLIP controlled) - Value of Public Works system (Red Dwarf, Ecbatana) (Agni Trading Post, NGR controlled) - Minya system (Yellow Main-Sequence, Aubaine) (Installation Trifuge, Independent) - Persei-277 system (Yellow Main-Sequence, Persei-277) (Yebiri Sipili, NT controlled) These sectors do not contain much of worth other than a small amount of hazards Colors WIP in order according to above ![]()
![]()
![]()
## Why It's Good For The Game canon outposts and the static sectors theyre within for consistency. lets the standard overmap be a "wild" sector that pirates can probably more reasonably skulk around in. give outposts more presence and ic believability than being in the middle of the unwashed pirate hordes at all times ## Changelog :cl: add: Second overmap containing the outpost that you spawn in, along with standard shiptest overmap (no outpost) add: High-Pier system (CLIP), Value of Public Works system (NGR), Minya system (Indie), Persei-277 system (NT) add: Outposts now spawn only in their corresponding system add: Jump between these two sectors with a 1 minute timer with bluespace jump del: Removed 20 minute "No-Jump" cooldown /:cl: --------- Signed-off-by: generalthrax <139387950+generalthrax@users.noreply.github.com> Co-authored-by: retlaw34 <58402542+retlaw34@users.noreply.github.com> Co-authored-by: FalloutFalcon <86381784+FalloutFalcon@users.noreply.github.com> (cherry picked from commit 3e1defb0792300f6b04bf262146d1f9bee86ebbd) --- code/controllers/subsystem/overmap.dm | 103 +++++++++++++++++++----- code/modules/admin/verbs/randomverbs.dm | 2 +- code/modules/overmap/helm.dm | 8 -- 3 files changed, 85 insertions(+), 28 deletions(-) diff --git a/code/controllers/subsystem/overmap.dm b/code/controllers/subsystem/overmap.dm index 6c474ef77b2..6a8986a46bd 100644 --- a/code/controllers/subsystem/overmap.dm +++ b/code/controllers/subsystem/overmap.dm @@ -23,6 +23,9 @@ SUBSYSTEM_DEF(overmap) /// The mandatory and default star system var/datum/overmap_star_system/default_system + /// The secondary star system that allows planet spawns + var/datum/overmap_star_system/wild_system + ///Should events be processed var/events_enabled = TRUE @@ -41,8 +44,6 @@ SUBSYSTEM_DEF(overmap) //if(length(tracked_star_systems) >= 1) // CRASH("Attempted to create more than 1 star system. Having mutiple star systems is not supported.") - if(length(tracked_star_systems) >= 1) - WARNING("Attempted to create more than 1 star system. Bugs may occur as this isn't very well supported, you have been warned") tracked_star_systems += new_starsystem return new_starsystem @@ -56,7 +57,9 @@ SUBSYSTEM_DEF(overmap) dynamic_encounters = list() events = list() - default_system = create_new_star_system(new /datum/overmap_star_system/shiptest) + var/list/sector_types = pick(subtypesof(/datum/overmap_star_system/safezone)) + default_system = create_new_star_system(new sector_types) + wild_system = create_new_star_system (new /datum/overmap_star_system/shiptest) return ..() /datum/controller/subsystem/overmap/proc/spawn_new_star_system(datum/overmap_star_system/system_to_spawn=/datum/overmap_star_system) @@ -64,7 +67,6 @@ SUBSYSTEM_DEF(overmap) return create_new_star_system(system_to_spawn) return create_new_star_system(new system_to_spawn) - /datum/controller/subsystem/overmap/fire() for(var/datum/overmap_star_system/current_system as anything in tracked_star_systems) if(!current_system.encounters_refresh) @@ -345,6 +347,9 @@ SUBSYSTEM_DEF(overmap) //can our pallete be selected randomly roundstart? set to no for subtypes or if you dont change the pallete var/can_be_selected_randomly = TRUE + /// Datum type for the main outpost spawned here + var/default_outpost_type + COOLDOWN_DECLARE(dynamic_despawn_cooldown) /datum/overmap_star_system/New(generate_now=TRUE) @@ -371,7 +376,7 @@ SUBSYSTEM_DEF(overmap) if(!size) size = CONFIG_GET(number/overmap_size) if(!max_overmap_dynamic_events) - max_overmap_dynamic_events = CONFIG_GET(number/max_overmap_dynamic_events) + max_overmap_dynamic_events = isnull(max_overmap_dynamic_events) overmap_container = new/list(size, size, 0) @@ -516,24 +521,23 @@ SUBSYSTEM_DEF(overmap) /datum/overmap_star_system/proc/spawn_outpost() var/list/location = get_unused_overmap_square_in_radius(rand(4, round(size/5))) - var/datum/overmap/outpost/found_type if(fexists(OUTPOST_OVERRIDE_FILEPATH)) var/file_text = trim_right(file2text(OUTPOST_OVERRIDE_FILEPATH)) // trim_right because there's often a trailing newline var/datum/overmap/outpost/potential_type = text2path(file_text) if(!potential_type || !ispath(potential_type, /datum/overmap/outpost)) stack_trace("SSovermap found an outpost override file at [OUTPOST_OVERRIDE_FILEPATH], but was unable to find the outpost type [potential_type]!") else - found_type = potential_type + default_outpost_type = potential_type fdel(OUTPOST_OVERRIDE_FILEPATH) // don't want it to affect 2 rounds in a row. - if(!found_type) + if(!default_outpost_type) var/list/possible_types = subtypesof(/datum/overmap/outpost) for(var/datum/overmap/outpost/outpost_type as anything in possible_types) if(!initial(outpost_type.main_template)) possible_types -= outpost_type - found_type = pick(possible_types) + default_outpost_type = pick(possible_types) - var/datum/overmap/outpost/our_outpost = new found_type(location, src) + var/datum/overmap/outpost/our_outpost = new default_outpost_type(location, src) //gets rid of nearby events that casue radio interference for(var/direction as anything in GLOB.cardinals) @@ -970,11 +974,7 @@ SUBSYSTEM_DEF(overmap) override_object_colors = TRUE overmap_icon_state = "overmap" - dynamic_probabilities = list(\ - DYNAMIC_WORLD_BEACHPLANET = 10, - DYNAMIC_WORLD_SPACERUIN = 5, - DYNAMIC_WORLD_MOON = 20, - ) + max_overmap_dynamic_events = 0 /datum/overmap_star_system/zx_spectrum_pallete //main colors, used for dockable terrestrials, and background @@ -1067,9 +1067,11 @@ SUBSYSTEM_DEF(overmap) else datum_to_edit.token.add_filter("gloweffect", 5, list("type"="drop_shadow", "color"= "#808080", "size"=2, "offset"=1)) -/datum/overmap_star_system/ngr - name = "Gorlex Controlled - Ecbatana" +/datum/overmap_star_system/safezone/ngr + name = "Gorlex Controlled - Value of Public Works" starname = "Ecbatana" + startype = /datum/overmap/star/dwarf + default_outpost_type = /datum/overmap/outpost/ngr_rock //main colors, used for dockable terrestrials, and background primary_color = "#d9ad82" @@ -1086,6 +1088,69 @@ SUBSYSTEM_DEF(overmap) override_object_colors = TRUE overmap_icon_state = "overmap_dark" +/datum/overmap_star_system/safezone/clip + name = "CLIP Controlled - High-Pier" + starname = "Chana" + startype = /datum/overmap/star/dwarf/orange + default_outpost_type = /datum/overmap/outpost/clip_ocean + + //main colors, used for dockable terrestrials, and background + primary_color = "#6fa8de" + secondary_color = "#96b6d4" + + //hazard colors, used for the overmap hazards and sun + hazard_primary_color = "#d5e3f0" + hazard_secondary_color = "#96a6b5" + + //structure colors, used for ships and outposts/colonies + primary_structure_color = "#97dfe8" + secondary_structure_color = "#6fa8de" + + override_object_colors = TRUE + overmap_icon_state = "overmap_dark" + +/datum/overmap_star_system/safezone/trifuge + name = "Independent - Minya" + starname = "Aubaine" + startype = /datum/overmap/star/medium + default_outpost_type = /datum/overmap/outpost/indie_space + + //main colors, used for dockable terrestrials, and background + primary_color = "#5e5e5e" + secondary_color = "#242424" + + //hazard colors, used for the overmap hazards and sun + hazard_primary_color = "#b56060" + hazard_secondary_color = "#824242" + + //structure colors, used for ships and outposts/colonies + primary_structure_color = "#ffffff" + secondary_structure_color = "#ffffff" + + override_object_colors = TRUE + overmap_icon_state = "overmap" + +/datum/overmap_star_system/safezone/nt + name = "Nanotrasen Controlled - Persei-277" + starname = "Persei-277" + startype = /datum/overmap/star/medium + default_outpost_type = /datum/overmap/outpost/nanotrasen_ice + + //main colors, used for dockable terrestrials, and background + primary_color = "#7e8cd9" + secondary_color = "#33324a" + + //hazard colors, used for the overmap hazards and sun + hazard_primary_color = "#ededed" + hazard_secondary_color = "#7f7db0" + + //structure colors, used for ships and outposts/colonies + primary_structure_color = "#4272db" + secondary_structure_color = "#38a0eb" + + override_object_colors = TRUE + overmap_icon_state = "overmap_dark" + /datum/overmap_star_system/c64 //main colors, used for dockable terrestrials, and background @@ -1105,13 +1170,13 @@ SUBSYSTEM_DEF(overmap) //default shiptest overmap /datum/overmap_star_system/shiptest - has_outpost = TRUE + has_outpost = FALSE can_be_selected_randomly = FALSE encounters_refresh = TRUE + max_overmap_dynamic_events = 15 /datum/overmap_star_system/shiptest/create_map() . = ..() - set_station_name(starname) /datum/overmap_star_system/admin_sandbox name = "Admin Sandbox" diff --git a/code/modules/admin/verbs/randomverbs.dm b/code/modules/admin/verbs/randomverbs.dm index 820c5ed62a7..a564e868ad9 100644 --- a/code/modules/admin/verbs/randomverbs.dm +++ b/code/modules/admin/verbs/randomverbs.dm @@ -961,7 +961,7 @@ nova.size = inputed inputed = input(usr, "Choose Maximum amount of Dynamic Events", "Spawn Overmap", nova.max_overmap_dynamic_events) as num - if(!inputed) + if(isnull(inputed)) QDEL_NULL(nova) return nova.max_overmap_dynamic_events = inputed diff --git a/code/modules/overmap/helm.dm b/code/modules/overmap/helm.dm index 79441152c3a..0a3078e4a30 100644 --- a/code/modules/overmap/helm.dm +++ b/code/modules/overmap/helm.dm @@ -50,12 +50,8 @@ icon_state = "computer-solgov" deconpath = /obj/structure/frame/computer/solgov -/datum/config_entry/number/bluespace_jump_wait - default = 5 MINUTES - /obj/machinery/computer/helm/Initialize(mapload, obj/item/circuitboard/C) . = ..() - jump_allowed = world.time + CONFIG_GET(number/bluespace_jump_wait) ntnet_relay = new(src) /obj/machinery/computer/helm/examine(mob/user) @@ -72,10 +68,6 @@ if(current_ship.docked_to || current_ship.docking) say("Bluespace Jump Calibration detected interference in the local area.") return - if(world.time < jump_allowed) - var/jump_wait = DisplayTimeText(jump_allowed - world.time) - say("Bluespace Jump Calibration is currently recharging. ETA: [jump_wait].") - return message_admins("[ADMIN_LOOKUPFLW(usr)] has initiated a bluespace jump in [ADMIN_VERBOSEJMP(src)]") jump_timer = addtimer(CALLBACK(src, PROC_REF(jump_sequence), TRUE), JUMP_CHARGEUP_TIME, TIMER_STOPPABLE) if(new_system)