Merge remote-tracking branch 'upstream/master'
This commit is contained in:
557
docs/company_colour_indexes.html
Normal file
557
docs/company_colour_indexes.html
Normal file
@@ -0,0 +1,557 @@
|
||||
<!DOCTYPE html>
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
|
||||
<!-- derived from Iron Horse branch at https://github.com/andythenorth/iron-horse/tree/company_colour_indexes -->
|
||||
<head>
|
||||
<title>OpenTTD Company Colour Indexes</title>
|
||||
<meta charset="UTF-8" />
|
||||
<style>
|
||||
th {
|
||||
vertical-align: top;
|
||||
border-bottom: solid 1px #ddd;
|
||||
padding-top: 30px;
|
||||
padding-right: 15px;
|
||||
text-align: right;
|
||||
}
|
||||
tr.top td {
|
||||
padding-top: 20px;
|
||||
}
|
||||
tr.bottom td {
|
||||
border-bottom: solid 1px #ddd;
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
td {
|
||||
text-align: right;
|
||||
}
|
||||
span {
|
||||
border: solid 1px #000;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
display: inline-block;
|
||||
vertical-align: top;
|
||||
margin-left: 0px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Company Colour Indexes</h1>
|
||||
<p>Hex / dec indexes into the DOS palette</p>
|
||||
<p>
|
||||
Visual representation of values derived from <a href="https://github.com/frosch123/TTDViewer/blob/master/src/recolor.xml#L186">https://github.com/frosch123/TTDViewer/blob/master/src/recolor.xml#L186</a>
|
||||
</p>
|
||||
<table style="margin-top:30px;">
|
||||
<tbody>
|
||||
<tr class="top">
|
||||
<th rowspan="3">COLOUR_DARK_BLUE</th>
|
||||
<td><span style="background-color:rgb( 8, 24, 88)"></span></td>
|
||||
<td><span style="background-color:rgb( 12, 36, 104)"></span></td>
|
||||
<td><span style="background-color:rgb( 20, 52, 124)"></span></td>
|
||||
<td><span style="background-color:rgb( 28, 68, 140)"></span></td>
|
||||
<td><span style="background-color:rgb( 40, 92, 164)"></span></td>
|
||||
<td><span style="background-color:rgb( 56, 120, 188)"></span></td>
|
||||
<td><span style="background-color:rgb( 72, 152, 216)"></span></td>
|
||||
<td><span style="background-color:rgb(100, 172, 224)"></span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>0xc6</td>
|
||||
<td>0xc7</td>
|
||||
<td>0xc8</td>
|
||||
<td>0xc9</td>
|
||||
<td>0xca</td>
|
||||
<td>0xcb</td>
|
||||
<td>0xcc</td>
|
||||
<td>0xcd</td>
|
||||
</tr>
|
||||
<tr class="bottom">
|
||||
<td>198</td>
|
||||
<td>199</td>
|
||||
<td>200</td>
|
||||
<td>201</td>
|
||||
<td>202</td>
|
||||
<td>203</td>
|
||||
<td>204</td>
|
||||
<td>205</td>
|
||||
</tr>
|
||||
|
||||
<tr class="top">
|
||||
<th rowspan="3">COLOUR_PALE_GREEN</th>
|
||||
<td><span style="background-color:rgb( 16, 52, 24)"></span></td>
|
||||
<td><span style="background-color:rgb( 32, 72, 44)"></span></td>
|
||||
<td><span style="background-color:rgb( 56, 96, 72)"></span></td>
|
||||
<td><span style="background-color:rgb( 76, 116, 88)"></span></td>
|
||||
<td><span style="background-color:rgb( 96, 136, 108)"></span></td>
|
||||
<td><span style="background-color:rgb(120, 164, 136)"></span></td>
|
||||
<td><span style="background-color:rgb(152, 192, 168)"></span></td>
|
||||
<td><span style="background-color:rgb(184, 220, 200)"></span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>0x60</td>
|
||||
<td>0x61</td>
|
||||
<td>0x62</td>
|
||||
<td>0x63</td>
|
||||
<td>0x64</td>
|
||||
<td>0x65</td>
|
||||
<td>0x66</td>
|
||||
<td>0x67</td>
|
||||
</tr>
|
||||
<tr class="bottom">
|
||||
<td>96</td>
|
||||
<td>97</td>
|
||||
<td>98</td>
|
||||
<td>99</td>
|
||||
<td>100</td>
|
||||
<td>101</td>
|
||||
<td>102</td>
|
||||
<td>103</td>
|
||||
</tr>
|
||||
|
||||
<tr class="top">
|
||||
<th rowspan="3">COLOUR_PINK</th>
|
||||
<td><span style="background-color:rgb(112, 16, 32)"></span></td>
|
||||
<td><span style="background-color:rgb(136, 32, 52)"></span></td>
|
||||
<td><span style="background-color:rgb(160, 56, 76)"></span></td>
|
||||
<td><span style="background-color:rgb(188, 84, 108)"></span></td>
|
||||
<td><span style="background-color:rgb(204, 104, 124)"></span></td>
|
||||
<td><span style="background-color:rgb(220, 132, 144)"></span></td>
|
||||
<td><span style="background-color:rgb(236, 156, 164)"></span></td>
|
||||
<td><span style="background-color:rgb(252, 188, 192)"></span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>0x2a</td>
|
||||
<td>0x2b</td>
|
||||
<td>0x2c</td>
|
||||
<td>0x2d</td>
|
||||
<td>0x2e</td>
|
||||
<td>0x2f</td>
|
||||
<td>0x30</td>
|
||||
<td>0x31</td>
|
||||
</tr>
|
||||
<tr class="bottom">
|
||||
<td>42</td>
|
||||
<td>43</td>
|
||||
<td>44</td>
|
||||
<td>45</td>
|
||||
<td>46</td>
|
||||
<td>47</td>
|
||||
<td>48</td>
|
||||
<td>49</td>
|
||||
</tr>
|
||||
|
||||
<tr class="top">
|
||||
<th rowspan="3">COLOUR_YELLOW</th>
|
||||
<td><span style="background-color:rgb(128, 68, 8)"></span></td>
|
||||
<td><span style="background-color:rgb(156, 96, 16)"></span></td>
|
||||
<td><span style="background-color:rgb(184, 120, 24)"></span></td>
|
||||
<td><span style="background-color:rgb(212, 156, 32)"></span></td>
|
||||
<td><span style="background-color:rgb(232, 184, 16)"></span></td>
|
||||
<td><span style="background-color:rgb(252, 212, 0)"></span></td>
|
||||
<td><span style="background-color:rgb(252, 248, 128)"></span></td>
|
||||
<td><span style="background-color:rgb(252, 252, 192)"></span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>0x3e</td>
|
||||
<td>0x3f</td>
|
||||
<td>0x40</td>
|
||||
<td>0x41</td>
|
||||
<td>0x42</td>
|
||||
<td>0x43</td>
|
||||
<td>0x44</td>
|
||||
<td>0x45</td>
|
||||
</tr>
|
||||
<tr class="bottom">
|
||||
<td>62</td>
|
||||
<td>63</td>
|
||||
<td>64</td>
|
||||
<td>65</td>
|
||||
<td>66</td>
|
||||
<td>67</td>
|
||||
<td>68</td>
|
||||
<td>69</td>
|
||||
</tr>
|
||||
|
||||
<tr class="top">
|
||||
<th rowspan="3">COLOUR_RED</th>
|
||||
<td><span style="background-color:rgb( 92, 0, 0)"></span></td>
|
||||
<td><span style="background-color:rgb(128, 0, 0)"></span></td>
|
||||
<td><span style="background-color:rgb(160, 0, 0)"></span></td>
|
||||
<td><span style="background-color:rgb(196, 0, 0)"></span></td>
|
||||
<td><span style="background-color:rgb(224, 0, 0)"></span></td>
|
||||
<td><span style="background-color:rgb(252, 52, 52)"></span></td>
|
||||
<td><span style="background-color:rgb(252, 100, 88)"></span></td>
|
||||
<td><span style="background-color:rgb(252, 144, 124)"></span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>0xb3</td>
|
||||
<td>0xb4</td>
|
||||
<td>0xb5</td>
|
||||
<td>0xb6</td>
|
||||
<td>0xb7</td>
|
||||
<td>0xa4</td>
|
||||
<td>0xa5</td>
|
||||
<td>0xa6</td>
|
||||
</tr>
|
||||
<tr class="bottom">
|
||||
<td>179</td>
|
||||
<td>180</td>
|
||||
<td>181</td>
|
||||
<td>182</td>
|
||||
<td>183</td>
|
||||
<td>164</td>
|
||||
<td>165</td>
|
||||
<td>166</td>
|
||||
</tr>
|
||||
|
||||
<tr class="top">
|
||||
<th rowspan="3">COLOUR_LIGHT_BLUE</th>
|
||||
<td><span style="background-color:rgb( 16, 64, 96)"></span></td>
|
||||
<td><span style="background-color:rgb( 24, 80, 108)"></span></td>
|
||||
<td><span style="background-color:rgb( 40, 96, 120)"></span></td>
|
||||
<td><span style="background-color:rgb( 52, 112, 132)"></span></td>
|
||||
<td><span style="background-color:rgb( 80, 140, 160)"></span></td>
|
||||
<td><span style="background-color:rgb(116, 172, 192)"></span></td>
|
||||
<td><span style="background-color:rgb(156, 204, 220)"></span></td>
|
||||
<td><span style="background-color:rgb(204, 240, 252)"></span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>0x9a</td>
|
||||
<td>0x9b</td>
|
||||
<td>0x9c</td>
|
||||
<td>0x9d</td>
|
||||
<td>0x9e</td>
|
||||
<td>0x9f</td>
|
||||
<td>0xa0</td>
|
||||
<td>0xa1</td>
|
||||
</tr>
|
||||
<tr class="bottom">
|
||||
<td>154</td>
|
||||
<td>155</td>
|
||||
<td>156</td>
|
||||
<td>157</td>
|
||||
<td>158</td>
|
||||
<td>159</td>
|
||||
<td>160</td>
|
||||
<td>161</td>
|
||||
</tr>
|
||||
|
||||
<tr class="top">
|
||||
<th rowspan="3">COLOUR_GREEN</th>
|
||||
<td><span style="background-color:rgb( 32, 80, 4)"></span></td>
|
||||
<td><span style="background-color:rgb( 48, 96, 4)"></span></td>
|
||||
<td><span style="background-color:rgb( 64, 112, 12)"></span></td>
|
||||
<td><span style="background-color:rgb( 84, 132, 20)"></span></td>
|
||||
<td><span style="background-color:rgb( 92, 156, 52)"></span></td>
|
||||
<td><span style="background-color:rgb(108, 176, 64)"></span></td>
|
||||
<td><span style="background-color:rgb(124, 200, 76)"></span></td>
|
||||
<td><span style="background-color:rgb(144, 224, 92)"></span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>0x52</td>
|
||||
<td>0x53</td>
|
||||
<td>0x54</td>
|
||||
<td>0x55</td>
|
||||
<td>0xce</td>
|
||||
<td>0xcf</td>
|
||||
<td>0xd0</td>
|
||||
<td>0xd1</td>
|
||||
</tr>
|
||||
<tr class="bottom">
|
||||
<td>82</td>
|
||||
<td>83</td>
|
||||
<td>84</td>
|
||||
<td>85</td>
|
||||
<td>206</td>
|
||||
<td>207</td>
|
||||
<td>208</td>
|
||||
<td>209</td>
|
||||
</tr>
|
||||
|
||||
<tr class="top">
|
||||
<th rowspan="3">COLOUR_DARK_GREEN</th>
|
||||
<td><span style="background-color:rgb( 28, 52, 24)"></span></td>
|
||||
<td><span style="background-color:rgb( 44, 68, 32)"></span></td>
|
||||
<td><span style="background-color:rgb( 60, 88, 48)"></span></td>
|
||||
<td><span style="background-color:rgb( 80, 104, 60)"></span></td>
|
||||
<td><span style="background-color:rgb(104, 124, 76)"></span></td>
|
||||
<td><span style="background-color:rgb(128, 148, 92)"></span></td>
|
||||
<td><span style="background-color:rgb(152, 176, 108)"></span></td>
|
||||
<td><span style="background-color:rgb(180, 204, 124)"></span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>0x58</td>
|
||||
<td>0x59</td>
|
||||
<td>0x5a</td>
|
||||
<td>0x5b</td>
|
||||
<td>0x5c</td>
|
||||
<td>0x5d</td>
|
||||
<td>0x5e</td>
|
||||
<td>0x5f</td>
|
||||
</tr>
|
||||
<tr class="bottom">
|
||||
<td>88</td>
|
||||
<td>89</td>
|
||||
<td>90</td>
|
||||
<td>91</td>
|
||||
<td>92</td>
|
||||
<td>93</td>
|
||||
<td>94</td>
|
||||
<td>95</td>
|
||||
</tr>
|
||||
|
||||
<tr class="top">
|
||||
<th rowspan="3">COLOUR_BLUE</th>
|
||||
<td><span style="background-color:rgb( 0, 52, 160)"></span></td>
|
||||
<td><span style="background-color:rgb( 0, 72, 184)"></span></td>
|
||||
<td><span style="background-color:rgb( 0, 96, 212)"></span></td>
|
||||
<td><span style="background-color:rgb( 24, 120, 220)"></span></td>
|
||||
<td><span style="background-color:rgb( 56, 144, 232)"></span></td>
|
||||
<td><span style="background-color:rgb( 88, 168, 240)"></span></td>
|
||||
<td><span style="background-color:rgb(128, 196, 252)"></span></td>
|
||||
<td><span style="background-color:rgb(188, 224, 252)"></span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>0x92</td>
|
||||
<td>0x93</td>
|
||||
<td>0x94</td>
|
||||
<td>0x95</td>
|
||||
<td>0x96</td>
|
||||
<td>0x97</td>
|
||||
<td>0x98</td>
|
||||
<td>0x99</td>
|
||||
</tr>
|
||||
<tr class="bottom">
|
||||
<td>146</td>
|
||||
<td>147</td>
|
||||
<td>148</td>
|
||||
<td>149</td>
|
||||
<td>150</td>
|
||||
<td>151</td>
|
||||
<td>152</td>
|
||||
<td>153</td>
|
||||
</tr>
|
||||
|
||||
<tr class="top">
|
||||
<th rowspan="3">COLOUR_CREAM</th>
|
||||
<td><span style="background-color:rgb(116, 68, 40)"></span></td>
|
||||
<td><span style="background-color:rgb(136, 84, 56)"></span></td>
|
||||
<td><span style="background-color:rgb(164, 96, 64)"></span></td>
|
||||
<td><span style="background-color:rgb(184, 112, 80)"></span></td>
|
||||
<td><span style="background-color:rgb(204, 128, 96)"></span></td>
|
||||
<td><span style="background-color:rgb(212, 148, 112)"></span></td>
|
||||
<td><span style="background-color:rgb(224, 168, 128)"></span></td>
|
||||
<td><span style="background-color:rgb(236, 188, 148)"></span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>0x72</td>
|
||||
<td>0x73</td>
|
||||
<td>0x74</td>
|
||||
<td>0x75</td>
|
||||
<td>0x76</td>
|
||||
<td>0x77</td>
|
||||
<td>0x78</td>
|
||||
<td>0x79</td>
|
||||
</tr>
|
||||
<tr class="bottom">
|
||||
<td>114</td>
|
||||
<td>115</td>
|
||||
<td>116</td>
|
||||
<td>117</td>
|
||||
<td>118</td>
|
||||
<td>119</td>
|
||||
<td>120</td>
|
||||
<td>121</td>
|
||||
</tr>
|
||||
|
||||
<tr class="top">
|
||||
<th rowspan="3">COLOUR_MAUVE</th>
|
||||
<td><span style="background-color:rgb( 36, 40, 68)"></span></td>
|
||||
<td><span style="background-color:rgb( 48, 52, 84)"></span></td>
|
||||
<td><span style="background-color:rgb( 64, 64, 100)"></span></td>
|
||||
<td><span style="background-color:rgb( 80, 80, 116)"></span></td>
|
||||
<td><span style="background-color:rgb(100, 100, 136)"></span></td>
|
||||
<td><span style="background-color:rgb(132, 132, 164)"></span></td>
|
||||
<td><span style="background-color:rgb(172, 172, 192)"></span></td>
|
||||
<td><span style="background-color:rgb(212, 212, 224)"></span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>0x80</td>
|
||||
<td>0x81</td>
|
||||
<td>0x82</td>
|
||||
<td>0x83</td>
|
||||
<td>0x84</td>
|
||||
<td>0x85</td>
|
||||
<td>0x86</td>
|
||||
<td>0x87</td>
|
||||
</tr>
|
||||
<tr class="bottom">
|
||||
<td>128</td>
|
||||
<td>129</td>
|
||||
<td>130</td>
|
||||
<td>131</td>
|
||||
<td>132</td>
|
||||
<td>133</td>
|
||||
<td>134</td>
|
||||
<td>135</td>
|
||||
</tr>
|
||||
|
||||
<tr class="top">
|
||||
<th rowspan="3">COLOUR_PURPLE</th>
|
||||
<td><span style="background-color:rgb( 40, 20, 112)"></span></td>
|
||||
<td><span style="background-color:rgb( 64, 44, 144)"></span></td>
|
||||
<td><span style="background-color:rgb( 88, 64, 172)"></span></td>
|
||||
<td><span style="background-color:rgb(104, 76, 196)"></span></td>
|
||||
<td><span style="background-color:rgb(120, 88, 224)"></span></td>
|
||||
<td><span style="background-color:rgb(140, 104, 252)"></span></td>
|
||||
<td><span style="background-color:rgb(160, 136, 252)"></span></td>
|
||||
<td><span style="background-color:rgb(188, 168, 252)"></span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>0x88</td>
|
||||
<td>0x89</td>
|
||||
<td>0x8a</td>
|
||||
<td>0x8b</td>
|
||||
<td>0x8c</td>
|
||||
<td>0x8d</td>
|
||||
<td>0x8e</td>
|
||||
<td>0x8f</td>
|
||||
</tr>
|
||||
<tr class="bottom">
|
||||
<td>136</td>
|
||||
<td>137</td>
|
||||
<td>138</td>
|
||||
<td>139</td>
|
||||
<td>140</td>
|
||||
<td>141</td>
|
||||
<td>142</td>
|
||||
<td>143</td>
|
||||
</tr>
|
||||
|
||||
<tr class="top">
|
||||
<th rowspan="3">COLOUR_ORANGE</th>
|
||||
<td><span style="background-color:rgb(184, 120, 24)"></span></td>
|
||||
<td><span style="background-color:rgb(204, 136, 8)"></span></td>
|
||||
<td><span style="background-color:rgb(228, 144, 4)"></span></td>
|
||||
<td><span style="background-color:rgb(252, 156, 0)"></span></td>
|
||||
<td><span style="background-color:rgb(252, 176, 48)"></span></td>
|
||||
<td><span style="background-color:rgb(252, 196, 100)"></span></td>
|
||||
<td><span style="background-color:rgb(252, 216, 152)"></span></td>
|
||||
<td><span style="background-color:rgb(244, 220, 176)"></span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>0x40</td>
|
||||
<td>0xc0</td>
|
||||
<td>0xc1</td>
|
||||
<td>0xc2</td>
|
||||
<td>0xc3</td>
|
||||
<td>0xc4</td>
|
||||
<td>0xc5</td>
|
||||
<td>0x27</td>
|
||||
</tr>
|
||||
<tr class="bottom">
|
||||
<td>64</td>
|
||||
<td>192</td>
|
||||
<td>193</td>
|
||||
<td>194</td>
|
||||
<td>195</td>
|
||||
<td>196</td>
|
||||
<td>197</td>
|
||||
<td>39</td>
|
||||
</tr>
|
||||
|
||||
<tr class="top">
|
||||
<th rowspan="3">COLOUR_BROWN</th>
|
||||
<td><span style="background-color:rgb( 72, 44, 4)"></span></td>
|
||||
<td><span style="background-color:rgb( 88, 60, 20)"></span></td>
|
||||
<td><span style="background-color:rgb(104, 80, 44)"></span></td>
|
||||
<td><span style="background-color:rgb(124, 104, 72)"></span></td>
|
||||
<td><span style="background-color:rgb(152, 132, 92)"></span></td>
|
||||
<td><span style="background-color:rgb(184, 160, 120)"></span></td>
|
||||
<td><span style="background-color:rgb(212, 188, 148)"></span></td>
|
||||
<td><span style="background-color:rgb(244, 220, 176)"></span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>0x20</td>
|
||||
<td>0x21</td>
|
||||
<td>0x22</td>
|
||||
<td>0x23</td>
|
||||
<td>0x24</td>
|
||||
<td>0x25</td>
|
||||
<td>0x26</td>
|
||||
<td>0x27</td>
|
||||
</tr>
|
||||
<tr class="bottom">
|
||||
<td>32</td>
|
||||
<td>33</td>
|
||||
<td>34</td>
|
||||
<td>35</td>
|
||||
<td>36</td>
|
||||
<td>37</td>
|
||||
<td>38</td>
|
||||
<td>39</td>
|
||||
</tr>
|
||||
|
||||
<tr class="top">
|
||||
<th rowspan="3">COLOUR_GREY</th>
|
||||
<td><span style="background-color:rgb( 64, 64, 64)"></span></td>
|
||||
<td><span style="background-color:rgb( 80, 80, 80)"></span></td>
|
||||
<td><span style="background-color:rgb(100, 100, 100)"></span></td>
|
||||
<td><span style="background-color:rgb(116, 116, 116)"></span></td>
|
||||
<td><span style="background-color:rgb(132, 132, 132)"></span></td>
|
||||
<td><span style="background-color:rgb(148, 148, 148)"></span></td>
|
||||
<td><span style="background-color:rgb(168, 168, 168)"></span></td>
|
||||
<td><span style="background-color:rgb(184, 184, 184)"></span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>0x4</td>
|
||||
<td>0x5</td>
|
||||
<td>0x6</td>
|
||||
<td>0x7</td>
|
||||
<td>0x8</td>
|
||||
<td>0x9</td>
|
||||
<td>0xa</td>
|
||||
<td>0xb</td>
|
||||
</tr>
|
||||
<tr class="bottom">
|
||||
<td>4</td>
|
||||
<td>5</td>
|
||||
<td>6</td>
|
||||
<td>7</td>
|
||||
<td>8</td>
|
||||
<td>9</td>
|
||||
<td>10</td>
|
||||
<td>11</td>
|
||||
</tr>
|
||||
|
||||
<tr class="top">
|
||||
<th rowspan="3">COLOUR_WHITE</th>
|
||||
<td><span style="background-color:rgb(132, 132, 132)"></span></td>
|
||||
<td><span style="background-color:rgb(148, 148, 148)"></span></td>
|
||||
<td><span style="background-color:rgb(168, 168, 168)"></span></td>
|
||||
<td><span style="background-color:rgb(184, 184, 184)"></span></td>
|
||||
<td><span style="background-color:rgb(200, 200, 200)"></span></td>
|
||||
<td><span style="background-color:rgb(216, 216, 216)"></span></td>
|
||||
<td><span style="background-color:rgb(232, 232, 232)"></span></td>
|
||||
<td><span style="background-color:rgb(252, 252, 252)"></span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>0x8</td>
|
||||
<td>0x9</td>
|
||||
<td>0xa</td>
|
||||
<td>0xb</td>
|
||||
<td>0xc</td>
|
||||
<td>0xd</td>
|
||||
<td>0xe</td>
|
||||
<td>0xf</td>
|
||||
</tr>
|
||||
<tr class="bottom">
|
||||
<td>8</td>
|
||||
<td>9</td>
|
||||
<td>10</td>
|
||||
<td>11</td>
|
||||
<td>12</td>
|
||||
<td>13</td>
|
||||
<td>14</td>
|
||||
<td>15</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
||||
83
docs/game_coordinator.md
Normal file
83
docs/game_coordinator.md
Normal file
@@ -0,0 +1,83 @@
|
||||
# Game Coordinator
|
||||
|
||||
To allow two players to play together, OpenTTD uses a Game Coordinator to
|
||||
facilitate this.
|
||||
|
||||
When a server starts, it can register itself to the Game Coordinator. This
|
||||
happens when `server_game_type` is set to either `invite-only` or `public`.
|
||||
Upon registration, the Game Coordinator probes the network of the server, and
|
||||
assigns the server an unique code, called an `invite code`.
|
||||
|
||||
When a client wants to join a server, it asks the Game Coordinator to help
|
||||
with this by giving it the `invite code` of the server. The Game Coordinator
|
||||
will, in this order, attempt several ways to connect the client and server
|
||||
together:
|
||||
|
||||
## 1) Via direct IPv4 / IPv6
|
||||
|
||||
Upon registration, the Game Coordinator probes the server to see if a
|
||||
direction connection to the server is possible based on the game port. It
|
||||
tries this over the public IPv4 and IPv6, as announced by the server.
|
||||
If either (or both) are successful, a client will always be asked to try
|
||||
these direct IPs first when it wants to connect to this server.
|
||||
|
||||
- If the server is IPv4 only, the client is only asked to connect via IPv4.
|
||||
- If the server is IPv6 only, the client is only asked to connect via IPv6.
|
||||
- If the server is both IPv4 and IPv6, the client is asked to connect to to
|
||||
one of those first. If that fails, it is asked to connect to the other.
|
||||
Whether it tries IPv4 or IPv6 first, strongly depends on several network
|
||||
infrastructure related events. The biggest influence is the network
|
||||
latency over both protocols to the OpenTTD infrastructure.
|
||||
|
||||
In the end, if either the server is not reachable directly from the Internet
|
||||
or the client fails to connect to either one of them, the connection attempt
|
||||
continues with the next available method.
|
||||
|
||||
## 2) Via STUN
|
||||
|
||||
When a client wants to join a server via STUN, both the client and server
|
||||
are asked to create a connection to the STUN server (normally
|
||||
`stun.openttd.org`) via both IPv4 and IPv6. If the client or server has no
|
||||
IPv4 or IPv6, it will not make a connection attempt via that protocol.
|
||||
|
||||
The STUN server collects the public IPv4 and/or IPv6 of the client and server,
|
||||
together with the port the connection came in from. For most NAT gateways it
|
||||
holds true that as long as you use the same local IP + port, your public
|
||||
IP + port will remain the same, and allow for bi-directional communication.
|
||||
And this fact is used to later on pair the client and server.
|
||||
|
||||
The STUN server reports this information directly to the Game Coordinator
|
||||
(this in contrast to most STUN implementation, where this information is
|
||||
first reported back to the peer itself, which has to relay it back to the
|
||||
coordinator. OpenTTD skips this step, as the STUN server can directly talk to
|
||||
the Game Coordinator). When the Game Coordinator sees a matching pair (in
|
||||
terms of IPv4 / IPv6), it will ask both the client and server to connect to
|
||||
their peer based on this public IP + port.
|
||||
|
||||
As the NAT gateway forwards the traffic on the public IP + port to the local
|
||||
port, this creates a bi-directional socket between client and server. The
|
||||
connection to the STUN server can now safely be closed, and the client and
|
||||
server can continue to talk to each other.
|
||||
|
||||
Some NAT gateways do not allow this method; for those this attempt will fail,
|
||||
and this also means that it is not possible to create a connection between
|
||||
the client and server.
|
||||
|
||||
## 3) Via TURN
|
||||
|
||||
As a last resort, the Game Coordinator can decide to connect the client and
|
||||
server together via TURN. TURN is a relay service, relaying the messages
|
||||
between client and server.
|
||||
|
||||
As the client and server can already connect to the Game Coordinator, it is
|
||||
very likely this is successful.
|
||||
|
||||
It is important to note that a relay service has full view of the traffic
|
||||
send between client and server, and as such it is important that you trust
|
||||
the relay service used.
|
||||
For official binaries, this relay service is hosted by openttd.org. The relay
|
||||
service as hosted by openttd.org only validates it is relaying valid OpenTTD
|
||||
packets and does no further inspection of the payload itself.
|
||||
Although in our experience most patch-packs also use the services as offered
|
||||
by openttd.org, it is possible they use different services. Please be mindful
|
||||
about this.
|
||||
@@ -48,6 +48,10 @@ Last updated: 2011-02-16
|
||||
- click add server
|
||||
- type in the ip address or hostname
|
||||
- if you want to add a port use :<port>
|
||||
- If you want to play and you have the invite code of the game server you
|
||||
want connect to.
|
||||
- click add server
|
||||
- type in the invite code
|
||||
- Now you can select a company and press: "Join company", to help that company
|
||||
- Or you can press "Spectate game", to spectate the game
|
||||
- Or you can press "New company", and start your own company (if there are
|
||||
@@ -110,9 +114,10 @@ Last updated: 2011-02-16
|
||||
- You can let your server automatically restart a map when, let's say, year 2030
|
||||
is reached. See 'set restart_game_date' for detail.
|
||||
|
||||
- If you want to be on the server-list, enable Advertising. To do this, select
|
||||
'Internet (advertise)' in the Start Server menu, or type in console:
|
||||
'set server_advertise 1'.
|
||||
- If you want to be on the server-list, make your server public. You can do
|
||||
this either from the Start Server GUI, via the in-game Online Players GUI,
|
||||
or by typing in the console:
|
||||
'set server_game_type public'.
|
||||
|
||||
- You can protect your server with a password via the console: 'set server_pw',
|
||||
or via the Start Server menu.
|
||||
|
||||
214
docs/savegame_format.md
Normal file
214
docs/savegame_format.md
Normal file
@@ -0,0 +1,214 @@
|
||||
# OpenTTD's Savegame Format
|
||||
|
||||
Last updated: 2021-06-15
|
||||
|
||||
## Outer container
|
||||
|
||||
Savegames for OpenTTD start with an outer container, to contain the compressed data for the rest of the savegame.
|
||||
|
||||
`[0..3]` - The first four bytes indicate what compression is used.
|
||||
In ASCII, these values are possible:
|
||||
|
||||
- `OTTD` - Compressed with LZO (deprecated, only really old savegames would use this).
|
||||
- `OTTN` - No compression.
|
||||
- `OTTZ` - Compressed with zlib.
|
||||
- `OTTX` - Compressed with LZMA.
|
||||
|
||||
`[4..5]` - The next two bytes indicate which savegame version used.
|
||||
|
||||
`[6..7]` - The next two bytes can be ignored, and were only used in really old savegames.
|
||||
|
||||
`[8..N]` - Next follows a binary blob which is compressed with the indicated compression algorithm.
|
||||
|
||||
The rest of this document talks about this decompressed blob of data.
|
||||
|
||||
## Data types
|
||||
|
||||
The savegame is written in Big Endian, so when we talk about a 16-bit unsigned integer (`uint16`), we mean it is stored in Big Endian.
|
||||
|
||||
The following types are valid:
|
||||
|
||||
- `1` - `int8` / `SLE_FILE_I8` -8-bit signed integer
|
||||
- `2` - `uint8` / `SLE_FILE_U8` - 8-bit unsigned integer
|
||||
- `3` - `int16` / `SLE_FILE_I16` - 16-bit signed integer
|
||||
- `4` - `uint16` / `SLE_FILE_U16` - 16-bit unsigned integer
|
||||
- `5` - `int32` / `SLE_FILE_I32` - 32-bit signed integer
|
||||
- `6` - `uint32` / `SLE_FILE_U32` - 32-bit unsigned integer
|
||||
- `7` - `int64` / `SLE_FILE_I64` - 64-bit signed integer
|
||||
- `8` - `uint64` / `SLE_FILE_U64` - 64-bit unsigned integer
|
||||
- `9` - `StringID` / `SLE_FILE_STRINGID` - a StringID inside the OpenTTD's string table
|
||||
- `10` - `str` / `SLE_FILE_STRING` - a string (prefixed with a length-field)
|
||||
- `11` - `struct` / `SLE_FILE_STRUCT` - a struct
|
||||
|
||||
### Gamma value
|
||||
|
||||
There is also a field-type called `gamma`.
|
||||
This is most often used for length-fields, and uses as few bytes as possible to store an integer.
|
||||
For values <= 127, it uses a single byte.
|
||||
For values > 127, it uses two bytes and sets the highest bit to high.
|
||||
For values > 32767, it uses three bytes and sets the two highest bits to high.
|
||||
And this continues till the value fits.
|
||||
In a more visual approach:
|
||||
```
|
||||
0xxxxxxx
|
||||
10xxxxxx xxxxxxxx
|
||||
110xxxxx xxxxxxxx xxxxxxxx
|
||||
1110xxxx xxxxxxxx xxxxxxxx xxxxxxxx
|
||||
11110--- xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx
|
||||
```
|
||||
|
||||
## Chunks
|
||||
|
||||
Savegames for OpenTTD store their data in chunks.
|
||||
Each chunk contains data for a certain part of the game, for example "Companies", "Vehicles", etc.
|
||||
|
||||
`[0..3]` - Each chunk starts with four bytes to indicate the tag.
|
||||
If the tag is `\x00\x00\x00\x00` it means the end of the savegame is reached.
|
||||
An example of a valid tag is `PLYR` when looking at it via ASCII, which contains the information of all the companies.
|
||||
|
||||
`[4..4]` - Next follows a byte where the lower 4 bits contain the type.
|
||||
The possible valid types are:
|
||||
|
||||
- `0` - `CH_RIFF` - This chunk is a binary blob.
|
||||
- `1` - `CH_ARRAY` - This chunk is a list of items.
|
||||
- `2` - `CH_SPARSE_ARRAY` - This chunk is a list of items.
|
||||
- `3` - `CH_TABLE` - This chunk is self-describing list of items.
|
||||
- `4` - `CH_SPARSE_TABLE` - This chunk is self-describing list of items.
|
||||
|
||||
Now per type the format is (slightly) different.
|
||||
|
||||
### CH_RIFF
|
||||
|
||||
(since savegame version 295, this chunk type is only used for MAP-chunks, containing bit-information about each tile on the map)
|
||||
|
||||
A `CH_RIFF` starts with an `uint24` which together with the upper-bits of the type defines the length of the chunk.
|
||||
In pseudo-code:
|
||||
|
||||
```
|
||||
type = read uint8
|
||||
if type == 0
|
||||
length = read uint24
|
||||
length |= ((type >> 4) << 24)
|
||||
```
|
||||
|
||||
The next `length` bytes are part of the chunk.
|
||||
What those bytes mean depends on the tag of the chunk; further details per chunk can be found in the source-code.
|
||||
|
||||
### CH_ARRAY / CH_SPARSE_ARRAY
|
||||
|
||||
(this chunk type is deprecated since savegame version 295 and is no longer in use)
|
||||
|
||||
`[0..G1]` - A `CH_ARRAY` / `CH_SPARSE_ARRAY` starts with a `gamma`, indicating the size of the next item plus one.
|
||||
If this size value is zero, it indicates the end of the list.
|
||||
This indicates the full length of the next item minus one.
|
||||
In psuedo-code:
|
||||
|
||||
```
|
||||
loop
|
||||
size = read gamma - 1
|
||||
if size == -1
|
||||
break loop
|
||||
read <size> bytes
|
||||
```
|
||||
|
||||
`[]` - For `CH_ARRAY` there is an implicit index.
|
||||
The loop starts at zero, and every iteration adds one to the index.
|
||||
For entries in the game that were not allocated, the `size` will be zero.
|
||||
|
||||
`[G1+1..G2]` - For `CH_SPARSE_ARRAY` there is an explicit index.
|
||||
The `gamma` following the size indicates the index.
|
||||
|
||||
The content of the item is a binary blob, and similar to `CH_RIFF`, it depends on the tag of the chunk what it means.
|
||||
Please check the source-code for further details.
|
||||
|
||||
### CH_TABLE / CH_SPARSE_TABLE
|
||||
|
||||
(this chunk type only exists since savegame version 295)
|
||||
|
||||
Both `CH_TABLE` and `CH_SPARSE_TABLE` are very similar to `CH_ARRAY` / `CH_SPARSE_ARRAY` respectively.
|
||||
The only change is that the chunk starts with a header.
|
||||
This header describes the chunk in details; with the header you know the meaning of each byte in the binary blob that follows.
|
||||
|
||||
`[0..G]` - The header starts with a `gamma` to indicate the size of all the headers in this chunk plus one.
|
||||
If this size value is zero, it means there is no header, which should never be the case.
|
||||
|
||||
Next follows a list of `(type, key)` pairs:
|
||||
|
||||
- `[0..0]` - Type of the field.
|
||||
- `[1..G]` - `gamma` to indicate length of key.
|
||||
- `[G+1..N]` - Key (in UTF-8) of the field.
|
||||
|
||||
If at any point `type` is zero, the list stops (and no `key` follows).
|
||||
|
||||
The `type`'s lower 4 bits indicate the data-type (see chapter above).
|
||||
The `type`'s 5th bit (so `0x10`) indicates if the field is a list, and if this field in every record starts with a `gamma` to indicate how many times the `type` is repeated.
|
||||
|
||||
If the `type` indicates either a `struct` or `str`, the `0x10` flag is also always set.
|
||||
|
||||
As the savegame format allows (list of) structs in structs, if any `struct` type is found, this header will be followed by a header of that struct.
|
||||
This nesting of structs is stored depth-first, so given this table:
|
||||
|
||||
```
|
||||
type | key
|
||||
-----------------
|
||||
uint8 | counter
|
||||
struct | substruct1
|
||||
struct | substruct2
|
||||
```
|
||||
|
||||
With `substruct1` being like:
|
||||
|
||||
```
|
||||
type | key
|
||||
-----------------
|
||||
uint8 | counter
|
||||
struct | substruct3
|
||||
```
|
||||
|
||||
The headers will be, in order: `table`, `substruct1`, `substruct3`, `substruct2`, each ending with a `type` is zero field.
|
||||
|
||||
After reading all the fields of all the headers, there is a list of records.
|
||||
To read this, see `CH_ARRAY` / `CH_SPARSE_ARRAY` for details.
|
||||
|
||||
As each `type` has a well defined length, you can read the records even without knowing anything about the chunk-tag yourself.
|
||||
|
||||
Do remember, that if the `type` had the `0x10` flag active, the field in the record first has a `gamma` to indicate how many times that `type` is repeated.
|
||||
|
||||
#### Guidelines for network-compatible patch-packs
|
||||
|
||||
For network-compatible patch-packs (client-side patches that can play together with unpatched clients) we advise to prefix the field-name with `__<shortname>` when introducing new fields to an existing chunk.
|
||||
|
||||
Example: you have an extra setting called `auto_destroy_rivers` you want to store in the savegame for your patched client called `mypp`.
|
||||
We advise you to call this setting `__mypp_auto_destroy_rivers` in the settings chunk.
|
||||
|
||||
Doing it this way ensures that a savegame created by these patch-packs can still safely be loaded by unpatched clients.
|
||||
They will simply ignore the field and continue loading the savegame as usual.
|
||||
The prefix is strongly advised to avoid conflicts with future-settings in an unpatched client or conflicts with other patch-packs.
|
||||
|
||||
## Scripts custom data format
|
||||
|
||||
Script chunks (`AIPL` and `GSDT`) use `CH_TABLE` chunk type.
|
||||
|
||||
At the end of each record there's an `uint8` to indicate if there's custom data (1) or not (0).
|
||||
|
||||
There are 6 data types for scripts, called `script-data-type`.
|
||||
When saving, each `script-data-type` starts with the type marker saved as `uint8` followed by the actual data.
|
||||
- `0` - `SQSL_INT`:
|
||||
- an `int64` with the actual value (`int32` before savegame version 296).
|
||||
- `1` - `SQSL_STRING`:
|
||||
- an `uint8` with the string length.
|
||||
- a list of `int8` for the string itself.
|
||||
- `2` - `SQSL_ARRAY`:
|
||||
- each element saved as `script-data-type`.
|
||||
- an `SQSL_ARRAY_TABLE_END` (0xFF) marker (`uint8`).
|
||||
- `3` - `SQSL_TABLE`:
|
||||
- for each element:
|
||||
- key saved as `script-data-type`.
|
||||
- value saved as `script-data-type`.
|
||||
- an `SQSL_ARRAY_TABLE_END` (0xFF) marker (`uint8`).
|
||||
- `4` - `SQSL_BOOL`:
|
||||
- an `uint8` with 0 (false) or 1 (true).
|
||||
- `5` - `SQSL_NULL`:
|
||||
- (no data follows)
|
||||
|
||||
The first data type is always a `SQSL_TABLE`.
|
||||
Reference in New Issue
Block a user