diff --git a/bin/ai/regression/regression.nut b/bin/ai/regression/regression.nut
index 82154c9dbe..7ec415639e 100644
--- a/bin/ai/regression/regression.nut
+++ b/bin/ai/regression/regression.nut
@@ -1077,9 +1077,10 @@ function Regression::Sign()
print(" BuildSign(33409, 'Some other Sign'): " + sign_id);
print(" RemoveSign(" + sign_id + "): " + AISign.RemoveSign(sign_id));
print("");
- print(" GetMaxSignID(): " + AISign.GetMaxSignID());
- for (local i = -1; i < AISign.GetMaxSignID() + 1; i++) {
- if (AISign.IsValidSign(i)) j++;
+ local list = AISignList();
+ list.Sort(AIAbstractList.SORT_BY_ITEM, true);
+ for (local i = list.Begin(); list.HasNext(); i = list.Next()) {
+ j++;
print(" Sign " + i);
print(" IsValidSign(): " + AISign.IsValidSign(i));
print(" GetName(): " + AISign.GetName(i));
diff --git a/bin/ai/regression/regression.txt b/bin/ai/regression/regression.txt
index d19c93605a..c6745d0565 100644
--- a/bin/ai/regression/regression.txt
+++ b/bin/ai/regression/regression.txt
@@ -7242,11 +7242,6 @@
BuildSign(33409, 'Some other Sign'): 2
RemoveSign(2): true
- GetMaxSignID(): 3
- Sign -1
- IsValidSign(): false
- GetName(): (null : 0x00000000)
- GetLocation(): -1
Sign 0
IsValidSign(): true
GetName(): Some Sign
@@ -7255,14 +7250,6 @@
IsValidSign(): true
GetName(): Test2
GetLocation(): 33411
- Sign 2
- IsValidSign(): false
- GetName(): (null : 0x00000000)
- GetLocation(): -1
- Sign 3
- IsValidSign(): false
- GetName(): (null : 0x00000000)
- GetLocation(): -1
Valid Signs: 2
--Station--
diff --git a/projects/openttd_vs80.vcproj b/projects/openttd_vs80.vcproj
index ff547623b0..37273e8b12 100644
--- a/projects/openttd_vs80.vcproj
+++ b/projects/openttd_vs80.vcproj
@@ -2659,6 +2659,10 @@
RelativePath=".\..\src\ai\api\ai_sign.hpp"
>
+
+
@@ -2863,6 +2867,10 @@
RelativePath=".\..\src\ai\api\ai_sign.cpp"
>
+
+
diff --git a/projects/openttd_vs90.vcproj b/projects/openttd_vs90.vcproj
index ee5c4a1e4b..283fcda362 100644
--- a/projects/openttd_vs90.vcproj
+++ b/projects/openttd_vs90.vcproj
@@ -2656,6 +2656,10 @@
RelativePath=".\..\src\ai\api\ai_sign.hpp"
>
+
+
@@ -2860,6 +2864,10 @@
RelativePath=".\..\src\ai\api\ai_sign.cpp"
>
+
+
diff --git a/source.list b/source.list
index 6622024693..508cd10efb 100644
--- a/source.list
+++ b/source.list
@@ -620,6 +620,7 @@ ai/api/ai_rail.hpp
ai/api/ai_railtypelist.hpp
ai/api/ai_road.hpp
ai/api/ai_sign.hpp
+ai/api/ai_signlist.hpp
ai/api/ai_station.hpp
ai/api/ai_stationlist.hpp
ai/api/ai_subsidy.hpp
@@ -672,6 +673,7 @@ ai/api/ai_rail.cpp
ai/api/ai_railtypelist.cpp
ai/api/ai_road.cpp
ai/api/ai_sign.cpp
+ai/api/ai_signlist.cpp
ai/api/ai_station.cpp
ai/api/ai_stationlist.cpp
ai/api/ai_subsidy.cpp
diff --git a/src/ai/ai_instance.cpp b/src/ai/ai_instance.cpp
index 0ad34836ba..68be5fdd6d 100644
--- a/src/ai/ai_instance.cpp
+++ b/src/ai/ai_instance.cpp
@@ -60,6 +60,7 @@
#include "api/ai_railtypelist.hpp.sq"
#include "api/ai_road.hpp.sq"
#include "api/ai_sign.hpp.sq"
+#include "api/ai_signlist.hpp.sq"
#include "api/ai_station.hpp.sq"
#include "api/ai_stationlist.hpp.sq"
#include "api/ai_subsidy.hpp.sq"
@@ -212,6 +213,7 @@ void AIInstance::RegisterAPI()
SQAIRailTypeList_Register(this->engine);
SQAIRoad_Register(this->engine);
SQAISign_Register(this->engine);
+ SQAISignList_Register(this->engine);
SQAIStation_Register(this->engine);
SQAIStationList_Register(this->engine);
SQAIStationList_Vehicle_Register(this->engine);
diff --git a/src/ai/api/ai_sign.hpp b/src/ai/api/ai_sign.hpp
index 441b9b3493..f6f0a422a5 100644
--- a/src/ai/api/ai_sign.hpp
+++ b/src/ai/api/ai_sign.hpp
@@ -30,6 +30,7 @@ public:
/**
* Gets the maximum sign index; there are no valid signs with a higher index.
+ * @deprecated This function is deprecated and might be removed in future versions of the API. Use AISignList() instead.
* @return The maximum sign index.
* @post Return value is always non-negative.
*/
diff --git a/src/ai/api/ai_signlist.cpp b/src/ai/api/ai_signlist.cpp
new file mode 100644
index 0000000000..33cb7fed4e
--- /dev/null
+++ b/src/ai/api/ai_signlist.cpp
@@ -0,0 +1,15 @@
+/* $Id$ */
+
+/** @file ai_signlist.cpp Implementation of AISignList and friends. */
+
+#include "ai_signlist.hpp"
+#include "ai_sign.hpp"
+#include "../../signs_base.h"
+
+AISignList::AISignList()
+{
+ Sign *s;
+ FOR_ALL_SIGNS(s) {
+ if (AISign::IsValidSign(s->index)) this->AddItem(s->index);
+ }
+}
diff --git a/src/ai/api/ai_signlist.hpp b/src/ai/api/ai_signlist.hpp
new file mode 100644
index 0000000000..17faa9a80e
--- /dev/null
+++ b/src/ai/api/ai_signlist.hpp
@@ -0,0 +1,20 @@
+/* $Id$ */
+
+/** @file ai_signlist.hpp List all the signs of your company. */
+
+#ifndef AI_SIGNLIST_HPP
+#define AI_SIGNLIST_HPP
+
+#include "ai_abstractlist.hpp"
+
+/**
+ * Create a list of signs your company has created.
+ * @ingroup AIList
+ */
+class AISignList : public AIAbstractList {
+public:
+ static const char *GetClassName() { return "AISignList"; }
+ AISignList();
+};
+
+#endif /* AI_SIGNLIST_HPP */
diff --git a/src/ai/api/ai_signlist.hpp.sq b/src/ai/api/ai_signlist.hpp.sq
new file mode 100644
index 0000000000..b350e86f60
--- /dev/null
+++ b/src/ai/api/ai_signlist.hpp.sq
@@ -0,0 +1,21 @@
+/* $Id$ */
+/* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */
+
+#include "ai_signlist.hpp"
+
+namespace SQConvert {
+ /* Allow AISignList to be used as Squirrel parameter */
+ template <> AISignList *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (AISignList *)instance; }
+ template <> AISignList &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(AISignList *)instance; }
+ template <> const AISignList *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (AISignList *)instance; }
+ template <> const AISignList &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(AISignList *)instance; }
+ template <> int Return(HSQUIRRELVM vm, AISignList *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "AISignList", res, NULL, DefSQDestructorCallback); return 1; }
+}; // namespace SQConvert
+
+void SQAISignList_Register(Squirrel *engine) {
+ DefSQClass SQAISignList("AISignList");
+ SQAISignList.PreRegister(engine, "AIAbstractList");
+ SQAISignList.AddConstructor(engine, "x");
+
+ SQAISignList.PostRegister(engine);
+}
diff --git a/src/console_cmds.cpp b/src/console_cmds.cpp
index 058aa77df9..c6a3c8cd73 100644
--- a/src/console_cmds.cpp
+++ b/src/console_cmds.cpp
@@ -1518,6 +1518,8 @@ bool NetworkChangeCompanyPassword(byte argc, char *argv[])
return true;
}
+/* Content downloading only is available with ZLIB */
+#if defined(WITH_ZLIB)
#include "network/network_content.h"
/** Resolve a string to a content type. */
@@ -1626,7 +1628,7 @@ DEF_CONSOLE_CMD(ConContent)
return false;
}
-
+#endif /* defined(WITH_ZLIB) */
#endif /* ENABLE_NETWORK */
DEF_CONSOLE_CMD(ConSetting)
@@ -1773,7 +1775,11 @@ void IConsoleStdLibRegister()
#ifdef ENABLE_NETWORK
/* Network hooks; only active in network */
IConsoleCmdHookAdd ("resetengines", ICONSOLE_HOOK_ACCESS, ConHookNoNetwork);
+
+/* Content downloading is only available with ZLIB */
+#if defined(WITH_ZLIB)
IConsoleCmdRegister("content", ConContent);
+#endif /* defined(WITH_ZLIB) */
/*** Networking commands ***/
IConsoleCmdRegister("say", ConSay);
diff --git a/src/economy.cpp b/src/economy.cpp
index 71be0f50fd..2f3d36a5fd 100644
--- a/src/economy.cpp
+++ b/src/economy.cpp
@@ -1366,11 +1366,11 @@ static Money DeliverGoods(int num_pieces, CargoID cargo_type, StationID source,
}
/* Get station pointers. */
- s_from = GetStation(source);
+ s_from = IsValidStationID(source) ? GetStation(source) : NULL;
s_to = GetStation(dest);
/* Check if a subsidy applies. */
- subsidised = CheckSubsidised(s_from, s_to, cargo_type);
+ subsidised = s_from != NULL && CheckSubsidised(s_from, s_to, cargo_type);
/* Increase town's counter for some special goods types */
const CargoSpec *cs = GetCargo(cargo_type);
diff --git a/src/newgrf.cpp b/src/newgrf.cpp
index f0b00fd129..3790d0ad83 100644
--- a/src/newgrf.cpp
+++ b/src/newgrf.cpp
@@ -3478,7 +3478,7 @@ static void FeatureNewName(byte *buf, size_t len)
StringID string = AddGRFString(_cur_grffile->grfid, e->index, lang, new_scheme, name, e->info.string_id);
e->info.string_id = string;
} else {
- AddGRFString(_cur_grffile->grfid, id, lang, new_scheme, name, id);
+ AddGRFString(_cur_grffile->grfid, id, lang, new_scheme, name, STR_UNDEFINED);
}
break;
@@ -5851,6 +5851,16 @@ static void FinaliseHouseArray()
continue;
}
+ /* Some places sum population by only counting north tiles. Other places use all tiles causing desyncs.
+ * As the newgrf specs define population to be zero for non-north tiles, we just disable the offending house.
+ * If you want to allow non-zero populations somewhen, make sure to sum the population of all tiles in all places. */
+ if (((hs->building_flags & BUILDING_HAS_2_TILES) != 0 && next1->population != 0) ||
+ ((hs->building_flags & BUILDING_HAS_4_TILES) != 0 && (next2->population != 0 || next3->population != 0))) {
+ hs->enabled = false;
+ DEBUG(grf, 1, "FinaliseHouseArray: %s defines multitile house %d with non-zero population on additional tiles. Disabling house.", file->filename, hs->local_id);
+ continue;
+ }
+
_house_mngr.SetEntitySpec(hs);
if (hs->min_year < min_year) min_year = hs->min_year;
}
diff --git a/src/newgrf_text.cpp b/src/newgrf_text.cpp
index 9edd243da0..0e5e620f7a 100644
--- a/src/newgrf_text.cpp
+++ b/src/newgrf_text.cpp
@@ -120,7 +120,13 @@ char *TranslateTTDPatchCodes(uint32 grfid, const char *str)
if (unicode && Utf8EncodedCharLen(*str) != 0) {
c = Utf8Consume(&str);
/* 'Magic' range of control codes. */
- if (GB(c, 8, 8) == 0xE0) c = GB(c, 0, 8);
+ if (GB(c, 8, 8) == 0xE0) {
+ c = GB(c, 0, 8);
+ } else if (c >= 0x20) {
+ if (!IsValidChar(c, CS_ALPHANUMERAL)) c = '?';
+ d += Utf8Encode(d, c);
+ continue;
+ }
} else {
c = (byte)*str++;
}
diff --git a/src/spritecache.cpp b/src/spritecache.cpp
index 990f407262..1470522d23 100644
--- a/src/spritecache.cpp
+++ b/src/spritecache.cpp
@@ -306,8 +306,18 @@ void DupSprite(SpriteID old_spr, SpriteID new_spr)
scnew->warned = false;
}
+/**
+ * S_FREE_MASK is used to mask-out lower bits of MemBlock::size
+ * If they are non-zero, the block is free.
+ * S_FREE_MASK has to ensure MemBlock is correctly aligned -
+ * it means 8B (S_FREE_MASK == 7) on 64bit systems!
+ */
+static const size_t S_FREE_MASK = sizeof(size_t) - 1;
-#define S_FREE_MASK 1
+/* to make sure nobody adds things to MemBlock without checking S_FREE_MASK first */
+assert_compile(sizeof(MemBlock) == sizeof(size_t));
+/* make sure it's a power of two */
+assert_compile((sizeof(size_t) & (sizeof(size_t) - 1)) == 0);
static inline MemBlock *NextBlock(MemBlock *block)
{
@@ -439,9 +449,9 @@ void *AllocSprite(size_t mem_req)
{
mem_req += sizeof(MemBlock);
- /* Align this to an uint32 boundary. This also makes sure that the 2 least
- * bits are not used, so we could use those for other things. */
- mem_req = Align(mem_req, sizeof(uint32));
+ /* Align this to correct boundary. This also makes sure at least one
+ * bit is not used, so we can use it for other things. */
+ mem_req = Align(mem_req, S_FREE_MASK + 1);
for (;;) {
MemBlock *s;