From cb7d734e745e82bb3aca87de7e00b6820900da42 Mon Sep 17 00:00:00 2001
From: Allanis <allanis.saracraft.studios@gmail.com>
Date: Sun, 21 Jan 2018 20:27:43 +0000
Subject: [PATCH] [Add] Make orbital starports in system generation.

---
 icons/object_orbital_starport.png | Bin 0 -> 3347 bytes
 src/glfreetype.cpp                |   4 +-
 src/sbre/models.cpp               |  62 +++++++++++++++---------------
 src/sbre/sbre_models.h            |   2 +-
 src/space.cpp                     |  24 +++++++++++-
 src/star_system.cpp               |  43 +++++++++++++++++++--
 src/star_system.h                 |   6 ++-
 7 files changed, 102 insertions(+), 39 deletions(-)
 create mode 100644 icons/object_orbital_starport.png

diff --git a/icons/object_orbital_starport.png b/icons/object_orbital_starport.png
new file mode 100644
index 0000000000000000000000000000000000000000..524470d6682369be65d1fed5b03b685466147695
GIT binary patch
literal 3347
zcmV+u4eauXP)<h;3K|Lk000e1NJLTq000mG000mO1^@s6AM^iV000V4X+uL$P-t&-
zZ*ypGa3D!TLm+T+Z)Rz1WdHzp+MQEpR8#2|J@?-9LQ9B%luK_?6$l_wLW_VDktQl3
z2@pz%A)(n7QNa;KMFbnjpojyGj)066Q7jCK3fKqaA)=0hqlk*i`{8?|Yu3E?=FR@K
z*FNX0^PRKL2fzpnmPj*EHGmAMLLL#|gU7_i;p8qrfeIvW01ybXWFd3?BLM*Temp!Y
zBESc}00DT@3kU$fO`E_l9Ebl8>Oz@Z0f2-7z;ux~O9+4z06=<<LZ$#fMgf4Gm?l#I
zpacM5%VT2W08lLeU?+d((*S^-_?deF09%wH6#<};03Z`(h(rKrI{>WDR*FRcSTFz-
zW=q650N5=6FiBTtNC2?60Km==3$g$R3;-}uh=nNt1bYBr$Ri_o0EC$U6h`t_Jn<{8
z5a%iY0C<_QJh>z}MS)ugEpZ1|S1ukX&Pf+56gFW3VVXcL!g-k)GJ!M?;PcD?0HBc-
z5#WRK{dmp}uFlRjj<yb8E$Y7p{~}^y<NoE(t8hR70O53g(f%wivl@Uq27qn;q9yJG
zXkH7Tb@z*AvJXJD0HEpGSMzZAemp!yp^&-R+2!Qq*h<7gTVcvqeg0>{U%*%WZ25jX
z{P*?XzTzZ-GF^d31o+^>%=Ap99M6&ogks$0k4OBs3;+Bb(;~!4V!2o<6ys46agIcq
zjPo+3B8fthDa9qy|77CdEc*jK-!%ZRYCZvbku9iQV*~a}ClFY4z~c7+0P?$U!PF=S
z1Au6Q;m>#f??3%Vpd|o+W=WE9003S@Bra6Svp>fO002awfhw>;8}z{#EWidF!3EsG
z3;bX<ghC|5!a@*23S@vBa$qT}f<h>U&9EIRU@z1_9W=mEXoiz;4lcq~xDGvV5BgyU
zp1~-*fe8db$Osc*A=-!mVv1NJjtCc-h4>-CNCXm#Bp}I%6j35eku^v$Qi@a{RY)E3
zJ#qp$hg?Rwkvqr$GJ^buyhkyVfwECO)C{#lxu`c9ghrwZ&}4KmnvWKso6vH!8a<3Q
zq36)6Xb;+tK10Vaz~~qUGsJ8#F2=(`u{bOVlVi)VBCHIn#u~6ztOL7=^<&SmcLWlF
zMZgI*1b0FpVIDz9SWH+>*hr`#93(Um+6gxa1B6k+CnA%mOSC4s5&6UzVlpv@SV$}*
z))J2sFA#f(L&P^E5{W}HC%KRUNwK6<(h|}}(r!{C=`5+6G)NjFlgZj-YqAG9lq?`C
z$c5yc<iq4M<QwE6@>>d>VnA`E_*3F2Qp##d8RZb=H01_mm@+|Cqnc9PsG(F5HIG_C
zt)aG3uTh7n6Et<2In9F>NlT@zqLtGcXcuVrX|L#Xx)I%#9!{6gSJKPrN9dR61N3(c
z4Tcqi$B1Vr8Jidf7-t!G7_XR2rWw<V8OKyGH!<s&=a~<gZ&g?-wkmuTk;)2{N|h#+
z8!9hUsj8-`-l_{#^Hs}KkEvc$eXd4TGgITK3DlOWRjQp(>r)$3XQ?}=hpK0&Z&W{|
zep&sA23f;Q!%st`QJ}G3<GjWo3u76xcq}1n4XcKAfi=V?vCY|hb}GA={T;iDJ*ugp
zIYTo_Ggq@x^OR;k2jiG=_?&c33Fj!Mm-Bv#-W2aC;wc-ZG)%cMWn62jmY0@Tt4OO+
zt4Hg-Hm>cbou<7-yIK2z4nfCCCtN2-XOGSWo##{8Q{ATurxr~;I`ytDs%xbip}RzP
zziy}Qn4Z2~fSycmr`~zJ=lUFdFa1>gZThG6M+{g7vkW8#+YHVaJjFF}Z#*3@$J_By
zLtVo_L#1JrVVB{Ak-5=4qt!-@Mh}c>#$4kh<88)m#-k<%CLtzEP3leVno>=<rYWX7
zOgl`+&CJcB&DNPUn>{htGUuD;o7bD)w_sX$S}eAxwzy?UvgBH(S?;#HZiQMoS*2K2
zT3xe7t(~nU*1N5{rxB;QPLocnp4Ml>u<^FZwyC!nu;thW+pe~4wtZn|Vi#w(#jeBd
zlf9FDx_yoPJqHbk*$%56S{;6Kv~m<WRyy9A&YbQ)eZ};a=`Uwk&k)bpGvl@s%PGWZ
zol~3BM`ssjxpRZ_h>M9!g3B(KJ}#RZ#@)!h<Vtk)ab4kh()FF2vzx;0sN1jZHtuQe
zhuojcG@mJ+Su=Cc!^lJ6QRUG;3!jxRYu~JXPeV_EXSL@eFJmu}SFP8ux21Qg_hIiB
zKK4FxpW{B`JU8Al-dSJFH^8^Zx64n%Z=PR;-$Q>R|78Dq|Iq-afF%KE1Brn_fm;Im
z_<DRHzm7jT+hz8$+3i7$pt(U6L63s1g5|-jA!x|#kgXy2=a|ls&S?&XP=4sv&<A1W
zVT;3l3@3$$g;$0@j&O)r8qqPAHFwe6Lv!Cm`b3sQ-kWDJPdTqGN;N7zsxE3g+Bdp1
zx<AG)W?9VDSe;l&Y)c$DE-J1zZfw5a{O$9H;+^6P<9ipFFUVbRd7;k2^o6GusV)*M
zI+j38h)y_^@IeqNs1}SR@)LI@jtY6g9l~cKFVQy9h}c71DjrVqNGeTwlI)SZHF+e(
zGo>u$xr8UFki1L{Ox>G0o)(&RAZ;=|I=wN2l97;cLaHH6leTB-XXa*h%dBOEvi`+x
zi?=Txl?TadvyiL>SuF~-LZ;|cS}4~l2eM~nS7yJ>iOM;atDY;(?aZ^v+mJV$@1Ote
z62cPUlD4IWOIIx&SmwQ~YB{nzae3Pc;}r!fhE@iwJh+OsDs9zItL;~pu715HdQEGA
zUct(O!L<Qv>kCy1<%NCg+}G`0PgpNm-?d@-hMgNe6^V+j6x$b<6@S<$+<4_1hi}Ti
zncS4LsjI}fWY1>OX6feMEuLErma3QLmkw?X+1j)X-&VBk_4Y;EFPF_I+q;9dL%E~B
zJh;4Nr^(LEJ3myURP<E(R5tF?-L+xY_-@he8+*L=H0;&eTfF!EKFPk@RRL8^)n?UY
z`$_w=_dl+Qs_FQa`)ysVPHl1R#{<#>{Rblsw%57T)g973R8o)DE9*xN#~;4_o$q%o
z4K@u`jhx2fBXC4{<mvYb-}fF3I@)%Od#vFH(;s#nXB{tULYnfLMw?Tb`&(jLx=+kL
z(bnqTdi+P*9}k=~JXv{4^Hj-c+UbJRlV|eJjGdL8eSR+a++f?HwtMGe&fjVeZ|}Mg
zbm7uP|BL54ygSZZ^0;*JvfJeoSGZT2uR33C>U8Qn{*%*B$Ge=nny$HAYq{=vy|sI0
z_vss+H_qMky?OB#|JK!>IX&II^LlUh#rO5!7TtbwC;iULyV-Xq?ybB}ykGP{?LpZ?
z-G|jbTmIbG@7#ZCz;~eY(cDM(28Dyq{*m>M4?_iynUBkc4TkHUI6gT!;y-fz>HMcd
z&t%Ugo)`Y2{>!cx7B7DI)$7;J(U{Spm-3gBzioV_{p!H$8L!*M!p0uH$#^p{Ui4P`
z?ZJ24cOCDe-w#jZd?0@)|7iKK^;6KN`;!@ylm7$*nDhK&GcDTy000JJOGiWi{{a60
z|De66lK=n!32;bRa{vG?BLDy{BLR4&KXw2B00(qQO+^RT2?`SmD;Oub6aWAMMM*?K
zR5;6}lRs+|K^Vq=vzxs?yBC(zM1qZl3HS{x1Q9z4DEJwIVxdKBZAAPE0l{D;SXdgd
zvQUwLe+s#PHjxmB$>r|6z1!W{nVZdPA-Nc%Ha;*g%scOoXJ(#(|CIl);=;lLlarIo
z&CRjCzW&EO>i31^hszji$n%_byG^UrVtad=q9};MkazFj|J}jr>MD&!gCGd7#<IJ+
zi!l~sErTS%SWC0nq}S_>d%XS0hYueS5#l(e*=%y-<V`8d66Z#|UVJN!Mgst?H8V3a
zM*(@B;he)cN2OBXse7WrFl2gqnk$dyRUF5pX^OQLYwZ{^26&!F9LJpfc21mgXswB&
zh<d$Fp66_AY_PS|meFX0h%j;vfQfxTXSc)7&JHiaXUbYjr_<qaaz{R22)Ov^yb=*k
zTsx+m=P1h(1ddNl9XP1fYeZ3mHI`Oujp1;}^|N0&^JX-5I59DC=>7Iwc>qY$lq5;G
zELWu{G+CDM>G?f1_vNy())GY#TT5-JR;zfPhlqgs<qnim^uPDHzjjv{W9aw$lx0Z}
z1XL;&_V)HTefyLW5q#fADTRm}0D>SO*Ew2idc7VGE-g!*=lH(Q%UiF+7(<$-j7C3?
z<oiDTe*bV17Z(>vl7!)42nw<+BT16+D2f7CIur_}6rE1zXq4yY=TS;wjG^1@qP0du
z$n%_{C;)J!qu1>n&cVJ`R#p%Zs?{ok!GN+X$+C<v45`&>0ORIAex~0wJ3EW#d1$TK
d+}u1;{{bJxH~e{wSvUXy002ovPDHLkV1kLgNDlx2

literal 0
HcmV?d00001

diff --git a/src/glfreetype.cpp b/src/glfreetype.cpp
index 111f35c..63e8b03 100644
--- a/src/glfreetype.cpp
+++ b/src/glfreetype.cpp
@@ -24,7 +24,7 @@ static GLUtesselator* tobj;
 static inline double fac(int n) {
   double r = 1.0;
 
-  for(int i = 2; i < n; i++) {
+  for(int i = 2; i <= n; i++) {
     r *= (double)i;
   }
   return r;
@@ -361,7 +361,7 @@ FontFace::FontFace(const char* filename_ttf) {
             temppts.clear();
             GenContourPoints(chr, outline, contour, BEZIER_STEPS, &temppts);
             for(size_t i = 0; i < temppts.size(); i++) pts.push_back(temppts[i]);
-            for(size_t i = 0; i < temppts.size(); i+=4, nv++)
+            for(size_t i = 0; i < temppts.size(); i+=3, nv++)
               gluTessVertex(tobj, &pts[nv*3], &g_index[nv]);
           gluTessEndContour(tobj);
         }
diff --git a/src/sbre/models.cpp b/src/sbre/models.cpp
index 06145aa..bf767e1 100644
--- a/src/sbre/models.cpp
+++ b/src/sbre/models.cpp
@@ -638,48 +638,48 @@ Model ship2model = { 1.0f, 35.0f, 98, ship2vtx1, 120, 1, ship2vtx2, 10,
                    { { 0, ship2data, 0, 14, ship2thruster } } };
 
 static PlainVertex station1vtx1[] = {
-  { VTYPE_PLAIN, { -15.0f, 30.0f, 20.0f } },    /* 6, front octagon. */
-  { VTYPE_PLAIN, { 15.0f, 30.0f, 20.0f } },
-  { VTYPE_PLAIN, { 30.0f, 15.0f, 20.0f } },
-  { VTYPE_PLAIN, { 30.0f, -15.0f, 20.0f } },
-  { VTYPE_PLAIN, { 15.0f, -30.0f, 20.0f } },
-  { VTYPE_PLAIN, { -15.0f, -30.0f, 20.0f } },
+  { VTYPE_PLAIN, { -15.0f, -20.0f, 30.0f } },    /* 6, front octagon. */
+  { VTYPE_PLAIN, { 15.0f, -20.0f, 30.0f } },
+  { VTYPE_PLAIN, { 30.0f, -20.0f, 15.0f } },
+  { VTYPE_PLAIN, { 30.0f, -20.0f, -15.0f } },
+  { VTYPE_PLAIN, { 15.0f, -20.0f, -30.0f } },
+  { VTYPE_PLAIN, { -15.0f, -20.0f, -30.0f } },
 
-  { VTYPE_PLAIN, { -15.0f, 30.0f, -20.0f } },   /* 12, back octagon. */
-  { VTYPE_PLAIN, { 15.0f, 30.0f, -20.0f } },
-  { VTYPE_PLAIN, { 30.0f, 15.0f, -20.0f } },
-  { VTYPE_PLAIN, { 30.0f, -15.0f, -20.0f } },
-  { VTYPE_PLAIN, { 15.0f, -30.0f, -20.0f } },
-  { VTYPE_PLAIN, { -15.0f, -30.0f, -20.0f } },
+  { VTYPE_PLAIN, { -15.0f, 20.0f, 30.0f } },   /* 12, back octagon. */
+  { VTYPE_PLAIN, { 15.0f, 20.0f, 30.0f } },
+  { VTYPE_PLAIN, { 30.0f, 20.0f, 15.0f } },
+  { VTYPE_PLAIN, { 30.0f, 20.0f, -15.0f } },
+  { VTYPE_PLAIN, { 15.0f, 20.0f, -30.0f } },
+  { VTYPE_PLAIN, { -15.0f, 20.0f, -30.0f } },
 
-  { VTYPE_PLAIN, { -10.0f, 5.0f, 20.0f } },  /* 18, inlet front. */
-  { VTYPE_PLAIN, { 10.0f, 5.0f, 20.0f } },
-  { VTYPE_PLAIN, { 10.0f, -5.0f, 20.0f } },
-  { VTYPE_PLAIN, { -10.0f, -5.0f, 20.0f } },
+  { VTYPE_PLAIN, { -10.0f, -20.0f, 5.0f } },  /* 18, inlet front. */
+  { VTYPE_PLAIN, { 10.0f, -20.0f, 5.0f } },
+  { VTYPE_PLAIN, { 10.0f, -20.0f, -5.0f } },
+  { VTYPE_PLAIN, { -10.0f, -20.0f, -5.0f } },
 
-  { VTYPE_PLAIN, { -10.0f, 5.0f, 0.0f } },  /* 22, inlet rear. */
-  { VTYPE_PLAIN, { 10.0f, 5.0f, 0.0f } },
-  { VTYPE_PLAIN, { 10.0f, -5.0f, 0.0f } },
-  { VTYPE_PLAIN, { -10.0f, -5.0f, 0.0f } },
+  { VTYPE_PLAIN, { -10.0f, 0.0f, 5.0f } },  /* 22, inlet rear. */
+  { VTYPE_PLAIN, { 10.0f, 0.0f, 5.0f } },
+  { VTYPE_PLAIN, { 10.0f, 0.0f, -5.0f } },
+  { VTYPE_PLAIN, { -10.0f, 0.0f, -5.0f } },
 
 
-  { VTYPE_PLAIN, { 30.0f, 10.0f, 10.0f } },  /* 26, strut inner. */
+  { VTYPE_PLAIN, { 30.0f, -10.0f, 10.0f } },  /* 26, strut inner. */
   { VTYPE_PLAIN, { 30.0f, -10.0f, 10.0f } },
   { VTYPE_PLAIN, { 30.0f, -10.0f, -10.0f } },
-  { VTYPE_PLAIN, { 30.0f, 10.0f, -10.0f } },
+  { VTYPE_PLAIN, { 30.0f, 10.0f, 10.0f } },
 
-  { VTYPE_PLAIN, { 100.0f, 10.0f, 10.0f } },  /* 30, strut outer. */
-  { VTYPE_PLAIN, { 100.0f, -10.0f, 10.0f } },
+  { VTYPE_PLAIN, { 100.0f, -10.0f, 10.0f } }, /* 30, strut outer. */
   { VTYPE_PLAIN, { 100.0f, -10.0f, -10.0f } },
   { VTYPE_PLAIN, { 100.0f, 10.0f, -10.0f } },
+  { VTYPE_PLAIN, { 100.0f, 10.0f, 10.0f } },
 
-  { VTYPE_PLAIN, { 0.0f, 0.0f, 25.0f } },  /* 34, ring start, end. */
-  { VTYPE_PLAIN, { 0.0f, 0.0f, -25.0f } },
+  { VTYPE_PLAIN, { 0.0f, -25.0f, 0.0f } },  /* 34, ring start, end. */
+  { VTYPE_PLAIN, { 0.0f, 25.0f, 0.0f } },
 
-  { VTYPE_PLAIN, { -9.0f, 4.5f, 10.0f } },
-  { VTYPE_PLAIN, { 9.0f, 4.5f, 10.0f } },    /* 36, inlet middle (for docking). */
-  { VTYPE_PLAIN, { 9.0f, -4.5f, 10.0f } },
-  { VTYPE_PLAIN, { -9.0f, -4.5f, 10.0f } },
+  { VTYPE_PLAIN, { -9.0f, -10.0f, 4.5f } },
+  { VTYPE_PLAIN, { 9.0f, -10.0f, 4.5f } },    /* 36, inlet middle (for docking). */
+  { VTYPE_PLAIN, { 9.0f, -10.0f, -4.5f } },
+  { VTYPE_PLAIN, { -9.0f, -10.0f, -4.5f } },
 
 #if 0
     { VTYPE_PLAIN, { 0.0f, 120.0f, 15.0f } },   /* 34, ring top. */
@@ -774,7 +774,7 @@ static uint16 station1data[] = {
   PTYPE_QUADFLAT | RFLAG_XREF, 28, 29, 33, 32,
   PTYPE_QUADFLAT | RFLAG_XREF, 29, 26, 30, 33,
 
-  PTYPE_TUBE | RFLAG_XREF, 0, 38, 34, 35, 1, 11500, 10000,
+  PTYPE_TUBE | RFLAG_XREF, 0, 38, 34, 35, 2, 11500, 10000,
 
   PTYPE_SETCFLAG, 0x10,
   PTYPE_QUADFLAT | RFLAG_INVISIBLE, 39, 38, 37, 36,
diff --git a/src/sbre/sbre_models.h b/src/sbre/sbre_models.h
index 14c5ebd..7c97735 100644
--- a/src/sbre/sbre_models.h
+++ b/src/sbre/sbre_models.h
@@ -53,7 +53,7 @@ Model* const ppModel[] = {
   /* 80. */
   0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
   /* 90, other people's ships. */
-  &starport1model, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  &starport1model, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 	/* 100, more sub-objects. */
 	&metalFrameTowerModel
 };
diff --git a/src/space.cpp b/src/space.cpp
index 28c46dd..3651ddb 100644
--- a/src/space.cpp
+++ b/src/space.cpp
@@ -9,6 +9,7 @@
 #include "l3d.h"
 #include "player.h"
 #include "star_system.h"
+#include "space_station.h"
 #include "sbre/sbre.h"
 
 dWorldID Space::world;
@@ -97,7 +98,7 @@ static Frame* MakeFrameFor(StarSystem::SBody* sbody, Body* b, Frame* f) {
     rotFrame->m_astroBody = b;
     b->SetFrame(rotFrame);
     return orbFrame;
-  } else {
+  } else if(supertype == StarSystem::SUPERTYPE_STAR) {
     /* Stars want a single small non-rotating frame. */
     orbFrame = new Frame(f, sbody->name.c_str());
     orbFrame->m_sbody = sbody;
@@ -105,6 +106,24 @@ static Frame* MakeFrameFor(StarSystem::SBody* sbody, Body* b, Frame* f) {
     orbFrame->SetRadius(sbody->GetMaxChildOrbitalDistance()*1.1);
     b->SetFrame(orbFrame);
     return orbFrame;
+  } else if(supertype == StarSystem::SUPERTYPE_STARPORT) {
+    /*
+     * Space stations want non-rotating frame to some distance
+     * and a much closer rotating frame.
+     */
+    frameRadius = 1000000.0; /* XXX No idea. */
+    orbFrame = new Frame(f, sbody->name.c_str());
+    orbFrame->m_sbody = sbody;
+    orbFrame->SetRadius(frameRadius ? frameRadius : 10*sbody->GetRadius());
+
+    assert(sbody->GetRotationPeriod() != 0);
+    rotFrame = new Frame(orbFrame, sbody->name.c_str());
+    rotFrame->SetRadius(5000.0);
+    rotFrame->SetAngVelocity(vector3d(0,2*M_PI/sbody->GetRotationPeriod(), 0));
+    b->SetFrame(rotFrame);
+    return orbFrame;
+  } else {
+    assert(0);
   }
 }
 
@@ -115,6 +134,9 @@ void Space::GenBody(StarSystem::SBody* sbody, Frame* f) {
     if(sbody->GetSuperType() == StarSystem::SUPERTYPE_STAR) {
       Star* star = new Star(sbody);
       b = star;
+    } else if(sbody->type == StarSystem::TYPE_STARPORT_ORBITAL) {
+      SpaceStation* ss = new SpaceStation(SpaceStation::JJHOOP);
+      b = ss;
     } else {
       Planet* planet = new Planet(sbody);
       b = planet;
diff --git a/src/star_system.cpp b/src/star_system.cpp
index 52dd5a1..18ccee7 100644
--- a/src/star_system.cpp
+++ b/src/star_system.cpp
@@ -145,6 +145,15 @@ static const struct SBodySubTypeInfo {
     StarSystem::SUPERTYPE_ROCKY_PLANET,
     {}, 100, "World with indigenous life and an oxygen atmosphere",
     "icons/object_planet_life.png"
+  },
+  {
+    StarSystem::SUPERTYPE_STARPORT,
+    {}, 0, "Orbital starport",
+    "icons/object_orbital_starport.png"
+  },
+  {
+    StarSystem::SUPERTYPE_STARPORT,
+    {}, 0, "Starport",
   }
 };
 
@@ -561,6 +570,13 @@ StarSystem::StarSystem(int sector_x, int sector_y, int system_idx) {
     }
   }
 
+  {
+    /* Decide how infested the place is. */
+    const int dist = 1+MAX(abs(sector_x), abs(sector_y));
+    m_humanInfested = (fixed(1,2)+fixed(1,2)*rand.Fixed()) / dist;
+    printf("Infested %f\n", m_humanInfested.ToDouble());
+  }
+
   for(int i = 0; i < m_numStars; i++) MakePlanetsAround(star[i]);
 
   if(m_numStars > 1) MakePlanetsAround(centGrav1);
@@ -631,7 +647,7 @@ void StarSystem::MakePlanetsAround(SBody* primary) {
     buf[2] = 0;
     (*i)->name = primary->name+buf;
     fixed d = ((*i)->orbMin + (*i)->orbMax) >> 1;
-    (*i)->PickPlanetType(primary, d, rand, true);
+    (*i)->PickPlanetType(this, primary, d, rand, true);
 
 #ifdef DEBUG_DUMP
     /*printf("%s: mass %f, semi-major axis %fAU, ecc %f\n",
@@ -641,7 +657,7 @@ void StarSystem::MakePlanetsAround(SBody* primary) {
   }
 }
 
-void StarSystem::SBody::PickPlanetType(SBody* star, const fixed distToPrimary, MTRand& rand, bool genMoons) {
+void StarSystem::SBody::PickPlanetType(StarSystem* system, SBody* star, const fixed distToPrimary, MTRand& rand, bool genMoons) {
   fixed albedo = rand.Fixed() * fixed(1,2);
   fixed globalwarming = rand.Fixed() * fixed(9,10);
   /* Light planets have like.. no atmosphere. */
@@ -766,9 +782,30 @@ void StarSystem::SBody::PickPlanetType(SBody* star, const fixed distToPrimary, M
       buf[0] = '1'+(idx++);
       buf[1] = 0;
       (*i)->name = name+buf;
-      (*i)->PickPlanetType(star, distToPrimary, rand, false);
+      (*i)->PickPlanetType(system, star, distToPrimary, rand, false);
     }
   }
+  /* Starports. */
+  if((averageTemp < CELSIUS+100) && (averageTemp > 100) &&
+      (rand.Fixed() < system->m_humanInfested)) {
+    SBody* sp = new SBody;
+    sp->type = TYPE_STARPORT_ORBITAL;
+    sp->seed = rand.Int32();
+    sp->tmp = 0;
+    sp->parent = this;
+    sp->rotationPeriod = fixed(1, 3600);
+    sp->averageTemp = this->averageTemp;
+    sp->mass = 0;
+    sp->name = "Starport";
+    fixed semiMajorAxis = fixed(1, 2000);
+    sp->orbit.eccentricity = 0;
+    sp->orbit.semiMajorAxis = semiMajorAxis.ToDouble()*AU;
+    sp->orbit.period = calc_orbital_period(sp->orbit.semiMajorAxis, this->mass.ToDouble()*EARTH_MASS);
+    sp->orbit.rotMatrix = matrix4x4d::Identity();
+    this->children.push_back(sp);
+    sp->orbMin = semiMajorAxis;
+    sp->orbMax = semiMajorAxis;
+  }
 }
 
 StarSystem::~StarSystem(void) {
diff --git a/src/star_system.h b/src/star_system.h
index f482514..e75fa1a 100644
--- a/src/star_system.h
+++ b/src/star_system.h
@@ -64,6 +64,8 @@ public:
     TYPE_PLANET_METHANE_THICK_ATMOS,
     TYPE_PLANET_HIGHLY_VOLCANIC,
     TYPE_PLANET_INDIGENOUS_LIFE,
+    TYPE_STARPORT_ORBITAL,
+    TYPE_STARPORT_SURFACE,
     TYPE_MAX,
     TYPE_STAR_MIN = TYPE_STAR_M,
     TYPE_STAR_MAX = TYPE_WHITE_DWARF
@@ -71,7 +73,7 @@ public:
   };
 
   enum BodySuperType {
-    SUPERTYPE_NONE, SUPERTYPE_STAR, SUPERTYPE_ROCKY_PLANET, SUPERTYPE_GAS_GIANT
+    SUPERTYPE_NONE, SUPERTYPE_STAR, SUPERTYPE_ROCKY_PLANET, SUPERTYPE_GAS_GIANT, SUPERTYPE_STARPORT
   };
 
   struct BodyStats {
@@ -83,6 +85,7 @@ public:
     friend class StarSystem;
     ~SBody(void);
     void EliminateBadChildren(void); /* :D */
+    void PickPlanetType(StarSystem*, SBody*, fixed distToPrimary, MTRand& drand, bool genMoons);
     void PickPlanetType(SBody*, fixed distToPrimary, MTRand& drand, bool genMoons);
     SBody* parent;
     std::vector<SBody*> children;
@@ -127,6 +130,7 @@ public:
   };
 
   SBody* rootBody;
+  fixed m_humanInfested; /* 0 to 1 */
 
 private:
   void MakePlanetsAround(SBody* primary);