summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/landscape.html666
-rw-r--r--docs/landscape_externals.html616
-rw-r--r--docs/landscape_grid.html41
-rw-r--r--projects/openttd.vcproj12
-rw-r--r--projects/openttd_vs80.vcproj20
-rw-r--r--source.list4
-rw-r--r--src/map.cpp13
-rw-r--r--src/map.h7
-rw-r--r--src/misc.cpp31
-rw-r--r--src/misc_gui.cpp1
-rw-r--r--src/newgrf.cpp426
-rw-r--r--src/newgrf.h3
-rw-r--r--src/newgrf_callbacks.h61
-rw-r--r--src/newgrf_house.cpp609
-rw-r--r--src/newgrf_house.h71
-rw-r--r--src/newgrf_sound.cpp9
-rw-r--r--src/newgrf_sound.h1
-rw-r--r--src/newgrf_spritegroup.cpp6
-rw-r--r--src/newgrf_spritegroup.h13
-rw-r--r--src/newgrf_town.cpp91
-rw-r--r--src/newgrf_town.h13
-rw-r--r--src/openttd.cpp45
-rw-r--r--src/table/sprites.h3
-rw-r--r--src/table/town_land.h810
-rw-r--r--src/town.h116
-rw-r--r--src/town_cmd.cpp282
-rw-r--r--src/town_map.h303
-rw-r--r--src/void_map.h1
28 files changed, 3027 insertions, 1247 deletions
diff --git a/docs/landscape.html b/docs/landscape.html
index 4ef9815d7..a89643654 100644
--- a/docs/landscape.html
+++ b/docs/landscape.html
@@ -568,621 +568,67 @@
<td valign=top nowrap>&nbsp;</td>
<td>
<ul>
- <li>m2: Index into the array of towns</li>
- <li>m3 bits 7..6: stage of construction (<tt>3</tt> = completed)</li>
- <li>m4: <a name="HouseTypes">town building type</a>:<br>
- <small>Note: In the climate list, 'sub-arctic' means below the snow line, and 'snow' means above the snow line in the sub-arctic climate.</small>
- <table>
- <tr>
- <th align=left>Type&nbsp;</th>
- <th align=left>Size&nbsp;</th>
- <th align=left>Climates&nbsp;</th>
- <th align=left>Description</th>
- </tr>
-
- <tr>
- <td nowrap valign=top><tt>00</tt>&nbsp; </td>
- <td>1&times;1</td>
- <td>temperate</td>
- <td align=left>tall office block</td>
- </tr>
-
- <tr>
- <td nowrap valign=top><tt>01</tt>&nbsp; </td>
- <td>1&times;1</td>
- <td>temperate</td>
- <td align=left>office block</td>
- </tr>
-
- <tr>
- <td nowrap valign=top><tt>02</tt>&nbsp; </td>
- <td>1&times;1</td>
- <td>temperate</td>
- <td align=left>small block of flats</td>
- </tr>
-
- <tr>
- <td nowrap valign=top><tt>03</tt>&nbsp; </td>
- <td>1&times;1</td>
- <td>temperate</td>
- <td align=left>church</td>
- </tr>
-
- <tr>
- <td nowrap valign=top><tt>04</tt>&nbsp; </td>
- <td>1&times;1</td>
- <td>temperate, sub-arctic, sub-tropical</td>
- <td align=left>large office block</td>
- </tr>
-
- <tr>
- <td nowrap valign=top><tt>05</tt>&nbsp; </td>
- <td>1&times;1</td>
- <td>snow</td>
- <td align=left>large office block</td>
- </tr>
-
- <tr>
- <td nowrap valign=top><tt>06</tt>&nbsp; </td>
- <td>1&times;1</td>
- <td>temperate</td>
- <td align=left>town houses</td>
- </tr>
-
- <tr>
- <td nowrap valign=top><tt>07</tt>..<tt>08</tt>&nbsp; </td>
- <td>1&times;2</td>
- <td>temperate</td>
- <td align=left>hotel</td>
- </tr>
-
- <tr>
- <td nowrap valign=top><tt>09</tt>&nbsp; </td>
- <td>1&times;1</td>
- <td>temperate, sub-arctic, sub-tropical&nbsp;&nbsp;</td>
- <td align=left>statue</td>
- </tr>
-
- <tr>
- <td nowrap valign=top><tt>0A</tt>&nbsp; </td>
- <td>1&times;1</td>
- <td>temperate, sub-arctic, sub-tropical</td>
- <td align=left>fountain</td>
- </tr>
-
- <tr>
- <td nowrap valign=top><tt>0B</tt>&nbsp; </td>
- <td>1&times;1</td>
- <td>temperate</td>
- <td align=left>park (with a pond)</td>
- </tr>
-
- <tr>
- <td nowrap valign=top><tt>0C</tt>&nbsp; </td>
- <td>1&times;1</td>
- <td>temperate</td>
- <td align=left>park (with an alley)</td>
- </tr>
-
- <tr>
- <td nowrap valign=top><tt>0D</tt>&nbsp; </td>
- <td>1&times;1</td>
- <td>temperate</td>
- <td align=left>office block</td>
- </tr>
-
- <tr>
- <td nowrap valign=top><tt>0E</tt>..<tt>10</tt>&nbsp; </td>
- <td>1&times;1</td>
- <td>temperate</td>
- <td align=left>various types of shops and offices</td>
- </tr>
-
- <tr>
- <td nowrap valign=top><tt>11</tt>&nbsp; </td>
- <td>1&times;1</td>
- <td>temperate, sub-arctic, sub-tropical</td>
- <td align=left>modern office building</td>
- </tr>
-
- <tr>
- <td nowrap valign=top><tt>12</tt>&nbsp; </td>
- <td>1&times;1</td>
- <td>temperate</td>
- <td align=left>warehouse</td>
- </tr>
-
- <tr>
- <td nowrap valign=top><tt>13</tt>&nbsp; </td>
- <td>1&times;1</td>
- <td>temperate</td>
- <td align=left>office block (with spiral stairway on the side)</td>
- </tr>
-
- <tr>
- <td nowrap valign=top><tt>14</tt>..<tt>17</tt>&nbsp; </td>
- <td>2&times;2</td>
- <td>temperate</td>
- <td align=left>stadium</td>
- </tr>
-
- <tr>
- <td nowrap valign=top><tt>18</tt>&nbsp; </td>
- <td>1&times;1</td>
- <td>temperate</td>
- <td align=left>old houses</td>
- </tr>
-
- <tr>
- <td nowrap valign=top><tt>19</tt>&nbsp; </td>
- <td>1&times;1</td>
- <td>temperate</td>
- <td align=left>cottages</td>
- </tr>
-
- <tr>
- <td nowrap valign=top><tt>1A</tt>&nbsp; </td>
- <td>1&times;1</td>
- <td>temperate</td>
- <td align=left>houses</td>
- </tr>
-
- <tr>
- <td nowrap valign=top><tt>1B</tt>&nbsp; </td>
- <td>1&times;1</td>
- <td>temperate</td>
- <td align=left>flats</td>
- </tr>
-
- <tr>
- <td nowrap valign=top><tt>1C</tt>&nbsp; </td>
- <td>1&times;1</td>
- <td>temperate</td>
- <td align=left>tall office block</td>
- </tr>
-
- <tr>
- <td nowrap valign=top><tt>1D</tt>&nbsp; </td>
- <td>1&times;1</td>
- <td>temperate</td>
- <td align=left>shops and offices</td>
- </tr>
-
- <tr>
- <td nowrap valign=top><tt>1E</tt>&nbsp; </td>
- <td>1&times;1</td>
- <td>temperate, sub-tropical</td>
- <td align=left>shops and offices</td>
- </tr>
-
- <tr>
- <td nowrap valign=top><tt>1F</tt>&nbsp; </td>
- <td>1&times;1</td>
- <td>temperate</td>
- <td align=left>theatre</td>
- </tr>
-
- <tr>
- <td nowrap valign=top><tt>20</tt>..<tt>23</tt>&nbsp; </td>
- <td>2&times;2</td>
- <td>temperate, sub-arctic, sub-tropical</td>
- <td align=left>stadium (modern style)</td>
- </tr>
-
- <tr>
- <td nowrap valign=top><tt>24</tt>&nbsp; </td>
- <td>1&times;1</td>
- <td>temperate, sub-arctic, sub-tropical</td>
- <td align=left>offices (the modern 'vertical tube' style)</td>
- </tr>
-
- <tr>
- <td nowrap valign=top><tt>25</tt>&nbsp; </td>
- <td>1&times;1</td>
- <td>sub-arctic</td>
- <td align=left>houses</td>
- </tr>
-
- <tr>
- <td nowrap valign=top><tt>26</tt>&nbsp; </td>
- <td>1&times;1</td>
- <td>snow</td>
- <td align=left>houses</td>
- </tr>
-
- <tr>
- <td nowrap valign=top><tt>27</tt>&nbsp; </td>
- <td>1&times;1</td>
- <td>temperate</td>
- <td align=left>cinema</td>
- </tr>
-
- <tr>
- <td nowrap valign=top><tt>28</tt>..<tt>2B</tt>&nbsp; </td>
- <td>2&times;2</td>
- <td>temperate</td>
- <td align=left>shopping mall</td>
- </tr>
-
- <tr>
- <td nowrap valign=top><tt>2C</tt>&nbsp; </td>
- <td>1&times;1</td>
- <td>sub-arctic</td>
- <td align=left>flats</td>
- </tr>
-
- <tr>
- <td nowrap valign=top><tt>2D</tt>&nbsp; </td>
- <td>1&times;1</td>
- <td>snow</td>
- <td align=left>flats</td>
- </tr>
-
- <tr>
- <td nowrap valign=top><tt>2E</tt>&nbsp; </td>
- <td>1&times;1</td>
- <td>sub-arctic</td>
- <td align=left>houses</td>
- </tr>
-
- <tr>
- <td nowrap valign=top><tt>2F</tt>&nbsp; </td>
- <td>1&times;1</td>
- <td>snow</td>
- <td align=left>houses</td>
- </tr>
-
- <tr>
- <td nowrap valign=top><tt>30</tt>&nbsp; </td>
- <td>1&times;1</td>
- <td>sub-arctic</td>
- <td align=left>houses</td>
- </tr>
-
- <tr>
- <td nowrap valign=top><tt>31</tt>&nbsp; </td>
- <td>1&times;1</td>
- <td>snow</td>
- <td align=left>houses</td>
- </tr>
-
- <tr>
- <td nowrap valign=top><tt>32</tt>&nbsp; </td>
- <td>1&times;1</td>
- <td>sub-arctic, sub-tropical</td>
- <td align=left>tall office block</td>
- </tr>
-
- <tr>
- <td nowrap valign=top><tt>33</tt>&nbsp; </td>
- <td>1&times;1</td>
- <td>snow</td>
- <td align=left>tall office block</td>
- </tr>
-
- <tr>
- <td nowrap valign=top><tt>34</tt>&nbsp; </td>
- <td>1&times;1</td>
- <td>sub-arctic</td>
- <td align=left>tall office block</td>
- </tr>
-
- <tr>
- <td nowrap valign=top><tt>35</tt>&nbsp; </td>
- <td>1&times;1</td>
- <td>snow</td>
- <td align=left>tall office block</td>
- </tr>
-
- <tr>
- <td nowrap valign=top><tt>36</tt>&nbsp; </td>
- <td>1&times;1</td>
- <td>sub-arctic, sub-tropical</td>
- <td align=left>tall office block</td>
- </tr>
-
- <tr>
- <td nowrap valign=top><tt>37</tt>&nbsp; </td>
- <td>1&times;1</td>
- <td>snow</td>
- <td align=left>tall office block</td>
- </tr>
-
- <tr>
- <td nowrap valign=top><tt>38</tt>&nbsp; </td>
- <td>1&times;1</td>
- <td>sub-arctic</td>
- <td align=left>houses</td>
- </tr>
-
- <tr>
- <td nowrap valign=top><tt>39</tt>&nbsp; </td>
- <td>1&times;1</td>
- <td>snow</td>
- <td align=left>houses</td>
- </tr>
-
- <tr>
- <td nowrap valign=top><tt>3A</tt>&nbsp; </td>
- <td>1&times;1</td>
- <td>sub-arctic</td>
- <td align=left>shops and offices</td>
- </tr>
-
- <tr>
- <td nowrap valign=top><tt>3B</tt>&nbsp; </td>
- <td>1&times;1</td>
- <td>snow</td>
- <td align=left>shops and offices</td>
- </tr>
-
- <tr>
- <td nowrap valign=top><tt>3C</tt>&nbsp; </td>
- <td>1&times;1</td>
- <td>sub-arctic</td>
- <td align=left>church</td>
- </tr>
-
- <tr>
- <td nowrap valign=top><tt>3D</tt>&nbsp; </td>
- <td>1&times;1</td>
- <td>snow</td>
- <td align=left>church</td>
- </tr>
-
- <tr>
- <td nowrap valign=top><tt>3E</tt>&nbsp; </td>
- <td>1&times;1</td>
- <td>sub-arctic</td>
- <td align=left>houses</td>
- </tr>
-
- <tr>
- <td nowrap valign=top><tt>3F</tt>&nbsp; </td>
- <td>1&times;1</td>
- <td>snow</td>
- <td align=left>houses</td>
- </tr>
-
- <tr>
- <td nowrap valign=top><tt>40</tt>&nbsp; </td>
- <td>1&times;1</td>
- <td>sub-arctic</td>
- <td align=left>shops and offices</td>
- </tr>
-
- <tr>
- <td nowrap valign=top><tt>41</tt>&nbsp; </td>
- <td>1&times;1</td>
- <td>snow</td>
- <td align=left>shops and offices</td>
- </tr>
-
- <tr>
- <td nowrap valign=top><tt>42</tt>..<tt>43</tt>&nbsp; </td>
- <td>1&times;2</td>
- <td>sub-arctic</td>
- <td align=left>hotel</td>
- </tr>
-
- <tr>
- <td nowrap valign=top><tt>44</tt>..<tt>45</tt>&nbsp; </td>
- <td>1&times;2</td>
- <td>snow</td>
- <td align=left>hotel</td>
- </tr>
-
- <tr>
- <td nowrap valign=top><tt>46</tt>&nbsp; </td>
- <td>1&times;1</td>
- <td>sub-arctic, sub-tropical</td>
- <td align=left>shops and offices</td>
- </tr>
-
- <tr>
- <td nowrap valign=top><tt>47</tt>&nbsp; </td>
- <td>1&times;1</td>
- <td>snow</td>
- <td align=left>shops and offices</td>
- </tr>
-
- <tr>
- <td nowrap valign=top><tt>48</tt>&nbsp; </td>
- <td>1&times;1</td>
- <td>sub-arctic</td>
- <td align=left>tall office block</td>
- </tr>
-
- <tr>
- <td nowrap valign=top><tt>49</tt>&nbsp; </td>
- <td>1&times;1</td>
- <td>snow</td>
- <td align=left>tall office block</td>
- </tr>
-
- <tr>
- <td nowrap valign=top><tt>4A</tt>..<tt>4B</tt>&nbsp; </td>
- <td>2&times;1</td>
- <td>sub-arctic</td>
- <td align=left>tall office block</td>
- </tr>
-
- <tr>
- <td nowrap valign=top><tt>4C</tt>..<tt>4D</tt>&nbsp; </td>
- <td>2&times;1</td>
- <td>snow</td>
- <td align=left>tall office block</td>
- </tr>
-
- <tr>
- <td nowrap valign=top><tt>4E</tt>&nbsp; </td>
- <td>1&times;1</td>
- <td>sub-tropical</td>
- <td align=left>houses (with a tree in a corner)</td>
- </tr>
-
- <tr>
- <td nowrap valign=top><tt>4F</tt>, <tt>50</tt>&nbsp; </td>
- <td>1&times;1</td>
- <td>sub-tropical</td>
- <td align=left>houses</td>
- </tr>
-
- <tr>
- <td nowrap valign=top><tt>51</tt>&nbsp; </td>
- <td>1&times;1</td>
- <td>sub-tropical</td>
- <td align=left>houses (suburb-type)</td>
- </tr>
-
- <tr>
- <td nowrap valign=top><tt>52</tt>&nbsp; </td>
- <td>1&times;1</td>
- <td>sub-tropical</td>
- <td align=left>flats</td>
- </tr>
-
- <tr>
- <td nowrap valign=top><tt>53</tt>&nbsp; </td>
- <td>1&times;1</td>
- <td>sub-tropical</td>
- <td align=left>church</td>
- </tr>
-
- <tr>
- <td nowrap valign=top><tt>54</tt>&nbsp; </td>
- <td>1&times;1</td>
- <td>sub-tropical</td>
- <td align=left>houses (with two trees in front)</td>
- </tr>
-
- <tr>
- <td nowrap valign=top><tt>55</tt>, <tt>56</tt>&nbsp; </td>
- <td>1&times;1</td>
- <td>sub-tropical</td>
- <td align=left>flats</td>
- </tr>
-
- <tr>
- <td nowrap valign=top><tt>57</tt>..<tt>58</tt>&nbsp; </td>
- <td>2&times;1</td>
- <td>sub-tropical</td>
- <td align=left>tall office block</td>
- </tr>
-
- <tr>
- <td nowrap valign=top><tt>59</tt>&nbsp; </td>
- <td>1&times;1</td>
- <td>sub-tropical</td>
- <td align=left>flats</td>
- </tr>
-
- <tr>
- <td nowrap valign=top><tt>5A</tt>&nbsp; </td>
- <td>1&times;1</td>
- <td>sub-tropical</td>
- <td align=left>tall office block</td>
- </tr>
-
- <tr>
- <td nowrap valign=top><tt>5B</tt>&nbsp; </td>
- <td>1&times;1</td>
- <td>toyland</td>
- <td align=left>church</td>
- </tr>
-
- <tr>
- <td nowrap valign=top><tt>5C</tt>..<tt>61</tt>&nbsp; </td>
- <td>1&times;1</td>
- <td>toyland</td>
- <td align=left>various types of toyland houses</td>
- </tr>
-
- <tr>
- <td nowrap valign=top><tt>62</tt>&nbsp; </td>
- <td>1&times;1</td>
- <td>toyland</td>
- <td align=left>tall office block</td>
- </tr>
-
- <tr>
- <td nowrap valign=top><tt>63</tt>..<tt>64</tt>&nbsp; </td>
- <td>1&times;2</td>
- <td>toyland</td>
- <td align=left>houses ('shoe' style)</td>
- </tr>
-
- <tr>
- <td nowrap valign=top><tt>65</tt>&nbsp; </td>
- <td>1&times;1</td>
- <td>toyland</td>
- <td align=left>tall office block</td>
- </tr>
-
- <tr>
- <td nowrap valign=top><tt>66</tt>&nbsp; </td>
- <td>1&times;1</td>
- <td>toyland</td>
- <td align=left>igloo</td>
- </tr>
-
- <tr>
- <td nowrap valign=top><tt>67</tt>&nbsp; </td>
- <td>1&times;1</td>
- <td>toyland</td>
- <td align=left>tepees</td>
- </tr>
-
- <tr>
- <td nowrap valign=top><tt>68</tt>, <tt>69</tt>&nbsp; </td>
- <td>1&times;1</td>
- <td>toyland</td>
- <td align=left>shops and offices</td>
- </tr>
-
- <tr>
- <td nowrap valign=top><tt>6A</tt>&nbsp; </td>
- <td>1&times;1</td>
- <td>toyland</td>
- <td align=left>tall office block</td>
- </tr>
-
- <tr>
- <td nowrap valign=top><tt>6B</tt>&nbsp; </td>
- <td>1&times;1</td>
- <td>toyland</td>
- <td align=left>statue</td>
- </tr>
-
- <tr>
- <td nowrap valign=top><tt>6C</tt>&nbsp; </td>
- <td>1&times;1</td>
- <td>toyland</td>
- <td align=left>teapot-house</td>
- </tr>
-
- <tr>
- <td nowrap valign=top><tt>6D</tt>&nbsp; </td>
- <td>1&times;1</td>
- <td>toyland</td>
- <td align=left>piggy-bank</td>
- </tr>
- </table>
- </li>
- <li>m5 bits 2..0: construction counter, for buildings under construction incremented on every periodic tile processing<br>
- On wraparound the stage of construction in m3 is increased
+ <li>m1 : Random bits <a href="#newhouses">(newhouses)</a> </li>
+ <li>m2 : index into the array of industries</li>
+ <li>m3 bit 7 :
+ <ul>
+ <li> set : House is complete
+ <ul>
+ <li>m5 : age of House. Maximum been 255, which means 255 years and more</li>
+ </ul>
+ </li>
+ <li> clear : House is in construction
+ <ul>
+ <li>m5 bits 7..5 : free</li>
+ <li>m5 bits 4..3 : construction stage</li>
+ <li>m5 bits 2..0 : construction counter</li>
+ </ul>
+ </li>
+ </ul>
+ <li>m3 bit 6 : 9th bit of house type (m4), allowing 512 different types.</li>
+ <li>m3 bits 5..0 : triggers activated <a href="#newhouses">(newhouses)</a></li>
+ <li>m4 : <a href="landscape_externals.html">town building type</a> (with m3[6] bit)</li>
+ <li>m5 : see m3 bit 7</li>
+ <li>m6 :
+ <ul>
+ <li>If <a href="#newhouses">newhouses</a> is activated
+ <ul>
+ <li>bits 7..3 : Current animation frame</li>
+ <li>bit 2 : free</li>
+ </ul>
+ </li>
+ <li>Standard behaviour
+ <ul>
+ <li>bits 7..2 : lift position (for houses type 04 and 05)</li>
+ </ul>
+ </li>
+ <li>bits 1..0 : tropic zone specifier</li>
+ </ul>
</li>
- <li>for large office blocks (types <tt>04</tt> and <tt>05</tt>):
+ <li>m7 :
<ul>
- <li>m1 bits 6..0: position of the lift</li>
- <li>m1 bit 7: if set the lift is moving</li>
- <li>m5 bit 7: if set then m5 bits 5..0 hold the destination floor of the lift, which could be 0..6, except 1.<br>
- So the building has 6 effective floors. This is due to the fact that the first floor is 2 'normal' floors high.<br>
- One 'normal' floor has a height of 6 lift positions.</li>
+ <li>If <a href="#newhouses">newhouses</a> is activated
+ <ul>
+ <li>Periodic processing time remaining</li>
+ </ul>
+ </li>
+ <li>Standard behaviour (only for houses type 04 and 05)
+ <ul>
+ <li>bits 7..4 : free</li>
+ <li>bits 3..1 : lift destination. Values can be 0..6, except 1.<br>
+ So the building has 6 effective floors. This is due to the fact that the first floor is 2 'normal' floors high.<br>
+ One 'normal' floor has a height of 6 lift positions.
+ </li>
+ <li>bit 0 : Lift has destination when set</li>
+ </ul>
+ </li>
</ul>
</li>
- <li>m6 bits 1..0 : <a href="#tropic_zone">Tropic zone definition</a></li>
</ul>
+ <small><a name="newhouses">Newhouses is the name englobing a newGRF feature developped by TTDPatch devs (mainly Csaboka).<br>
+ It allows the replacement of the properties as well as the graphics of houses in the game.<br>
+ To distinguish between the standard behaviour and the newGRF one, HouseID (m4 + m3[6]) is tested for anything above 110.<br>
+ 110 is the count of standard houses. So above 110 means there is a new definition of at least one house</small>
</td>
</tr>
diff --git a/docs/landscape_externals.html b/docs/landscape_externals.html
new file mode 100644
index 000000000..16f130532
--- /dev/null
+++ b/docs/landscape_externals.html
@@ -0,0 +1,616 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+
+<head>
+ <meta name="Author" content="Marcin Grzegorczyk">
+ <meta name="Description" content="Structure of OpenTTD (OTTD) landscape arrays">
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+ <title>OpenTTD Landscape externals</title>
+</head>
+
+<body>
+ <h3><a name="Landscape">Landscape</a></h3>
+ <p>
+ These are the different house types available on standard game.<br>
+ <small>Note: In the climate list, 'sub-arctic' means below the snow line, and 'snow' means above the snow line in the sub-arctic climate.</small>
+ </p>
+
+ <table>
+ <tr>
+ <th align=left>Type&nbsp;</th>
+ <th align=left>Size&nbsp;</th>
+ <th align=left>Climates&nbsp;</th>
+ <th align=left>Description</th>
+ </tr>
+
+ <tr>
+ <td nowrap valign=top><tt>00</tt>&nbsp; </td>
+ <td>1&times;1</td>
+ <td>temperate</td>
+ <td align=left>tall office block</td>
+ </tr>
+
+ <tr>
+ <td nowrap valign=top><tt>01</tt>&nbsp; </td>
+ <td>1&times;1</td>
+ <td>temperate</td>
+ <td align=left>office block</td>
+ </tr>
+
+ <tr>
+ <td nowrap valign=top><tt>02</tt>&nbsp; </td>
+ <td>1&times;1</td>
+ <td>temperate</td>
+ <td align=left>small block of flats</td>
+ </tr>
+
+ <tr>
+ <td nowrap valign=top><tt>03</tt>&nbsp; </td>
+ <td>1&times;1</td>
+ <td>temperate</td>
+ <td align=left>church</td>
+ </tr>
+
+ <tr>
+ <td nowrap valign=top><tt>04</tt>&nbsp; </td>
+ <td>1&times;1</td>
+ <td>temperate, sub-arctic, sub-tropical</td>
+ <td align=left>large office block</td>
+ </tr>
+
+ <tr>
+ <td nowrap valign=top><tt>05</tt>&nbsp; </td>
+ <td>1&times;1</td>
+ <td>snow</td>
+ <td align=left>large office block</td>
+ </tr>
+
+ <tr>
+ <td nowrap valign=top><tt>06</tt>&nbsp; </td>
+ <td>1&times;1</td>
+ <td>temperate</td>
+ <td align=left>town houses</td>
+ </tr>
+
+ <tr>
+ <td nowrap valign=top><tt>07</tt>..<tt>08</tt>&nbsp; </td>
+ <td>1&times;2</td>
+ <td>temperate</td>
+ <td align=left>hotel</td>
+ </tr>
+
+ <tr>
+ <td nowrap valign=top><tt>09</tt>&nbsp; </td>
+ <td>1&times;1</td>
+ <td>temperate, sub-arctic, sub-tropical&nbsp;&nbsp;</td>
+ <td align=left>statue</td>
+ </tr>
+
+ <tr>
+ <td nowrap valign=top><tt>0A</tt>&nbsp; </td>
+ <td>1&times;1</td>
+ <td>temperate, sub-arctic, sub-tropical</td>
+ <td align=left>fountain</td>
+ </tr>
+
+ <tr>
+ <td nowrap valign=top><tt>0B</tt>&nbsp; </td>
+ <td>1&times;1</td>
+ <td>temperate</td>
+ <td align=left>park (with a pond)</td>
+ </tr>
+
+ <tr>
+ <td nowrap valign=top><tt>0C</tt>&nbsp; </td>
+ <td>1&times;1</td>
+ <td>temperate</td>
+ <td align=left>park (with an alley)</td>
+ </tr>
+
+ <tr>
+ <td nowrap valign=top><tt>0D</tt>&nbsp; </td>
+ <td>1&times;1</td>
+ <td>temperate</td>
+ <td align=left>office block</td>
+ </tr>
+
+ <tr>
+ <td nowrap valign=top><tt>0E</tt>..<tt>10</tt>&nbsp; </td>
+ <td>1&times;1</td>
+ <td>temperate</td>
+ <td align=left>various types of shops and offices</td>
+ </tr>
+
+ <tr>
+ <td nowrap valign=top><tt>11</tt>&nbsp; </td>
+ <td>1&times;1</td>
+ <td>temperate, sub-arctic, sub-tropical</td>
+ <td align=left>modern office building</td>
+ </tr>
+
+ <tr>
+ <td nowrap valign=top><tt>12</tt>&nbsp; </td>
+ <td>1&times;1</td>
+ <td>temperate</td>
+ <td align=left>warehouse</td>
+ </tr>
+
+ <tr>
+ <td nowrap valign=top><tt>13</tt>&nbsp; </td>
+ <td>1&times;1</td>
+ <td>temperate</td>
+ <td align=left>office block (with spiral stairway on the side)</td>
+ </tr>
+
+ <tr>
+ <td nowrap valign=top><tt>14</tt>..<tt>17</tt>&nbsp; </td>
+ <td>2&times;2</td>
+ <td>temperate</td>
+ <td align=left>stadium</td>
+ </tr>
+
+ <tr>
+ <td nowrap valign=top><tt>18</tt>&nbsp; </td>
+ <td>1&times;1</td>
+ <td>temperate</td>
+ <td align=left>old houses</td>
+ </tr>
+
+ <tr>
+ <td nowrap valign=top><tt>19</tt>&nbsp; </td>
+ <td>1&times;1</td>
+ <td>temperate</td>
+ <td align=left>cottages</td>
+ </tr>
+
+ <tr>
+ <td nowrap valign=top><tt>1A</tt>&nbsp; </td>
+ <td>1&times;1</td>
+ <td>temperate</td>
+ <td align=left>houses</td>
+ </tr>
+
+ <tr>
+ <td nowrap valign=top><tt>1B</tt>&nbsp; </td>
+ <td>1&times;1</td>
+ <td>temperate</td>
+ <td align=left>flats</td>
+ </tr>
+
+ <tr>
+ <td nowrap valign=top><tt>1C</tt>&nbsp; </td>
+ <td>1&times;1</td>
+ <td>temperate</td>
+ <td align=left>tall office block</td>
+ </tr>
+
+ <tr>
+ <td nowrap valign=top><tt>1D</tt>&nbsp; </td>
+ <td>1&times;1</td>
+ <td>temperate</td>
+ <td align=left>shops and offices</td>
+ </tr>
+
+ <tr>
+ <td nowrap valign=top><tt>1E</tt>&nbsp; </td>
+ <td>1&times;1</td>
+ <td>temperate, sub-tropical</td>
+ <td align=left>shops and offices</td>
+ </tr>
+
+ <tr>
+ <td nowrap valign=top><tt>1F</tt>&nbsp; </td>
+ <td>1&times;1</td>
+ <td>temperate</td>
+ <td align=left>theatre</td>
+ </tr>
+
+ <tr>
+ <td nowrap valign=top><tt>20</tt>..<tt>23</tt>&nbsp; </td>
+ <td>2&times;2</td>
+ <td>temperate, sub-arctic, sub-tropical</td>
+ <td align=left>stadium (modern style)</td>
+ </tr>
+
+ <tr>
+ <td nowrap valign=top><tt>24</tt>&nbsp; </td>
+ <td>1&times;1</td>
+ <td>temperate, sub-arctic, sub-tropical</td>
+ <td align=left>offices (the modern 'vertical tube' style)</td>
+ </tr>
+
+ <tr>
+ <td nowrap valign=top><tt>25</tt>&nbsp; </td>
+ <td>1&times;1</td>
+ <td>sub-arctic</td>
+ <td align=left>houses</td>
+ </tr>
+
+ <tr>
+ <td nowrap valign=top><tt>26</tt>&nbsp; </td>
+ <td>1&times;1</td>
+ <td>snow</td>
+ <td align=left>houses</td>
+ </tr>
+
+ <tr>
+ <td nowrap valign=top><tt>27</tt>&nbsp; </td>
+ <td>1&times;1</td>
+ <td>temperate</td>
+ <td align=left>cinema</td>
+ </tr>
+
+ <tr>
+ <td nowrap valign=top><tt>28</tt>..<tt>2B</tt>&nbsp; </td>
+ <td>2&times;2</td>
+ <td>temperate</td>
+ <td align=left>shopping mall</td>
+ </tr>
+
+ <tr>
+ <td nowrap valign=top><tt>2C</tt>&nbsp; </td>
+ <td>1&times;1</td>
+ <td>sub-arctic</td>
+ <td align=left>flats</td>
+ </tr>
+
+ <tr>
+ <td nowrap valign=top><tt>2D</tt>&nbsp; </td>
+ <td>1&times;1</td>
+ <td>snow</td>
+ <td align=left>flats</td>
+ </tr>
+
+ <tr>
+ <td nowrap valign=top><tt>2E</tt>&nbsp; </td>
+ <td>1&times;1</td>
+ <td>sub-arctic</td>
+ <td align=left>houses</td>
+ </tr>
+
+ <tr>
+ <td nowrap valign=top><tt>2F</tt>&nbsp; </td>
+ <td>1&times;1</td>
+ <td>snow</td>
+ <td align=left>houses</td>
+ </tr>
+
+ <tr>
+ <td nowrap valign=top><tt>30</tt>&nbsp; </td>
+ <td>1&times;1</td>
+ <td>sub-arctic</td>
+ <td align=left>houses</td>
+ </tr>
+
+ <tr>
+ <td nowrap valign=top><tt>31</tt>&nbsp; </td>
+ <td>1&times;1</td>
+ <td>snow</td>
+ <td align=left>houses</td>
+ </tr>
+
+ <tr>
+ <td nowrap valign=top><tt>32</tt>&nbsp; </td>
+ <td>1&times;1</td>
+ <td>sub-arctic, sub-tropical</td>
+ <td align=left>tall office block</td>
+ </tr>
+
+ <tr>
+ <td nowrap valign=top><tt>33</tt>&nbsp; </td>
+ <td>1&times;1</td>
+ <td>snow</td>
+ <td align=left>tall office block</td>
+ </tr>
+
+ <tr>
+ <td nowrap valign=top><tt>34</tt>&nbsp; </td>
+ <td>1&times;1</td>
+ <td>sub-arctic</td>
+ <td align=left>tall office block</td>
+ </tr>
+
+ <tr>
+ <td nowrap valign=top><tt>35</tt>&nbsp; </td>
+ <td>1&times;1</td>
+ <td>snow</td>
+ <td align=left>tall office block</td>
+ </tr>
+
+ <tr>
+ <td nowrap valign=top><tt>36</tt>&nbsp; </td>
+ <td>1&times;1</td>
+ <td>sub-arctic, sub-tropical</td>
+ <td align=left>tall office block</td>
+ </tr>
+
+ <tr>
+ <td nowrap valign=top><tt>37</tt>&nbsp; </td>
+ <td>1&times;1</td>
+ <td>snow</td>
+ <td align=left>tall office block</td>
+ </tr>
+
+ <tr>
+ <td nowrap valign=top><tt>38</tt>&nbsp; </td>
+ <td>1&times;1</td>
+ <td>sub-arctic</td>
+ <td align=left>houses</td>
+ </tr>
+
+ <tr>
+ <td nowrap valign=top><tt>39</tt>&nbsp; </td>
+ <td>1&times;1</td>
+ <td>snow</td>
+ <td align=left>houses</td>
+ </tr>
+
+ <tr>
+ <td nowrap valign=top><tt>3A</tt>&nbsp; </td>
+ <td>1&times;1</td>
+ <td>sub-arctic</td>
+ <td align=left>shops and offices</td>
+ </tr>
+
+ <tr>
+ <td nowrap valign=top><tt>3B</tt>&nbsp; </td>
+ <td>1&times;1</td>
+ <td>snow</td>
+ <td align=left>shops and offices</td>
+ </tr>
+
+ <tr>
+ <td nowrap valign=top><tt>3C</tt>&nbsp; </td>
+ <td>1&times;1</td>
+ <td>sub-arctic</td>
+ <td align=left>church</td>
+ </tr>
+
+ <tr>
+ <td nowrap valign=top><tt>3D</tt>&nbsp; </td>
+ <td>1&times;1</td>
+ <td>snow</td>
+ <td align=left>church</td>
+ </tr>
+
+ <tr>
+ <td nowrap valign=top><tt>3E</tt>&nbsp; </td>
+ <td>1&times;1</td>
+ <td>sub-arctic</td>
+ <td align=left>houses</td>
+ </tr>
+
+ <tr>
+ <td nowrap valign=top><tt>3F</tt>&nbsp; </td>
+ <td>1&times;1</td>
+ <td>snow</td>
+ <td align=left>houses</td>
+ </tr>
+
+ <tr>
+ <td nowrap valign=top><tt>40</tt>&nbsp; </td>
+ <td>1&times;1</td>
+ <td>sub-arctic</td>
+ <td align=left>shops and offices</td>
+ </tr>
+
+ <tr>
+ <td nowrap valign=top><tt>41</tt>&nbsp; </td>
+ <td>1&times;1</td>
+ <td>snow</td>
+ <td align=left>shops and offices</td>
+ </tr>
+
+ <tr>
+ <td nowrap valign=top><tt>42</tt>..<tt>43</tt>&nbsp; </td>
+ <td>1&times;2</td>
+ <td>sub-arctic</td>
+ <td align=left>hotel</td>
+ </tr>
+
+ <tr>
+ <td nowrap valign=top><tt>44</tt>..<tt>45</tt>&nbsp; </td>
+ <td>1&times;2</td>
+ <td>snow</td>
+ <td align=left>hotel</td>
+ </tr>
+
+ <tr>
+ <td nowrap valign=top><tt>46</tt>&nbsp; </td>
+ <td>1&times;1</td>
+ <td>sub-arctic, sub-tropical</td>
+ <td align=left>shops and offices</td>
+ </tr>
+
+ <tr>
+ <td nowrap valign=top><tt>47</tt>&nbsp; </td>
+ <td>1&times;1</td>
+ <td>snow</td>
+ <td align=left>shops and offices</td>
+ </tr>
+
+ <tr>
+ <td nowrap valign=top><tt>48</tt>&nbsp; </td>
+ <td>1&times;1</td>
+ <td>sub-arctic</td>
+ <td align=left>tall office block</td>
+ </tr>
+
+ <tr>
+ <td nowrap valign=top><tt>49</tt>&nbsp; </td>
+ <td>1&times;1</td>
+ <td>snow</td>
+ <td align=left>tall office block</td>
+ </tr>
+
+ <tr>
+ <td nowrap valign=top><tt>4A</tt>..<tt>4B</tt>&nbsp; </td>
+ <td>2&times;1</td>
+ <td>sub-arctic</td>
+ <td align=left>tall office block</td>
+ </tr>
+
+ <tr>
+ <td nowrap valign=top><tt>4C</tt>..<tt>4D</tt>&nbsp; </td>
+ <td>2&times;1</td>
+ <td>snow</td>
+ <td align=left>tall office block</td>
+ </tr>
+
+ <tr>
+ <td nowrap valign=top><tt>4E</tt>&nbsp; </td>
+ <td>1&times;1</td>
+ <td>sub-tropical</td>
+ <td align=left>houses (with a tree in a corner)</td>
+ </tr>
+
+ <tr>
+ <td nowrap valign=top><tt>4F</tt>, <tt>50</tt>&nbsp; </td>
+ <td>1&times;1</td>
+ <td>sub-tropical</td>
+ <td align=left>houses</td>
+ </tr>
+
+ <tr>
+ <td nowrap valign=top><tt>51</tt>&nbsp; </td>
+ <td>1&times;1</td>
+ <td>sub-tropical</td>
+ <td align=left>houses (suburb-type)</td>
+ </tr>
+
+ <tr>
+ <td nowrap valign=top><tt>52</tt>&nbsp; </td>
+ <td>1&times;1</td>
+ <td>sub-tropical</td>
+ <td align=left>flats</td>
+ </tr>
+
+ <tr>
+ <td nowrap valign=top><tt>53</tt>&nbsp; </td>
+ <td>1&times;1</td>
+ <td>sub-tropical</td>
+ <td align=left>church</td>
+ </tr>
+
+ <tr>
+ <td nowrap valign=top><tt>54</tt>&nbsp; </td>
+ <td>1&times;1</td>
+ <td>sub-tropical</td>
+ <td align=left>houses (with two trees in front)</td>
+ </tr>
+
+ <tr>
+ <td nowrap valign=top><tt>55</tt>, <tt>56</tt>&nbsp; </td>
+ <td>1&times;1</td>
+ <td>sub-tropical</td>
+ <td align=left>flats</td>
+ </tr>
+
+ <tr>
+ <td nowrap valign=top><tt>57</tt>..<tt>58</tt>&nbsp; </td>
+ <td>2&times;1</td>
+ <td>sub-tropical</td>
+ <td align=left>tall office block</td>
+ </tr>
+
+ <tr>
+ <td nowrap valign=top><tt>59</tt>&nbsp; </td>
+ <td>1&times;1</td>
+ <td>sub-tropical</td>
+ <td align=left>flats</td>
+ </tr>
+
+ <tr>
+ <td nowrap valign=top><tt>5A</tt>&nbsp; </td>
+ <td>1&times;1</td>
+ <td>sub-tropical</td>
+ <td align=left>tall office block</td>
+ </tr>
+
+ <tr>
+ <td nowrap valign=top><tt>5B</tt>&nbsp; </td>
+ <td>1&times;1</td>
+ <td>toyland</td>
+ <td align=left>church</td>
+ </tr>
+
+ <tr>
+ <td nowrap valign=top><tt>5C</tt>..<tt>61</tt>&nbsp; </td>
+ <td>1&times;1</td>
+ <td>toyland</td>
+ <td align=left>various types of toyland houses</td>
+ </tr>
+
+ <tr>
+ <td nowrap valign=top><tt>62</tt>&nbsp; </td>
+ <td>1&times;1</td>
+ <td>toyland</td>
+ <td align=left>tall office block</td>
+ </tr>
+
+ <tr>
+ <td nowrap valign=top><tt>63</tt>..<tt>64</tt>&nbsp; </td>
+ <td>1&times;2</td>
+ <td>toyland</td>
+ <td align=left>houses ('shoe' style)</td>
+ </tr>
+
+ <tr>
+ <td nowrap valign=top><tt>65</tt>&nbsp; </td>
+ <td>1&times;1</td>
+ <td>toyland</td>
+ <td align=left>tall office block</td>
+ </tr>
+
+ <tr>
+ <td nowrap valign=top><tt>66</tt>&nbsp; </td>
+ <td>1&times;1</td>
+ <td>toyland</td>
+ <td align=left>igloo</td>
+ </tr>
+
+ <tr>
+ <td nowrap valign=top><tt>67</tt>&nbsp; </td>
+ <td>1&times;1</td>
+ <td>toyland</td>
+ <td align=left>tepees</td>
+ </tr>
+
+ <tr>
+ <td nowrap valign=top><tt>68</tt>, <tt>69</tt>&nbsp; </td>
+ <td>1&times;1</td>
+ <td>toyland</td>
+ <td align=left>shops and offices</td>
+ </tr>
+
+ <tr>
+ <td nowrap valign=top><tt>6A</tt>&nbsp; </td>
+ <td>1&times;1</td>
+ <td>toyland</td>
+ <td align=left>tall office block</td>
+ </tr>
+
+ <tr>
+ <td nowrap valign=top><tt>6B</tt>&nbsp; </td>
+ <td>1&times;1</td>
+ <td>toyland</td>
+ <td align=left>statue</td>
+ </tr>
+
+ <tr>
+ <td nowrap valign=top><tt>6C</tt>&nbsp; </td>
+ <td>1&times;1</td>
+ <td>toyland</td>
+ <td align=left>teapot-house</td>
+ </tr>
+
+ <tr>
+ <td nowrap valign=top><tt>6D</tt>&nbsp; </td>
+ <td>1&times;1</td>
+ <td>toyland</td>
+ <td align=left>piggy-bank</td>
+ </tr>
+ </table>
+</body>
+
+</html> \ No newline at end of file
diff --git a/docs/landscape_grid.html b/docs/landscape_grid.html
index 2d9196f3b..6539dfc57 100644
--- a/docs/landscape_grid.html
+++ b/docs/landscape_grid.html
@@ -33,6 +33,7 @@ the array so you can quickly see what is used and what is not.
<li><span style="font-weight: bold;">m4</span> - 8 bits in size, is used for general storage</li>
<li><span style="font-weight: bold;">m5</span> - 8 bits in size, is used for general storage</li>
<li><span style="font-weight: bold;">m6</span> - 8 bits in size, special meaning : lower 2 bits only valid in tropic climate, upper 2 bits for bridges</li>
+ <li><span style="font-weight: bold;">m7</span> - 8 bits in size, is used for general storage</li>
</ul>
<table align=center border="1" cellpadding="2" cellspacing="2">
@@ -46,6 +47,7 @@ the array so you can quickly see what is used and what is not.
<th>m4 (8)</th>
<th>m5 (8)</th>
<th>m6 (8)</th>
+ <th>m7 (8)</th>
</tr>
<tr>
<td colspan=2 class="caption">bits</td>
@@ -56,6 +58,7 @@ the array so you can quickly see what is used and what is not.
<td class="bits">7654 3210</td>
<td class="bits">7654 3210</td>
<td class="bits">7654 3210</td>
+ <td class="bits">7654 3210</td>
</tr>
<tr>
<td rowspan="2">0</td>
@@ -67,6 +70,7 @@ the array so you can quickly see what is used and what is not.
<td class="bits">XXXX XX<span class="free">OO</span></td>
<td class="bits">XXXX XXXX</td>
<td class="bits">XX<span class="free">OO OO</span>XX</td>
+ <td class="bits"><span class="free">OOOO OOOO</span></td>
</tr>
<tr>
<td class="caption">farmland</td>
@@ -77,6 +81,7 @@ the array so you can quickly see what is used and what is not.
<td class="bits">-inherit-</td>
<td class="bits"><span class="free">OOO</span>X XXXX</td>
<td class="bits">XX<span class="free">OO OO</span>XX</td>
+ <td class="bits"><span class="free">OOOO OOOO</span></td>
</tr>
<tr>
<td rowspan=3>1</td>
@@ -88,6 +93,7 @@ the array so you can quickly see what is used and what is not.
<td class="bits"><span class="free">OOOO O</span>XXX</td>
<td class="bits">XXXX XXXX</td>
<td class="bits">XX<span class="free">OO OO</span>XX</td>
+ <td class="bits"><span class="free">OOOO OOOO</span></td>
</tr>
<tr>
<td class="caption">depot</td>
@@ -98,6 +104,7 @@ the array so you can quickly see what is used and what is not.
<td class="bits"><span class="free">OOOO</span> XXXX</td>
<td class="bits">XX<span class="free">OO O</span>XXX</td>
<td class="bits">XX<span class="free">OO OO</span>XX</td>
+ <td class="bits"><span class="free">OOOO OOOO</span></td>
</tr>
<tr>
<td class="caption">waypoint</td>
@@ -108,6 +115,7 @@ the array so you can quickly see what is used and what is not.
<td class="bits"><span class="free">OOOO</span> XXXX</td>
<td class="bits">XX<span class="free">OO O</span>XXX</td>
<td class="bits">XX<span class="free">OO OO</span>XX</td>
+ <td class="bits"><span class="free">OOOO OOOO</span></td>
</tr>
<tr>
<td rowspan=3>2</td>
@@ -119,6 +127,7 @@ the array so you can quickly see what is used and what is not.
<td class="bits">XXXX XXXX</td>
<td class="bits">XXXX XXXX</td>
<td class="bits">XX<span class="free">OO OO</span>XX</td>
+ <td class="bits"><span class="free">OOOO OOOO</span></td>
</tr>
<tr>
<td class="caption">level crossing</td>
@@ -129,6 +138,7 @@ the array so you can quickly see what is used and what is not.
<td class="bits">XXXX XXXX</td>
<td class="bits">XXXX XX<span class="free">OO</span></td>
<td class="bits">XX<span class="free">OO OO</span>XX</td>
+ <td class="bits"><span class="free">OOOO OOOO</span></td>
</tr>
<tr>
<td class="caption">road depot</td>
@@ -139,17 +149,19 @@ the array so you can quickly see what is used and what is not.
<td class="bits"><span class="free">OOOO OOOO</span></td>
<td class="bits">XXXX XXXX</td>
<td class="bits">XX<span class="free">OO OO</span>XX</td>
+ <td class="bits"><span class="free">OOOO OOOO</span></td>
</tr>
<tr>
<td>3</td>
- <td class="caption">town</td>
+ <td class="caption">house</td>
+ <td class="bits">XXXX XXXX</td>
<td class="bits">XXXX XXXX</td>
- <td class="bits"><span class="abuse">XXXX XXXX</span></td>
<td class="bits">XXXX XXXX XXXX XXXX</td>
- <td class="bits">XX<span class="free">OO OOOO</span></td>
+ <td class="bits">XX<span class="free">O</span>X XXXX</td>
<td class="bits">XXXX XXXX</td>
- <td class="bits">X<span class="free">O</span>XX XXXX</td>
- <td class="bits"><span class="free">OOOO OO</span>XX</td>
+ <td class="bits">XX<span class="abuse">XX XXXX</span></td>
+ <td class="bits"><span class="abuse">XXXX XX</span>XX</td>
+ <td class="bits"><span class="abuse">X</span>XX<span class="abuse">X XXX</span>X</td>
</tr>
<tr>
<td>4</td>
@@ -161,6 +173,7 @@ the array so you can quickly see what is used and what is not.
<td class="bits">XXXX XX<span class="free">OO</span></td>
<td class="bits">XX<span class="free">OO O</span>XXX</td>
<td class="bits"><span class="free">OOOO OO</span>XX</td>
+ <td class="bits"><span class="free">OOOO OOOO</span></td>
</tr>
<tr>
<td>5</td>
@@ -172,6 +185,7 @@ the array so you can quickly see what is used and what is not.
<td class="bits">XXXX XXXX</td>
<td class="bits">XXXX XXXX</td>
<td class="bits"><span class="free">OOOO O</span>XXX</td>
+ <td class="bits"><span class="free">OOOO OOOO</span></td>
</tr>
<tr>
<td>6</td>
@@ -183,20 +197,25 @@ the array so you can quickly see what is used and what is not.
<td class="bits"><span class="free">OOOO OOOO</span></td>
<td class="bits"><span class="free">OOOO OO</span>XX</td>
<td class="bits">XX<span class="free">OO OO</span>XX</td>
+ <td class="bits"><span class="free">OOOO OOOO</span></td>
</tr>
<tr>
<td rowspan=3>8</td>
<td class="caption">industry</td>
<td class="bits">XXXX XXXX</td>
- <td class="bits"><span class="abuse">X</span><span class="free">OO</span><span class="abuse">X XXXX</span></td>
+ <td class="bits"><span class="abuse">X</span><span class="free">OO</span><span class="abuse">X
+ XXXX</span></td>
<td class="bits">XXXX XXXX XXXX XXXX</td>
<td class="bits"><span class="free">OOOO OOOO</span></td>
<td class="bits"><span class="free">OOOO OOOO</span></td>
<td class="bits">XXXX XXXX</td>
<td class="bits"><span class="free">OOOO OO</span>XX</td>
+ <td class="bits"><span class="free">OOOO OOOO</span></td>
</tr>
<tr>
- <td>bubble/sugar/toffee,<BR>gold/copper/coal,<BR>oil wells, power station</td>
+ <td>bubble/sugar/toffee,<BR>
+ gold/copper/coal,<BR>
+ oil wells, power station</td>
<td class="bits">-inherit-</td>
<td class="bits"><span class="abuse">X</span><span class="free">OOO OOOO</span></td>
<td class="bits">-inherit-</td>
@@ -204,6 +223,7 @@ the array so you can quickly see what is used and what is not.
<td class="bits"><span class="free">OOOO OOOO</span></td>
<td class="bits">-inherit-</td>
<td class="bits">-inherit-</td>
+ <td class="bits"><span class="free">OOOO OOOO</span></td>
</tr>
<tr>
<td>toy factory</td>
@@ -214,6 +234,7 @@ the array so you can quickly see what is used and what is not.
<td class="bits">XXXX XXXX</td>
<td class="bits">-inherit-</td>
<td class="bits">-inherit-</td>
+ <td class="bits"><span class="free">OOOO OOOO</span></td>
</tr>
<tr>
<td rowspan=2>9</td>
@@ -225,16 +246,19 @@ the array so you can quickly see what is used and what is not.
<td class="bits">X<span class="free">OOO OOOO</span></td>
<td class="bits">X<span class="free">OOO</span> XXXX</td>
<td class="bits">XX<span class="free">OO OO</span>XX</td>
+ <td class="bits"><span class="free">OOOO OOOO</span></td>
</tr>
<tr>
<td>bridge ramp</td>
<td class="bits">XXXX XXXX</td>
<td class="bits">XXXX XXXX</td>
- <td class="bits"><span class="free">OOOO OOOO</span> <span class="abuse">XXXX</span> <span class="free">OOOO</span></td>
+ <td class="bits"><span class="free">OOOO OOOO</span> <span class="abuse">XXXX</span>
+ <span class="free">OOOO</span></td>
<td class="bits"><span class="free">OOOO</span> XXXX</td>
<td class="bits">X<span class="free">OOO OOOO</span></td>
<td class="bits">X<span class="free">OOO</span> XXXX</td>
<td class="bits">XX<span class="free">OO OO</span>XX</td>
+ <td class="bits"><span class="free">OOOO OOOO</span></td>
</tr>
<tr>
<td>A</td>
@@ -246,6 +270,7 @@ the array so you can quickly see what is used and what is not.
<td class="bits"><span class="free">OOOO OOOO</span></td>
<td class="bits">XXXX XXXX</td>
<td class="bits">XX<span class="free">OO OO</span>XX</td>
+ <td class="bits"><span class="free">OOOO OOOO</span></td>
</tr>
</tbody>
</table>
diff --git a/projects/openttd.vcproj b/projects/openttd.vcproj
index db9fa427c..2e01dfaca 100644
--- a/projects/openttd.vcproj
+++ b/projects/openttd.vcproj
@@ -519,6 +519,9 @@
RelativePath=".\..\src\newgrf_engine.h">
</File>
<File
+ RelativePath=".\..\src\newgrf_house.h">
+ </File>
+ <File
RelativePath=".\..\src\newgrf_sound.h">
</File>
<File
@@ -531,6 +534,9 @@
RelativePath=".\..\src\newgrf_text.h">
</File>
<File
+ RelativePath=".\..\src\newgrf_town.h">
+ </File>
+ <File
RelativePath=".\..\src\news.h">
</File>
<File
@@ -926,6 +932,9 @@
RelativePath=".\..\src\newgrf_engine.cpp">
</File>
<File
+ RelativePath=".\..\src\newgrf_house.cpp">
+ </File>
+ <File
RelativePath=".\..\src\newgrf_sound.cpp">
</File>
<File
@@ -937,6 +946,9 @@
<File
RelativePath=".\..\src\newgrf_text.cpp">
</File>
+ <File
+ RelativePath=".\..\src\newgrf_town.cpp">
+ </File>
</Filter>
<Filter
Name="Map Accessors"
diff --git a/projects/openttd_vs80.vcproj b/projects/openttd_vs80.vcproj
index 86c6b1f35..668094f1a 100644
--- a/projects/openttd_vs80.vcproj
+++ b/projects/openttd_vs80.vcproj
@@ -448,11 +448,11 @@
>
</File>
<File
- RelativePath=".\..\src\aystar.cpp"
+ RelativePath=".\..\src\autoreplace_cmd.cpp"
>
</File>
<File
- RelativePath=".\..\src\autoreplace_cmd.cpp"
+ RelativePath=".\..\src\aystar.cpp"
>
</File>
<File
@@ -920,6 +920,10 @@
>
</File>
<File
+ RelativePath=".\..\src\newgrf_house.h"
+ >
+ </File>
+ <File
RelativePath=".\..\src\newgrf_sound.h"
>
</File>
@@ -936,6 +940,10 @@
>
</File>
<File
+ RelativePath=".\..\src\newgrf_town.h"
+ >
+ </File>
+ <File
RelativePath=".\..\src\news.h"
>
</File>
@@ -1456,6 +1464,10 @@
>
</File>
<File
+ RelativePath=".\..\src\newgrf_house.cpp"
+ >
+ </File>
+ <File
RelativePath=".\..\src\newgrf_sound.cpp"
>
</File>
@@ -1471,6 +1483,10 @@
RelativePath=".\..\src\newgrf_text.cpp"
>
</File>
+ <File
+ RelativePath=".\..\src\newgrf_town.cpp"
+ >
+ </File>
</Filter>
<Filter
Name="Map Accessors"
diff --git a/source.list b/source.list
index 7c0c1da74..36347e9d3 100644
--- a/source.list
+++ b/source.list
@@ -140,10 +140,12 @@ newgrf_callbacks.h
newgrf_cargo.h
newgrf_config.h
newgrf_engine.h
+newgrf_house.h
newgrf_sound.h
newgrf_spritegroup.h
newgrf_station.h
newgrf_text.h
+newgrf_town.h
news.h
npf.h
music/null_m.h
@@ -279,10 +281,12 @@ ai/trolly/trolly.cpp
newgrf.cpp
newgrf_config.cpp
newgrf_engine.cpp
+newgrf_house.cpp
newgrf_sound.cpp
newgrf_spritegroup.cpp
newgrf_station.cpp
newgrf_text.cpp
+newgrf_town.cpp
# Map Accessors
bridge_map.cpp
diff --git a/src/map.cpp b/src/map.cpp
index 4ae44930a..00655a42e 100644
--- a/src/map.cpp
+++ b/src/map.cpp
@@ -22,7 +22,8 @@ uint _map_size_y;
uint _map_tile_mask;
uint _map_size;
-Tile* _m = NULL;
+Tile *_m = NULL;
+TileExtended *_me = NULL;
void AllocateMap(uint size_x, uint size_y)
@@ -44,10 +45,16 @@ void AllocateMap(uint size_x, uint size_y)
_map_tile_mask = _map_size - 1;
free(_m);
+ free(_me);
+
_m = CallocT<Tile>(_map_size);
+ _me = CallocT<TileExtended>(_map_size);
- /* XXX TODO handle memory shortage more gracefully */
- if (_m == NULL) error("Failed to allocate memory for the map");
+ /* XXX @todo handle memory shortage more gracefully
+ * Maybe some attemps could be made to try with smaller maps down to 64x64
+ * Maybe check for available memory before doing the calls, after all, we know how big
+ * the map is */
+ if ((_m == NULL) || (_me == NULL)) error("Failed to allocate memory for the map");
}
diff --git a/src/map.h b/src/map.h
index 67e141c53..72e6c0c27 100644
--- a/src/map.h
+++ b/src/map.h
@@ -28,7 +28,12 @@ struct Tile {
byte m6;
};
-extern Tile* _m;
+struct TileExtended {
+ byte m7;
+};
+
+extern Tile *_m;
+extern TileExtended *_me;
void AllocateMap(uint size_x, uint size_y);
diff --git a/src/misc.cpp b/src/misc.cpp
index 01b73fee2..fdd35ad56 100644
--- a/src/misc.cpp
+++ b/src/misc.cpp
@@ -18,6 +18,7 @@
#include "vehicle_gui.h"
#include "variables.h"
#include "ai/ai.h"
+#include "newgrf_house.h"
#include "date.h"
#include "cargotype.h"
@@ -132,6 +133,7 @@ void InitializeGame(int mode, uint size_x, uint size_y)
InitializeSigns();
InitializeStations();
InitializeIndustries();
+ InitializeBuildingCounts();
InitializeMainGui();
InitializeNameMgr();
@@ -578,6 +580,34 @@ static void Save_MAP6()
}
}
+static void Load_MAP7()
+{
+ uint size = MapSize();
+ uint i;
+
+ for (i = 0; i != size;) {
+ uint8 buf[4096];
+ uint j;
+
+ SlArray(buf, lengthof(buf), SLE_UINT8);
+ for (j = 0; j != lengthof(buf); j++) _me[i++].m7 = buf[j];
+ }
+}
+
+static void Save_MAP7()
+{
+ uint size = MapSize();
+ uint i;
+
+ SlSetLength(size);
+ for (i = 0; i != size;) {
+ uint8 buf[4096];
+ uint j;
+
+ for (j = 0; j != lengthof(buf); j++) buf[j] = _me[i++].m7;
+ SlArray(buf, lengthof(buf), SLE_UINT8);
+ }
+}
static void Save_CHTS()
{
@@ -614,6 +644,7 @@ extern const ChunkHandler _misc_chunk_handlers[] = {
{ 'M3HI', Save_MAP4, Load_MAP4, CH_RIFF },
{ 'MAP5', Save_MAP5, Load_MAP5, CH_RIFF },
{ 'MAPE', Save_MAP6, Load_MAP6, CH_RIFF },
+ { 'MAP7', Save_MAP7, Load_MAP7, CH_RIFF },
{ 'NAME', Save_NAME, Load_NAME, CH_ARRAY},
{ 'DATE', SaveLoad_DATE, SaveLoad_DATE, CH_RIFF},
diff --git a/src/misc_gui.cpp b/src/misc_gui.cpp
index c2c0ff120..792afe302 100644
--- a/src/misc_gui.cpp
+++ b/src/misc_gui.cpp
@@ -188,6 +188,7 @@ static void Place_LandInfo(TileIndex tile)
DEBUG(misc, LANDINFOD_LEVEL, "m4 = %#x", _m[tile].m4);
DEBUG(misc, LANDINFOD_LEVEL, "m5 = %#x", _m[tile].m5);
DEBUG(misc, LANDINFOD_LEVEL, "m6 = %#x", _m[tile].m6);
+ DEBUG(misc, LANDINFOD_LEVEL, "m7 = %#x", _me[tile].m7);
#undef LANDINFOD_LEVEL
}
diff --git a/src/newgrf.cpp b/src/newgrf.cpp
index 09e63d6ee..7323a0107 100644
--- a/src/newgrf.cpp
+++ b/src/newgrf.cpp
@@ -18,6 +18,7 @@
#include "string.h"
#include "table/strings.h"
#include "bridge.h"
+#include "town.h"
#include "economy.h"
#include "newgrf_engine.h"
#include "vehicle.h"
@@ -28,9 +29,11 @@
#include "currency.h"
#include "sound.h"
#include "newgrf_config.h"
+#include "newgrf_house.h"
#include "newgrf_sound.h"
#include "newgrf_spritegroup.h"
#include "helpers.hpp"
+#include "table/town_land.h"
#include "cargotype.h"
/* TTDPatch extended GRF format codec
@@ -68,6 +71,9 @@ static byte *_preload_sprite = NULL;
/* Set if any vehicle is loaded which uses 2cc (two company colours) */
bool _have_2cc = false;
+/* Set if there are any newhouses loaded. */
+bool _have_newhouses = false;
+
/* Default cargo translation table. By default there are 27 possible cargo types */
static const uint _default_cargo_max = 27;
static CargoLabel _default_cargo_list[_default_cargo_max];
@@ -227,6 +233,32 @@ static GRFFile *GetFileByFilename(const char *filename)
}
+/** Used when setting an object's property to map to the GRF's strings
+ * while taking in consideration the "drift" between TTDPatch string system and OpenTTD's one
+ * @param str StringID that we want to have the equivalent in OoenTTD
+ * @return the properly adjusted StringID
+ */
+static StringID MapGRFStringID(StringID str)
+{
+ /* 0xD0 and 0xDC stand for all the TextIDs in the range
+ * of 0xD000 (misc graphics texts) and 0xDC00 (misc persistent texts).
+ * These strings are unique to each grf file, and thus require to be used with the
+ * grfid in which they are declared */
+ if (GB(str, 8, 8) == 0xD0 || GB(str, 8, 8) == 0xDC) {
+ return GetGRFStringID(_cur_grffile->grfid, str);
+ }
+
+ /* Map building names according to our lang file changes
+ * 0x200F = Tall Office Block, first house name in the original data, the one that TTDPatch stil uses
+ * 0x201F = Old houses is the last house name.
+ * OpenTTD does not have exactly the same order aymore, so, the code below allows
+ * to compensate for the difference */
+ if (str >= 0x200F && str <= 0x201F) return str + (STR_200F_TALL_OFFICE_BLOCK - 0x200F);
+
+ return str;
+}
+
+
typedef bool (*VCI_Handler)(uint engine, int numinfo, int prop, byte **buf, int len);
#define FOR_EACH_OBJECT for (i = 0; i < numinfo; i++)
@@ -1168,6 +1200,206 @@ static bool BridgeChangeInfo(uint brid, int numinfo, int prop, byte **bufp, int
return ret;
}
+static bool TownHouseChangeInfo(uint hid, int numinfo, int prop, byte **bufp, int len)
+{
+ HouseSpec **housespec;
+ byte *buf = *bufp;
+ int i;
+ bool ret = false;
+
+ if (hid + numinfo >= HOUSE_MAX) {
+ grfmsg(1, "TownHouseChangeInfo: Too many houses loaded (%u), max (%u). Ignoring.", hid + numinfo, HOUSE_MAX-1);
+ return false;
+ }
+
+ /* Allocate house specs if they haven't been allocated already. */
+ if (_cur_grffile->housespec == NULL) {
+ _cur_grffile->housespec = CallocT<HouseSpec*>(HOUSE_MAX);
+
+ /* Reset any overrides that have been set. */
+ ResetHouseOverrides();
+ }
+
+ housespec = &_cur_grffile->housespec[hid];
+
+ if (prop != 0x08) {
+ /* Check that all the houses being modified have been defined. */
+ FOR_EACH_OBJECT {
+ if (housespec[i] == NULL) {
+ grfmsg(2, "TownHouseChangeInfo: Attempt to modify undefined house %u. Ignoring.", hid + i);
+ return false;
+ }
+ }
+ }
+
+ switch (prop) {
+ case 0x08: // Substitute building type, and definition of a new house
+ FOR_EACH_OBJECT {
+ byte subs_id = grf_load_byte(&buf);
+
+ if (subs_id == 0xFF) {
+ /* Instead of defining a new house, a substitute house id
+ * of 0xFF disables the old house with the current id. */
+ _house_specs[hid + i].enabled = false;
+ continue;
+ } else if (subs_id >= NEW_HOUSE_OFFSET) {
+ /* The substitute id must be one of the original houses. */
+ grfmsg(2, "TownHouseChangeInfo: Attempt to use new house %u as substitute house for %u. Ignoring.", subs_id, hid + i);
+ return false;
+ }
+
+ /* Allocate space for this house. */
+ if (housespec[i] == NULL) housespec[i] = CallocT<HouseSpec>(1);
+
+ memcpy(housespec[i], &_house_specs[subs_id], sizeof(_house_specs[subs_id]));
+
+ housespec[i]->enabled = true;
+ housespec[i]->local_id = hid + i;
+ housespec[i]->substitute_id = subs_id;
+ housespec[i]->random_colour[0] = 0x04; // those 4 random colours are the base colour
+ housespec[i]->random_colour[1] = 0x08; // for all new houses
+ housespec[i]->random_colour[2] = 0x0C; // they stand for red, blue, orange and green
+ housespec[i]->random_colour[3] = 0x06;
+
+ /* New houses do not (currently) expect to have a default start
+ * date before 1930, as this breaks the build date stuff. See
+ * FinaliseHouseArray() for more details. */
+ if (housespec[i]->min_date < 1930) housespec[i]->min_date = 1930;
+ }
+ _have_newhouses = true;
+ break;
+
+ case 0x09: // Building flags
+ FOR_EACH_OBJECT {
+ byte state = grf_load_byte(&buf);
+ housespec[i]->building_flags = (BuildingFlags)state;
+ }
+ break;
+
+ case 0x0A: // Availability years
+ FOR_EACH_OBJECT {
+ uint16 years = grf_load_word(&buf);
+ housespec[i]->min_date = GB(years, 0, 8) > 150 ? MAX_YEAR : ORIGINAL_BASE_YEAR + GB(years, 0, 8);
+ housespec[i]->max_date = GB(years, 8, 8) > 150 ? MAX_YEAR : ORIGINAL_BASE_YEAR + GB(years, 8, 8);
+ }
+ break;
+
+ case 0x0B: // Population
+ FOR_EACH_OBJECT housespec[i]->population = grf_load_byte(&buf);
+ break;
+
+ case 0x0C: // Mail generation multiplier
+ FOR_EACH_OBJECT housespec[i]->mail_generation = grf_load_byte(&buf);
+ break;
+
+ case 0x0D: // Passenger acceptance
+ FOR_EACH_OBJECT housespec[i]->passenger_acceptance = grf_load_byte(&buf);
+ break;
+
+ case 0x0E: // Mail acceptance
+ FOR_EACH_OBJECT housespec[i]->mail_acceptance = grf_load_byte(&buf);
+ break;
+
+ case 0x0F: // Goods, food or fizzy drinks acceptance
+ FOR_EACH_OBJECT {
+ int8 goods = grf_load_byte(&buf);
+ if (goods > 0) {
+ housespec[i]->goods_acceptance = goods;
+ } else {
+ housespec[i]->food_acceptance = -goods;
+ }
+ }
+ break;
+
+ case 0x10: // Local authority rating decrease on removal
+ FOR_EACH_OBJECT housespec[i]->remove_rating_decrease = grf_load_word(&buf);
+ break;
+
+ case 0x11: // Removal cost multiplier
+ FOR_EACH_OBJECT housespec[i]->removal_cost = grf_load_byte(&buf);
+ break;
+
+ case 0x12: // Building name ID
+ FOR_EACH_OBJECT housespec[i]->building_name = MapGRFStringID(grf_load_word(&buf));
+ break;
+
+ case 0x13: // Building availability mask
+ FOR_EACH_OBJECT {
+ uint16 avail = grf_load_word(&buf);
+ housespec[i]->building_availability = (HouseZones)avail;
+ }
+ break;
+
+ case 0x14: // House callback flags
+ FOR_EACH_OBJECT housespec[i]->callback_mask = grf_load_byte(&buf);
+ break;
+
+ case 0x15: // House override byte
+ FOR_EACH_OBJECT {
+ byte override = grf_load_byte(&buf);
+
+ /* The house being overridden must be an original house. */
+ if (override >= NEW_HOUSE_OFFSET) {
+ grfmsg(2, "TownHouseChangeInfo: Attempt to override new house %u with house id %u. Ignoring.", override, hid);
+ return false;
+ }
+
+ AddHouseOverride(hid, override);
+ }
+ break;
+
+ case 0x16: // Periodic refresh multiplier
+ FOR_EACH_OBJECT housespec[i]->processing_time = grf_load_byte(&buf);
+ break;
+
+ case 0x17: // Four random colours to use
+ FOR_EACH_OBJECT {
+ uint j;
+ for (j = 0; j < 4; j++) housespec[i]->random_colour[j] = grf_load_byte(&buf);
+ }
+ break;
+
+ case 0x18: // Relative probability of appearing
+ FOR_EACH_OBJECT housespec[i]->probability = grf_load_byte(&buf);
+ break;
+
+ case 0x19: // Extra flags
+ FOR_EACH_OBJECT {
+ byte flags = grf_load_byte(&buf);
+ housespec[i]->extra_flags = (HouseExtraFlags)flags;
+ }
+ break;
+
+ case 0x1A: // Animation frames
+ FOR_EACH_OBJECT housespec[i]->animation_frames = grf_load_byte(&buf);
+ break;
+
+ case 0x1B: // Animation speed
+ FOR_EACH_OBJECT housespec[i]->animation_speed = clamp(grf_load_byte(&buf), 2, 16);
+ break;
+
+ case 0x1C: // Class of the building type
+ FOR_EACH_OBJECT housespec[i]->class_id = AllocateHouseClassID(grf_load_byte(&buf), _cur_grffile->grfid);
+ break;
+
+ case 0x1D: // Callback flags 2
+ FOR_EACH_OBJECT housespec[i]->callback_mask |= (grf_load_byte(&buf) << 8);
+ break;
+
+ case 0x1E: // Accepted cargo types
+ FOR_EACH_OBJECT grf_load_dword(&buf);
+ ret = true;
+ break;
+
+ default:
+ ret = true;
+ break;
+ }
+
+ *bufp = buf;
+ return ret;
+}
+
static bool GlobalVarChangeInfo(uint gvid, int numinfo, int prop, byte **bufp, int len)
{
byte *buf = *bufp;
@@ -1375,7 +1607,7 @@ static void FeatureChangeInfo(byte *buf, int len)
/* GSF_STATION */ StationChangeInfo,
/* GSF_CANAL */ NULL,
/* GSF_BRIDGE */ BridgeChangeInfo,
- /* GSF_TOWNHOUSE */ NULL,
+ /* GSF_TOWNHOUSE */ TownHouseChangeInfo,
/* GSF_GLOBALVAR */ GlobalVarChangeInfo,
/* GSF_INDUSTRYTILES */NULL,
/* GSF_INDUSTRIES */ NULL,
@@ -1853,6 +2085,86 @@ static void NewSpriteGroup(byte *buf, int len)
break;
}
+ case GSF_TOWNHOUSE: {
+ byte sprites = _cur_grffile->spriteset_numents;
+ byte num_sprites = max((uint8)1, type);
+ uint i;
+
+ group = AllocateSpriteGroup();
+ group->type = SGT_TILELAYOUT;
+ group->g.layout.num_sprites = sprites;
+ group->g.layout.dts = CallocT<DrawTileSprites>(1);
+
+ /* Groundsprite */
+ group->g.layout.dts->ground_sprite = grf_load_word(&buf);
+ group->g.layout.dts->ground_pal = grf_load_word(&buf);
+ /* Remap transparent/colour modifier bits */
+ if (HASBIT(group->g.layout.dts->ground_sprite, 14)) {
+ CLRBIT(group->g.layout.dts->ground_sprite, 14);
+ SETBIT(group->g.layout.dts->ground_sprite, PALETTE_MODIFIER_TRANSPARENT);
+ }
+ if (HASBIT(group->g.layout.dts->ground_sprite, 15)) {
+ CLRBIT(group->g.layout.dts->ground_sprite, 15);
+ SETBIT(group->g.layout.dts->ground_sprite, PALETTE_MODIFIER_COLOR);
+ }
+ if (HASBIT(group->g.layout.dts->ground_pal, 14)) {
+ CLRBIT(group->g.layout.dts->ground_pal, 14);
+ SETBIT(group->g.layout.dts->ground_sprite, SPRITE_MODIFIER_OPAQUE);
+ }
+ if (HASBIT(group->g.layout.dts->ground_pal, 15)) {
+ /* Bit 31 set means this is a custom sprite, so rewrite it to the
+ * last spriteset defined. */
+ SpriteID sprite = _cur_grffile->spriteset_start + GB(group->g.layout.dts->ground_sprite, 0, 14) * sprites;
+ SB(group->g.layout.dts->ground_sprite, 0, SPRITE_WIDTH, sprite);
+ CLRBIT(group->g.layout.dts->ground_pal, 15);
+ }
+
+ group->g.layout.dts->seq = CallocT<DrawTileSeqStruct>(num_sprites + 1);
+
+ for (i = 0; i < num_sprites; i++) {
+ DrawTileSeqStruct *seq = (DrawTileSeqStruct*)&group->g.layout.dts->seq[i];
+
+ seq->image = grf_load_word(&buf);
+ seq->pal = grf_load_word(&buf);
+ seq->delta_x = grf_load_byte(&buf);
+ seq->delta_y = grf_load_byte(&buf);
+
+ if (HASBIT(seq->image, 14)) {
+ CLRBIT(seq->image, 14);
+ SETBIT(seq->image, PALETTE_MODIFIER_TRANSPARENT);
+ }
+ if (HASBIT(seq->image, 15)) {
+ CLRBIT(seq->image, 15);
+ SETBIT(seq->image, PALETTE_MODIFIER_COLOR);
+ }
+ if (HASBIT(seq->pal, 14)) {
+ CLRBIT(seq->pal, 14);
+ SETBIT(seq->image, SPRITE_MODIFIER_OPAQUE);
+ }
+ if (HASBIT(seq->pal, 15)) {
+ /* Bit 31 set means this is a custom sprite, so rewrite it to the
+ * last spriteset defined. */
+ SpriteID sprite = _cur_grffile->spriteset_start + GB(seq->image, 0, 14) * sprites;
+ SB(seq->image, 0, SPRITE_WIDTH, sprite);
+ CLRBIT(seq->pal, 15);
+ }
+
+ if (type > 0) {
+ seq->delta_z = grf_load_byte(&buf);
+ if ((byte)seq->delta_z == 0x80) continue;
+ }
+
+ seq->size_x = grf_load_byte(&buf);
+ seq->size_y = grf_load_byte(&buf);
+ seq->size_z = grf_load_byte(&buf);
+ }
+
+ /* Set the terminator value. */
+ ((DrawTileSeqStruct*)group->g.layout.dts->seq)[i].delta_x = (byte)0x80;
+
+ break;
+ }
+
/* Loading of Tile Layout and Production Callback groups would happen here */
default: grfmsg(1, "NewSpriteGroup: Unsupported feature %d, skipping", feature);
}
@@ -1934,7 +2246,7 @@ static void FeatureMapSpriteGroup(byte *buf, int len)
grfmsg(6, "FeatureMapSpriteGroup: Feature %d, %d ids, %d cids, wagon override %d",
feature, idcount, cidcount, wagover);
- if (feature > GSF_STATION) {
+ if (feature > GSF_STATION && feature != GSF_TOWNHOUSE) {
grfmsg(1, "FeatureMapSpriteGroup: Unsupported feature %d, skipping", feature);
return;
}
@@ -1986,6 +2298,29 @@ static void FeatureMapSpriteGroup(byte *buf, int len)
}
}
return;
+ } else if (feature == GSF_TOWNHOUSE) {
+ byte *bp = &buf[4 + idcount + cidcount * 3];
+ uint16 groupid = grf_load_word(&bp);
+
+ if (groupid >= _cur_grffile->spritegroups_count || _cur_grffile->spritegroups[groupid] == NULL) {
+ grfmsg(1, "FeatureMapSpriteGroup: Spriteset 0x%04X out of range 0x%X or empty, skipping.",
+ groupid, _cur_grffile->spritegroups_count);
+ return;
+ }
+
+ for (uint i = 0; i < idcount; i++) {
+ uint8 hid = buf[3 + i];
+ HouseSpec *hs = _cur_grffile->housespec[hid];
+
+ if (hs == NULL) {
+ grfmsg(1, "FeatureMapSpriteGroup: Too many houses defined, skipping");
+ return;
+ }
+
+ hs->spritegroup = _cur_grffile->spritegroups[groupid];
+ hs->grffile = _cur_grffile;
+ }
+ return;
}
// FIXME: Tropicset contains things like:
@@ -2148,6 +2483,7 @@ static void FeatureNewName(byte *buf, int len)
break;
}
+ case GSF_TOWNHOUSE:
default:
switch (GB(id, 8, 8)) {
case 0xC4: /* Station class name */
@@ -2167,7 +2503,15 @@ static void FeatureNewName(byte *buf, int len)
}
break;
- case 0xC9:
+ case 0xC9: { /* House name */
+ if (_cur_grffile->housespec == NULL || _cur_grffile->housespec[GB(id, 0, 8)] == NULL) {
+ grfmsg(1, "FeatureNewName: Attempt to name undefined house 0x%X, ignoring.", GB(id, 0, 8));
+ } else {
+ _cur_grffile->housespec[GB(id, 0, 8)]->building_name = AddGRFString(_cur_grffile->grfid, id, lang, new_scheme, name, STR_UNDEFINED);
+ }
+ break;
+ }
+
case 0xD0:
case 0xDC:
AddGRFString(_cur_grffile->grfid, id, lang, new_scheme, name, STR_UNDEFINED);
@@ -2182,7 +2526,6 @@ static void FeatureNewName(byte *buf, int len)
#if 0
case GSF_CANAL :
case GSF_BRIDGE :
- case GSF_TOWNHOUSE :
AddGRFString(_cur_spriteid, id, lang, name);
switch (GB(id, 8,8)) {
case 0xC9: /* House name */
@@ -3478,7 +3821,7 @@ static void InitializeGRFSpecial()
| (1 << 0x16) // canals
| (1 << 0x17) // newstartyear
| (0 << 0x18) // freighttrains
- | (0 << 0x19) // newhouses
+ | (1 << 0x19) // newhouses
| (1 << 0x1A) // newbridges
| (0 << 0x1B) // newtownnames
| (0 << 0x1C) // moreanimations
@@ -3550,6 +3893,20 @@ static void ResetCustomStations()
}
}
+static void ResetCustomHouses()
+{
+ GRFFile *file;
+ uint i;
+
+ for (file = _first_grffile; file != NULL; file = file->next) {
+ if (file->housespec == NULL) continue;
+ for (i = 0; i < HOUSE_MAX; i++) free(file->housespec[i]);
+
+ free(file->housespec);
+ file->housespec = NULL;
+ }
+}
+
static void ResetNewGRF()
{
GRFFile *next;
@@ -3610,6 +3967,10 @@ static void ResetNewGRFData()
/* Reset the curencies array */
ResetCurrencies();
+ /* Reset the house array */
+ ResetCustomHouses();
+ ResetHouses();
+
// Reset station classes
ResetStationClasses();
ResetCustomStations();
@@ -3635,6 +3996,7 @@ static void ResetNewGRFData()
_traininfo_vehicle_pitch = 0;
_traininfo_vehicle_width = 29;
_have_2cc = false;
+ _have_newhouses = false;
_signal_base = 0;
_coast_base = 0;
@@ -3838,6 +4200,41 @@ static void CalculateRefitMasks()
}
}
+/** Add all new houses to the house array. House properties can be set at any
+ * time in the GRF file, so we can only add a house spec to the house array
+ * after the file has finished loading. We also need to check the dates, due to
+ * the TTDPatch behaviour described below that we need to emulate. */
+static void FinaliseHouseArray()
+{
+ /* If there are no houses with start dates before 1930, then all houses
+ * with start dates of 1930 have them reset to 0. This is in order to be
+ * compatible with TTDPatch, where if no houses have start dates before
+ * 1930 and the date is before 1930, the game pretends that this is 1930.
+ * If there have been any houses defined with start dates before 1930 then
+ * the dates are left alone. */
+ bool reset_dates = true;
+
+ for (GRFFile *file = _first_grffile; file != NULL; file = file->next) {
+ if (file->housespec == NULL) continue;
+
+ for (int i = 0; i < HOUSE_MAX; i++) {
+ HouseSpec *hs = file->housespec[i];
+ if (hs != NULL) {
+ SetHouseSpec(hs);
+ if (hs->min_date < 1930) reset_dates = false;
+ }
+ }
+ }
+
+ if (reset_dates) {
+ for (int i = NEW_HOUSE_OFFSET; i < HOUSE_MAX; i++) {
+ HouseSpec *hs = GetHouseSpecs(i);
+
+ if (hs->enabled && hs->min_date == 1930) hs->min_date = 0;
+ }
+ }
+}
+
/* Here we perform initial decoding of some special sprites (as are they
* described at http://www.ttdpatch.net/src/newgrf.txt, but this is only a very
* partial implementation yet). */
@@ -4003,6 +4400,18 @@ void LoadNewGRFFile(GRFConfig *config, uint file_index, GrfLoadingStage stage)
void InitDepotWindowBlockSizes();
+static void AfterLoadGRFs()
+{
+ /* Pre-calculate all refit masks after loading GRF files. */
+ CalculateRefitMasks();
+
+ /* Set the block size in the depot windows based on vehicle sprite sizes */
+ InitDepotWindowBlockSizes();
+
+ /* Add all new houses to the house array. */
+ FinaliseHouseArray();
+}
+
void LoadNewGRF(uint load_index, uint file_index)
{
InitializeGRFSpecial();
@@ -4033,9 +4442,6 @@ void LoadNewGRF(uint load_index, uint file_index)
}
}
- // Pre-calculate all refit masks after loading GRF files
- CalculateRefitMasks();
-
- /* Set the block size in the depot windows based on vehicle sprite sizes */
- InitDepotWindowBlockSizes();
+ /* Call any functions that should be run after GRFs have been loaded. */
+ AfterLoadGRFs();
}
diff --git a/src/newgrf.h b/src/newgrf.h
index 963145f65..e9e5418b0 100644
--- a/src/newgrf.h
+++ b/src/newgrf.h
@@ -4,6 +4,7 @@
#define NEWGRF_H
#include "station.h"
+#include "town.h"
#include "newgrf_config.h"
#include "helpers.hpp"
#include "cargotype.h"
@@ -56,6 +57,7 @@ struct GRFFile {
uint sound_offset;
StationSpec **stations;
+ HouseSpec **housespec;
uint32 param[0x80];
uint param_end; /// one more than the highest set parameter
@@ -72,6 +74,7 @@ extern GRFFile *_first_grffile;
extern SpriteID _signal_base;
extern SpriteID _coast_base;
extern bool _have_2cc;
+extern bool _have_newhouses;
void LoadNewGRFFile(GRFConfig *config, uint file_index, GrfLoadingStage stage);
void LoadNewGRF(uint load_index, uint file_index);
diff --git a/src/newgrf_callbacks.h b/src/newgrf_callbacks.h
index 22aecc649..348bfb6cc 100644
--- a/src/newgrf_callbacks.h
+++ b/src/newgrf_callbacks.h
@@ -37,10 +37,42 @@ enum CallbackID {
CBID_TRAIN_ARTIC_ENGINE = 0x16,
+ /* Called (if appropriate bit in callback mask is set) to determine whether
+ * the house can be built on the specified tile. */
+ CBID_HOUSE_ALLOW_CONSTRUCTION = 0x17,
+
CBID_VEHICLE_CARGO_SUFFIX = 0x19,
+ /* Called (if appropriate bit in callback mask is set) to determine
+ * the next animation frame. */
+ CBID_HOUSE_ANIMATION_NEXT_FRAME = 0x1A,
+
+ /* Called (if appropriate bit in callback mask is set) for periodically
+ * starting or stopping the animation. */
+ CBID_HOUSE_ANIMATION_START_STOP = 0x1B,
+
+ /* Called (if appropriate bit in callback mask is set) whenever the
+ * construction state of a house changes. */
+ CBID_CONSTRUCTION_STATE_CHANGE = 0x1C,
+
CBID_TRAIN_ALLOW_WAGON_ATTACH = 0x1D,
+ /* Called (if appropriate bit in callback mask is set) to determine the
+ * colour of a town building. */
+ CBID_BUILDING_COLOUR = 0x1E,
+
+ /* Called (if appropriate bit in callback mask is set) to decide how much
+ * cargo a town building can accept. */
+ CBID_HOUSE_CARGO_ACCEPTANCE = 0x1F, // not yet implemented
+
+ /* Called (if appropriate bit in callback mask is set) to indicate
+ * how long the current animation frame should last. */
+ CBID_HOUSE_ANIMATION_SPEED = 0x20,
+
+ /* Called (if appropriate bit in callback mask is set) periodically to
+ * determine if a house should be destroyed. */
+ CBID_HOUSE_DESTRUCTION = 0x21,
+
/* This callback is called from vehicle purchase lists. It returns a value to be
* used as a custom string ID in the 0xD000 range. */
CBID_VEHICLE_ADDITIONAL_TEXT = 0x23,
@@ -48,16 +80,28 @@ enum CallbackID {
/* Called when building a station to customize the tile layout */
CBID_STATION_TILE_LAYOUT = 0x24,
+ /* Called (if appropriate bit in callback mask is set) to determine which
+ * cargoes a town building should accept. */
+ CBID_HOUSE_ACCEPT_CARGO = 0x2A, // not yet implemented
+
/* Called to determine if a specific colour map should be used for a vehicle
* instead of the default livery */
CBID_VEHICLE_COLOUR_MAPPING = 0x2D,
+ /* Called (if appropriate bit in callback mask is set) to determine how much
+ * cargo a town building produces. */
+ CBID_HOUSE_PRODUCE_CARGO = 0x2E, // not yet implemented
+
/* Called when the player (or AI) tries to start or stop a vehicle. Mainly
* used for preventing a vehicle from leaving the depot. */
CBID_VEHICLE_START_STOP_CHECK = 0x31,
/* Called to play a special sound effect */
CBID_VEHICLE_SOUND_EFFECT = 0x33,
+
+ /* Called (if appropriate bit in callback mask set) to determine whether a
+ * town building can be destroyed. */
+ CBID_HOUSE_DENY_DESTRUCTION = 0x143,
};
/**
@@ -84,6 +128,23 @@ enum StationCallbackMask {
};
/**
+ * Callback masks for houses.
+ */
+enum HouseCallbackMask {
+ CBM_HOUSE_ALLOW_CONSTRUCTION = 0,
+ CBM_ANIMATION_NEXT_FRAME = 1,
+ CBM_ANIMATION_START_STOP = 2,
+ CBM_CONSTRUCTION_STATE_CHANGE = 3,
+ CBM_BUILDING_COLOUR = 4,
+ CBM_CARGO_ACCEPTANCE = 5,
+ CBM_ANIMATION_SPEED = 6,
+ CBM_HOUSE_DESTRUCTION = 7,
+ CBM_HOUSE_ACCEPT_CARGO = 8,
+ CBM_HOUSE_PRODUCE_CARGO = 9,
+ CBM_HOUSE_DENY_DESTRUCTION = 10,
+};
+
+/**
* Result of a failed callback.
*/
enum {
diff --git a/src/newgrf_house.cpp b/src/newgrf_house.cpp
new file mode 100644
index 000000000..707825341
--- /dev/null
+++ b/src/newgrf_house.cpp
@@ -0,0 +1,609 @@
+/* $Id$ */
+
+/** @file newgrf_house.cpp */
+
+#include "stdafx.h"
+#include "openttd.h"
+#include "functions.h"
+#include "variables.h"
+#include "debug.h"
+#include "viewport.h"
+#include "date.h"
+#include "town.h"
+#include "town_map.h"
+#include "sound.h"
+#include "sprite.h"
+#include "strings.h"
+#include "table/strings.h"
+#include "table/sprites.h"
+#include "table/town_land.h"
+#include "newgrf.h"
+#include "newgrf_house.h"
+#include "newgrf_spritegroup.h"
+#include "newgrf_callbacks.h"
+#include "newgrf_town.h"
+#include "newgrf_sound.h"
+
+static BuildingCounts _building_counts;
+static HouseClassMapping _class_mapping[HOUSE_CLASS_MAX];
+HouseIDMapping _house_id_mapping[HOUSE_MAX];
+
+/* Since the house IDs defined by the GRF file don't necessarily correlate
+ * to those used by the game, the IDs used for overriding old houses must be
+ * translated when the house spec is set. */
+static uint16 _house_overrides[NEW_HOUSE_OFFSET];
+
+void AddHouseOverride(uint8 local_id, uint house_type)
+{
+ assert(house_type < NEW_HOUSE_OFFSET);
+ _house_overrides[house_type] = local_id;
+}
+
+void ResetHouseOverrides()
+{
+ for (int i = 0; i != lengthof(_house_overrides); i++) {
+ _house_overrides[i] = INVALID_HOUSE_ID;
+ }
+}
+
+static HouseID GetHouseID(byte grf_local_id, uint32 grfid)
+{
+ const HouseIDMapping *map;
+
+ for (HouseID house_id = NEW_HOUSE_OFFSET; house_id != lengthof(_house_id_mapping); house_id++) {
+ map = &_house_id_mapping[house_id];
+ if (map->house_id == grf_local_id && map->grfid == grfid) return house_id;
+ }
+ return INVALID_HOUSE_ID;
+}
+
+static HouseID AddHouseID(byte grf_local_id, uint32 grfid, byte substitute_id)
+{
+ HouseID house_id;
+ HouseIDMapping *map;
+
+ /* Look to see if this house has already been added. This is done
+ * separately from the loop below in case a GRF has been deleted, and there
+ * are any gaps in the array. */
+ house_id = GetHouseID(grf_local_id, grfid);
+ if (house_id != INVALID_HOUSE_ID) return house_id;
+
+ /* This house hasn't been defined before, so give it an ID now. */
+ for (house_id = NEW_HOUSE_OFFSET; house_id != lengthof(_house_id_mapping); house_id++) {
+ map = &_house_id_mapping[house_id];
+
+ if (map->house_id == 0 && map->grfid == 0) {
+ map->house_id = grf_local_id;
+ map->grfid = grfid;
+ map->substitute_id = substitute_id;
+ return house_id;
+ }
+ }
+
+ return INVALID_HOUSE_ID;
+}
+
+void SetHouseSpec(const HouseSpec *hs)
+{
+ HouseID house_id = AddHouseID(hs->local_id, hs->grffile->grfid, hs->substitute_id);
+
+ if (house_id == INVALID_HOUSE_ID) {
+ grfmsg(1, "SetHouseSpec: Too many houses allocated. Ignoring.");
+ return;
+ }
+
+ memcpy(&_house_specs[house_id], hs, sizeof(*hs));
+
+ /* Now add the overrides. */
+ for (int i = 0; i != lengthof(_house_overrides); i++) {
+ HouseSpec *overridden_hs = GetHouseSpecs(i);
+
+ if (_house_overrides[i] != hs->local_id) continue;
+
+ overridden_hs->override = house_id;
+ _house_overrides[i] = INVALID_HOUSE_ID;
+ }
+}
+
+void ResetHouseIDMapping()
+{
+ memset(&_house_id_mapping, 0, sizeof(_house_id_mapping));
+}
+
+void CheckHouseIDs()
+{
+ for (TileIndex t = 0; t < MapSize(); t++) {
+ HouseID house_id;
+
+ if (!IsTileType(t, MP_HOUSE)) continue;
+
+ house_id = GetHouseType(t);
+ if (!GetHouseSpecs(house_id)->enabled && house_id >= NEW_HOUSE_OFFSET) {
+ /* The specs for this type of house are not available any more, so
+ * replace it with the substitute original house type. */
+ SetHouseType(t, _house_id_mapping[house_id].substitute_id);
+ }
+ }
+
+ InitializeBuildingCounts();
+ AfterLoadCountBuildings();
+
+}
+
+HouseClassID AllocateHouseClassID(byte grf_class_id, uint32 grfid)
+{
+ /* Start from 1 because 0 means that no class has been assigned. */
+ for (int i = 1; i != lengthof(_class_mapping); i++) {
+ HouseClassMapping *map = &_class_mapping[i];
+
+ if (map->class_id == grf_class_id && map->grfid == grfid) return (HouseClassID)i;
+
+ if (map->class_id == 0 && map->grfid == 0) {
+ map->class_id = grf_class_id;
+ map->grfid = grfid;
+ return (HouseClassID)i;
+ }
+ }
+ return HOUSE_NO_CLASS;
+}
+
+void InitializeBuildingCounts()
+{
+ memset(&_building_counts, 0, sizeof(_building_counts));
+}
+
+/**
+ * IncreaseBuildingCount()
+ * Increase the count of a building when it has been added by a town.
+ * @param t The town that the building is being built in
+ * @param house_id The id of the house being added
+ */
+void IncreaseBuildingCount(Town *t, HouseID house_id)
+{
+ HouseClassID class_id = GetHouseSpecs(house_id)->class_id;
+
+ if (!_have_newhouses) return;
+
+ /* If there are 255 buildings of this type in this town, there are also
+ * at least that many houses of the same class in the town, and
+ * therefore on the map as well. */
+ if (t->building_counts.id_count[house_id] == 255) return;
+
+ t->building_counts.id_count[house_id]++;
+ if (_building_counts.id_count[house_id] < 255) _building_counts.id_count[house_id]++;
+
+ /* Similarly, if there are 255 houses of this class in this town, there
+ * must be at least that number on the map too. */
+ if (class_id == HOUSE_NO_CLASS || t->building_counts.class_count[class_id] == 255) return;
+
+ t->building_counts.class_count[class_id]++;
+ if (_building_counts.class_count[class_id] < 255) _building_counts.class_count[class_id]++;
+}
+
+/**
+ * DecreaseBuildingCount()
+ * Decrease the number of a building when it is deleted.
+ * @param t The town that the building was built in
+ * @param house_id The id of the house being removed
+ */
+void DecreaseBuildingCount(Town *t, HouseID house_id)
+{
+ HouseClassID class_id = GetHouseSpecs(house_id)->class_id;
+
+ if (!_have_newhouses) return;
+
+ if (t->building_counts.id_count[house_id] > 0) t->building_counts.id_count[house_id]--;
+ if (_building_counts.id_count[house_id] > 0) _building_counts.id_count[house_id]--;
+
+ if (class_id == HOUSE_NO_CLASS) return;
+
+ if (t->building_counts.class_count[class_id] > 0) t->building_counts.class_count[class_id]--;
+ if (_building_counts.class_count[class_id] > 0) _building_counts.class_count[class_id]--;
+}
+
+/**
+ * AfterLoadCountBuildings()
+ *
+ * After a savegame has been loaded, count the number of buildings on the map.
+ */
+void AfterLoadCountBuildings()
+{
+ if (!_have_newhouses) return;
+
+ for (TileIndex t = 0; t < MapSize(); t++) {
+ if (!IsTileType(t, MP_HOUSE)) continue;
+ IncreaseBuildingCount(GetTownByTile(t), GetHouseType(t));
+ }
+}
+
+
+static uint32 HouseGetRandomBits(const ResolverObject *object)
+{
+ const TileIndex tile = object->u.house.tile;
+ return (tile == INVALID_TILE || !IsTileType(tile, MP_HOUSE)) ? 0 : GetHouseRandomBits(tile);
+}
+
+static uint32 HouseGetTriggers(const ResolverObject *object)
+{
+ const TileIndex tile = object->u.house.tile;
+ return (tile == INVALID_TILE || !IsTileType(tile, MP_HOUSE)) ? 0 : GetHouseTriggers(tile);
+}
+
+static void HouseSetTriggers(const ResolverObject *object, int triggers)
+{
+ const TileIndex tile = object->u.house.tile;
+ if (IsTileType(tile, MP_HOUSE)) SetHouseTriggers(tile, triggers);
+}
+
+static uint32 GetNumHouses(HouseID house_id, const Town *town)
+{
+ uint8 map_id_count, town_id_count, map_class_count, town_class_count;
+ HouseClassID class_id = GetHouseSpecs(house_id)->class_id;
+
+ map_id_count = _building_counts.id_count[house_id];
+ map_class_count = _building_counts.class_count[class_id];
+ town_id_count = town->building_counts.id_count[house_id];
+ town_class_count = town->building_counts.class_count[class_id];
+
+ return map_class_count << 24 | town_class_count << 16 | map_id_count << 8 | town_id_count;
+}
+
+static uint32 GetTerrainType(TileIndex tile)
+{
+ switch (_opt.landscape) {
+ case LT_DESERT: return GetTropicZone(tile) == TROPICZONE_DESERT ? 1 : 2;
+ case LT_HILLY: return GetTileZ(tile) >= _opt.snow_line ? 4 : 0;
+ default: return 0;
+ }
+}
+
+static uint32 GetGRFParameter(HouseID house_id, byte parameter)
+{
+ const HouseSpec *hs = GetHouseSpecs(house_id);
+ const GRFFile *file = hs->grffile;
+
+ if (parameter >= file->param_end) return 0;
+ return file->param[parameter];
+}
+
+/**
+ * HouseGetVariable():
+ *
+ * Used by the resolver to get values for feature 07 deterministic spritegroups.
+ */
+static uint32 HouseGetVariable(const ResolverObject *object, byte variable, byte parameter, bool *available)
+{
+ const Town *town = object->u.house.town;
+ TileIndex tile = object->u.house.tile;
+ HouseID house_id = object->u.house.house_id;
+
+ if (object->scope == VSG_SCOPE_PARENT) {
+ return TownGetVariable(variable, parameter, available, town);
+ }
+
+ switch (variable) {
+ /* Construction stage. */
+ case 0x40: return (IsTileType(tile, MP_HOUSE) ? GetHouseBuildingStage(tile) : 0) | OriginalTileRandomiser(TileX(tile), TileY(tile)) << 2;
+
+ /* Building age. */
+ case 0x41: return clamp(_cur_year - GetHouseConstructionYear(tile), 0, 0xFF);
+
+ /* Town zone */
+ case 0x42: return GetTownRadiusGroup(town, tile);
+
+ /* Terrain type */
+ case 0x43: return GetTerrainType(tile);
+
+ /* Number of this type of building on the map. */
+ case 0x44: return GetNumHouses(house_id, town);
+
+ /* Whether the town is being created or just expanded. */
+ case 0x45: return _generating_world ? 1 : 0;
+
+ /* Current animation frame. */
+ case 0x46: return IsTileType(tile, MP_HOUSE) ? GetHouseAnimationFrame(tile) : 0;
+
+
+ /* Building counts for old houses with id = parameter. */
+ case 0x60: return GetNumHouses(parameter, town);
+
+ /* Building counts for new houses with id = parameter. */
+ case 0x61: {
+ const HouseSpec *hs = GetHouseSpecs(house_id);
+ if (hs->grffile == NULL) return 0;
+
+ HouseID new_house = GetHouseID(parameter, hs->grffile->grfid);
+ return new_house == INVALID_HOUSE_ID ? 0 : GetNumHouses(new_house, town);
+ }
+
+ /* Land info for nearby tiles. */
+ case 0x62: {
+ int8 x = GB(parameter, 0, 4);
+ int8 y = GB(parameter, 4, 4);
+ byte tile_type;
+
+ if (x >= 8) x -= 16;
+ if (y >= 8) y -= 16;
+
+ tile += TileDiffXY(x, y);
+
+ tile_type = GetTerrainType(tile) << 2 | (IsTileType(tile, MP_WATER) ? 1 : 0) << 1;
+
+ return GetTileType(tile) << 24 | (TileHeight(tile) * 8) << 16 | tile_type << 8 | GetTileSlope(tile, NULL);
+ }
+
+ /* Read GRF parameter */
+ case 0x7F: return GetGRFParameter(object->u.house.house_id, parameter);
+ }
+
+ DEBUG(grf, 1, "Unhandled house property 0x%X", variable);
+
+ *available = false;
+ return UINT_MAX;
+}
+
+static const SpriteGroup *HouseResolveReal(const ResolverObject *object, const SpriteGroup *group)
+{
+ /* Houses do not have 'real' groups */
+ return NULL;
+}
+
+/**
+ * NewHouseResolver():
+ *
+ * Returns a resolver object to be used with feature 07 spritegroups.
+ */
+static void NewHouseResolver(ResolverObject *res, HouseID house_id, TileIndex tile, Town *town)
+{
+ res->GetRandomBits = HouseGetRandomBits;
+ res->GetTriggers = HouseGetTriggers;
+ res->SetTriggers = HouseSetTriggers;
+ res->GetVariable = HouseGetVariable;
+ res->ResolveReal = HouseResolveReal;
+
+ res->u.house.tile = tile;
+ res->u.house.town = town;
+ res->u.house.house_id = house_id;
+
+ res->callback = 0;
+ res->callback_param1 = 0;
+ res->callback_param2 = 0;
+ res->last_value = 0;
+ res->trigger = 0;
+ res->reseed = 0;
+}
+
+uint16 GetHouseCallback(uint16 callback, uint32 param1, HouseID house_id, Town *town, TileIndex tile)
+{
+ ResolverObject object;
+ const SpriteGroup *group;
+
+ NewHouseResolver(&object, house_id, tile, town);
+ object.callback = callback;
+ object.callback_param1 = param1;
+ object.callback_param2 = 0;
+
+ group = Resolve(GetHouseSpecs(house_id)->spritegroup, &object);
+ if (group == NULL || group->type != SGT_CALLBACK) return CALLBACK_FAILED;
+
+ return group->g.callback.result;
+}
+
+void DrawTileLayout(const TileInfo *ti, const SpriteGroup *group, byte stage, HouseID house_id)
+{
+ const DrawTileSprites *dts = group->g.layout.dts;
+ const DrawTileSeqStruct *dtss;
+
+ SpriteID image = dts->ground_sprite;
+ SpriteID pal = dts->ground_pal;
+
+ if (GB(image, 0, SPRITE_WIDTH) != 0) DrawGroundSprite(image, pal);
+
+ foreach_draw_tile_seq(dtss, dts->seq) {
+ if (GB(dtss->image, 0, SPRITE_WIDTH) == 0) continue;
+
+ image = dtss->image + stage;
+ pal = dtss->pal;
+
+ if (!HASBIT(image, SPRITE_MODIFIER_OPAQUE) && ((_display_opt & DO_TRANS_BUILDINGS))) {
+ SETBIT(image, PALETTE_MODIFIER_TRANSPARENT);
+ pal = PALETTE_TO_TRANSPARENT;
+ } else if (HASBIT(image, PALETTE_MODIFIER_COLOR)) {
+ if (pal == 0) {
+ const HouseSpec *hs = GetHouseSpecs(house_id);
+ if (HASBIT(hs->callback_mask, CBM_BUILDING_COLOUR)) {
+ uint16 callback = GetHouseCallback(CBID_BUILDING_COLOUR, 0, house_id, GetTownByTile(ti->tile), ti->tile);
+ if (callback != CALLBACK_FAILED) {
+ /* If bit 14 is set, we should use a 2cc colour map, else use the callback value. */
+ pal = HASBIT(callback, 14) ? GB(callback, 0, 8) + SPR_2CCMAP_BASE : callback;
+ }
+ } else {
+ pal = hs->random_colour[OriginalTileRandomiser(ti->x, ti->y)] + PALETTE_RECOLOR_START;
+ }
+ }
+ } else {
+ pal = PAL_NONE;
+ }
+
+ if ((byte)dtss->delta_z != 0x80) {
+ AddSortableSpriteToDraw(
+ image, pal,
+ ti->x + dtss->delta_x, ti->y + dtss->delta_y,
+ dtss->size_x, dtss->size_y,
+ dtss->size_z, ti->z + dtss->delta_z
+ );
+ } else {
+ AddChildSpriteScreen(image, pal, dtss->delta_x, dtss->delta_y);
+ }
+ }
+}
+
+void DrawNewHouseTile(TileInfo *ti, HouseID house_id)
+{
+ const HouseSpec *hs = GetHouseSpecs(house_id);
+ const SpriteGroup *group;
+ ResolverObject object;
+
+ if (ti->tileh != SLOPE_FLAT) DrawFoundation(ti, ti->tileh);
+
+ NewHouseResolver(&object, house_id, ti->tile, GetTownByTile(ti->tile));
+
+ group = Resolve(hs->spritegroup, &object);
+ if (group == NULL || group->type != SGT_TILELAYOUT) {
+ /* XXX: This is for debugging purposes really, and shouldn't stay. */
+ DrawGroundSprite(SPR_SHADOW_CELL, PAL_NONE);
+ } else {
+ /* Limit the building stage to the number of stages supplied. */
+ byte stage = GetHouseBuildingStage(ti->tile);
+ stage = clamp(stage - 4 + group->g.layout.num_sprites, 0, group->g.layout.num_sprites - 1);
+ DrawTileLayout(ti, group, stage, house_id);
+ }
+}
+
+void AnimateNewHouseTile(TileIndex tile)
+{
+ const HouseSpec *hs = GetHouseSpecs(GetHouseType(tile));
+ byte animation_speed = hs->animation_speed;
+ bool frame_set_by_callback = false;
+
+ if (HASBIT(hs->callback_mask, CBM_ANIMATION_SPEED)) {
+ uint16 callback_res = GetHouseCallback(CBID_HOUSE_ANIMATION_SPEED, 0, GetHouseType(tile), GetTownByTile(tile), tile);
+ if (callback_res != CALLBACK_FAILED) animation_speed = clamp(callback_res & 0xFF, 2, 16);
+ }
+
+ /* An animation speed of 2 means the animation frame changes 4 ticks, and
+ * increasing this value by one doubles the wait. 2 is the minimum value
+ * allowed for animation_speed, which corresponds to 120ms, and 16 is the
+ * maximum, corresponding to around 33 minutes. */
+ if (_tick_counter % (1 << animation_speed) != 0) return;
+
+ byte frame = GetHouseAnimationFrame(tile);
+ byte num_frames = GB(hs->animation_frames, 0, 7);
+
+ if (HASBIT(hs->callback_mask, CBM_ANIMATION_NEXT_FRAME)) {
+ uint32 param = (hs->extra_flags & CALLBACK_1A_RANDOM_BITS) ? Random() : 0;
+ uint16 callback_res = GetHouseCallback(CBID_HOUSE_ANIMATION_NEXT_FRAME, param, GetHouseType(tile), GetTownByTile(tile), tile);
+
+ if (callback_res != CALLBACK_FAILED) {
+ frame_set_by_callback = true;
+
+ switch (callback_res & 0xFF) {
+ case 0xFF:
+ DeleteAnimatedTile(tile);
+ break;
+ case 0xFE:
+ /* Carry on as normal. */
+ frame_set_by_callback = false;
+ break;
+ default:
+ frame = callback_res & 0xFF;
+ break;
+ }
+
+ /* If the lower 7 bits of the upper byte of the callback
+ * result are not empty, it is a sound effect. */
+ if (GB(callback_res, 8, 7) != 0) PlayHouseSound(GB(callback_res, 8, 7), tile);
+ }
+ }
+
+ if (!frame_set_by_callback) {
+ if (frame < num_frames) {
+ frame++;
+ } else if (frame == num_frames && HASBIT(hs->animation_frames, 7)) {
+ /* This animation loops, so start again from the beginning */
+ frame = 0;
+ } else {
+ /* This animation doesn't loop, so stay here */
+ DeleteAnimatedTile(tile);
+ }
+ }
+
+ SetHouseAnimationFrame(tile, frame);
+ MarkTileDirtyByTile(tile);
+}
+
+void ChangeHouseAnimationFrame(TileIndex tile, uint16 callback_result)
+{
+ switch (callback_result & 0xFF) {
+ case 0xFD: /* Do nothing. */ break;
+ case 0xFE: AddAnimatedTile(tile); break;
+ case 0xFF: DeleteAnimatedTile(tile); break;
+ default:
+ SetHouseAnimationFrame(tile, callback_result & 0xFF);
+ AddAnimatedTile(tile);
+ break;
+ }
+ /* If the lower 7 bits of the upper byte of the callback
+ * result are not empty, it is a sound effect. */
+ if (GB(callback_result, 8, 7) != 0) PlayHouseSound(GB(callback_result, 8, 7), tile);
+}
+
+bool CanDeleteHouse(TileIndex tile)
+{
+ const HouseSpec *hs = GetHouseSpecs(GetHouseType(tile));
+
+ /* Human players are always allowed to remove buildings, as is water and
+ * anyone using the scenario editor. */
+ if ((IsValidPlayer(_current_player) && IsHumanPlayer(_current_player))
+ || _current_player == OWNER_WATER || _current_player == OWNER_NONE) return true;
+
+ if (HASBIT(hs->callback_mask, CBM_HOUSE_DENY_DESTRUCTION)) {
+ uint16 callback_res = GetHouseCallback(CBID_HOUSE_DENY_DESTRUCTION, 0, GetHouseType(tile), GetTownByTile(tile), tile);
+ return (callback_res == CALLBACK_FAILED || callback_res == 0);
+ } else {
+ return !(hs->extra_flags & BUILDING_IS_PROTECTED);
+ }
+}
+
+static void AnimationControl(TileIndex tile, uint16 random_bits)
+{
+ const HouseSpec *hs = GetHouseSpecs(GetHouseType(tile));
+
+ if (HASBIT(hs->callback_mask, CBM_ANIMATION_START_STOP)) {
+ uint32 param = (hs->extra_flags & SYNCHRONISED_CALLBACK_1B) ? (GB(Random(), 0, 16) | random_bits << 16) : Random();
+ uint16 callback_res = GetHouseCallback(CBID_HOUSE_ANIMATION_START_STOP, param, GetHouseType(tile), GetTownByTile(tile), tile);
+
+ if (callback_res != CALLBACK_FAILED) ChangeHouseAnimationFrame(tile, callback_res);
+ }
+}
+
+bool NewHouseTileLoop(TileIndex tile)
+{
+ const HouseSpec *hs = GetHouseSpecs(GetHouseType(tile));
+
+ if (GetHouseProcessingTime(tile) > 0) {
+ DecHouseProcessingTime(tile);
+ return true;
+ }
+
+ /* @todo: Magic with triggers goes here. Got to implement that, one day. .. */
+
+ if (HASBIT(hs->callback_mask, CBM_ANIMATION_START_STOP)) {
+ /* If this house is marked as having a synchronised callback, all the
+ * tiles will have the callback called at once, rather than when the
+ * tile loop reaches them. This should only be enabled for the northern
+ * tile, or strange things will happen (here, and in TTDPatch). */
+ if (hs->extra_flags & SYNCHRONISED_CALLBACK_1B) {
+ uint16 random = GB(Random(), 0, 16);
+
+ if (hs->building_flags & BUILDING_HAS_1_TILE) AnimationControl(tile, random);
+ if (hs->building_flags & BUILDING_2_TILES_Y) AnimationControl(TILE_ADDXY(tile, 0, 1), random);
+ if (hs->building_flags & BUILDING_2_TILES_X) AnimationControl(TILE_ADDXY(tile, 1, 0), random);
+ if (hs->building_flags & BUILDING_HAS_4_TILES) AnimationControl(TILE_ADDXY(tile, 1, 1), random);
+ } else {
+ AnimationControl(tile, 0);
+ }
+ }
+
+ /* Check callback 21, which determines if a house should be destroyed. */
+ if (HASBIT(hs->callback_mask, CBM_HOUSE_DESTRUCTION)) {
+ uint16 callback_res = GetHouseCallback(CBID_HOUSE_DESTRUCTION, 0, GetHouseType(tile), GetTownByTile(tile), tile);
+ if (callback_res != CALLBACK_FAILED && callback_res > 0) {
+ ClearTownHouse(GetTownByTile(tile), tile);
+ return false;
+ }
+ }
+
+ SetHouseProcessingTime(tile, hs->processing_time);
+ return true;
+}
diff --git a/src/newgrf_house.h b/src/newgrf_house.h
new file mode 100644
index 000000000..513b46094
--- /dev/null
+++ b/src/newgrf_house.h
@@ -0,0 +1,71 @@
+/* $Id$ */
+
+/** @file newgrf_house.h */
+
+#ifndef NEWGRF_HOUSE_H
+#define NEWGRF_HOUSE_H
+
+#include "town.h"
+
+/**
+ * Maps a house id stored on the map to a GRF file.
+ * House IDs are stored on the map, so there needs to be a way to tie them to
+ * GRF files. An array of HouseIDMapping structs is saved with the savegame so
+ * that house GRFs can be loaded in a different order, or removed safely. The
+ * index in the array is the house ID stored on the map.
+ *
+ * The substitute ID is the ID of an original house that should be used instead
+ * if the GRF containing the new house is not available.
+ */
+struct HouseIDMapping {
+ uint32 grfid; ///< The GRF ID of the file this house belongs to
+ uint8 house_id; ///< The house ID within the GRF file
+ uint8 substitute_id; ///< The (original) house ID to use if this GRF is not available
+};
+
+/**
+ * Makes class IDs unique to each GRF file.
+ * Houses can be assigned class IDs which are only comparable within the GRF
+ * file they were defined in. This mapping ensures that if two houses have the
+ * same class as defined by the GRF file, the classes are different within the
+ * game. An array of HouseClassMapping structs is created, and the array index
+ * of the struct that matches both the GRF ID and the class ID is the class ID
+ * used in the game.
+ *
+ * Although similar to the HouseIDMapping struct above, this serves a different
+ * purpose. Since the class ID is not saved anywhere, this mapping does not
+ * need to be persistent; it just needs to keep class ids unique.
+ */
+struct HouseClassMapping {
+ uint32 grfid; ////< The GRF ID of the file this class belongs to
+ uint8 class_id; ////< The class id within the grf file
+};
+
+extern HouseIDMapping _house_id_mapping[HOUSE_MAX]; ///< Declared in newgrf_house.cpp
+
+void AddHouseOverride(uint8 local_id, uint house_type);
+void ResetHouseOverrides();
+
+void SetHouseSpec(const HouseSpec *hs);
+
+void CheckHouseIDs();
+void ResetHouseIDMapping();
+
+HouseClassID AllocateHouseClassID(byte grf_class_id, uint32 grfid);
+
+void InitializeBuildingCounts();
+void IncreaseBuildingCount(Town *t, HouseID house_id);
+void DecreaseBuildingCount(Town *t, HouseID house_id);
+void AfterLoadCountBuildings();
+
+void DrawNewHouseTile(TileInfo *ti, HouseID house_id);
+void AnimateNewHouseTile(TileIndex tile);
+void ChangeHouseAnimationFrame(TileIndex tile, uint16 callback_result);
+
+uint16 GetHouseCallback(uint16 callback, uint32 param1, HouseID house_id, Town *town, TileIndex tile);
+
+bool CanDeleteHouse(TileIndex tile);
+
+bool NewHouseTileLoop(TileIndex tile);
+
+#endif /* NEWGRF_HOUSE_H */
diff --git a/src/newgrf_sound.cpp b/src/newgrf_sound.cpp
index 136ea84a3..8064546fe 100644
--- a/src/newgrf_sound.cpp
+++ b/src/newgrf_sound.cpp
@@ -66,3 +66,12 @@ bool PlayVehicleSound(const Vehicle *v, VehicleSoundEvent event)
if (callback < GetNumSounds()) SndPlayVehicleFx((SoundFx)callback, v);
return true;
}
+
+bool PlayHouseSound(uint16 sound_id, TileIndex tile)
+{
+ if (sound_id < GetNumOriginalSounds()) {
+ SndPlayTileFx((SoundFx)sound_id, tile);
+ return true;
+ }
+ return false;
+}
diff --git a/src/newgrf_sound.h b/src/newgrf_sound.h
index 61f7df12e..3b52d68cb 100644
--- a/src/newgrf_sound.h
+++ b/src/newgrf_sound.h
@@ -21,5 +21,6 @@ void InitializeSoundPool();
FileEntry *GetSound(uint index);
uint GetNumSounds();
bool PlayVehicleSound(const Vehicle *v, VehicleSoundEvent event);
+bool PlayHouseSound(uint16 sound_id, TileIndex tile);
#endif /* NEWGRF_SOUND_H */
diff --git a/src/newgrf_spritegroup.cpp b/src/newgrf_spritegroup.cpp
index b73377dd0..fcde3cc28 100644
--- a/src/newgrf_spritegroup.cpp
+++ b/src/newgrf_spritegroup.cpp
@@ -8,6 +8,7 @@
#include "newgrf_callbacks.h"
#include "newgrf_spritegroup.h"
#include "date.h"
+#include "sprite.h"
static void SpriteGroupPoolCleanBlock(uint start_item, uint end_item);
@@ -33,6 +34,11 @@ static void DestroySpriteGroup(SpriteGroup *group)
free((SpriteGroup**)group->g.random.groups);
break;
+ case SGT_TILELAYOUT:
+ free((void*)group->g.layout.dts->seq);
+ free(group->g.layout.dts);
+ break;
+
default:
break;
}
diff --git a/src/newgrf_spritegroup.h b/src/newgrf_spritegroup.h
index cbd79a97d..bf1c54fe5 100644
--- a/src/newgrf_spritegroup.h
+++ b/src/newgrf_spritegroup.h
@@ -3,6 +3,7 @@
#ifndef NEWGRF_SPRITEGROUP_H
#define NEWGRF_SPRITEGROUP_H
+#include "town.h"
struct SpriteGroup;
@@ -128,6 +129,11 @@ struct ResultSpriteGroup {
byte num_sprites;
};
+struct TileLayoutSpriteGroup {
+ byte num_sprites; /* Number of sprites in the spriteset, used for loading stages */
+ struct DrawTileSprites *dts;
+};
+
/* List of different sprite group types */
enum SpriteGroupType {
SGT_INVALID,
@@ -136,6 +142,7 @@ enum SpriteGroupType {
SGT_RANDOMIZED,
SGT_CALLBACK,
SGT_RESULT,
+ SGT_TILELAYOUT,
};
/* Common wrapper for all the different sprite group types */
@@ -148,6 +155,7 @@ struct SpriteGroup {
RandomizedSpriteGroup random;
CallbackResultSpriteGroup callback;
ResultSpriteGroup result;
+ TileLayoutSpriteGroup layout;
} g;
};
@@ -180,6 +188,11 @@ struct ResolverObject {
const struct StationSpec *statspec;
CargoID cargo_type;
} station;
+ struct {
+ TileIndex tile;
+ Town *town;
+ HouseID house_id;
+ } house;
} u;
uint32 (*GetRandomBits)(const struct ResolverObject*);
diff --git a/src/newgrf_town.cpp b/src/newgrf_town.cpp
new file mode 100644
index 000000000..497684e59
--- /dev/null
+++ b/src/newgrf_town.cpp
@@ -0,0 +1,91 @@
+/* $Id$ */
+
+/** @file newgrf_town.cpp */
+
+#include "stdafx.h"
+#include "openttd.h"
+#include "debug.h"
+#include "functions.h"
+#include "town.h"
+
+/** This function implements the town variables that newGRF defines.
+ * @param variable that is queried
+ * @param parameter unused
+ * @param available will return false if ever the variable asked for does not exist
+ * @param t is of course the town we are inquiring
+ * @return the value stored in the corresponding variable*/
+uint32 TownGetVariable(byte variable, byte parameter, bool *available, const Town *t)
+{
+ switch (variable) {
+ /* Larger towns */
+ case 0x40: return 1;
+
+ /* Town index */
+ case 0x41: return t->index;
+
+ /* Town properties */
+ case 0x80: return t->xy;
+ case 0x81: return GB(t->xy, 8, 8);
+ case 0x82: return t->population;
+ case 0x83: return GB(t->population, 8, 8);
+ case 0x8A: return t->grow_counter;
+ case 0x92: return t->flags12; // In original game, 0x92 and 0x93 are really one word. Since flags12 is a byte, this is to adjust
+ case 0x93: return 0;
+ case 0x94: return t->radius[0];
+ case 0x95: return GB(t->radius[0], 8, 8);
+ case 0x96: return t->radius[1];
+ case 0x97: return GB(t->radius[1], 8, 8);
+ case 0x98: return t->radius[2];
+ case 0x99: return GB(t->radius[2], 8, 8);
+ case 0x9A: return t->radius[3];
+ case 0x9B: return GB(t->radius[3], 8, 8);
+ case 0x9C: return t->radius[4];
+ case 0x9D: return GB(t->radius[4], 8, 8);
+ case 0x9E: return t->ratings[0];
+ case 0x9F: return t->ratings[1];
+ case 0xA0: return t->ratings[2];
+ case 0xA1: return t->ratings[3];
+ case 0xA2: return t->ratings[4];
+ case 0xA3: return t->ratings[5];
+ case 0xA4: return t->ratings[6];
+ case 0xA5: return t->ratings[7];
+ case 0xA6: return t->ratings[8];
+ case 0xAE: return t->have_ratings;
+ case 0xB2: return t->statues;
+ case 0xB6: return t->num_houses;
+ case 0xB9: return t->growth_rate;
+ case 0xBA: return t->new_max_pass;
+ case 0xBB: return GB(t->new_max_pass, 8, 8);
+ case 0xBC: return t->new_max_mail;
+ case 0xBD: return GB(t->new_max_mail, 8, 8);
+ case 0xBE: return t->new_act_pass;
+ case 0xBF: return GB(t->new_act_pass, 8, 8);
+ case 0xC0: return t->new_act_mail;
+ case 0xC1: return GB(t->new_act_mail, 8, 8);
+ case 0xC2: return t->max_pass;
+ case 0xC3: return GB(t->max_pass, 8, 8);
+ case 0xC4: return t->max_mail;
+ case 0xC5: return GB(t->max_mail, 8, 8);
+ case 0xC6: return t->act_pass;
+ case 0xC7: return GB(t->act_pass, 8, 8);
+ case 0xC8: return t->act_mail;
+ case 0xC9: return GB(t->act_mail, 8, 8);
+ case 0xCA: return t->pct_pass_transported;
+ case 0xCB: return t->pct_mail_transported;
+ case 0xCC: return t->new_act_food;
+ case 0xCD: return GB(t->new_act_food, 8, 8);
+ case 0xCE: return t->new_act_water;
+ case 0xCF: return GB(t->new_act_water, 8, 8);
+ case 0xD0: return t->act_food;
+ case 0xD1: return GB(t->act_food, 8, 8);
+ case 0xD2: return t->act_water;
+ case 0xD3: return GB(t->act_water, 8, 8);
+ case 0xD4: return t->road_build_months;
+ case 0xD5: return t->fund_buildings_months;
+ }
+
+ DEBUG(grf, 1, "Unhandled town property 0x%X", variable);
+
+ *available = false;
+ return (uint32)-1;
+}
diff --git a/src/newgrf_town.h b/src/newgrf_town.h
new file mode 100644
index 000000000..ec53fcc9a
--- /dev/null
+++ b/src/newgrf_town.h
@@ -0,0 +1,13 @@
+/* $Id$ */
+
+/** @file newgrf_town.h */
+
+#ifndef NEWGRF_TOWN_H
+#define NEWGRF_TOWN_H
+
+/* Currently there is no direct town resolver; we only need to get town
+ * variable results from inside stations, house tiles and industry tiles. */
+
+uint32 TownGetVariable(byte variable, byte parameter, bool *available, const Town *t);
+
+#endif /* NEWGRF_TOWN_H */
diff --git a/src/openttd.cpp b/src/openttd.cpp
index 57e99a71a..88a460429 100644
--- a/src/openttd.cpp
+++ b/src/openttd.cpp
@@ -56,6 +56,7 @@
#include "clear_map.h"
#include "fontcache.h"
#include "newgrf_config.h"
+#include "newgrf_house.h"
#include "player_face.h"
#include "bridge_map.h"
@@ -677,6 +678,7 @@ static void MakeNewGame(bool from_heightmap)
_game_mode = GM_NORMAL;
ResetGRFConfig(true);
+ ResetHouseIDMapping();
GenerateWorldSetCallback(&MakeNewGameDone);
GenerateWorld(from_heightmap ? GW_HEIGHTMAP : GW_NEWGAME, 1 << _patches.map_x, 1 << _patches.map_y);
@@ -1756,6 +1758,47 @@ bool AfterLoadGame()
/* do the same as when elrails were enabled/disabled manually just now */
SettingsDisableElrail(_patches.disable_elrails);
+ /* From version 52, the map array was changed for house tiles to allow
+ * space for newhouses grf features. A new byte, m7, was also added. */
+ if (CheckSavegameVersion(52)) {
+ for (TileIndex t = 0; t < map_size; t++) {
+ _me[t].m7 = 0;
+
+ if (IsTileType(t, MP_HOUSE)) {
+ if (GB(_m[t].m3, 6, 2) != TOWN_HOUSE_COMPLETED) {
+ /* Move the construction stage from m3[7..6] to m5[5..4].
+ * The construction counter does not have to move. */
+ SB(_m[t].m5, 3, 2, GB(_m[t].m3, 6, 2));
+ SB(_m[t].m3, 6, 2, 0);
+
+ /* The "house is completed" bit is now in m6[2]. */
+ SetHouseCompleted(t, false);
+ } else {
+ /* The "lift has destination" bit has been moved from
+ * m5[7] to m7[0]. */
+ SB(_me[t].m7, 0, 1, HASBIT(_m[t].m5, 7));
+ CLRBIT(_m[t].m5, 7);
+
+ /* The "lift is moving" bit has been removed, as it does
+ * the same job as the "lift has destination" bit. */
+ CLRBIT(_m[t].m1, 7);
+
+ /* The position of the lift goes from m1[7..0] to m6[7..2],
+ * making m1 totally free, now. The lift position does not
+ * have to be a full byte since the maximum value is 36. */
+ SetLiftPosition(t, GB(_m[t].m1, 0, 6 ));
+
+ _m[t].m1 = 0;
+ _m[t].m3 = 0;
+ SetHouseCompleted(t, true);
+ }
+ }
+ }
+ }
+
+ /* Count the buildings after updating the map array. */
+ AfterLoadCountBuildings();
+
if (CheckSavegameVersion(43)) {
for (TileIndex t = 0; t < map_size; t++) {
if (IsTileType(t, MP_INDUSTRY)) {
@@ -1886,6 +1929,8 @@ void ReloadNewGRFData()
/* update station and waypoint graphics */
AfterLoadWaypoints();
AfterLoadStations();
+ /* check that house ids are still valid */
+ CheckHouseIDs();
/* redraw the whole screen */
MarkWholeScreenDirty();
}
diff --git a/src/table/sprites.h b/src/table/sprites.h
index e9b9c9b69..0301d9f20 100644
--- a/src/table/sprites.h
+++ b/src/table/sprites.h
@@ -35,7 +35,6 @@
* @todo Split the "Sprites" enum into smaller chunks and document them
*/
-
enum Sprites {
SPR_SELECT_TILE = 752,
SPR_DOT = 774, // corner marker for lower/raise land
@@ -1324,6 +1323,7 @@ enum SpriteSetup {
*/
enum Modifiers {
SPRITE_MODIFIER_USE_OFFSET = OFFSET_BIT,
+ SPRITE_MODIFIER_OPAQUE = OFFSET_BIT,
///when a sprite is to be displayed transparently, this bit needs to be set.
PALETTE_MODIFIER_TRANSPARENT = TRANSPARENT_BIT,
///this bit is set when a recoloring process is in action
@@ -1418,6 +1418,5 @@ enum PaletteSprites {
PALETTE_59E = 0x59E,
PALETTE_59F = 0x59F,
};
-#undef PALETTE_RECOLOR_SPRITE
#endif /* SPRITES_H */
diff --git a/src/table/town_land.h b/src/table/town_land.h
index 091b8926a..313c2b2b0 100644
--- a/src/table/town_land.h
+++ b/src/table/town_land.h
@@ -2,17 +2,6 @@
/** @file town_land.h */
-enum {
- HOUSE_TEMP_CHURCH = 0x03,
- HOUSE_STADIUM = 0x14,
- HOUSE_MODERN_STADIUM = 0x20,
- HOUSE_ARCT_CHURCH = 0x3c,
- HOUSE_SNOW_CHURCH = 0x3d,
- HOUSE_TROP_CHURCH = 0x53,
- HOUSE_TOY_CHURCH = 0x5b,
-
- HOUSE_MAX = 110
-};
/** Writes the data into the Town Tile Drawing Struct
* @param s1 The first sprite of the building, mostly the ground sprite
@@ -1790,437 +1779,372 @@ static const DrawBuildingsTileStruct _town_draw_tile_data[] = {
M(0x1244, PAL_NONE, 0x125a, PAL_NONE, 0, 0, 16, 16, 50, 0),
};
#undef M
-// 4 variants * 4 build stages
-assert_compile(lengthof(_town_draw_tile_data) == HOUSE_MAX * 4 * 4);
-
-
-static const StringID _town_tile_names[] = {
- STR_200F_TALL_OFFICE_BLOCK,
- STR_2010_OFFICE_BLOCK,
- STR_2011_SMALL_BLOCK_OF_FLATS,
- STR_2012_CHURCH,
- STR_2013_LARGE_OFFICE_BLOCK,
- STR_2013_LARGE_OFFICE_BLOCK,
- STR_2014_TOWN_HOUSES,
- STR_2015_HOTEL,
- STR_2015_HOTEL,
- STR_2016_STATUE,
- STR_2017_FOUNTAIN,
- STR_2018_PARK,
- STR_2018_PARK,
- STR_2019_OFFICE_BLOCK,
- STR_201A_SHOPS_AND_OFFICES,
- STR_201A_SHOPS_AND_OFFICES,
- STR_201A_SHOPS_AND_OFFICES,
- STR_201B_MODERN_OFFICE_BUILDING,
- STR_201C_WAREHOUSE,
- STR_201D_OFFICE_BLOCK,
- STR_201E_STADIUM,
- STR_201E_STADIUM,
- STR_201E_STADIUM,
- STR_201E_STADIUM,
- STR_201F_OLD_HOUSES,
- STR_2036_COTTAGES,
- STR_2037_HOUSES,
- STR_2038_FLATS,
- STR_2039_TALL_OFFICE_BLOCK,
- STR_203A_SHOPS_AND_OFFICES,
- STR_203B_SHOPS_AND_OFFICES,
- STR_203C_THEATER,
- STR_203D_STADIUM,
- STR_203D_STADIUM,
- STR_203D_STADIUM,
- STR_203D_STADIUM,
- STR_203E_OFFICES,
- STR_203F_HOUSES,
- STR_203F_HOUSES,
- STR_2040_CINEMA,
- STR_2041_SHOPPING_MALL,
- STR_2041_SHOPPING_MALL,
- STR_2041_SHOPPING_MALL,
- STR_2041_SHOPPING_MALL,
- STR_2038_FLATS,
- STR_2038_FLATS,
- STR_203F_HOUSES,
- STR_203F_HOUSES,
- STR_203F_HOUSES,
- STR_203F_HOUSES,
- STR_200F_TALL_OFFICE_BLOCK,
- STR_200F_TALL_OFFICE_BLOCK,
- STR_200F_TALL_OFFICE_BLOCK,
- STR_200F_TALL_OFFICE_BLOCK,
- STR_200F_TALL_OFFICE_BLOCK,
- STR_200F_TALL_OFFICE_BLOCK,
- STR_203F_HOUSES,
- STR_203F_HOUSES,
- STR_201A_SHOPS_AND_OFFICES,
- STR_201A_SHOPS_AND_OFFICES,
- STR_2012_CHURCH,
- STR_2012_CHURCH,
- STR_203F_HOUSES,
- STR_203F_HOUSES,
- STR_201A_SHOPS_AND_OFFICES,
- STR_201A_SHOPS_AND_OFFICES,
- STR_2015_HOTEL,
- STR_2015_HOTEL,
- STR_2015_HOTEL,
- STR_2015_HOTEL,
- STR_201A_SHOPS_AND_OFFICES,
- STR_201A_SHOPS_AND_OFFICES,
- STR_200F_TALL_OFFICE_BLOCK,
- STR_200F_TALL_OFFICE_BLOCK,
- STR_200F_TALL_OFFICE_BLOCK,
- STR_200F_TALL_OFFICE_BLOCK,
- STR_200F_TALL_OFFICE_BLOCK,
- STR_200F_TALL_OFFICE_BLOCK,
- STR_203F_HOUSES,
- STR_203F_HOUSES,
- STR_203F_HOUSES,
- STR_203F_HOUSES,
- STR_2038_FLATS,
- STR_2012_CHURCH,
- STR_203F_HOUSES,
- STR_2038_FLATS,
- STR_2038_FLATS,
- STR_200F_TALL_OFFICE_BLOCK,
- STR_200F_TALL_OFFICE_BLOCK,
- STR_2038_FLATS,
- STR_200F_TALL_OFFICE_BLOCK,
- STR_2012_CHURCH,
- STR_203F_HOUSES,
- STR_203F_HOUSES,
- STR_203F_HOUSES,
- STR_203F_HOUSES,
- STR_203F_HOUSES,
- STR_203F_HOUSES,
- STR_200F_TALL_OFFICE_BLOCK,
- STR_203F_HOUSES,
- STR_203F_HOUSES,
- STR_200F_TALL_OFFICE_BLOCK,
- STR_2059_IGLOO,
- STR_205A_TEPEES,
- STR_201A_SHOPS_AND_OFFICES,
- STR_201A_SHOPS_AND_OFFICES,
- STR_200F_TALL_OFFICE_BLOCK,
- STR_2016_STATUE,
- STR_205B_TEAPOT_HOUSE,
- STR_205C_PIGGY_BANK,
-};
-assert_compile(lengthof(_town_tile_names) == HOUSE_MAX);
-
-static const uint16 _housetype_flags[] = {
- 0x1010, 0x1018, 0x100E, 0x100F, 0x7010, 0x0810, 0x100F, 0x1014,
- 0x0000, 0x7018, 0x7010, 0x1004, 0x1008, 0x1018, 0x101C, 0x101C,
- 0x101C, 0x7010, 0x1010, 0x1010, 0x100F, 0x0000, 0x0000, 0x0000,
- 0x1003, 0x1001, 0x100F, 0x101C, 0x101C, 0x101C, 0x5014, 0x1018,
- 0x700F, 0x0000, 0x0000, 0x0000, 0x7018, 0x2003, 0x0803, 0x101C,
- 0x101E, 0x0000, 0x0000, 0x0000, 0x201C, 0x081C, 0x200F, 0x080F,
- 0x2007, 0x0807, 0x6018, 0x0818, 0x2018, 0x0818, 0x6018, 0x0818,
- 0x2001, 0x0801, 0x201E, 0x081E, 0x200F, 0x080F, 0x2007, 0x0807,
- 0x201C, 0x081C, 0x201C, 0x0000, 0x081C, 0x0000, 0x601C, 0x081C,
- 0x2018, 0x0818, 0x201C, 0x0000, 0x081C, 0x0000, 0x401E, 0x401E,
- 0x401E, 0x4001, 0x401C, 0x400E, 0x401E, 0x401C, 0x401C, 0x4018,
- 0x4000, 0x401C, 0x4018, 0x801F, 0x801F, 0x8003, 0x800F, 0x800F,
- 0x800F, 0x800F, 0x801C, 0x801F, 0x0000, 0x801C, 0x8001, 0x8001,
- 0x801C, 0x801C, 0x801C, 0x801C, 0x801F, 0x801F,
-};
-assert_compile(lengthof(_housetype_flags) == HOUSE_MAX);
-
-static const byte _housetype_extra_flags[] = {
- 0, 0, 0, 0, 32, 32, 0, 8,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 16, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 16, 0, 0, 0, 0, 0, 0, 0,
- 16, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 8, 0, 8, 0, 0, 0,
- 0, 0, 4, 0, 4, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 4,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 8, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0,
-};
-assert_compile(lengthof(_housetype_extra_flags) == HOUSE_MAX);
-
-static const byte _housetype_population[] = {
- 187, 85, 40, 5, 220, 220, 30, 140,
- 0, 0, 0, 0, 0, 150, 95, 95,
- 95, 130, 6, 110, 65, 0, 0, 0,
- 15, 12, 13, 100, 170, 100, 180, 35,
- 65, 0, 0, 0, 140, 15, 15, 35,
- 180, 0, 0, 0, 80, 80, 16, 16,
- 14, 14, 135, 135, 170, 170, 210, 210,
- 10, 10, 25, 25, 6, 6, 17, 17,
- 90, 90, 140, 0, 140, 0, 105, 105,
- 190, 190, 250, 0, 250, 0, 16, 16,
- 16, 7, 45, 8, 18, 90, 120, 250,
- 0, 80, 180, 8, 18, 7, 15, 17,
- 19, 21, 75, 35, 0, 85, 11, 10,
- 67, 86, 95, 30, 25, 18,
-};
-assert_compile(lengthof(_housetype_population) == HOUSE_MAX);
-
-static const byte _housetype_mailamount[] = {
- 70, 55, 20, 2, 85, 85, 12, 22,
- 22, 0, 0, 0, 0, 65, 48, 48,
- 48, 50, 10, 55, 5, 5, 5, 5,
- 6, 7, 8, 35, 50, 40, 64, 23,
- 5, 5, 5, 5, 65, 6, 6, 23,
- 5, 5, 5, 5, 20, 20, 6, 6,
- 6, 6, 60, 60, 70, 70, 80, 80,
- 5, 5, 20, 20, 2, 2, 7, 7,
- 45, 45, 25, 25, 25, 25, 50, 50,
- 75, 75, 60, 60, 60, 60, 6, 6,
- 5, 4, 15, 3, 7, 24, 25, 80,
- 80, 23, 90, 3, 5, 3, 6, 6,
- 6, 6, 20, 9, 0, 18, 3, 3,
- 22, 23, 28, 10, 8, 7,
-};
-assert_compile(lengthof(_housetype_mailamount) == HOUSE_MAX);
-
-static const byte _housetype_remove_cost[] = {
- 150, 140, 100, 90, 160, 160, 80, 180,
- 180, 65, 65, 60, 60, 130, 110, 105,
- 107, 200, 145, 155, 250, 250, 250, 250,
- 70, 75, 71, 135, 145, 132, 155, 220,
- 250, 250, 250, 250, 170, 70, 70, 210,
- 250, 250, 250, 250, 100, 100, 70, 70,
- 80, 80, 150, 150, 170, 170, 200, 200,
- 60, 60, 100, 100, 85, 85, 80, 80,
- 140, 140, 160, 160, 160, 160, 130, 130,
- 190, 190, 140, 140, 140, 140, 80, 80,
- 80, 30, 130, 90, 80, 110, 120, 190,
- 190, 110, 180, 90, 90, 70, 80, 80,
- 80, 80, 160, 90, 90, 150, 60, 60,
- 140, 145, 165, 90, 75, 85,
-};
-assert_compile(lengthof(_housetype_remove_cost) == HOUSE_MAX);
-
-static const uint16 _housetype_remove_ratingmod[] = {
- 140, 130, 90, 230, 160, 160, 80, 150,
- 150, 40, 40, 75, 75, 110, 100, 100,
- 100, 150, 110, 110, 300, 300, 300, 300,
- 75, 75, 75, 100, 170, 135, 180, 230,
- 300, 300, 300, 300, 250, 75, 75, 230,
- 300, 300, 300, 300, 90, 90, 70, 70,
- 70, 70, 120, 120, 130, 130, 140, 140,
- 60, 60, 80, 80, 230, 230, 80, 80,
- 110, 110, 160, 160, 160, 160, 105, 105,
- 135, 135, 200, 200, 200, 200, 80, 80,
- 80, 30, 95, 200, 80, 95, 95, 140,
- 140, 95, 150, 200, 90, 50, 75, 75,
- 75, 75, 130, 80, 80, 130, 45, 45,
- 130, 130, 130, 70, 65, 95,
-};
-assert_compile(lengthof(_housetype_remove_ratingmod) == HOUSE_MAX);
-
-
-struct HousetypeYear {
- Year min, max;
-};
-
-static const HousetypeYear _housetype_years[] = {
- { 1963, MAX_YEAR },
- { 1957, MAX_YEAR },
- { 1968, MAX_YEAR },
- { 0, MAX_YEAR },
- { 1975, MAX_YEAR },
- { 1975, MAX_YEAR },
- { 0, MAX_YEAR },
- { 1959, MAX_YEAR },
- { 1959, MAX_YEAR },
- { 1945, MAX_YEAR },
- { 1945, MAX_YEAR },
- { 0, MAX_YEAR },
- { 1935, MAX_YEAR },
- { 1951, MAX_YEAR },
- { 1930, 1960 },
- { 1930, 1960 },
- { 1930, 1960 },
- { 1977, MAX_YEAR },
- { 1983, MAX_YEAR },
- { 1985, MAX_YEAR },
- { 0, MAX_YEAR },
- { 0, MAX_YEAR },
- { 0, MAX_YEAR },
- { 0, MAX_YEAR },
- { 0, 1951 },
- { 0, 1952 },
- { 1931, MAX_YEAR },
- { 1935, MAX_YEAR },
- { 1963, MAX_YEAR },
- { 0, 1955 },
- { 1973, MAX_YEAR },
- { 0, MAX_YEAR },
- { 1958, MAX_YEAR },
- { 1958, MAX_YEAR },
- { 1958, MAX_YEAR },
- { 1958, MAX_YEAR },
- { 2000, MAX_YEAR },
- { 0, 1960 },
- { 0, 1960 },
- { 1945, MAX_YEAR },
- { 1983, MAX_YEAR },
- { 1983, MAX_YEAR },
- { 1983, MAX_YEAR },
- { 1983, MAX_YEAR },
- { 0, MAX_YEAR },
- { 0, MAX_YEAR },
- { 0, MAX_YEAR },
- { 0, MAX_YEAR },
- { 0, 1963 },
- { 0, 1963 },
- { 1966, MAX_YEAR },
- { 1966, MAX_YEAR },
- { 1970, MAX_YEAR },
- { 1970, MAX_YEAR },
- { 1974, MAX_YEAR },
- { 1974, MAX_YEAR },
- { 0, MAX_YEAR },
- { 0, MAX_YEAR },
- { 0, MAX_YEAR },
- { 0, MAX_YEAR },
- { 0, MAX_YEAR },
- { 0, MAX_YEAR },
- { 0, MAX_YEAR },
- { 0, MAX_YEAR },
- { 0, 1960 },
- { 0, 1960 },
- { 1972, MAX_YEAR },
- { 1972, MAX_YEAR },
- { 1972, MAX_YEAR },
- { 1972, MAX_YEAR },
- { 1963, MAX_YEAR },
- { 1963, MAX_YEAR },
- { 1978, MAX_YEAR },
- { 1978, MAX_YEAR },
- { 1967, MAX_YEAR },
- { 1967, MAX_YEAR },
- { 1967, MAX_YEAR },
- { 1967, MAX_YEAR },
- { 0, MAX_YEAR },
- { 0, MAX_YEAR },
- { 0, MAX_YEAR },
- { 0, MAX_YEAR },
- { 0, MAX_YEAR },
- { 0, MAX_YEAR },
- { 0, MAX_YEAR },
- { 1973, MAX_YEAR },
- { 1962, MAX_YEAR },
- { 1984, MAX_YEAR },
- { 1984, MAX_YEAR },
- { 0, MAX_YEAR },
- { 1993, MAX_YEAR },
- { 0, MAX_YEAR },
- { 0, MAX_YEAR },
- { 0, MAX_YEAR },
- { 0, MAX_YEAR },
- { 0, MAX_YEAR },
- { 0, MAX_YEAR },
- { 0, MAX_YEAR },
- { 0, MAX_YEAR },
- { 0, MAX_YEAR },
- { 0, MAX_YEAR },
- { 0, MAX_YEAR },
- { 0, MAX_YEAR },
- { 0, MAX_YEAR },
- { 0, MAX_YEAR },
- { 0, MAX_YEAR },
- { 0, MAX_YEAR },
- { 0, MAX_YEAR },
- { 0, MAX_YEAR },
- { 0, MAX_YEAR },
-};
-assert_compile(lengthof(_housetype_years) == HOUSE_MAX);
-
-static const byte _housetype_cargo_passengers[] = {
- 8, 8, 8, 2, 10, 10, 4, 6,
- 6, 2, 2, 2, 2, 8, 6, 6,
- 6, 10, 6, 6, 4, 4, 4, 4,
- 3, 3, 3, 7, 8, 6, 8, 8,
- 4, 4, 4, 4, 8, 3, 3, 8,
- 8, 8, 8, 8, 5, 5, 3, 3,
- 3, 3, 8, 8, 9, 9, 10, 10,
- 2, 2, 3, 3, 2, 2, 3, 3,
- 6, 6, 6, 6, 6, 6, 7, 7,
- 9, 9, 7, 7, 7, 7, 3, 3,
- 3, 3, 6, 2, 3, 6, 6, 8,
- 8, 6, 8, 2, 6, 3, 3, 3,
- 3, 3, 8, 4, 4, 8, 3, 3,
- 8, 8, 8, 4, 3, 3,
-};
-assert_compile(lengthof(_housetype_cargo_passengers) == HOUSE_MAX);
+/* 4 variants * 4 build stages */
+assert_compile(lengthof(_town_draw_tile_data) == (NEW_HOUSE_OFFSET) * 4 * 4);
-static const byte _housetype_cargo_mail[] = {
- 3, 3, 3, 0, 4, 4, 1, 1,
- 1, 0, 0, 0, 0, 2, 2, 2,
- 2, 3, 3, 2, 0, 0, 0, 0,
- 1, 1, 1, 2, 3, 2, 3, 2,
- 0, 0, 0, 0, 3, 1, 1, 2,
- 2, 2, 2, 2, 2, 2, 1, 1,
- 1, 1, 3, 3, 3, 3, 3, 3,
- 1, 1, 1, 1, 0, 0, 1, 1,
- 2, 2, 1, 1, 1, 1, 2, 2,
- 3, 3, 2, 2, 2, 2, 1, 1,
- 1, 1, 2, 0, 1, 2, 2, 3,
- 3, 2, 3, 0, 2, 1, 1, 1,
- 1, 1, 4, 1, 1, 4, 1, 1,
- 4, 4, 4, 1, 1, 2,
-};
-assert_compile(lengthof(_housetype_cargo_mail) == HOUSE_MAX);
-
-static const byte _housetype_cargo_goods[] = {
- 4, 4, 1, 0, 6, 6, 0, 2,
- 2, 0, 0, 0, 0, 4, 3, 3,
- 3, 6, 8, 6, 0, 0, 0, 0,
- 0, 0, 0, 2, 3, 3, 3, 2,
- 0, 0, 0, 0, 2, 0, 0, 2,
- 3, 3, 3, 3, 0, 0, 0, 0,
- 0, 0, 4, 4, 4, 4, 5, 5,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 3, 3, 0, 2, 0, 2, 3, 3,
- 4, 4, 2, 2, 2, 2, 0, 0,
- 0, 0, 1, 0, 0, 1, 1, 4,
- 4, 1, 4, 0, 2, 1, 2, 2,
- 2, 2, 2, 2, 2, 2, 1, 1,
- 0, 0, 2, 2, 2, 0
-};
-assert_compile(lengthof(_housetype_cargo_goods) == HOUSE_MAX);
-
-static const byte _housetype_cargo_food[] = {
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 1, 1, 0,
- 0, 0, 0, 0, 2, 2, 2, 2,
- 2, 2, 0, 0, 0, 0, 0, 0,
- 1, 1, 1, 1, 0, 0, 1, 1,
- 0, 0, 3, 0, 3, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 2, 2,
- 2, 1, 0, 0, 2, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 4, 4, 0, 0, 0, 4
-};
-assert_compile(lengthof(_housetype_cargo_food) == HOUSE_MAX);
-
-static const byte _house_more_flags[] = {
- 8, 8, 8, 8, 8, 8, 8, 12,
- 0, 8, 8, 8, 8, 8, 8, 8,
- 8, 8, 8, 8, 15, 0, 0, 0,
- 8, 8, 8, 8, 8, 8, 8, 8,
- 15, 0, 0, 0, 8, 8, 8, 8,
- 15, 0, 0, 0, 8, 8, 8, 8,
- 8, 8, 8, 8, 8, 8, 8, 8,
- 8, 8, 8, 8, 8, 8, 8, 8,
- 8, 8, 12, 0, 12, 0, 8, 8,
- 8, 8, 10, 0, 10, 0, 8, 8,
- 8, 8, 8, 8, 8, 8, 8, 10,
- 0, 8, 8, 8, 8, 8, 8, 8,
- 8, 8, 8, 12, 0, 8, 8, 8,
- 8, 8, 8, 8, 8, 8,
+/** Describes the data that defines each house in the game
+ * @param mnd introduction year of the house
+ * @param mxd last year it can be built
+ * @param p population
+ * @param rc cost multiplier for removing it
+ * @param bn building name
+ * @param rr rating decrease if removed
+ * @param mg mail generation multiplier
+ * @param pa passenger acceptance
+ * @param ma mail acceptance
+ * @param ga goods acceptance
+ * @param fa food acceptance
+ * @param bf building flags (size, stadium etc...)
+ * @param ba building availability (zone, climate...)
+ * @see HouseSpec
+ */
+#define M(mnd, mxd, p, rc, bn, rr, mg, pa, ma, ga, fa, bf, ba) \
+ {mnd, mxd, p, rc, bn, rr, mg, pa, ma, ga, fa, bf, ba, true, \
+ 0, NULL, 0, 0, {0, 0, 0, 0}, 16, NO_EXTRA_FLAG, HOUSE_NO_CLASS, 0, 2, 0, 0, NULL}
+static const HouseSpec _original_house_specs[] = {
+ /**
+ * remove_rating_decrease
+ * | mail_generation
+ * min_date | | passenger_acceptance
+ * | max_date | | | mail_acceptance
+ * | | population | | | | goods_acceptance
+ * | | | removal_cost | | | | | food_acceptance
+ * | | | | building_name | | | | | |
+ * | | | | | | | | | | |
+ * | | | | | | | | | | |
+ * +-building_flags | | | | | | | | |
+ * +-building_availability | | | | | | | |
+ * | | | | | | | | | | | |*/
+ M( 1963, MAX_YEAR, 187, 150, STR_200F_TALL_OFFICE_BLOCK, 140, 70, 8, 3, 4, 0,
+ TILE_SIZE_1x1,
+ HZ_TEMP | HZ_ZON5),
+ M( 1957, MAX_YEAR, 85, 140, STR_2010_OFFICE_BLOCK, 130, 55, 8, 3, 4, 0,
+ TILE_SIZE_1x1,
+ HZ_TEMP | HZ_ZON5 | HZ_ZON4),
+ M( 1968, MAX_YEAR, 40, 100, STR_2011_SMALL_BLOCK_OF_FLATS, 90, 20, 8, 3, 1, 0,
+ TILE_SIZE_1x1,
+ HZ_TEMP | HZ_ZON4 | HZ_ZON3 | HZ_ZON2),
+ M( 0, MAX_YEAR, 5, 90, STR_2012_CHURCH, 230, 2, 2, 0, 0, 0,
+ BUILDING_IS_CHURCH | TILE_SIZE_1x1,
+ HZ_TEMP | HZ_ZON4 | HZ_ZON3 | HZ_ZON2 | HZ_ZON1),
+ M( 1975, MAX_YEAR, 220, 160, STR_2013_LARGE_OFFICE_BLOCK, 160, 85, 10, 4, 6, 0,
+ BUILDING_IS_ANIMATED | TILE_SIZE_1x1,
+ HZ_TEMP | HZ_SUBARTC_BELOW | HZ_SUBTROPIC | HZ_ZON5),
+ M( 1975, MAX_YEAR, 220, 160, STR_2013_LARGE_OFFICE_BLOCK, 160, 85, 10, 4, 6, 0,
+ BUILDING_IS_ANIMATED | TILE_SIZE_1x1,
+ HZ_SUBARTC_ABOVE | HZ_ZON5),
+ M( 0, MAX_YEAR, 30, 80, STR_2014_TOWN_HOUSES, 80, 12, 4, 1, 0, 0,
+ TILE_SIZE_1x1,
+ HZ_TEMP | HZ_ZON4 | HZ_ZON3 | HZ_ZON2 | HZ_ZON1),
+ M( 1959, MAX_YEAR, 140, 180, STR_2015_HOTEL, 150, 22, 6, 1, 2, 0,
+ TILE_SIZE_1x2,
+ HZ_TEMP | HZ_ZON5 | HZ_ZON3),
+ M( 1959, MAX_YEAR, 0, 180, STR_2015_HOTEL, 150, 22, 6, 1, 2, 0,
+ TILE_NO_FLAG,
+ HZ_NOZNS),
+ M( 1945, MAX_YEAR, 0, 65, STR_2016_STATUE, 40, 0, 2, 0, 0, 0,
+ TILE_SIZE_1x1,
+ HZ_TEMP | HZ_SUBARTC_BELOW | HZ_SUBTROPIC | HZ_ZON5 | HZ_ZON4),
+ M( 1945, MAX_YEAR, 0, 65, STR_2017_FOUNTAIN, 40, 0, 2, 0, 0, 0,
+ TILE_SIZE_1x1,
+ HZ_TEMP | HZ_SUBARTC_BELOW | HZ_SUBTROPIC | HZ_ZON5),
+ M( 0, MAX_YEAR, 0, 60, STR_2018_PARK, 75, 0, 2, 0, 0, 0,
+ TILE_SIZE_1x1,
+ HZ_TEMP | HZ_ZON3),
+ M( 1935, MAX_YEAR, 0, 60, STR_2018_PARK, 75, 0, 2, 0, 0, 0,
+ TILE_SIZE_1x1,
+ HZ_TEMP | HZ_ZON4),
+ M( 1951, MAX_YEAR, 150, 130, STR_2019_OFFICE_BLOCK, 110, 65, 8, 2, 4, 0,
+ TILE_SIZE_1x1,
+ HZ_TEMP | HZ_ZON5 | HZ_ZON4),
+ M( 1930, 1960, 95, 110, STR_201A_SHOPS_AND_OFFICES, 100, 48, 6, 2, 3, 0,
+ TILE_SIZE_1x1,
+ HZ_TEMP | HZ_ZON5 | HZ_ZON4 | HZ_ZON3),
+ M( 1930, 1960, 95, 105, STR_201A_SHOPS_AND_OFFICES, 100, 48, 6, 2, 3, 0,
+ TILE_SIZE_1x1,
+ HZ_TEMP | HZ_ZON5 | HZ_ZON4 | HZ_ZON3),
+ M( 1930, 1960, 95, 107, STR_201A_SHOPS_AND_OFFICES, 100, 48, 6, 2, 3, 0,
+ TILE_SIZE_1x1,
+ HZ_TEMP | HZ_ZON5 | HZ_ZON4 | HZ_ZON3),
+ M( 1977, MAX_YEAR, 130, 200, STR_201B_MODERN_OFFICE_BUILDING, 150, 50, 10, 3, 6, 0,
+ TILE_SIZE_1x1,
+ HZ_TEMP | HZ_SUBARTC_BELOW | HZ_SUBTROPIC | HZ_ZON5),
+ M( 1983, MAX_YEAR, 6, 145, STR_201C_WAREHOUSE, 110, 10, 6, 3, 8, 0,
+ TILE_SIZE_1x1,
+ HZ_TEMP | HZ_ZON5),
+ M( 1985, MAX_YEAR, 110, 155, STR_201D_OFFICE_BLOCK, 110, 55, 6, 2, 6, 0,
+ TILE_SIZE_1x1,
+ HZ_TEMP | HZ_ZON5),
+ M( 0, MAX_YEAR, 65, 250, STR_201E_STADIUM, 300, 5, 4, 0, 0, 0,
+ BUILDING_IS_STADIUM | TILE_SIZE_2x2,
+ HZ_TEMP | HZ_ZON4 | HZ_ZON3 | HZ_ZON2 | HZ_ZON1),
+ M( 0, MAX_YEAR, 0, 250, STR_201E_STADIUM, 300, 5, 4, 0, 0, 0,
+ TILE_NO_FLAG,
+ HZ_NOZNS),
+ M( 0, MAX_YEAR, 0, 250, STR_201E_STADIUM, 300, 5, 4, 0, 0, 0,
+ TILE_NO_FLAG,
+ HZ_NOZNS),
+ M( 0, MAX_YEAR, 0, 250, STR_201E_STADIUM, 300, 5, 4, 0, 0, 0,
+ TILE_NO_FLAG,
+ HZ_NOZNS),
+ M( 0, 1951, 15, 70, STR_201F_OLD_HOUSES, 75, 6, 3, 1, 0, 0,
+ TILE_SIZE_1x1,
+ HZ_TEMP | HZ_ZON2 | HZ_ZON1),
+ M( 0, 1952, 12, 75, STR_2036_COTTAGES, 75, 7, 3, 1, 0, 0,
+ TILE_SIZE_1x1,
+ HZ_TEMP | HZ_ZON1),
+ M( 1931, MAX_YEAR, 13, 71, STR_2037_HOUSES, 75, 8, 3, 1, 0, 0,
+ TILE_SIZE_1x1,
+ HZ_TEMP | HZ_ZON4 | HZ_ZON3 | HZ_ZON2 | HZ_ZON1),
+ M( 1935, MAX_YEAR, 100, 135, STR_2038_FLATS, 100, 35, 7, 2, 2, 0,
+ TILE_SIZE_1x1,
+ HZ_TEMP | HZ_ZON5 | HZ_ZON4 | HZ_ZON3),
+ M( 1963, MAX_YEAR, 170, 145, STR_2039_TALL_OFFICE_BLOCK, 170, 50, 8, 3, 3, 0,
+ TILE_SIZE_1x1,
+ HZ_TEMP | HZ_ZON5 | HZ_ZON4 | HZ_ZON3),
+ M( 0, 1955, 100, 132, STR_203A_SHOPS_AND_OFFICES, 135, 40, 6, 2, 3, 0,
+ TILE_SIZE_1x1,
+ HZ_TEMP | HZ_ZON5 | HZ_ZON4 | HZ_ZON3),
+ M( 1973, MAX_YEAR, 180, 155, STR_203B_SHOPS_AND_OFFICES, 180, 64, 8, 3, 3, 0,
+ TILE_SIZE_1x1,
+ HZ_TEMP | HZ_SUBTROPIC | HZ_ZON5 | HZ_ZON3),
+ M( 0, MAX_YEAR, 35, 220, STR_203C_THEATER, 230, 23, 8, 2, 2, 0,
+ TILE_SIZE_1x1,
+ HZ_TEMP | HZ_ZON5 | HZ_ZON4),
+ M( 1958, MAX_YEAR, 65, 250, STR_203D_STADIUM, 300, 5, 4, 0, 0, 0,
+ BUILDING_IS_STADIUM | TILE_SIZE_2x2,
+ HZ_TEMP | HZ_SUBARTC_BELOW | HZ_SUBTROPIC | HZ_ZON4 | HZ_ZON3 | HZ_ZON2 | HZ_ZON1),
+ M( 1958, MAX_YEAR, 0, 250, STR_203D_STADIUM, 300, 5, 4, 0, 0, 0,
+ TILE_NO_FLAG,
+ HZ_NOZNS),
+ M( 1958, MAX_YEAR, 0, 250, STR_203D_STADIUM, 300, 5, 4, 0, 0, 0,
+ TILE_NO_FLAG,
+ HZ_NOZNS),
+ M( 1958, MAX_YEAR, 0, 250, STR_203D_STADIUM, 300, 5, 4, 0, 0, 0,
+ TILE_NO_FLAG,
+ HZ_NOZNS),
+ M( 2000, MAX_YEAR, 140, 170, STR_203E_OFFICES, 250, 65, 8, 3, 2, 0,
+ TILE_SIZE_1x1,
+ HZ_TEMP | HZ_SUBARTC_BELOW | HZ_SUBTROPIC | HZ_ZON5 | HZ_ZON4),
+ M( 0, 1960, 15, 70, STR_203F_HOUSES, 75, 6, 3, 1, 0, 1,
+ TILE_SIZE_1x1,
+ HZ_SUBARTC_BELOW | HZ_ZON2 | HZ_ZON1),
+ M( 0, 1960, 15, 70, STR_203F_HOUSES, 75, 6, 3, 1, 0, 1,
+ TILE_SIZE_1x1,
+ HZ_SUBARTC_ABOVE | HZ_ZON2 | HZ_ZON1),
+ M( 1945, MAX_YEAR, 35, 210, STR_2040_CINEMA, 230, 23, 8, 2, 2, 0,
+ TILE_SIZE_1x1,
+ HZ_TEMP | HZ_ZON5 | HZ_ZON4 | HZ_ZON3),
+ M( 1983, MAX_YEAR, 180, 250, STR_2041_SHOPPING_MALL, 300, 5, 8, 2, 3, 0,
+ TILE_SIZE_2x2,
+ HZ_TEMP | HZ_ZON5 | HZ_ZON4 | HZ_ZON3 |HZ_ZON2),
+ M( 1983, MAX_YEAR, 0, 250, STR_2041_SHOPPING_MALL, 300, 5, 8, 2, 3, 0,
+ TILE_NO_FLAG,
+ HZ_NOZNS),
+ M( 1983, MAX_YEAR, 0, 250, STR_2041_SHOPPING_MALL, 300, 5, 8, 2, 3, 0,
+ TILE_NO_FLAG,
+ HZ_NOZNS),
+ M( 1983, MAX_YEAR, 0, 250, STR_2041_SHOPPING_MALL, 300, 5, 8, 2, 3, 0,
+ TILE_NO_FLAG,
+ HZ_NOZNS),
+ M( 0, MAX_YEAR, 80, 100, STR_2038_FLATS, 90, 20, 5, 2, 0, 2,
+ TILE_SIZE_1x1,
+ HZ_SUBARTC_BELOW | HZ_ZON5 | HZ_ZON4 | HZ_ZON3),
+ M( 0, MAX_YEAR, 80, 100, STR_2038_FLATS, 90, 20, 5, 2, 0, 2,
+ TILE_SIZE_1x1,
+ HZ_SUBARTC_ABOVE | HZ_ZON5 | HZ_ZON4 | HZ_ZON3),
+ M( 0, MAX_YEAR, 16, 70, STR_203F_HOUSES, 70, 6, 3, 1, 0, 2,
+ TILE_SIZE_1x1,
+ HZ_SUBARTC_BELOW | HZ_ZON4 | HZ_ZON3 | HZ_ZON2 | HZ_ZON1),
+ M( 0, MAX_YEAR, 16, 70, STR_203F_HOUSES, 70, 6, 3, 1, 0, 2,
+ TILE_SIZE_1x1,
+ HZ_SUBARTC_ABOVE | HZ_ZON4 | HZ_ZON3 | HZ_ZON2 | HZ_ZON1),
+ M( 0, 1963, 14, 80, STR_203F_HOUSES, 70, 6, 3, 1, 0, 2,
+ TILE_SIZE_1x1,
+ HZ_SUBARTC_BELOW | HZ_ZON3 | HZ_ZON2 | HZ_ZON1),
+ M( 0, 1963, 14, 80, STR_203F_HOUSES, 70, 6, 3, 1, 0, 2,
+ TILE_SIZE_1x1,
+ HZ_SUBARTC_ABOVE | HZ_ZON3 | HZ_ZON2 | HZ_ZON1),
+ M( 1966, MAX_YEAR, 135, 150, STR_200F_TALL_OFFICE_BLOCK, 120, 60, 8, 3, 4, 0,
+ TILE_SIZE_1x1,
+ HZ_SUBARTC_BELOW | HZ_SUBTROPIC | HZ_ZON5 | HZ_ZON4),
+ M( 1966, MAX_YEAR, 135, 150, STR_200F_TALL_OFFICE_BLOCK, 120, 60, 8, 3, 4, 0,
+ TILE_SIZE_1x1,
+ HZ_SUBARTC_ABOVE | HZ_ZON5 | HZ_ZON4),
+ M( 1970, MAX_YEAR, 170, 170, STR_200F_TALL_OFFICE_BLOCK, 130, 70, 9, 3, 4, 0,
+ TILE_SIZE_1x1,
+ HZ_SUBARTC_BELOW | HZ_ZON5 | HZ_ZON4),
+ M( 1970, MAX_YEAR, 170, 170, STR_200F_TALL_OFFICE_BLOCK, 130, 70, 9, 3, 4, 0,
+ TILE_SIZE_1x1,
+ HZ_SUBARTC_ABOVE | HZ_ZON5 | HZ_ZON4),
+ M( 1974, MAX_YEAR, 210, 200, STR_200F_TALL_OFFICE_BLOCK, 140, 80, 10, 3, 5, 0,
+ TILE_SIZE_1x1,
+ HZ_SUBARTC_BELOW | HZ_SUBTROPIC | HZ_ZON5 | HZ_ZON4),
+ M( 1974, MAX_YEAR, 210, 200, STR_200F_TALL_OFFICE_BLOCK, 140, 80, 10, 3, 5, 0,
+ TILE_SIZE_1x1,
+ HZ_SUBARTC_ABOVE | HZ_ZON5 | HZ_ZON4),
+ M( 0, MAX_YEAR, 10, 60, STR_203F_HOUSES, 60, 5, 2, 1, 0, 1,
+ TILE_SIZE_1x1,
+ HZ_SUBARTC_BELOW | HZ_ZON1),
+ M( 0, MAX_YEAR, 10, 60, STR_203F_HOUSES, 60, 5, 2, 1, 0, 1,
+ TILE_SIZE_1x1,
+ HZ_SUBARTC_ABOVE | HZ_ZON1),
+ M( 0, MAX_YEAR, 25, 100, STR_201A_SHOPS_AND_OFFICES, 80, 20, 3, 1, 0, 1,
+ TILE_SIZE_1x1,
+ HZ_SUBARTC_BELOW | HZ_ZON5 | HZ_ZON4 | HZ_ZON3 | HZ_ZON2),
+ M( 0, MAX_YEAR, 25, 100, STR_201A_SHOPS_AND_OFFICES, 80, 20, 3, 1, 0, 1,
+ TILE_SIZE_1x1,
+ HZ_SUBARTC_ABOVE | HZ_ZON5 | HZ_ZON4 | HZ_ZON3 | HZ_ZON2),
+ M( 0, MAX_YEAR, 6, 85, STR_2012_CHURCH, 230, 2, 2, 0, 0, 0,
+ BUILDING_IS_CHURCH | TILE_SIZE_1x1,
+ HZ_SUBARTC_BELOW | HZ_ZON4 | HZ_ZON3 | HZ_ZON2 | HZ_ZON1),
+ M( 0, MAX_YEAR, 6, 85, STR_2012_CHURCH, 230, 2, 2, 0, 0, 0,
+ BUILDING_IS_CHURCH | TILE_SIZE_1x1,
+ HZ_SUBARTC_ABOVE | HZ_ZON4 | HZ_ZON3 | HZ_ZON2 | HZ_ZON1),
+ M( 0, MAX_YEAR, 17, 80, STR_203F_HOUSES, 80, 7, 3, 1, 0, 1,
+ TILE_SIZE_1x1,
+ HZ_SUBARTC_BELOW | HZ_ZON3 | HZ_ZON2 | HZ_ZON1),
+ M( 0, MAX_YEAR, 17, 80, STR_203F_HOUSES, 80, 7, 3, 1, 0, 1,
+ TILE_SIZE_1x1,
+ HZ_SUBARTC_ABOVE | HZ_ZON3 | HZ_ZON2 | HZ_ZON1),
+ M( 0, 1960, 90, 140, STR_201A_SHOPS_AND_OFFICES, 110, 45, 6, 2, 3, 0,
+ TILE_SIZE_1x1,
+ HZ_SUBARTC_BELOW| HZ_ZON5 | HZ_ZON4 | HZ_ZON3),
+ M( 0, 1960, 90, 140, STR_201A_SHOPS_AND_OFFICES, 110, 45, 6, 2, 3, 0,
+ TILE_SIZE_1x1,
+ HZ_SUBARTC_ABOVE| HZ_ZON5 | HZ_ZON4 | HZ_ZON3),
+ M( 1972, MAX_YEAR, 140, 160, STR_2015_HOTEL, 160, 25, 6, 1, 0, 3,
+ TILE_SIZE_1x2,
+ HZ_SUBARTC_BELOW| HZ_ZON5 | HZ_ZON4 | HZ_ZON3),
+ M( 1972, MAX_YEAR, 0, 160, STR_2015_HOTEL, 160, 25, 6, 1, 2, 0,
+ TILE_NO_FLAG,
+ HZ_NOZNS),
+ M( 1972, MAX_YEAR, 140, 160, STR_2015_HOTEL, 160, 25, 6, 1, 0, 3,
+ TILE_SIZE_1x2,
+ HZ_SUBARTC_ABOVE| HZ_ZON5 | HZ_ZON4 | HZ_ZON3),
+ M( 1972, MAX_YEAR, 0, 160, STR_2015_HOTEL, 160, 25, 6, 1, 2, 0,
+ TILE_NO_FLAG,
+ HZ_NOZNS),
+ M( 1963, MAX_YEAR, 105, 130, STR_201A_SHOPS_AND_OFFICES, 105, 50, 7, 2, 3, 0,
+ TILE_SIZE_1x1,
+ HZ_SUBARTC_BELOW | HZ_SUBTROPIC | HZ_ZON5 | HZ_ZON4 | HZ_ZON3),
+ M( 1963, MAX_YEAR, 105, 130, STR_201A_SHOPS_AND_OFFICES, 105, 50, 7, 2, 3, 0,
+ TILE_SIZE_1x1,
+ HZ_SUBARTC_ABOVE| HZ_ZON5 | HZ_ZON4 | HZ_ZON3),
+ M( 1978, MAX_YEAR, 190, 190, STR_200F_TALL_OFFICE_BLOCK, 135, 75, 9, 3, 4, 0,
+ TILE_SIZE_1x1,
+ HZ_SUBARTC_BELOW | HZ_ZON5 | HZ_ZON4),
+ M( 1978, MAX_YEAR, 190, 190, STR_200F_TALL_OFFICE_BLOCK, 135, 75, 9, 3, 4, 0,
+ TILE_SIZE_1x1,
+ HZ_SUBARTC_ABOVE | HZ_ZON5 | HZ_ZON4),
+ M( 1967, MAX_YEAR, 250, 140, STR_200F_TALL_OFFICE_BLOCK, 200, 60, 7, 2, 2, 0,
+ TILE_SIZE_2x1,
+ HZ_SUBARTC_BELOW| HZ_ZON5 | HZ_ZON4 | HZ_ZON3),
+ M( 1967, MAX_YEAR, 0, 140, STR_200F_TALL_OFFICE_BLOCK, 200, 60, 7, 2, 2, 0,
+ TILE_NO_FLAG,
+ HZ_NOZNS),
+ M( 1967, MAX_YEAR, 250, 140, STR_200F_TALL_OFFICE_BLOCK, 200, 60, 7, 2, 2, 0,
+ TILE_SIZE_2x1,
+ HZ_SUBARTC_ABOVE | HZ_ZON5 | HZ_ZON4 | HZ_ZON3),
+ M( 1967, MAX_YEAR, 0, 140, STR_200F_TALL_OFFICE_BLOCK, 200, 60, 7, 2, 2, 0,
+ TILE_NO_FLAG,
+ HZ_NOZNS),
+ M( 0, MAX_YEAR, 16, 80, STR_203F_HOUSES, 80, 6, 3, 1, 0, 2,
+ TILE_SIZE_1x1,
+ HZ_SUBTROPIC | HZ_ZON5 | HZ_ZON4 | HZ_ZON3 | HZ_ZON2),
+ M( 0, MAX_YEAR, 16, 80, STR_203F_HOUSES, 80, 6, 3, 1, 0, 2,
+ TILE_SIZE_1x1,
+ HZ_SUBTROPIC | HZ_ZON5 | HZ_ZON4 | HZ_ZON3 | HZ_ZON2),
+ M( 0, MAX_YEAR, 16, 80, STR_203F_HOUSES, 80, 5, 3, 1, 0, 2,
+ TILE_SIZE_1x1,
+ HZ_SUBTROPIC | HZ_ZON5 | HZ_ZON4 | HZ_ZON3 | HZ_ZON2),
+ M( 0, MAX_YEAR, 7, 30, STR_203F_HOUSES, 30, 4, 3, 1, 0, 1,
+ TILE_SIZE_1x1,
+ HZ_SUBTROPIC | HZ_ZON1),
+ M( 0, MAX_YEAR, 45, 130, STR_2038_FLATS, 95, 15, 6, 2, 1, 0,
+ TILE_SIZE_1x1,
+ HZ_SUBTROPIC | HZ_ZON5 | HZ_ZON4 | HZ_ZON3),
+ M( 0, MAX_YEAR, 8, 90, STR_2012_CHURCH, 200, 3, 2, 0, 0, 0,
+ BUILDING_IS_CHURCH | TILE_SIZE_1x1,
+ HZ_SUBTROPIC | HZ_ZON4 | HZ_ZON3 | HZ_ZON2),
+ M( 0, MAX_YEAR, 18, 80, STR_203F_HOUSES, 80, 7, 3, 1, 0, 2,
+ TILE_SIZE_1x1,
+ HZ_SUBTROPIC | HZ_ZON5 | HZ_ZON4 | HZ_ZON3 | HZ_ZON2),
+ M( 1973, MAX_YEAR, 90, 110, STR_2038_FLATS, 95, 24, 6, 2, 1, 0,
+ TILE_SIZE_1x1,
+ HZ_SUBTROPIC | HZ_ZON5 | HZ_ZON4 | HZ_ZON3),
+ M( 1962, MAX_YEAR, 120, 120, STR_2038_FLATS, 95, 25, 6, 2, 1, 0,
+ TILE_SIZE_1x1,
+ HZ_SUBTROPIC | HZ_ZON5 | HZ_ZON4 | HZ_ZON3),
+ M( 1984, MAX_YEAR, 250, 190, STR_200F_TALL_OFFICE_BLOCK, 140, 80, 8, 3, 4, 0,
+ TILE_SIZE_2x1,
+ HZ_SUBTROPIC | HZ_ZON5 | HZ_ZON4),
+ M( 1984, MAX_YEAR, 0, 190, STR_200F_TALL_OFFICE_BLOCK, 140, 80, 8, 3, 4, 0,
+ TILE_NO_FLAG,
+ HZ_SUBTROPIC),
+ M( 0, MAX_YEAR, 80, 110, STR_2038_FLATS, 95, 23, 6, 2, 1, 0,
+ TILE_SIZE_1x1,
+ HZ_SUBTROPIC | HZ_ZON5 | HZ_ZON4 | HZ_ZON3),
+ M( 1993, MAX_YEAR, 180, 180, STR_200F_TALL_OFFICE_BLOCK, 150, 90, 8, 3, 4, 0,
+ TILE_SIZE_1x1,
+ HZ_SUBTROPIC | HZ_ZON5 | HZ_ZON4 | HZ_ZON3),
+ M( 0, MAX_YEAR, 8, 90, STR_2012_CHURCH, 200, 3, 2, 0, 0, 0,
+ BUILDING_IS_CHURCH | TILE_SIZE_1x1,
+ HZ_TOYLND | HZ_ZON5 | HZ_ZON4 | HZ_ZON3 | HZ_ZON2 | HZ_ZON1),
+ M( 0, MAX_YEAR, 18, 90, STR_203F_HOUSES, 90, 5, 6, 2, 2, 0,
+ TILE_SIZE_1x1,
+ HZ_TOYLND | HZ_ZON5 | HZ_ZON4 | HZ_ZON3 | HZ_ZON2 | HZ_ZON1),
+ M( 0, MAX_YEAR, 7, 70, STR_203F_HOUSES, 50, 3, 3, 1, 1, 0,
+ TILE_SIZE_1x1,
+ HZ_TOYLND | HZ_ZON2 | HZ_ZON1),
+ M( 0, MAX_YEAR, 15, 80, STR_203F_HOUSES, 75, 6, 3, 1, 2, 0,
+ TILE_SIZE_1x1,
+ HZ_TOYLND | HZ_ZON4 | HZ_ZON3 | HZ_ZON2 | HZ_ZON1),
+ M( 0, MAX_YEAR, 17, 80, STR_203F_HOUSES, 75, 6, 3, 1, 2, 0,
+ TILE_SIZE_1x1,
+ HZ_TOYLND | HZ_ZON4 | HZ_ZON3 | HZ_ZON2 | HZ_ZON1),
+ M( 0, MAX_YEAR, 19, 80, STR_203F_HOUSES, 75, 6, 3, 1, 2, 0,
+ TILE_SIZE_1x1,
+ HZ_TOYLND | HZ_ZON4 | HZ_ZON3 | HZ_ZON2 | HZ_ZON1),
+ M( 0, MAX_YEAR, 21, 80, STR_203F_HOUSES, 75, 6, 3, 1, 2, 0,
+ TILE_SIZE_1x1,
+ HZ_TOYLND | HZ_ZON4 | HZ_ZON3 | HZ_ZON2 | HZ_ZON1),
+ M( 0, MAX_YEAR, 75, 160, STR_200F_TALL_OFFICE_BLOCK, 130, 20, 8, 4, 2, 0,
+ TILE_SIZE_1x1,
+ HZ_TOYLND | HZ_ZON5 | HZ_ZON4 | HZ_ZON3),
+ M( 0, MAX_YEAR, 35, 90, STR_203F_HOUSES, 80, 9, 4, 1, 2, 0,
+ TILE_SIZE_1x2,
+ HZ_TOYLND | HZ_ZON5 | HZ_ZON4 | HZ_ZON3 | HZ_ZON2 | HZ_ZON1),
+ M( 0, MAX_YEAR, 0, 90, STR_203F_HOUSES, 80, 0, 4, 1, 2, 0,
+ TILE_NO_FLAG,
+ HZ_NOZNS),
+ M( 0, MAX_YEAR, 85, 150, STR_200F_TALL_OFFICE_BLOCK, 130, 18, 8, 4, 2, 0,
+ TILE_SIZE_1x1,
+ HZ_TOYLND | HZ_ZON5 | HZ_ZON4 | HZ_ZON3),
+ M( 0, MAX_YEAR, 11, 60, STR_2059_IGLOO, 45, 3, 3, 1, 1, 0,
+ TILE_SIZE_1x1,
+ HZ_TOYLND | HZ_ZON1),
+ M( 0, MAX_YEAR, 10, 60, STR_205A_TEPEES, 45, 3, 3, 1, 1, 0,
+ TILE_SIZE_1x1,
+ HZ_TOYLND | HZ_ZON1),
+ M( 0, MAX_YEAR, 67, 140, STR_201A_SHOPS_AND_OFFICES, 130, 22, 8, 4, 0, 4,
+ TILE_SIZE_1x1,
+ HZ_TOYLND | HZ_ZON5 | HZ_ZON4 | HZ_ZON3),
+ M( 0, MAX_YEAR, 86, 145, STR_201A_SHOPS_AND_OFFICES, 130, 23, 8, 4, 0, 4,
+ TILE_SIZE_1x1,
+ HZ_TOYLND | HZ_ZON5 | HZ_ZON4 | HZ_ZON3),
+ M( 0, MAX_YEAR, 95, 165, STR_200F_TALL_OFFICE_BLOCK, 130, 28, 8, 4, 2, 0,
+ TILE_SIZE_1x1,
+ HZ_TOYLND | HZ_ZON5 | HZ_ZON4 | HZ_ZON3),
+ M( 0, MAX_YEAR, 30, 90, STR_2016_STATUE, 70, 10, 4, 1, 2, 0,
+ TILE_SIZE_1x1,
+ HZ_TOYLND | HZ_ZON5 | HZ_ZON4 | HZ_ZON3),
+ M( 0, MAX_YEAR, 25, 75, STR_205B_TEAPOT_HOUSE, 65, 8, 3, 1, 2, 0,
+ TILE_SIZE_1x1,
+ HZ_TOYLND | HZ_ZON5 | HZ_ZON4 | HZ_ZON3 | HZ_ZON2 | HZ_ZON1),
+ M( 0, MAX_YEAR, 18, 85, STR_205C_PIGGY_BANK, 95, 7, 3, 2, 0, 4,
+ TILE_SIZE_1x1,
+ HZ_TOYLND | HZ_ZON5 | HZ_ZON4 | HZ_ZON3 | HZ_ZON2 | HZ_ZON1),
};
-assert_compile(lengthof(_house_more_flags) == HOUSE_MAX);
+#undef M
+assert_compile(lengthof(_original_house_specs) == NEW_HOUSE_OFFSET);
diff --git a/src/town.h b/src/town.h
index ad3b60ee5..3bc81f2b6 100644
--- a/src/town.h
+++ b/src/town.h
@@ -5,9 +5,72 @@
#include "oldpool.h"
#include "player.h"
+#include "functions.h"
+#include "helpers.hpp"
enum {
- INVALID_TOWN = 0xFFFF,
+ HOUSE_NO_CLASS = 0,
+ NEW_HOUSE_OFFSET = 110,
+ HOUSE_MAX = 512,
+ INVALID_TOWN = 0xFFFF,
+ INVALID_HOUSE_ID = 0xFFFF,
+
+ /* There can only be as many classes as there are new houses, plus one for
+ * NO_CLASS, as the original houses don't have classes. */
+ HOUSE_CLASS_MAX = HOUSE_MAX - NEW_HOUSE_OFFSET + 1,
+};
+
+enum BuildingFlags {
+ TILE_NO_FLAG = 0,
+ TILE_SIZE_1x1 = 1U << 0,
+ TILE_NOT_SLOPED = 1U << 1,
+ TILE_SIZE_2x1 = 1U << 2,
+ TILE_SIZE_1x2 = 1U << 3,
+ TILE_SIZE_2x2 = 1U << 4,
+ BUILDING_IS_ANIMATED = 1U << 5,
+ BUILDING_IS_CHURCH = 1U << 6,
+ BUILDING_IS_STADIUM = 1U << 7,
+ BUILDING_HAS_1_TILE = TILE_SIZE_1x1 | TILE_SIZE_2x1 | TILE_SIZE_1x2 | TILE_SIZE_2x2,
+ BUILDING_2_TILES_X = TILE_SIZE_2x1 | TILE_SIZE_2x2,
+ BUILDING_2_TILES_Y = TILE_SIZE_1x2 | TILE_SIZE_2x2,
+ BUILDING_HAS_4_TILES = TILE_SIZE_2x2,
+};
+
+DECLARE_ENUM_AS_BIT_SET(BuildingFlags)
+
+enum HouseZones { ///< Bit Value Meaning
+ HZ_NOZNS = 0x0000, ///< 0 This is just to get rid of zeros, meaning none
+ HZ_ZON1 = 0x0001, ///< 0..4 1,2,4,8,10 which town zones the building can be built in, Zone1 been the further suburb
+ HZ_ZON2 = 0x0002,
+ HZ_ZON3 = 0x0004,
+ HZ_ZON4 = 0x0008,
+ HZ_ZON5 = 0x0010, ///< center of town
+ HZ_ZONALL = 0x001F, ///< 1F This is just to englobe all above types at once
+ HZ_SUBARTC_ABOVE = 0x0800, ///< 11 800 can appear in sub-arctic climate above the snow line
+ HZ_TEMP = 0x1000, ///< 12 1000 can appear in temperate climate
+ HZ_SUBARTC_BELOW = 0x2000, ///< 13 2000 can appear in sub-arctic climate below the snow line
+ HZ_SUBTROPIC = 0x4000, ///< 14 4000 can appear in subtropical climate
+ HZ_TOYLND = 0x8000 ///< 15 8000 can appear in toyland climate
+};
+
+DECLARE_ENUM_AS_BIT_SET(HouseZones)
+
+enum HouseExtraFlags {
+ NO_EXTRA_FLAG = 0,
+ BUILDING_IS_HISTORICAL = 1U << 0, ///< this house will only appear during town generation in random games, thus the historical
+ BUILDING_IS_PROTECTED = 1U << 1, ///< towns and AI will not remove this house, while human players will be able tp
+ SYNCHRONISED_CALLBACK_1B = 1U << 2, ///< synchronized callback 1B will be performed, on multi tile houses
+ CALLBACK_1A_RANDOM_BITS = 1U << 3, ///< callback 1A needs random bits
+};
+
+DECLARE_ENUM_AS_BIT_SET(HouseExtraFlags)
+
+typedef uint16 HouseID;
+typedef uint16 HouseClassID;
+
+struct BuildingCounts {
+ uint8 id_count[HOUSE_MAX];
+ uint8 class_count[HOUSE_CLASS_MAX];
};
struct Town {
@@ -78,8 +141,48 @@ struct Town {
// NOSAVE: UpdateTownRadius updates this given the house count.
uint16 radius[5];
+
+ // NOSAVE: The number of each type of building in the town.
+ BuildingCounts building_counts;
};
+struct HouseSpec {
+ /* Standard properties */
+ Year min_date; ///< introduction year of the house
+ Year max_date; ///< last year it can be built
+ byte population; ///< population (Zero on other tiles in multi tile house.)
+ byte removal_cost; ///< cost multiplier for removing it
+ StringID building_name; ///< building name
+ uint16 remove_rating_decrease; ///< rating decrease if removed
+ byte mail_generation; ///< mail generation multiplier (tile based, as the acceptances below)
+ byte passenger_acceptance; ///< passenger acceptance, given in 1/8th unit, max is 8, as the 3 next properies
+ byte mail_acceptance; ///< mail acceptance
+ byte goods_acceptance; ///< good acceptance
+ byte food_acceptance; ///< food (or fizzy drink) acceptance
+ BuildingFlags building_flags; ///< some flags that describe the house (size, stadium etc...)
+ HouseZones building_availability; ///< where can it be built (climates, zones)
+ bool enabled; ///< the house is still avaible (by default, true.newgrf can disable it, though)
+
+ /* NewHouses properties */
+ HouseID substitute_id; ///< which house this one is based on
+ struct SpriteGroup *spritegroup; ///< pointer to the different sprites of the house
+ HouseID override; ///< which house this one replaces
+ uint16 callback_mask; ///< House callback flags
+ byte random_colour[4]; ///< 4 "random" colours
+ byte probability; ///< Relative probability of appearing (16 is the standard value)
+ HouseExtraFlags extra_flags; ///< some more flags
+ HouseClassID class_id; ///< defines the class this house has (grf file based) @See HouseGetVariable, prop 0x44
+ byte animation_frames; ///< number of animation frames
+ byte animation_speed; ///< amount of time between each of those frames
+ byte processing_time; ///< Periodic refresh multiplier
+
+ /* grf file related properties*/
+ uint8 local_id; ///< id defined by the grf file for this house
+ const struct GRFFile *grffile; ///< grf file that introduced this house
+};
+
+VARDEF HouseSpec _house_specs[HOUSE_MAX];
+
uint32 GetWorldPopulation();
void UpdateTownVirtCoord(Town *t);
@@ -158,6 +261,12 @@ VARDEF const Town** _town_sort;
DECLARE_OLD_POOL(Town, Town, 3, 8000)
+static inline HouseSpec *GetHouseSpecs(HouseID house_id)
+{
+ assert(house_id < HOUSE_MAX);
+ return &_house_specs[house_id];
+}
+
/**
* Check if a Town really exists.
*/
@@ -229,4 +338,9 @@ VARDEF byte _town_sort_order;
VARDEF Town *_cleared_town;
VARDEF int _cleared_town_rating;
+uint OriginalTileRandomiser(uint x, uint y);
+void ResetHouses();
+
+void ClearTownHouse(Town *t, TileIndex tile);
+
#endif /* TOWN_H */
diff --git a/src/town_cmd.cpp b/src/town_cmd.cpp
index 14079e98b..bdc4c6d12 100644
--- a/src/town_cmd.cpp
+++ b/src/town_cmd.cpp
@@ -5,6 +5,7 @@
#include "stdafx.h"
#include "openttd.h"
#include "functions.h"
+#include "debug.h"
#include "strings.h"
#include "road_map.h"
#include "table/strings.h"
@@ -19,6 +20,7 @@
#include "gfx.h"
#include "industry.h"
#include "station.h"
+#include "vehicle.h"
#include "player.h"
#include "news.h"
#include "saveload.h"
@@ -32,6 +34,9 @@
#include "date.h"
#include "table/town_land.h"
#include "genworld.h"
+#include "newgrf.h"
+#include "newgrf_callbacks.h"
+#include "newgrf_house.h"
/**
* Called if a new block is added to the town-pool
@@ -91,7 +96,6 @@ void DestroyTown(Town *t)
static int _grow_town_result;
static bool BuildTownHouse(Town *t, TileIndex tile);
-static void ClearTownHouse(Town *t, TileIndex tile);
static void DoBuildTownHouse(Town *t, TileIndex tile);
static void TownDrawHouseLift(const TileInfo *ti)
@@ -104,25 +108,32 @@ static TownDrawTileProc * const _town_draw_tile_procs[1] = {
TownDrawHouseLift
};
+uint OriginalTileRandomiser(uint x, uint y)
+{
+ uint variant;
+ variant = x >> 4;
+ variant ^= x >> 6;
+ variant ^= y >> 4;
+ variant -= y >> 6;
+ variant &= 3;
+ return variant;
+}
static void DrawTile_Town(TileInfo *ti)
{
const DrawBuildingsTileStruct *dcts;
SpriteID image;
SpriteID pal;
+ HouseID house_id = GetHouseType(ti->tile);
- /* Retrieve pointer to the draw town tile struct */
- {
- /* this "randomizes" on the (up to) 4 variants of a building */
- uint variant;
- variant = ti->x >> 4;
- variant ^= ti->x >> 6;
- variant ^= ti->y >> 4;
- variant -= ti->y >> 6;
- variant &= 3;
- dcts = &_town_draw_tile_data[GetHouseType(ti->tile) << 4 | variant << 2 | GetHouseBuildingStage(ti->tile)];
+ if (house_id >= NEW_HOUSE_OFFSET) {
+ DrawNewHouseTile(ti, house_id);
+ return;
}
+ /* Retrieve pointer to the draw town tile struct */
+ dcts = &_town_draw_tile_data[house_id << 4 | OriginalTileRandomiser(ti->x, ti->y) << 2 | GetHouseBuildingStage(ti->tile)];
+
if (ti->tileh != SLOPE_FLAT) DrawFoundation(ti, ti->tileh);
image = dcts->ground.sprite;
@@ -172,18 +183,23 @@ static void AnimateTile_Town(TileIndex tile)
{
int pos, dest;
+ if (GetHouseType(tile) >= NEW_HOUSE_OFFSET) {
+ AnimateNewHouseTile(tile);
+ return;
+ }
+
if (_tick_counter & 3) return;
// If the house is not one with a lift anymore, then stop this animating.
// Not exactly sure when this happens, but probably when a house changes.
// Before this was just a return...so it'd leak animated tiles..
// That bug seems to have been here since day 1??
- if (!(_housetype_extra_flags[GetHouseType(tile)] & 0x20)) {
+ if (!(GetHouseSpecs(GetHouseType(tile))->building_flags & BUILDING_IS_ANIMATED)) {
DeleteAnimatedTile(tile);
return;
}
- if (!IsLiftMoving(tile)) {
+ if (!LiftHasDestination(tile)) {
int i;
/** Building has 6 floors, number 0 .. 6, where 1 is illegal.
@@ -270,44 +286,53 @@ static void MakeSingleHouseBigger(TileIndex tile)
IncHouseConstructionTick(tile);
if (GetHouseConstructionTick(tile) != 0) return;
- IncHouseBuildingStage(tile); /*increase construction stage of one more step*/
+ if (HASBIT(GetHouseSpecs(GetHouseType(tile))->callback_mask, CBM_CONSTRUCTION_STATE_CHANGE)) {
+ uint16 callback_res = GetHouseCallback(CBID_CONSTRUCTION_STATE_CHANGE, 0, GetHouseType(tile), GetTownByTile(tile), tile);
+ if (callback_res != CALLBACK_FAILED) ChangeHouseAnimationFrame(tile, callback_res);
+ }
- if (GetHouseBuildingStage(tile) == TOWN_HOUSE_COMPLETED){
- /*Now, construction is completed. Can add population of building to the town*/
- ChangePopulation(GetTownByTile(tile), _housetype_population[GetHouseType(tile)]);
+ if (IsHouseCompleted(tile)) {
+ /* Now that construction is complete, we can add the population of the
+ * building to the town. */
+ ChangePopulation(GetTownByTile(tile), GetHouseSpecs(GetHouseType(tile))->population);
}
MarkTileDirtyByTile(tile);
}
static void MakeTownHouseBigger(TileIndex tile)
{
- uint flags = _house_more_flags[GetHouseType(tile)];
- if (flags & 8) MakeSingleHouseBigger(TILE_ADDXY(tile, 0, 0));
- if (flags & 4) MakeSingleHouseBigger(TILE_ADDXY(tile, 0, 1));
- if (flags & 2) MakeSingleHouseBigger(TILE_ADDXY(tile, 1, 0));
- if (flags & 1) MakeSingleHouseBigger(TILE_ADDXY(tile, 1, 1));
+ uint flags = GetHouseSpecs(GetHouseType(tile))->building_flags;
+ if (flags & BUILDING_HAS_1_TILE) MakeSingleHouseBigger(TILE_ADDXY(tile, 0, 0));
+ if (flags & BUILDING_2_TILES_Y) MakeSingleHouseBigger(TILE_ADDXY(tile, 0, 1));
+ if (flags & BUILDING_2_TILES_X) MakeSingleHouseBigger(TILE_ADDXY(tile, 1, 0));
+ if (flags & BUILDING_HAS_4_TILES) MakeSingleHouseBigger(TILE_ADDXY(tile, 1, 1));
}
static void TileLoop_Town(TileIndex tile)
{
- int house;
Town *t;
uint32 r;
+ HouseID house_id = GetHouseType(tile);
+ HouseSpec *hs = GetHouseSpecs(house_id);
+
+ /* NewHouseTileLoop returns false if Callback 21 succeeded, i.e. the house
+ * doesn't exist any more, so don't continue here. */
+ if (house_id >= NEW_HOUSE_OFFSET && !NewHouseTileLoop(tile)) return;
- if (GetHouseBuildingStage(tile) != TOWN_HOUSE_COMPLETED) {
+ if (!IsHouseCompleted(tile)) {
/*Construction is not completed. See if we can go further in construction*/
MakeTownHouseBigger(tile);
return;
}
- house = GetHouseType(tile);
- if ((_housetype_extra_flags[house] & 0x20) && !LiftHasDestination(tile) && CHANCE16(1, 2) && AddAnimatedTile(tile)) BeginLiftMovement(tile);
+ /* If the lift has a destination, it is already an animated tile. */
+ if ((hs->building_flags & BUILDING_IS_ANIMATED) && house_id < NEW_HOUSE_OFFSET && !LiftHasDestination(tile) && CHANCE16(1, 2)) AddAnimatedTile(tile);
t = GetTownByTile(tile);
r = Random();
- if (GB(r, 0, 8) < _housetype_population[house]) {
+ if (GB(r, 0, 8) < hs->population) {
uint amt = GB(r, 0, 8) / 8 + 1;
uint moved;
@@ -317,7 +342,7 @@ static void TileLoop_Town(TileIndex tile)
t->new_act_pass += moved;
}
- if (GB(r, 8, 8) < _housetype_mailamount[house] ) {
+ if (GB(r, 8, 8) < hs->mail_generation) {
uint amt = GB(r, 8, 8) / 8 + 1;
uint moved;
@@ -327,18 +352,18 @@ static void TileLoop_Town(TileIndex tile)
t->new_act_mail += moved;
}
- if (_house_more_flags[house] & 8 && HASBIT(t->flags12, TOWN_IS_FUNDED) && --t->time_until_rebuild == 0) {
- t->time_until_rebuild = GB(r, 16, 6) + 130;
+ _current_player = OWNER_TOWN;
- _current_player = OWNER_TOWN;
+ if (hs->building_flags & BUILDING_HAS_1_TILE && HASBIT(t->flags12, TOWN_IS_FUNDED) && CanDeleteHouse(tile) && --t->time_until_rebuild == 0) {
+ t->time_until_rebuild = GB(r, 16, 6) + 130;
ClearTownHouse(t, tile);
// rebuild with another house?
if (GB(r, 24, 8) >= 12) DoBuildTownHouse(t, tile);
-
- _current_player = OWNER_NONE;
}
+
+ _current_player = OWNER_NONE;
}
static void ClickTile_Town(TileIndex tile)
@@ -348,16 +373,17 @@ static void ClickTile_Town(TileIndex tile)
static int32 ClearTile_Town(TileIndex tile, byte flags)
{
- int house, rating;
+ int rating;
int32 cost;
Town *t;
+ HouseSpec *hs = GetHouseSpecs(GetHouseType(tile));
if (flags&DC_AUTO && !(flags&DC_AI_BUILDING)) return_cmd_error(STR_2004_BUILDING_MUST_BE_DEMOLISHED);
+ if (!CanDeleteHouse(tile)) return CMD_ERROR;
- house = GetHouseType(tile);
- cost = _price.remove_house * _housetype_remove_cost[house] >> 8;
+ cost = _price.remove_house * hs->removal_cost >> 8;
- rating = _housetype_remove_ratingmod[house];
+ rating = hs->remove_rating_decrease;
_cleared_town_rating += rating;
_cleared_town = t = GetTownByTile(tile);
@@ -378,18 +404,18 @@ static int32 ClearTile_Town(TileIndex tile, byte flags)
static void GetAcceptedCargo_Town(TileIndex tile, AcceptedCargo ac)
{
- byte type = GetHouseType(tile);
+ HouseSpec *hs = GetHouseSpecs(GetHouseType(tile));
- ac[CT_PASSENGERS] = _housetype_cargo_passengers[type];
- ac[CT_MAIL] = _housetype_cargo_mail[type];
- ac[CT_GOODS] = _housetype_cargo_goods[type];
- ac[CT_FOOD] = _housetype_cargo_food[type];
+ ac[CT_PASSENGERS] = hs->passenger_acceptance;
+ ac[CT_MAIL] = hs->mail_acceptance;
+ ac[CT_GOODS] = hs->goods_acceptance;
+ ac[CT_FOOD] = hs->food_acceptance;
}
static void GetTileDesc_Town(TileIndex tile, TileDesc *td)
{
- td->str = _town_tile_names[GetHouseType(tile)];
- if (GetHouseBuildingStage(tile) != TOWN_HOUSE_COMPLETED) {
+ td->str = GetHouseSpecs(GetHouseType(tile))->building_name;
+ if (!IsHouseCompleted(tile)) {
SetDParamX(td->dparam, 0, td->str);
td->str = STR_2058_UNDER_CONSTRUCTION;
}
@@ -1186,10 +1212,11 @@ static void DoBuildTownHouse(Town *t, TileIndex tile)
{
int i;
uint bitmask;
- int house;
+ HouseID house;
Slope slope;
uint z;
uint oneof = 0;
+ HouseSpec *hs;
// Above snow?
slope = GetTileSlope(tile, &z);
@@ -1208,45 +1235,63 @@ static void DoBuildTownHouse(Town *t, TileIndex tile)
// bits 11-15 are used
// bits 5-10 are not used.
{
- byte houses[lengthof(_housetype_flags)];
+ HouseID houses[HOUSE_MAX];
int num = 0;
+ uint cumulative_probs[HOUSE_MAX];
+ uint probability_max = 0;
// Generate a list of all possible houses that can be built.
- for (i=0; i!=lengthof(_housetype_flags); i++) {
- if ((~_housetype_flags[i] & bitmask) == 0)
- houses[num++] = (byte)i;
+ for (i = 0; i < HOUSE_MAX; i++) {
+ hs = GetHouseSpecs(i);
+ if ((~hs->building_availability & bitmask) == 0 && hs->enabled) {
+ if (_have_newhouses) {
+ probability_max += hs->probability;
+ cumulative_probs[num] = probability_max;
+ }
+ houses[num++] = (HouseID)i;
+ }
}
for (;;) {
- house = houses[RandomRange(num)];
+ if (_have_newhouses) {
+ uint r = RandomRange(probability_max);
+ for (i = 0; i < num; i++) if (cumulative_probs[i] >= r) break;
+
+ house = houses[i];
+ } else {
+ house = houses[RandomRange(num)];
+ }
+
+ hs = GetHouseSpecs(house);
+
+ if (_have_newhouses) {
+ if (hs->override != 0) hs = GetHouseSpecs(hs->override);
- if (_cur_year < _housetype_years[house].min || _cur_year > _housetype_years[house].max)
- continue;
+ if ((hs->extra_flags & BUILDING_IS_HISTORICAL) && !_generating_world) continue;
+
+ if (HASBIT(hs->callback_mask, CBM_HOUSE_ALLOW_CONSTRUCTION)) {
+ uint16 callback_res = GetHouseCallback(CBID_HOUSE_ALLOW_CONSTRUCTION, 0, house, t, tile);
+ if (callback_res != CALLBACK_FAILED && callback_res == 0) continue;
+ }
+ }
+
+ if (_cur_year < hs->min_date || _cur_year > hs->max_date) continue;
// Special houses that there can be only one of.
- switch (house) {
- case HOUSE_TEMP_CHURCH:
- case HOUSE_ARCT_CHURCH:
- case HOUSE_SNOW_CHURCH:
- case HOUSE_TROP_CHURCH:
- case HOUSE_TOY_CHURCH:
- SETBIT(oneof, TOWN_HAS_CHURCH);
- break;
- case HOUSE_STADIUM:
- case HOUSE_MODERN_STADIUM:
- SETBIT(oneof, TOWN_HAS_STADIUM);
- break;
- default:
- oneof = 0;
- break;
+ if (hs->building_flags & BUILDING_IS_CHURCH) {
+ SETBIT(oneof, TOWN_HAS_CHURCH);
+ } else if (hs->building_flags & BUILDING_IS_STADIUM) {
+ SETBIT(oneof, TOWN_HAS_STADIUM);
+ } else {
+ oneof = 0;
}
if (HASBITS(t->flags12 , oneof)) continue;
// Make sure there is no slope?
- if (_housetype_extra_flags[house] & 0x12 && slope != SLOPE_FLAT) continue;
+ if (hs->building_flags & TILE_NOT_SLOPED && slope != SLOPE_FLAT) continue;
- if (_housetype_extra_flags[house] & 0x10) {
+ if (hs->building_flags & TILE_SIZE_2x2) {
if (CheckFree2x2Area(tile) ||
CheckFree2x2Area(tile += TileDiffXY(-1, 0)) ||
CheckFree2x2Area(tile += TileDiffXY( 0, -1)) ||
@@ -1254,14 +1299,14 @@ static void DoBuildTownHouse(Town *t, TileIndex tile)
break;
}
tile += TileDiffXY(0, 1);
- } else if (_housetype_extra_flags[house] & 4) {
+ } else if (hs->building_flags & TILE_SIZE_2x1) {
if (CheckBuildHouseMode(tile + TileDiffXY(1, 0), slope, 0)) break;
if (CheckBuildHouseMode(tile + TileDiffXY(-1, 0), slope, 1)) {
tile += TileDiffXY(-1, 0);
break;
}
- } else if (_housetype_extra_flags[house] & 8) {
+ } else if (hs->building_flags & TILE_SIZE_1x2) {
if (CheckBuildHouseMode(tile + TileDiffXY(0, 1), slope, 2)) break;
if (CheckBuildHouseMode(tile + TileDiffXY(0, -1), slope, 3)) {
@@ -1275,12 +1320,13 @@ static void DoBuildTownHouse(Town *t, TileIndex tile)
}
t->num_houses++;
+ IncreaseBuildingCount(t, house);
// Special houses that there can be only one of.
t->flags12 |= oneof;
{
- byte construction_counter = 0, construction_stage = 0, size_flags;
+ byte construction_counter = 0, construction_stage = 0;
if (_generating_world) {
uint32 r = Random();
@@ -1289,13 +1335,12 @@ static void DoBuildTownHouse(Town *t, TileIndex tile)
if (CHANCE16(1, 7)) construction_stage = GB(r, 0, 2);
if (construction_stage == TOWN_HOUSE_COMPLETED) {
- ChangePopulation(t, _housetype_population[house]);
+ ChangePopulation(t, hs->population);
} else {
construction_counter = GB(r, 2, 2);
}
}
- size_flags = GB(_housetype_extra_flags[house], 2, 3);
- MakeTownHouse(tile, t->index, construction_counter, construction_stage, size_flags, house);
+ MakeTownHouse(tile, t->index, construction_counter, construction_stage, house, VehicleRandomBits());
}
}
@@ -1321,60 +1366,54 @@ static void DoClearTownHouseHelper(TileIndex tile)
DeleteAnimatedTile(tile);
}
-static void ClearTownHouse(Town *t, TileIndex tile)
+void ClearTownHouse(Town *t, TileIndex tile)
{
- uint house = GetHouseType(tile);
+ HouseID house = GetHouseType(tile);
uint eflags;
+ HouseSpec *hs;
assert(IsTileType(tile, MP_HOUSE));
// need to align the tile to point to the upper left corner of the house
if (house >= 3) { // house id 0,1,2 MUST be single tile houses, or this code breaks.
- if (_housetype_extra_flags[house-1] & 0x04) {
+ if (GetHouseSpecs(house-1)->building_flags & TILE_SIZE_2x1) {
house--;
tile += TileDiffXY(-1, 0);
- } else if (_housetype_extra_flags[house-1] & 0x18) {
+ } else if (GetHouseSpecs(house-1)->building_flags & BUILDING_2_TILES_Y) {
house--;
tile += TileDiffXY(0, -1);
- } else if (_housetype_extra_flags[house-2] & 0x10) {
+ } else if (GetHouseSpecs(house-2)->building_flags & BUILDING_HAS_4_TILES) {
house-=2;
tile += TileDiffXY(-1, 0);
- } else if (_housetype_extra_flags[house-3] & 0x10) {
+ } else if (GetHouseSpecs(house-3)->building_flags & BUILDING_HAS_4_TILES) {
house-=3;
tile += TileDiffXY(-1, -1);
}
}
+ hs = GetHouseSpecs(house);
+
// Remove population from the town if the house is finished.
- if (GetHouseBuildingStage(tile) == TOWN_HOUSE_COMPLETED) {
- ChangePopulation(t, -_housetype_population[house]);
+ if (IsHouseCompleted(tile)) {
+ ChangePopulation(t, -hs->population);
}
t->num_houses--;
+ DecreaseBuildingCount(t, house);
// Clear flags for houses that only may exist once/town.
- switch (house) {
- case HOUSE_TEMP_CHURCH:
- case HOUSE_ARCT_CHURCH:
- case HOUSE_SNOW_CHURCH:
- case HOUSE_TROP_CHURCH:
- case HOUSE_TOY_CHURCH:
- CLRBIT(t->flags12, TOWN_HAS_CHURCH);
- break;
- case HOUSE_STADIUM:
- case HOUSE_MODERN_STADIUM:
- CLRBIT(t->flags12, TOWN_HAS_STADIUM);
- break;
- default:
- break;
+ if (hs->building_flags & BUILDING_IS_CHURCH) {
+ CLRBIT(t->flags12, TOWN_HAS_CHURCH);
+ } else if (hs->building_flags & BUILDING_IS_STADIUM) {
+ CLRBIT(t->flags12, TOWN_HAS_STADIUM);
}
// Do the actual clearing of tiles
- eflags = _housetype_extra_flags[house];
+ eflags = hs->building_flags;
DoClearTownHouseHelper(tile);
- if (eflags & 0x14) DoClearTownHouseHelper(tile + TileDiffXY(1, 0));
- if (eflags & 0x18) DoClearTownHouseHelper(tile + TileDiffXY(0, 1));
- if (eflags & 0x10) DoClearTownHouseHelper(tile + TileDiffXY(1, 1));
+ if (eflags & BUILDING_2_TILES_X) DoClearTownHouseHelper(tile + TileDiffXY(1, 0));
+ if (eflags & BUILDING_2_TILES_Y) DoClearTownHouseHelper(tile + TileDiffXY(0, 1));
+ if (eflags & BUILDING_HAS_4_TILES) DoClearTownHouseHelper(tile + TileDiffXY(1, 1));
}
/** Rename a town (server-only).
@@ -1922,6 +1961,37 @@ static const SaveLoad _town_desc[] = {
SLE_END()
};
+/* Save and load the mapping between the house id on the map, and the grf file
+ * it came from. */
+static const SaveLoad _house_id_mapping_desc[] = {
+ SLE_VAR(HouseIDMapping, grfid, SLE_UINT32),
+ SLE_VAR(HouseIDMapping, house_id, SLE_UINT8),
+ SLE_VAR(HouseIDMapping, substitute_id, SLE_UINT8),
+ SLE_END()
+};
+
+static void Save_HOUSEIDS()
+{
+ uint i;
+
+ for (i = 0; i != lengthof(_house_id_mapping); i++) {
+ SlSetArrayIndex(i);
+ SlObject(&_house_id_mapping[i], _house_id_mapping_desc);
+ }
+}
+
+static void Load_HOUSEIDS()
+{
+ int index;
+
+ ResetHouseIDMapping();
+
+ while ((index = SlIterateArray()) != -1) {
+ if ((uint)index >= lengthof(_house_id_mapping)) break;
+ SlObject(&_house_id_mapping[index], _house_id_mapping_desc);
+ }
+}
+
static void Save_TOWN()
{
Town *t;
@@ -1966,7 +2036,13 @@ void AfterLoadTown()
_town_sort_dirty = true;
}
-
extern const ChunkHandler _town_chunk_handlers[] = {
- { 'CITY', Save_TOWN, Load_TOWN, CH_ARRAY | CH_LAST},
+ { 'HIDS', Save_HOUSEIDS, Load_HOUSEIDS, CH_ARRAY },
+ { 'CITY', Save_TOWN, Load_TOWN, CH_ARRAY | CH_LAST},
};
+
+void ResetHouses()
+{
+ memset(&_house_specs, 0, sizeof(_house_specs));
+ memcpy(&_house_specs, &_original_house_specs, sizeof(_original_house_specs));
+}
diff --git a/src/town_map.h b/src/town_map.h
index fe4bee33e..cf20e9c9a 100644
--- a/src/town_map.h
+++ b/src/town_map.h
@@ -6,7 +6,14 @@
#define TOWN_MAP_H
#include "town.h"
+#include "date.h"
+/**
+ * Get the index of which town this house/street is attached to.
+ * @param t the tile
+ * @pre IsTileType(t, MP_HOUSE) or IsTileType(t, MP_STREET)
+ * @return TownID
+ */
static inline TownID GetTownIndex(TileIndex t)
{
assert(IsTileType(t, MP_HOUSE) || IsTileType(t, MP_STREET)); // XXX incomplete
@@ -15,13 +22,14 @@ static inline TownID GetTownIndex(TileIndex t)
/**
* Set the town index for a road or house tile.
- * @param tile the tile
+ * @param t the tile
+ * @pre IsTileType(t, MP_HOUSE) or IsTileType(t, MP_STREET)
* @param index the index of the town
* @pre IsTileType(t, MP_STREET) || IsTileType(t, MP_HOUSE)
*/
static inline void SetTownIndex(TileIndex t, TownID index)
{
- assert(IsTileType(t, MP_STREET) || IsTileType(t, MP_HOUSE));
+ assert(IsTileType(t, MP_HOUSE) || IsTileType(t, MP_STREET));
_m[t].m2 = index;
}
@@ -35,84 +43,189 @@ static inline Town* GetTownByTile(TileIndex t)
return GetTown(GetTownIndex(t));
}
+/**
+ * Get the type of this house, which is an index into the house spec array
+ * Since m4 is only a byte and we want to support 512 houses, we use the bit 6
+ * of m3 as an additional bit to house type.
+ * @param t the tile
+ * @pre IsTileType(t, MP_HOUSE)
+ * @return house type
+ */
+static inline HouseID GetHouseType(TileIndex t)
+{
+ assert(IsTileType(t, MP_HOUSE));
+ return _m[t].m4 | (GB(_m[t].m3, 6, 1) << 8);
+}
-static inline int GetHouseType(TileIndex t)
+/**
+ * Set the house type.
+ * @param t the tile
+ * @param house_id the new house type
+ * @pre IsTileType(t, MP_HOUSE)
+ */
+static inline void SetHouseType(TileIndex t, HouseID house_id)
{
assert(IsTileType(t, MP_HOUSE));
- return _m[t].m4;
+ _m[t].m4 = GB(house_id, 0, 8);
+ SB(_m[t].m3, 6, 1, GB(house_id, 8, 1));
}
+/**
+ * Check if the lift of this animated house has a destination
+ * @param t the tile
+ * @return has destination
+ */
static inline bool LiftHasDestination(TileIndex t)
{
- return HASBIT(_m[t].m5, 7);
+ return HASBIT(_me[t].m7, 0);
}
+/**
+ * Set the new destination of the lift for this animated house, and activate
+ * the LiftHasDestination bit.
+ * @param t the tile
+ * @param dest new destination
+ */
static inline void SetLiftDestination(TileIndex t, byte dest)
{
- SB(_m[t].m5, 0, 6, dest);
- SETBIT(_m[t].m1, 7); /* Start moving */
+ SETBIT(_me[t].m7, 0);
+ SB(_me[t].m7, 1, 3, dest);
}
+/**
+ * Get the current destination for this lift
+ * @param t the tile
+ * @return destination
+ */
static inline byte GetLiftDestination(TileIndex t)
{
- return GB(_m[t].m5, 0, 6);
+ return GB(_me[t].m7, 1, 3);
}
-static inline bool IsLiftMoving(TileIndex t)
+/**
+ * Stop the lift of this animated house from moving.
+ * Clears the first 4 bits of m7 at once, clearing the LiftHasDestination bit
+ * and the destination.
+ * @param t the tile
+ */
+static inline void HaltLift(TileIndex t)
{
- return HASBIT(_m[t].m1, 7);
+ SB(_me[t].m7, 0, 4, 0);
+ DeleteAnimatedTile(t);
}
-static inline void BeginLiftMovement(TileIndex t)
+/**
+ * Get the position of the lift on this animated house
+ * @param t the tile
+ * @return position, from 0 to 36
+ */
+static inline byte GetLiftPosition(TileIndex t)
{
- SETBIT(_m[t].m5, 7);
+ return GB(_m[t].m6, 2, 6);
}
-static inline void HaltLift(TileIndex t)
+/**
+ * Set the position of the lift on this animated house
+ * @param t the tile
+ * @param pos, from 0 to 36
+ */
+static inline void SetLiftPosition(TileIndex t, byte pos)
{
- CLRBIT(_m[t].m1, 7);
- CLRBIT(_m[t].m5, 7);
- SB(_m[t].m5, 0, 6, 0);
+ SB(_m[t].m6, 2, 6, pos);
+}
- DeleteAnimatedTile(t);
+/**
+ * Get the current animation frame for this house
+ * @param t the tile
+ * @pre IsTileType(t, MP_HOUSE)
+ * @return frame number
+ */
+static inline byte GetHouseAnimationFrame(TileIndex t)
+{
+ assert(IsTileType(t, MP_HOUSE));
+ return GB(_m[t].m6, 3, 5);
}
-static inline byte GetLiftPosition(TileIndex t)
+/**
+ * Set a new animation frame for this house
+ * @param t the tile
+ * @param frame the new frame number
+ * @pre IsTileType(t, MP_HOUSE)
+ */
+static inline void SetHouseAnimationFrame(TileIndex t, byte frame)
{
- return GB(_m[t].m1, 0, 7);
+ assert(IsTileType(t, MP_HOUSE));
+ SB(_m[t].m6, 3, 5, frame);
}
-static inline void SetLiftPosition(TileIndex t, byte pos)
+/**
+ * Get the completion of this house
+ * @param t the tile
+ * @return true if it is, false if it is not
+ */
+static inline bool IsHouseCompleted(TileIndex t)
{
- SB(_m[t].m1, 0, 7, pos);
+ assert(IsTileType(t, MP_HOUSE));
+ return HASBIT(_m[t].m3, 7);
}
-static inline void MakeHouseTile(TileIndex t, TownID tid, byte counter, byte stage, byte type)
+/**
+ * Mark this house as been completed
+ * @param t the tile
+ * @param status
+ */
+static inline void SetHouseCompleted(TileIndex t, bool status)
+{
+ assert(IsTileType(t, MP_HOUSE));
+ SB(_m[t].m3, 7, 1, !!status);
+}
+
+/**
+ * Make the tile a house.
+ * @param t tile index
+ * @param tid Town index
+ * @param counter of construction step
+ * @param stage of construction (used for drawing)
+ * @param type of house. Index into house specs array
+ * @param random_bits required for newgrf houses
+ * @pre IsTileType(t, MP_CLEAR)
+ */
+static inline void MakeHouseTile(TileIndex t, TownID tid, byte counter, byte stage, HouseID type, byte random_bits)
{
assert(IsTileType(t, MP_CLEAR));
SetTileType(t, MP_HOUSE);
- _m[t].m1 = 0;
+ _m[t].m1 = random_bits;
_m[t].m2 = tid;
- SB(_m[t].m3, 6, 2, stage);
- _m[t].m4 = type;
- SB(_m[t].m5, 0, 2, counter);
+ _m[t].m3 = 0;
+ SetHouseType(t, type);
+ SetHouseCompleted(t, stage == TOWN_HOUSE_COMPLETED);
+ _m[t].m5 = IsHouseCompleted(t) ? 0 : (stage << 3 | counter);
+ SetHouseAnimationFrame(t, 0);
+ _me[t].m7 = GetHouseSpecs(type)->processing_time;
+ if (GetHouseSpecs(type)->building_flags & BUILDING_IS_ANIMATED) AddAnimatedTile(t);
MarkTileDirtyByTile(t);
}
-enum {
- TWO_BY_TWO_BIT = 2, ///< House is two tiles in X and Y directions
- ONE_BY_TWO_BIT = 1, ///< House is two tiles in Y direction
- TWO_BY_ONE_BIT = 0, ///< House is two tiles in X direction
-};
-
-static inline void MakeTownHouse(TileIndex t, TownID tid, byte counter, byte stage, byte size, byte type)
+/**
+ * Helper function for MakeHouseTile.
+ * It is called for each tile of a multi-tile house.
+ * Parametes are the same.
+ * @param t tile index
+ * @param tid Town index
+ * @param counter of construction step
+ * @param stage of construction (used for drawing)
+ * @param type of house. Index into house specs array
+ * @param random_bits required for newgrf houses
+ */
+static inline void MakeTownHouse(TileIndex t, TownID tid, byte counter, byte stage, HouseID type, byte random_bits)
{
- MakeHouseTile(t, tid, counter, stage, type);
- if (HASBIT(size, TWO_BY_TWO_BIT) || HASBIT(size, ONE_BY_TWO_BIT)) MakeHouseTile(t + TileDiffXY(0, 1), tid, counter, stage, ++type);
- if (HASBIT(size, TWO_BY_TWO_BIT) || HASBIT(size, TWO_BY_ONE_BIT)) MakeHouseTile(t + TileDiffXY(1, 0), tid, counter, stage, ++type);
- if (HASBIT(size, TWO_BY_TWO_BIT)) MakeHouseTile(t + TileDiffXY(1, 1), tid, counter, stage, ++type);
+ BuildingFlags size = GetHouseSpecs(type)->building_flags;
+ MakeHouseTile(t, tid, counter, stage, type, random_bits);
+ if (size & BUILDING_2_TILES_Y) MakeHouseTile(t + TileDiffXY(0, 1), tid, counter, stage, ++type, random_bits);
+ if (size & BUILDING_2_TILES_X) MakeHouseTile(t + TileDiffXY(1, 0), tid, counter, stage, ++type, random_bits);
+ if (size & BUILDING_HAS_4_TILES) MakeHouseTile(t + TileDiffXY(1, 1), tid, counter, stage, ++type, random_bits);
}
/**
@@ -120,81 +233,143 @@ static inline void MakeTownHouse(TileIndex t, TownID tid, byte counter, byte sta
* Construction counter, for buildings under construction. Incremented on every
* periodic tile processing.
* On wraparound, the stage of building in is increased.
- * (Get|Set|Inc)HouseBuildingStage are taking care of the real stages,
+ * GetHouseBuildingStage is taking care of the real stages,
* (as the sprite for the next phase of house building)
- * (Get|Set|Inc)HouseConstructionTick is simply a tick counter between the
+ * (Get|Inc)HouseConstructionTick is simply a tick counter between the
* different stages
*/
/**
* Gets the building stage of a house
- * @param tile the tile of the house to get the building stage of
+ * Since the stage is used for determining what sprite to use,
+ * if the house is complete (and that stage no longuer is available),
+ * fool the system by returning the TOWN_HOUSE_COMPLETE (3),
+ * thus showing a beautiful complete house.
+ * @param t the tile of the house to get the building stage of
* @pre IsTileType(t, MP_HOUSE)
* @return the building stage of the house
*/
static inline byte GetHouseBuildingStage(TileIndex t)
{
assert(IsTileType(t, MP_HOUSE));
- return GB(_m[t].m3, 6, 2);
+ return IsHouseCompleted(t) ? (byte)TOWN_HOUSE_COMPLETED : GB(_m[t].m5, 3, 2);
}
/**
- * Sets the building stage of a house
- * @param tile the tile of the house to set the building stage of
- * @param stage the new stage
+ * Gets the construction stage of a house
+ * @param t the tile of the house to get the construction stage of
* @pre IsTileType(t, MP_HOUSE)
+ * @return the construction stage of the house
*/
-static inline void SetHouseBuildingStage(TileIndex t, byte stage)
+static inline byte GetHouseConstructionTick(TileIndex t)
{
assert(IsTileType(t, MP_HOUSE));
- SB(_m[t].m3, 6, 2, stage);
+ return IsHouseCompleted(t) ? 0 : GB(_m[t].m5, 0, 3);
}
/**
- * Increments the building stage of a house
- * @param tile the tile of the house to increment the building stage of
+ * Sets the increment stage of a house
+ * It is working with the whole counter + stage 5 bits, making it
+ * easier to work: the wraparound is automatic.
+ * @param t the tile of the house to increment the construction stage of
* @pre IsTileType(t, MP_HOUSE)
*/
-static inline void IncHouseBuildingStage( TileIndex t )
+static inline void IncHouseConstructionTick(TileIndex t)
{
assert(IsTileType(t, MP_HOUSE));
- AB(_m[t].m3, 6, 2, 1);
+ AB(_m[t].m5, 0, 5, 1);
+
+ if (GB(_m[t].m5, 3, 2) == TOWN_HOUSE_COMPLETED) {
+ /* House is now completed.
+ * Store the year of construction as well, for newgrf house purpose */
+ SetHouseCompleted(t, true);
+ _m[t].m5 = clamp(_cur_year - ORIGINAL_BASE_YEAR, 0, 0xFF);
+ }
}
/**
- * Gets the construction stage of a house
- * @param tile the tile of the house to get the construction stage of
+ * Get the year that this house was constructed (between 1920 and 2175).
+ * @param t the tile of this house
* @pre IsTileType(t, MP_HOUSE)
- * @return the construction stage of the house
+ * @return year
*/
-static inline byte GetHouseConstructionTick(TileIndex t)
+static inline Year GetHouseConstructionYear(TileIndex t)
{
assert(IsTileType(t, MP_HOUSE));
- return GB(_m[t].m5, 0, 3);
+ return IsHouseCompleted(t) ? _m[t].m5 + ORIGINAL_BASE_YEAR : 0;
}
/**
- * Sets the construction stage of a house
- * @param tile the tile of the house to set the construction stage of
- * @param stage the new stage
+ * Get the random bits for this house.
+ * This is required for newgrf house
+ * @param t the tile of this house
* @pre IsTileType(t, MP_HOUSE)
+ * @return random bits
*/
-static inline void SetHouseConstructionTick(TileIndex t, byte stage)
+static inline byte GetHouseRandomBits(TileIndex t)
{
assert(IsTileType(t, MP_HOUSE));
- SB(_m[t].m5, 0, 3, stage);
+ return _m[t].m1;
}
/**
- * Sets the increment stage of a house
- * @param tile the tile of the house to increment the construction stage of
+ * Set the activated triggers bits for this house.
+ * This is required for newgrf house
+ * @param t the tile of this house
* @pre IsTileType(t, MP_HOUSE)
*/
-static inline void IncHouseConstructionTick(TileIndex t)
+static inline void SetHouseTriggers(TileIndex t, byte triggers)
+{
+ assert(IsTileType(t, MP_HOUSE));
+ SB(_m[t].m3, 0, 5, triggers);
+}
+
+/**
+ * Get the already activated triggers bits for this house.
+ * This is required for newgrf house
+ * @param t the tile of this house
+ * @pre IsTileType(t, MP_HOUSE)
+ * @return triggers
+ */
+static inline byte GetHouseTriggers(TileIndex t)
+{
+ assert(IsTileType(t, MP_HOUSE));
+ return GB(_m[t].m3, 0, 5);
+}
+
+/**
+ * Get the amount of time remaining before the tile loop processes this tile.
+ * @param t the house tile
+ * @pre IsTileType(t, MP_HOUSE)
+ * @return time remaining
+ */
+static inline byte GetHouseProcessingTime(TileIndex t)
{
assert(IsTileType(t, MP_HOUSE));
- AB(_m[t].m5, 0, 3, 1);
+ return _me[t].m7;
}
+/**
+ * Set the amount of time remaining before the tile loop processes this tile.
+ * @param t the house tile
+ * @param time the time to be set
+ * @pre IsTileType(t, MP_HOUSE)
+ */
+static inline void SetHouseProcessingTime(TileIndex t, byte time)
+{
+ assert(IsTileType(t, MP_HOUSE));
+ _me[t].m7 = time;
+}
+
+/**
+ * Decrease the amount of time remaining before the tile loop processes this tile.
+ * @param t the house tile
+ * @pre IsTileType(t, MP_HOUSE)
+ */
+static inline void DecHouseProcessingTime(TileIndex t)
+{
+ assert(IsTileType(t, MP_HOUSE));
+ _me[t].m7--;
+}
#endif /* TOWN_MAP_H */
diff --git a/src/void_map.h b/src/void_map.h
index 21658746e..06c2570f9 100644
--- a/src/void_map.h
+++ b/src/void_map.h
@@ -13,6 +13,7 @@ static inline void MakeVoid(TileIndex t)
_m[t].m4 = 0;
_m[t].m5 = 0;
_m[t].m6 = 0;
+ _me[t].m7 = 0;
}
#endif /* VOID_MAP_H */